From ecf53cc13127a66c314c312555ea1b197ed6b83c Mon Sep 17 00:00:00 2001 From: Giovanni Bajo Date: Fri, 23 Jan 2015 16:42:18 +0100 Subject: [PATCH] crypto/openpgp: add serialization for encrypted key packets The new function allows an existing encrypted key packet to be serialized to a Writer. Change-Id: I20d82ca473d8ae738d239068626897c1ff868a15 Reviewed-on: https://go-review.googlesource.com/3167 Reviewed-by: Adam Langley --- openpgp/packet/encrypted_key.go | 49 +++++++++++++++++++++++----- openpgp/packet/encrypted_key_test.go | 21 ++++++++++++ 2 files changed, 61 insertions(+), 9 deletions(-) diff --git a/openpgp/packet/encrypted_key.go b/openpgp/packet/encrypted_key.go index b43522c..266840d 100644 --- a/openpgp/packet/encrypted_key.go +++ b/openpgp/packet/encrypted_key.go @@ -7,11 +7,12 @@ package packet import ( "crypto/rsa" "encoding/binary" - "golang.org/x/crypto/openpgp/elgamal" - "golang.org/x/crypto/openpgp/errors" "io" "math/big" "strconv" + + "golang.org/x/crypto/openpgp/elgamal" + "golang.org/x/crypto/openpgp/errors" ) const encryptedKeyVersion = 3 @@ -24,7 +25,7 @@ type EncryptedKey struct { CipherFunc CipherFunction // only valid after a successful Decrypt Key []byte // only valid after a successful Decrypt - encryptedMPI1, encryptedMPI2 []byte + encryptedMPI1, encryptedMPI2 parsedMPI } func (e *EncryptedKey) parse(r io.Reader) (err error) { @@ -40,13 +41,13 @@ func (e *EncryptedKey) parse(r io.Reader) (err error) { e.Algo = PublicKeyAlgorithm(buf[9]) switch e.Algo { case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly: - e.encryptedMPI1, _, err = readMPI(r) + e.encryptedMPI1.bytes, e.encryptedMPI1.bitLength, err = readMPI(r) case PubKeyAlgoElGamal: - e.encryptedMPI1, _, err = readMPI(r) + e.encryptedMPI1.bytes, e.encryptedMPI1.bitLength, err = readMPI(r) if err != nil { return } - e.encryptedMPI2, _, err = readMPI(r) + e.encryptedMPI2.bytes, e.encryptedMPI2.bitLength, err = readMPI(r) } _, err = consumeAll(r) return @@ -71,10 +72,10 @@ func (e *EncryptedKey) Decrypt(priv *PrivateKey, config *Config) error { // padding oracle attacks. switch priv.PubKeyAlgo { case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly: - b, err = rsa.DecryptPKCS1v15(config.Random(), priv.PrivateKey.(*rsa.PrivateKey), e.encryptedMPI1) + b, err = rsa.DecryptPKCS1v15(config.Random(), priv.PrivateKey.(*rsa.PrivateKey), e.encryptedMPI1.bytes) case PubKeyAlgoElGamal: - c1 := new(big.Int).SetBytes(e.encryptedMPI1) - c2 := new(big.Int).SetBytes(e.encryptedMPI2) + c1 := new(big.Int).SetBytes(e.encryptedMPI1.bytes) + c2 := new(big.Int).SetBytes(e.encryptedMPI2.bytes) b, err = elgamal.Decrypt(priv.PrivateKey.(*elgamal.PrivateKey), c1, c2) default: err = errors.InvalidArgumentError("cannot decrypted encrypted session key with private key of type " + strconv.Itoa(int(priv.PubKeyAlgo))) @@ -95,6 +96,36 @@ func (e *EncryptedKey) Decrypt(priv *PrivateKey, config *Config) error { return nil } +// Serialize writes the encrypted key packet, e, to w. +func (e *EncryptedKey) Serialize(w io.Writer) error { + var mpiLen int + switch e.Algo { + case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly: + mpiLen = 2 + len(e.encryptedMPI1.bytes) + case PubKeyAlgoElGamal: + mpiLen = 2 + len(e.encryptedMPI1.bytes) + 2 + len(e.encryptedMPI2.bytes) + default: + return errors.InvalidArgumentError("don't know how to serialize encrypted key type " + strconv.Itoa(int(e.Algo))) + } + + serializeHeader(w, packetTypeEncryptedKey, 1 /* version */ +8 /* key id */ +1 /* algo */ +mpiLen) + + w.Write([]byte{encryptedKeyVersion}) + binary.Write(w, binary.BigEndian, e.KeyId) + w.Write([]byte{byte(e.Algo)}) + + switch e.Algo { + case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly: + writeMPIs(w, e.encryptedMPI1) + case PubKeyAlgoElGamal: + writeMPIs(w, e.encryptedMPI1, e.encryptedMPI2) + default: + panic("internal error") + } + + return nil +} + // SerializeEncryptedKey serializes an encrypted key packet to w that contains // key, encrypted to pub. // If config is nil, sensible defaults will be used. diff --git a/openpgp/packet/encrypted_key_test.go b/openpgp/packet/encrypted_key_test.go index 0a8dcc6..fee14cf 100644 --- a/openpgp/packet/encrypted_key_test.go +++ b/openpgp/packet/encrypted_key_test.go @@ -7,6 +7,7 @@ package packet import ( "bytes" "crypto/rsa" + "encoding/hex" "fmt" "math/big" "testing" @@ -123,3 +124,23 @@ func TestEncryptingEncryptedKey(t *testing.T) { t.Errorf("bad key, got %s want %x", keyHex, expectedKeyHex) } } + +func TestSerializingEncryptedKey(t *testing.T) { + const encryptedKeyHex = "c18c032a67d68660df41c70104005789d0de26b6a50c985a02a13131ca829c413a35d0e6fa8d6842599252162808ac7439c72151c8c6183e76923fe3299301414d0c25a2f06a2257db3839e7df0ec964773f6e4c4ac7ff3b48c444237166dd46ba8ff443a5410dc670cb486672fdbe7c9dfafb75b4fea83af3a204fe2a7dfa86bd20122b4f3d2646cbeecb8f7be8" + + p, err := Read(readerFromHex(encryptedKeyHex)) + if err != nil { + t.Fatalf("error from Read: %s", err) + } + ek, ok := p.(*EncryptedKey) + if !ok { + t.Fatalf("didn't parse an EncryptedKey, got %#v", p) + } + + var buf bytes.Buffer + ek.Serialize(&buf) + + if bufHex := hex.EncodeToString(buf.Bytes()); bufHex != encryptedKeyHex { + t.Fatalf("serialization of encrypted key differed from original. Original was %s, but reserialized as %s", encryptedKeyHex, bufHex) + } +}