Browse Source

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 <agl@golang.org>
Giovanni Bajo 11 năm trước cách đây
mục cha
commit
ecf53cc131
2 tập tin đã thay đổi với 61 bổ sung9 xóa
  1. 40 9
      openpgp/packet/encrypted_key.go
  2. 21 0
      openpgp/packet/encrypted_key_test.go

+ 40 - 9
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.

+ 21 - 0
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)
+	}
+}