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 (
	
	
	
	
	
	

	
	
)

const encryptedKeyVersion = 3
EncryptedKey represents a public-key encrypted session key. See RFC 4880, section 5.1.
type EncryptedKey struct {
	KeyId      uint64
	Algo       PublicKeyAlgorithm
	CipherFunc CipherFunction // only valid after a successful Decrypt
	Key        []byte         // only valid after a successful Decrypt

	encryptedMPI1, encryptedMPI2 parsedMPI
}

func ( *EncryptedKey) ( io.Reader) ( error) {
	var  [10]byte
	_,  = readFull(, [:])
	if  != nil {
		return
	}
	if [0] != encryptedKeyVersion {
		return errors.UnsupportedError("unknown EncryptedKey version " + strconv.Itoa(int([0])))
	}
	.KeyId = binary.BigEndian.Uint64([1:9])
	.Algo = PublicKeyAlgorithm([9])
	switch .Algo {
	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
		.encryptedMPI1.bytes, .encryptedMPI1.bitLength,  = readMPI()
		if  != nil {
			return
		}
	case PubKeyAlgoElGamal:
		.encryptedMPI1.bytes, .encryptedMPI1.bitLength,  = readMPI()
		if  != nil {
			return
		}
		.encryptedMPI2.bytes, .encryptedMPI2.bitLength,  = readMPI()
		if  != nil {
			return
		}
	}
	_,  = consumeAll()
	return
}

func ( []byte) uint16 {
	var  uint16
	for ,  := range  {
		 += uint16()
	}
	return 
}
Decrypt decrypts an encrypted session key with the given private key. The private key must have been decrypted first. If config is nil, sensible defaults will be used.
func ( *EncryptedKey) ( *PrivateKey,  *Config) error {
	var  error
	var  []byte
TODO(agl): use session key decryption routines here to avoid padding oracle attacks.
	switch .PubKeyAlgo {
Supports both *rsa.PrivateKey and crypto.Decrypter
		 := .PrivateKey.(crypto.Decrypter)
		,  = .Decrypt(.Random(), padToKeySize(.Public().(*rsa.PublicKey), .encryptedMPI1.bytes), nil)
	case PubKeyAlgoElGamal:
		 := new(big.Int).SetBytes(.encryptedMPI1.bytes)
		 := new(big.Int).SetBytes(.encryptedMPI2.bytes)
		,  = elgamal.Decrypt(.PrivateKey.(*elgamal.PrivateKey), , )
	default:
		 = errors.InvalidArgumentError("cannot decrypted encrypted session key with private key of type " + strconv.Itoa(int(.PubKeyAlgo)))
	}

	if  != nil {
		return 
	}

	.CipherFunc = CipherFunction([0])
	.Key = [1 : len()-2]
	 := uint16([len()-2])<<8 | uint16([len()-1])
	 := checksumKeyMaterial(.Key)
	if  !=  {
		return errors.StructuralError("EncryptedKey checksum incorrect")
	}

	return nil
}
Serialize writes the encrypted key packet, e, to w.
func ( *EncryptedKey) ( io.Writer) error {
	var  int
	switch .Algo {
	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
		 = 2 + len(.encryptedMPI1.bytes)
	case PubKeyAlgoElGamal:
		 = 2 + len(.encryptedMPI1.bytes) + 2 + len(.encryptedMPI2.bytes)
	default:
		return errors.InvalidArgumentError("don't know how to serialize encrypted key type " + strconv.Itoa(int(.Algo)))
	}

	serializeHeader(, packetTypeEncryptedKey, 1 /* version */ +8 /* key id */ +1 /* algo */ +)

	.Write([]byte{encryptedKeyVersion})
	binary.Write(, binary.BigEndian, .KeyId)
	.Write([]byte{byte(.Algo)})

	switch .Algo {
	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
		writeMPIs(, .encryptedMPI1)
	case PubKeyAlgoElGamal:
		writeMPIs(, .encryptedMPI1, .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.
func ( io.Writer,  *PublicKey,  CipherFunction,  []byte,  *Config) error {
	var  [10]byte
	[0] = encryptedKeyVersion
	binary.BigEndian.PutUint64([1:9], .KeyId)
	[9] = byte(.PubKeyAlgo)

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

	switch .PubKeyAlgo {
	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
		return serializeEncryptedKeyRSA(, .Random(), , .PublicKey.(*rsa.PublicKey), )
	case PubKeyAlgoElGamal:
		return serializeEncryptedKeyElGamal(, .Random(), , .PublicKey.(*elgamal.PublicKey), )
	case PubKeyAlgoDSA, PubKeyAlgoRSASignOnly:
		return errors.InvalidArgumentError("cannot encrypt to public key of type " + strconv.Itoa(int(.PubKeyAlgo)))
	}

	return errors.UnsupportedError("encrypting a key to public key of type " + strconv.Itoa(int(.PubKeyAlgo)))
}

func ( io.Writer,  io.Reader,  [10]byte,  *rsa.PublicKey,  []byte) error {
	,  := rsa.EncryptPKCS1v15(, , )
	if  != nil {
		return errors.InvalidArgumentError("RSA encryption failed: " + .Error())
	}

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

	 = serializeHeader(, packetTypeEncryptedKey, )
	if  != nil {
		return 
	}
	_,  = .Write([:])
	if  != nil {
		return 
	}
	return writeMPI(, 8*uint16(len()), )
}

func ( io.Writer,  io.Reader,  [10]byte,  *elgamal.PublicKey,  []byte) error {
	, ,  := elgamal.Encrypt(, , )
	if  != nil {
		return errors.InvalidArgumentError("ElGamal encryption failed: " + .Error())
	}

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

	 = serializeHeader(, packetTypeEncryptedKey, )
	if  != nil {
		return 
	}
	_,  = .Write([:])
	if  != nil {
		return 
	}
	 = writeBig(, )
	if  != nil {
		return 
	}
	return writeBig(, )