failure in go.crypto and GnuPG interoperability

Bernd Fix brf at hoi-polloi.org
Thu Jan 30 13:30:57 CET 2014


I am working on an application that is encrypting content with the
openpgp functions from the go.crypto framework. This content is later to
be decrypted using the GnuPG application on a Linux box. There seems to
be an incompatibility between go.crypto and the GnuPG that fails to
decrypt the original content correctly - the decrypted content for
larger files is smaller than the original input.

I am using Debian7 with the tip version of Go, the current go.crypto
repository and GnuPG 1.4.12. The following steps will reproduce the problem:

(1) create a file with random content (1MB in this case):

    dd if=/dev/urandom of=xxx.in count=2048

(2) create a local keyring for testing:

    gpg --home . --gen-key

I used RSA-4096 keys and "testtest" as a password; if you use a
different password, change the source code of the test app; create only
one key in the keyring!

(3) compile the test app from the source code below:

    go build test.go

(4) Run the test app:

    ./test

The output "Compare: 0" indicates that the encryption/decryption cycle
in go.crypto worked fine and delivered the expected result.

(5) Decrypt output using GnuPG:

    gpg --home . -o xxx.out -d xxx.in.gpg

Compare the two files; you will see something like:

    -rw-r--r-- 1 test test 1048576 Jan 30 13:06 xxx.in
    -rw-r--r-- 1 test test 1044505 Jan 30 13:18 xxx.out


The two files don't match and neither the test app nor GnuPG showed any
warning or error message. Am I doing something wrong or what is going on
here?

Regards, Bernd.

=====[test.go]=================================================

package main

import (
    "bytes"
    "code.google.com/p/go.crypto/openpgp"
    "fmt"
    "io"
    "io/ioutil"
    "os"
)

const (
    FILE  = "xxx.in"
    GNUPG = "secring.gpg"
    PASSP = "testtest"
)

func main() {
    rdr, err := os.Open(GNUPG)
    if err != nil {
        panic(err.Error())
    }
    defer rdr.Close()
    ents, err := openpgp.ReadKeyRing(rdr)
    if err != nil {
        panic(err.Error())
    }

    f, err := os.Open(FILE)
    if err != nil {
        panic(err.Error())
    }
    plain, err := ioutil.ReadAll(f)
    if err != nil {
        panic(err.Error())
    }

    cBuf := new(bytes.Buffer)
    cWrt, err := openpgp.Encrypt(cBuf, ents, nil, nil, nil)
    if err != nil {
        panic(err.Error())
    }
    cWrt.Write(plain)
    cWrt.Close()
    cipher := cBuf.Bytes()

    out, err := os.Create(FILE + ".gpg")
    if err != nil {
        panic(err.Error())
    }
    out.Write(cipher)
    out.Close()

    cBuf = bytes.NewBuffer(cipher)
    pBuf := new(bytes.Buffer)
    md, err := openpgp.ReadMessage(
        cBuf,
        ents,
        func(keys []openpgp.Key, symmetric bool) ([]byte, error) {
            priv := keys[0].PrivateKey
            if priv.Encrypted {
                priv.Decrypt([]byte(PASSP))
            }
            buf := new(bytes.Buffer)
            priv.Serialize(buf)
            return buf.Bytes(), nil
        },
        nil)
    if err != nil {
        panic(err.Error())
    }
    buf := make([]byte, 1024)
    for {
        n, err := md.UnverifiedBody.Read(buf)
        pBuf.Write(buf[:n])
        if err != nil {
            if err == io.EOF {
                err = nil
                break
            }
            panic(err.Error())
        }
    }
    plain2 := pBuf.Bytes()
    fmt.Printf("Compare: %d\n", bytes.Compare(plain, plain2))
}


-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 551 bytes
Desc: OpenPGP digital signature
URL: </pipermail/attachments/20140130/ada41034/attachment.sig>


More information about the Gnupg-devel mailing list