Index: openpgp/packet/private_key.go
===================================================================
--- a/openpgp/packet/private_key.go
+++ b/openpgp/packet/private_key.go
@@ -115,7 +115,10 @@
}
func (pk *PrivateKey) Serialize(w io.Writer) (err error) {
- // TODO(agl): support encrypted private keys
+ if pk.Encrypted {
+ return pk.serializeEncrypted(w)
+ }
+
buf := bytes.NewBuffer(nil)
err = pk.PublicKey.serializeWithoutHeaders(buf)
if err != nil {
@@ -185,6 +188,135 @@
return writeBig(w, priv.X)
}
+func (pk *PrivateKey) serializeEncrypted(w io.Writer) (err error) {
+ if !pk.Encrypted {
+ return errors.UnsupportedError("private key is not encrypted")
+ }
+
+ buf := bytes.NewBuffer(nil)
agl1
2014年05月25日 21:09:33
var buf bytes.Buffer
and s/buf/&buf/
+ err = pk.PublicKey.serializeWithoutHeaders(buf)
agl1
2014年05月25日 21:09:33
merge into one line.
+ if err != nil {
+ return
+ }
+
+ /*
+ Encrypted Serialized PGP Key
agl1
2014年05月25日 21:09:34
tighten up comment - no need to waste blank lines.
+
+ Ssum type - 1 byte
+ Cipher Type - 1 byte
+ S2K Data
+ S2K Type - 1 byte
+ Hash Type - 1 byte
+ Salt - 0-8 bytes (Depends on S2K type)
+ IV - 8-16 bytes ??(Depends on Cipher Type)
+ Encrypted Data
+ */
+
+ /*
+ 0 - no encryption
+ 254 - encrypted with sha1sum
+ 255 - encypted without hashsum
+ */
+ buf.WriteByte(255)
+
+ // Next is Cipher type
agl1
2014年05月25日 21:09:33
give that this is explained above, some of these c
+ buf.WriteByte(byte(pk.cipher))
+
+ // Next comes the S2K data and their hashes and salts if appropriate
+ buf.WriteByte(0) // For now just use simple
+ buf.WriteByte(10) // And use SHA512 for now
+ // No salt for Simple S2K
+
+ // Next write the IV
+ buf.Write(pk.iv)
+
+ // Next write the encrypted data
+ buf.Write(pk.encryptedData)
+
+ ptype := packetTypePrivateKey
+ contents := buf.Bytes()
+ if pk.IsSubkey {
+ ptype = packetTypePrivateSubkey
+ }
+ err = serializeHeader(w, ptype, len(contents))
agl1
2014年05月25日 21:09:34
merge these lines and just below.
+ if err != nil {
+ return
+ }
+ _, err = w.Write(contents)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// Encrypt a private key using the given passphrase
+func (pk *PrivateKey) Encrypt(passphrase []byte) (err error) {
+ if pk.Encrypted {
+ // Should we return if already encrypted, or decrypt and re-encrypt with new passphrase
+ return
+ }
+
+ // Using AES256 Cipher
agl1
2014年05月25日 21:09:33
for example, this comment doesn't carry its weight
+ pk.cipher = CipherAES256
+
+ // Create random IV
+ pk.iv = make([]byte, pk.cipher.blockSize())
+ conf := Config{}
agl1
2014年05月25日 21:09:33
var conf *Config
(A nil Config works for .Random(
+ if _, err := readFull(conf.Random(), pk.iv); err != nil {
+ return err
+ }
+
+ // Use SHA512 Hash
+ hash, ok := s2k.HashIdToHash(10) // SHA512
+ if !ok {
+ return errors.UnsupportedError("hash for S2K function")
+ }
+ h := hash.New()
+
+ key := make([]byte, pk.cipher.KeySize())
+ pk.s2k = func(out, in []byte) {
+ s2k.Simple(out, h, in)
+ }
+ s2k.Simple(key, h, passphrase)
+ block := pk.cipher.new(key)
+ cfb := cipher.NewCFBEncrypter(block, pk.iv)
+
+ privateKeyBuf := bytes.NewBuffer(nil)
+
+ switch priv := pk.PrivateKey.(type) {
+ case *rsa.PrivateKey:
+ err = serializeRSAPrivateKey(privateKeyBuf, priv)
+ case *dsa.PrivateKey:
+ err = serializeDSAPrivateKey(privateKeyBuf, priv)
+ default:
+ err = errors.InvalidArgumentError("unknown private key type")
+ }
+ if err != nil {
+ return
+ }
+
+ data := privateKeyBuf.Bytes()
+
+ // Set up a sort of check sum
+ // Different if sha1sum is used
+
+ final_data := make([]byte, len(data)+2)
+ copy(final_data[:len(data)], data)
+ var sum uint16
+ for i := 0; i < len(data); i++ {
+ sum += uint16(data[i])
+ }
+ final_data[len(data)] = uint8(sum >> 8)
+ final_data[len(data)+1] = uint8(sum)
+
+ cfb.XORKeyStream(final_data, final_data)
+ pk.encryptedData = final_data
+ pk.Encrypted = true
+
+ return
+}
+
// Decrypt decrypts an encrypted private key using a passphrase.
func (pk *PrivateKey) Decrypt(passphrase []byte) error {
if !pk.Encrypted {