OpenPGP Armor OpenPGP是使用最广泛的电子邮件加密标准。它由Internet工程任务组(IETF)的OpenPGP工作组定义为RFC 4880中的建议标准.OpenPGP最初源自由Phil Zimmermann创建的PGP软件。
虽然OpenPGP的主要目的是端到端加密电子邮件通信,但它也用于加密消息传递和其他用例,如密码管理器。
OpenPGP的加密消息,签名证书和密钥的基本描述是八位的字节流。为了通过不能保障安全的网络通道传输OpenPGP的二进制八位字节,需要编码为可打印的二进制字符。OpenPGP提供将原始8位二进制八位字节流转换为可打印ASCII字符流,称为Radix-64编码或ASCII Armor。
ASCII Armor是OpenPGP的可选功能。当OpenPGP将数据编码为ASCII Armor时,它会在Radix-64编码数据中放置特定的Header。OpenPGP可以使用ASCII Armor来保护原始二进制数据。OpenPGP通过使用Header告知用户在ASCII Armor中编码了什么类型的数据。
ASCII Armor的数据结构如下:
Armor标题行,匹配数据类型
Armor Headers
A Blank(零长度或仅包含空格) Line
The ASCII-Armored data
An Armor Checksum
The Armor Tail,取决于护甲标题线
具体示例: 1 2 3 4 5 6 7 8 9 10 -----BEGIN PGP MESSAGE----- Version: OpenPrivacy 0.99 yDgBO22WxBHv7O8X7O/jygAEzol56iUKiXmV+XmpCtmpqQUKiQrFqclFqUDBovzSvBSFjNSiVHsuAA== =njUN -----END PGP MESSAGE-----
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 func Encode (out io.Writer, blockType string , headers map [string ]string ) (w io.WriteCloser, err error) { bType := []byte (blockType) err = writeSlices(out, armorStart, bType, armorEndOfLineOut) if err != nil { return } for k, v := range headers { err = writeSlices(out, []byte (k), armorHeaderSep, []byte (v), newline) if err != nil { return } } _, err = out.Write(newline) if err != nil { return } e := &encoding{ out: out, breaker: newLineBreaker(out, 64 ), crc: crc24Init, blockType: bType, } e.b64 = base64.NewEncoder(base64.StdEncoding, e.breaker) return e, nil }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 func EncodeArmor (blockType string , headers map [string ]string , data []byte ) string { buf := new (bytes.Buffer) w, err := armor.Encode(buf, blockType, headers) if err != nil { panic (fmt.Errorf("could not encode ascii armor: %s" , err)) } _, err = w.Write(data) if err != nil { panic (fmt.Errorf("could not encode ascii armor: %s" , err)) } err = w.Close() if err != nil { panic (fmt.Errorf("could not encode ascii armor: %s" , err)) } return buf.String() }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 func armorPubKeyBytes (bz []byte ) string { return armorBytes(bz, blockTypePubKey) } func armorBytes (bz []byte , blockType string ) string { header := map [string ]string { "type" : "Info" , "version" : "0.0.0" , } return armor.EncodeArmor(blockType, header, bz) } func ExportPubKey (name string ) (armor string , err error) { bz := Get(infoKey(name)) if bz == nil { return "" , fmt.Errorf("no key to export with name %s" , name) } info, err := readInfo(bz) if err != nil { return } return armorPubKeyBytes(info.GetPubKey().Bytes()), nil }
在 CovalentChain 公钥、私钥的导入导出和传输等情况,使用 ASCII Armor 编码格式非常合适。另外,在私钥情况下,通常都需要在加密后,再进行编码处理。
参考链接:
https://tools.ietf.org/html/rfc4880
https://www.openpgp.org/
golang.org/x/crypto/openpgp/armor