encrypted_key.go 4.9 KB
Newer Older
1 2 3 4 5 6 7
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package packet

import (
8
	"crypto/openpgp/elgamal"
9
	error_ "crypto/openpgp/error"
10 11 12 13
	"crypto/rand"
	"crypto/rsa"
	"encoding/binary"
	"io"
14
	"math/big"
15 16 17
	"strconv"
)

18 19
const encryptedKeyVersion = 3

20 21 22 23 24
// EncryptedKey represents a public-key encrypted session key. See RFC 4880,
// section 5.1.
type EncryptedKey struct {
	KeyId      uint64
	Algo       PublicKeyAlgorithm
25 26
	CipherFunc CipherFunction // only valid after a successful Decrypt
	Key        []byte         // only valid after a successful Decrypt
27 28

	encryptedMPI1, encryptedMPI2 []byte
29 30
}

31
func (e *EncryptedKey) parse(r io.Reader) (err error) {
32 33 34 35 36
	var buf [10]byte
	_, err = readFull(r, buf[:])
	if err != nil {
		return
	}
37
	if buf[0] != encryptedKeyVersion {
38
		return error_.UnsupportedError("unknown EncryptedKey version " + strconv.Itoa(int(buf[0])))
39 40 41
	}
	e.KeyId = binary.BigEndian.Uint64(buf[1:9])
	e.Algo = PublicKeyAlgorithm(buf[9])
42 43 44 45 46 47 48 49 50
	switch e.Algo {
	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
		e.encryptedMPI1, _, err = readMPI(r)
	case PubKeyAlgoElGamal:
		e.encryptedMPI1, _, err = readMPI(r)
		if err != nil {
			return
		}
		e.encryptedMPI2, _, err = readMPI(r)
51 52 53 54 55
	}
	_, err = consumeAll(r)
	return
}

56 57 58 59 60 61 62 63
func checksumKeyMaterial(key []byte) uint16 {
	var checksum uint16
	for _, v := range key {
		checksum += uint16(v)
	}
	return checksum
}

64 65
// Decrypt decrypts an encrypted session key with the given private key. The
// private key must have been decrypted first.
66 67
func (e *EncryptedKey) Decrypt(priv *PrivateKey) error {
	var err error
68 69 70 71 72 73 74 75 76 77 78 79
	var b []byte

	// TODO(agl): use session key decryption routines here to avoid
	// padding oracle attacks.
	switch priv.PubKeyAlgo {
	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
		b, err = rsa.DecryptPKCS1v15(rand.Reader, priv.PrivateKey.(*rsa.PrivateKey), e.encryptedMPI1)
	case PubKeyAlgoElGamal:
		c1 := new(big.Int).SetBytes(e.encryptedMPI1)
		c2 := new(big.Int).SetBytes(e.encryptedMPI2)
		b, err = elgamal.Decrypt(priv.PrivateKey.(*elgamal.PrivateKey), c1, c2)
	default:
80
		err = error_.InvalidArgumentError("cannot decrypted encrypted session key with private key of type " + strconv.Itoa(int(priv.PubKeyAlgo)))
81
	}
82

83
	if err != nil {
84
		return err
85
	}
86

87 88 89
	e.CipherFunc = CipherFunction(b[0])
	e.Key = b[1 : len(b)-2]
	expectedChecksum := uint16(b[len(b)-2])<<8 | uint16(b[len(b)-1])
90
	checksum := checksumKeyMaterial(e.Key)
91
	if checksum != expectedChecksum {
92
		return error_.StructuralError("EncryptedKey checksum incorrect")
93 94
	}

95
	return nil
96
}
97 98 99

// SerializeEncryptedKey serializes an encrypted key packet to w that contains
// key, encrypted to pub.
100
func SerializeEncryptedKey(w io.Writer, rand io.Reader, pub *PublicKey, cipherFunc CipherFunction, key []byte) error {
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
	var buf [10]byte
	buf[0] = encryptedKeyVersion
	binary.BigEndian.PutUint64(buf[1:9], pub.KeyId)
	buf[9] = byte(pub.PubKeyAlgo)

	keyBlock := make([]byte, 1 /* cipher type */ +len(key)+2 /* checksum */ )
	keyBlock[0] = byte(cipherFunc)
	copy(keyBlock[1:], key)
	checksum := checksumKeyMaterial(key)
	keyBlock[1+len(key)] = byte(checksum >> 8)
	keyBlock[1+len(key)+1] = byte(checksum)

	switch pub.PubKeyAlgo {
	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
		return serializeEncryptedKeyRSA(w, rand, buf, pub.PublicKey.(*rsa.PublicKey), keyBlock)
116 117
	case PubKeyAlgoElGamal:
		return serializeEncryptedKeyElGamal(w, rand, buf, pub.PublicKey.(*elgamal.PublicKey), keyBlock)
118
	case PubKeyAlgoDSA, PubKeyAlgoRSASignOnly:
119
		return error_.InvalidArgumentError("cannot encrypt to public key of type " + strconv.Itoa(int(pub.PubKeyAlgo)))
120 121
	}

122
	return error_.UnsupportedError("encrypting a key to public key of type " + strconv.Itoa(int(pub.PubKeyAlgo)))
123 124
}

125
func serializeEncryptedKeyRSA(w io.Writer, rand io.Reader, header [10]byte, pub *rsa.PublicKey, keyBlock []byte) error {
126 127
	cipherText, err := rsa.EncryptPKCS1v15(rand, pub, keyBlock)
	if err != nil {
128
		return error_.InvalidArgumentError("RSA encryption failed: " + err.Error())
129 130 131 132 133 134 135 136 137 138 139 140 141 142
	}

	packetLen := 10 /* header length */ + 2 /* mpi size */ + len(cipherText)

	err = serializeHeader(w, packetTypeEncryptedKey, packetLen)
	if err != nil {
		return err
	}
	_, err = w.Write(header[:])
	if err != nil {
		return err
	}
	return writeMPI(w, 8*uint16(len(cipherText)), cipherText)
}
143

144
func serializeEncryptedKeyElGamal(w io.Writer, rand io.Reader, header [10]byte, pub *elgamal.PublicKey, keyBlock []byte) error {
145 146
	c1, c2, err := elgamal.Encrypt(rand, pub, keyBlock)
	if err != nil {
147
		return error_.InvalidArgumentError("ElGamal encryption failed: " + err.Error())
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
	}

	packetLen := 10 /* header length */
	packetLen += 2 /* mpi size */ + (c1.BitLen()+7)/8
	packetLen += 2 /* mpi size */ + (c2.BitLen()+7)/8

	err = serializeHeader(w, packetTypeEncryptedKey, packetLen)
	if err != nil {
		return err
	}
	_, err = w.Write(header[:])
	if err != nil {
		return err
	}
	err = writeBig(w, c1)
	if err != nil {
		return err
	}
	return writeBig(w, c2)
}