【问题标题】:Issues with openpgp golang gpg libraryopenpgp golang gpg 库的问题
【发布时间】:2014-11-01 03:27:38
【问题描述】:

所以我对 golang 还是很陌生,我正在努力寻找一个使用 openpgp 加密一些文本并再次解密的工作示例。

这是我目前所拥有的:(https://gist.github.com/93750a142d3de4e8fdd2.git)

package main

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

// create gpg keys with
// $ gpg --gen-key
// ensure you correct paths and passphrase

const mysecretstring = "this is so very secret!"
const secretKeyring = "/Users/stuart-warren/.gnupg/secring.gpg"
const publicKeyring = "/Users/stuart-warren/.gnupg/pubring.gpg"
const passphrase = "1234"

func main() {
    log.Printf("Secret: ", mysecretstring)
    log.Printf("Secret Keyring: ", secretKeyring)
    log.Printf("Public Keyring: ", publicKeyring)
    log.Printf("Passphrase: ", passphrase)

    // Read in public key
    keyringFileBuffer, _ := os.Open(publicKeyring)
    defer keyringFileBuffer.Close()
    entitylist, _ := openpgp.ReadKeyRing(keyringFileBuffer)

    // encrypt string
    buf := new(bytes.Buffer)
    w, _ := openpgp.Encrypt(buf, entitylist, nil, nil, nil)
    w.Write([]byte(mysecretstring))

    // Encode to base64
    bytesp, _ := ioutil.ReadAll(buf)
    encstr := base64.StdEncoding.EncodeToString(bytesp)

    // Output encrypted/encoded string
    log.Printf("Encrypted Secret: ", encstr)

    // Here is where I would transfer the encrypted string to someone else 
    // but we'll just decrypt it in the same code

    // init some vars
    var entity2 *openpgp.Entity
    var entitylist2 openpgp.EntityList

    // Open the private key file
    keyringFileBuffer2, _ := os.Open(secretKeyring)
    defer keyringFileBuffer2.Close()
    entitylist2, _ = openpgp.ReadKeyRing(keyringFileBuffer2)
    entity2 = entitylist2[0]

    // Get the passphrase and read the private key.
    // Have not touched the encrypted string yet
    passphrasebyte := []byte(passphrase)
    log.Printf("Decrypting private key using passphrase")
    entity2.PrivateKey.Decrypt(passphrasebyte)
    for _, subkey := range entity2.Subkeys {
            subkey.PrivateKey.Decrypt(passphrasebyte)
    }
    log.Printf("Finished decrypting private key using passphrase")

    // Decode the base64 string
    dec, _ := base64.StdEncoding.DecodeString(encstr)

    // Decrypt it with the contents of the private key
    md, _ := openpgp.ReadMessage(bytes.NewBuffer(dec), entitylist2, nil, nil)
    bytess, _ := ioutil.ReadAll(md.UnverifiedBody)
    decstr := string(bytess)

    // should be done
    log.Printf("Decrypted Secret: ", decstr)

}

这是基于https://github.com/jyap808/jaeger

当我运行它时,它似乎部分工作,但只输出原始字符串的一些字符......更改原始字符串会导致一些非常奇怪的问题。

2014/09/07 22:59:38 Secret: %!(EXTRA string=this is so very secret!)
2014/09/07 22:59:38 Secret Keyring: %!(EXTRA string=/Users/stuart-warren/.gnupg/secring.gpg)
2014/09/07 22:59:38 Public Keyring: %!(EXTRA string=/Users/stuart-warren/.gnupg/pubring.gpg)
2014/09/07 22:59:38 Passphrase: %!(EXTRA string=1234)
2014/09/07 22:59:38 Encrypted Secret: %!(EXTRA string=wcBMA5a76vUxixWPAQgAOkrt/LQ3u++VbJ/20egxCUzMqcMYtq+JXL7SqbB5S1KrgHhGd8RHUmxy2h45hOLcAt+kfvSz0EJ/EsCmwnbP6HRPEqiMLt6XaVS26Rr9HQHPpRBZkqnwAP0EmlYNnF5zjnU5xTcEOyyr7EYhEgDv0Ro1FQkaCL2xdBhDCXs4EdQsjVrcECWOt0KgbCWs+N/0cEdeyHwodkaDgJ7NMq/pPuviaRu4JHCIxMiyz8yhOCHOM+bI80KsJesjGrgbjnGDfJUZNYDBNc8PqzfC39lB2MBrn/w07thJxvjbep39R0u2C4eEcroTRLB+t9i4fJNiVpoSclYRSZXm5OsYYv/XwtLgAeRZ07lFEsGoHSbqGLUnHFFw4Svk4FPgCuGVpOCS4vYiisDg+ORYj8dpu/Z3gSlVJ6mhSr7H4J3i9vItRuBx4WUB4HHgmQ==)
2014/09/07 22:59:38 Decrypting private key using passphrase
2014/09/07 22:59:38 Finished decrypting private key using passphrase
2014/09/07 22:59:38 Decrypted Secret: %!(EXTRA string=this)

显然有些东西我不明白,所以如果能提供任何帮助,我将不胜感激。

【问题讨论】:

  • 我注意到 Encrypt 返回一个 WriteCloser 而你从来没有 Close()d 它。对于像compress/gzip 这样的其他一些事情,我知道这可能导致并非所有输出都被刷新。 (也是从所有内容中检查errs 的最佳做法,即使是看似不会出错的内容。)

标签: encryption go public-key-encryption gnupg openpgp


【解决方案1】:

我无法测试您的代码,但我唯一能想到的是执行顺序错误。您首先制作一个字符串,然后将其制作为 Base64,然后对其进行加密。现在撤消 Base64,然后解密编码的字符串。最后两个必须交换。

【讨论】:

  • 谢谢,您的建议听起来似乎是个错误。
  • [愚蠢的评论编辑限制] 但是:第 32 行将字符串加密为字节,第 35 行将字节编码为 base64,第 55 行将 base64 解码为字节,第 56 行解密字节并转换回字符串。你是说顺序不对?
  • 加密字符串后,从 base64 解码。就是这一行: dec, _ := base64.StdEncoding.DecodeString(encstr) 另外,在您的示例中,不需要使用 base64。如果您使用 0-9 和 a-Z 以及空格,则不需要 base64。也许这会让你更容易测试。然后稍后,您可以使用 base64 捕获所有内容。
  • 我尝试通过将加密的字节数组直接发送到解密部分而不做任何更改来从等式中删除 base64。我不相信问题存在。我在代码中添加了更多的 cmets 和赏金。
【解决方案2】:

提醒您安全性是异常危险的领域,如果有一种方法可以调用其他经过良好测试的代码,甚至比 Go 的 OpenPGP 包为您处理的任务更多,请考虑它。至少将低级细节外包给openpgp 是一件好事,因为它们很讨厌而且很容易出错。但是任何级别的微小错误都可能使加密功能变得更糟。如果有办法编写对安全性要求不高的代码,那是任何人都可以为安全做的最好的事情之一。

关于具体问题:您必须Close() 作者才能清除所有内容(OpenPGP 的作者与 compress/gzip 分享的一个特征)。

不相关的变化:你打印东西的方式更适合log.Println,它只允许你传递一堆你想要打印的值,中间有空格(比如,Python print),而不是需要像"%s""%d" 这样的格式说明符。 (初始输出中的“EXTRA”是 Go 的 Printf 在传递的内容多于格式说明符时发出的内容。)检查错误也是最佳实践(我在看到需要的地方删除了 if err != nils,但是不雅且不加思索,我可能没有接到所有电话)并在您的代码上运行go fmt

同样,我无法证明此代码或类似代码的适航性。但现在它会往返所有文本。我结束了:

package main

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

// create gpg keys with
// $ gpg --gen-key
// ensure you correct paths and passphrase

const mysecretstring = "this is so very secret!"
const prefix, passphrase = "/Users/stuart-warren/", "1234"
const secretKeyring = prefix + ".gnupg/secring.gpg"
const publicKeyring = prefix + ".gnupg/pubring.gpg"

func encTest() error {
    log.Println("Secret:", mysecretstring)
    log.Println("Secret Keyring:", secretKeyring)
    log.Println("Public Keyring:", publicKeyring)
    log.Println("Passphrase:", passphrase)

    // Read in public key
    keyringFileBuffer, _ := os.Open(publicKeyring)
    defer keyringFileBuffer.Close()
    entitylist, err := openpgp.ReadKeyRing(keyringFileBuffer)
    if err != nil {
        return err
    }

    // encrypt string
    buf := new(bytes.Buffer)
    w, err := openpgp.Encrypt(buf, entitylist, nil, nil, nil)
    if err != nil {
        return err
    }
    _, err = w.Write([]byte(mysecretstring))
    if err != nil {
        return err
    }
    err = w.Close()
    if err != nil {
        return err
    }

    // Encode to base64
    bytesp, err := ioutil.ReadAll(buf)
    if err != nil {
        return err
    }
    encstr := base64.StdEncoding.EncodeToString(bytesp)

    // Output encrypted/encoded string
    log.Println("Encrypted Secret:", encstr)

    // Here is where I would transfer the encrypted string to someone else
    // but we'll just decrypt it in the same code

    // init some vars
    var entity2 *openpgp.Entity
    var entitylist2 openpgp.EntityList

    // Open the private key file
    keyringFileBuffer2, err := os.Open(secretKeyring)
    if err != nil {
        return err
    }
    defer keyringFileBuffer2.Close()
    entitylist2, err = openpgp.ReadKeyRing(keyringFileBuffer2)
    if err != nil {
        return err
    }
    entity2 = entitylist2[0]

    // Get the passphrase and read the private key.
    // Have not touched the encrypted string yet
    passphrasebyte := []byte(passphrase)
    log.Println("Decrypting private key using passphrase")
    entity2.PrivateKey.Decrypt(passphrasebyte)
    for _, subkey := range entity2.Subkeys {
        subkey.PrivateKey.Decrypt(passphrasebyte)
    }
    log.Println("Finished decrypting private key using passphrase")

    // Decode the base64 string
    dec, err := base64.StdEncoding.DecodeString(encstr)
    if err != nil {
        return err
    }

    // Decrypt it with the contents of the private key
    md, err := openpgp.ReadMessage(bytes.NewBuffer(dec), entitylist2, nil, nil)
    if err != nil {
        return err
    }
    bytess, err := ioutil.ReadAll(md.UnverifiedBody)
    if err != nil {
        return err
    }
    decstr := string(bytess)

    // should be done
    log.Println("Decrypted Secret:", decstr)

    return nil
}

func main() {
    err := encTest()
    if err != nil {
        log.Fatal(err)
    }
}

【讨论】:

  • 太棒了,你的传奇。这几天一直困扰着我!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多