Issues with openpgp golang gpg library

huangapple go评论76阅读模式
英文:

Issues with openpgp golang gpg library

问题

所以我对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"
)

// 使用以下命令创建gpg密钥
// $ gpg --gen-key
// 确保你正确设置了路径和密码

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)

	// 读取公钥
	keyringFileBuffer, _ := os.Open(publicKeyring)
	defer keyringFileBuffer.Close()
	entitylist, _ := openpgp.ReadKeyRing(keyringFileBuffer)

	// 加密字符串
	buf := new(bytes.Buffer)
	w, _ := openpgp.Encrypt(buf, entitylist, nil, nil, nil)
	w.Write([]byte(mysecretstring))

	// 编码为base64
	bytesp, _ := ioutil.ReadAll(buf)
	encstr := base64.StdEncoding.EncodeToString(bytesp)

	// 输出加密/编码后的字符串
	log.Printf("Encrypted Secret: ", encstr)

	// 这里我将把加密后的字符串传输给其他人
	// 但我们将在同一段代码中解密它

	// 初始化一些变量
	var entity2 *openpgp.Entity
	var entitylist2 openpgp.EntityList

	// 打开私钥文件
	keyringFileBuffer2, _ := os.Open(secretKeyring)
	defer keyringFileBuffer2.Close()
	entitylist2, _ = openpgp.ReadKeyRing(keyringFileBuffer2)
	entity2 = entitylist2[0]

	// 获取密码并读取私钥
	// 还没有处理加密的字符串
	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")

	// 解码base64字符串
	dec, _ := base64.StdEncoding.DecodeString(encstr)

	// 使用私钥的内容解密
	md, _ := openpgp.ReadMessage(bytes.NewBuffer(dec), entitylist2, nil, nil)
	bytess, _ := ioutil.ReadAll(md.UnverifiedBody)
	decstr := string(bytess)

	// 完成
	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)

显然,有些地方我理解得不对,所以希望得到任何帮助。

英文:

So I'm pretty new to golang and i'm struggling to get a working example going of encrypting some text with openpgp and decrypting it again.

Here is what I have so far: (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)
}

This is based off of https://github.com/jyap808/jaeger

When I run it, it seems to partially work, but only outputs some of the characters of the original string... Changing the original string causes some very weird issues.

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)

Clearly there is something I'm not understanding, so would appreciate any assistance given.

答案1

得分: 7

提醒您,安全性是异常棘手的领域,如果有办法调用其他经过充分测试的代码来处理比Go的OpenPGP包处理的更多的顶层任务,那就考虑一下。很好,至少低级细节被外包给了openpgp,因为它们很恶心,而且很容易出错。但是在任何级别上的微小错误都可能使加密功能变得比无用还糟糕;如果有办法编写较少涉及安全性的代码,那是对安全性做出的最好的贡献之一。

关于具体问题:你必须调用Close()方法来刷新所有内容(这是OpenPGP的写入器与compress/gzip等的共同特点)。

与此无关的更改:你打印内容的方式更适合使用log.Println,它允许你传递一堆要打印的值,值之间用空格分隔(就像Python的print一样),而不需要像"%s""%d"这样的格式说明符。(你初始输出中的"EXTRA"是当你传递的参数超过了你的格式说明符时,Go的Printf会输出的内容。)检查错误是最佳实践(我在需要的地方删除了if err != nil,但不够优雅,也没有经过深思熟虑,可能没有处理所有的调用),并且在代码上运行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)
	}
}
英文:

A reminder that security is unusually treacherous territory, and if there's a way to call on other well-tested code even more of your toplevel task than just what Go's OpenPGP package is handling for you, consider it. It's good that at least low-level details are outsourced to openpgp because they're nasty and so so easy to get wrong. But tiny mistakes at any level can make crypto features worse than useless; if there's a way to write less security-critical code, that's one of the best things anyone can do for security.

On the specific question: you have to Close() the writer to get everything flushed out (a trait OpenPGP's writer shares with, say, compress/gzip's).

Unrelated changes: the way you're printing things is a better fit log.Println, which just lets you pass a bunch of values you want printed with spaces in between (like, say, Python print), rather than needing format specifiers like "%s" or "%d". (The "EXTRA" in your initial output is what Go's Printf emits when you pass more things than you had format specifiers for.) It's also best practice to check errors (I dropped if err != nils where I saw a need, but inelegantly and without much thought, and I may not have gotten all the calls) and to run go fmt on your code.

Again, I can't testify to the seaworthiness of this code or anything like that. But now it round-trips all the text. I wound up with:

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)
}
}

答案2

得分: 0

我无法测试你的代码,但我能想到的唯一可能是执行顺序错误。你首先创建一个字符串,然后将其转换为Base64,然后对其进行加密。现在你撤销Base64,然后解密编码的字符串。这两个步骤的顺序应该交换一下。

英文:

I cannot test your code, but the only thing i can think off, is that the order of execution is wrong. You first make a string, then you make it Base64, then you encrypt it. Now you undo the Base64 and afterwards you decrypt the encoded string. These last two must be swapped.

huangapple
  • 本文由 发表于 2014年9月8日 06:21:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/25715304.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定