...

Source file src/golang.org/x/crypto/openpgp/packet/encrypted_key.go

Documentation: golang.org/x/crypto/openpgp/packet

     1  // Copyright 2011 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package packet
     6  
     7  import (
     8  	"crypto"
     9  	"crypto/rsa"
    10  	"encoding/binary"
    11  	"io"
    12  	"math/big"
    13  	"strconv"
    14  
    15  	"golang.org/x/crypto/openpgp/elgamal"
    16  	"golang.org/x/crypto/openpgp/errors"
    17  )
    18  
    19  const encryptedKeyVersion = 3
    20  
    21  // EncryptedKey represents a public-key encrypted session key. See RFC 4880,
    22  // section 5.1.
    23  type EncryptedKey struct {
    24  	KeyId      uint64
    25  	Algo       PublicKeyAlgorithm
    26  	CipherFunc CipherFunction // only valid after a successful Decrypt
    27  	Key        []byte         // only valid after a successful Decrypt
    28  
    29  	encryptedMPI1, encryptedMPI2 parsedMPI
    30  }
    31  
    32  func (e *EncryptedKey) parse(r io.Reader) (err error) {
    33  	var buf [10]byte
    34  	_, err = readFull(r, buf[:])
    35  	if err != nil {
    36  		return
    37  	}
    38  	if buf[0] != encryptedKeyVersion {
    39  		return errors.UnsupportedError("unknown EncryptedKey version " + strconv.Itoa(int(buf[0])))
    40  	}
    41  	e.KeyId = binary.BigEndian.Uint64(buf[1:9])
    42  	e.Algo = PublicKeyAlgorithm(buf[9])
    43  	switch e.Algo {
    44  	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
    45  		e.encryptedMPI1.bytes, e.encryptedMPI1.bitLength, err = readMPI(r)
    46  		if err != nil {
    47  			return
    48  		}
    49  	case PubKeyAlgoElGamal:
    50  		e.encryptedMPI1.bytes, e.encryptedMPI1.bitLength, err = readMPI(r)
    51  		if err != nil {
    52  			return
    53  		}
    54  		e.encryptedMPI2.bytes, e.encryptedMPI2.bitLength, err = readMPI(r)
    55  		if err != nil {
    56  			return
    57  		}
    58  	}
    59  	_, err = consumeAll(r)
    60  	return
    61  }
    62  
    63  func checksumKeyMaterial(key []byte) uint16 {
    64  	var checksum uint16
    65  	for _, v := range key {
    66  		checksum += uint16(v)
    67  	}
    68  	return checksum
    69  }
    70  
    71  // Decrypt decrypts an encrypted session key with the given private key. The
    72  // private key must have been decrypted first.
    73  // If config is nil, sensible defaults will be used.
    74  func (e *EncryptedKey) Decrypt(priv *PrivateKey, config *Config) error {
    75  	var err error
    76  	var b []byte
    77  
    78  	// TODO(agl): use session key decryption routines here to avoid
    79  	// padding oracle attacks.
    80  	switch priv.PubKeyAlgo {
    81  	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
    82  		// Supports both *rsa.PrivateKey and crypto.Decrypter
    83  		k := priv.PrivateKey.(crypto.Decrypter)
    84  		b, err = k.Decrypt(config.Random(), padToKeySize(k.Public().(*rsa.PublicKey), e.encryptedMPI1.bytes), nil)
    85  	case PubKeyAlgoElGamal:
    86  		c1 := new(big.Int).SetBytes(e.encryptedMPI1.bytes)
    87  		c2 := new(big.Int).SetBytes(e.encryptedMPI2.bytes)
    88  		b, err = elgamal.Decrypt(priv.PrivateKey.(*elgamal.PrivateKey), c1, c2)
    89  	default:
    90  		err = errors.InvalidArgumentError("cannot decrypted encrypted session key with private key of type " + strconv.Itoa(int(priv.PubKeyAlgo)))
    91  	}
    92  
    93  	if err != nil {
    94  		return err
    95  	}
    96  
    97  	e.CipherFunc = CipherFunction(b[0])
    98  	e.Key = b[1 : len(b)-2]
    99  	expectedChecksum := uint16(b[len(b)-2])<<8 | uint16(b[len(b)-1])
   100  	checksum := checksumKeyMaterial(e.Key)
   101  	if checksum != expectedChecksum {
   102  		return errors.StructuralError("EncryptedKey checksum incorrect")
   103  	}
   104  
   105  	return nil
   106  }
   107  
   108  // Serialize writes the encrypted key packet, e, to w.
   109  func (e *EncryptedKey) Serialize(w io.Writer) error {
   110  	var mpiLen int
   111  	switch e.Algo {
   112  	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
   113  		mpiLen = 2 + len(e.encryptedMPI1.bytes)
   114  	case PubKeyAlgoElGamal:
   115  		mpiLen = 2 + len(e.encryptedMPI1.bytes) + 2 + len(e.encryptedMPI2.bytes)
   116  	default:
   117  		return errors.InvalidArgumentError("don't know how to serialize encrypted key type " + strconv.Itoa(int(e.Algo)))
   118  	}
   119  
   120  	serializeHeader(w, packetTypeEncryptedKey, 1 /* version */ +8 /* key id */ +1 /* algo */ +mpiLen)
   121  
   122  	w.Write([]byte{encryptedKeyVersion})
   123  	binary.Write(w, binary.BigEndian, e.KeyId)
   124  	w.Write([]byte{byte(e.Algo)})
   125  
   126  	switch e.Algo {
   127  	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
   128  		writeMPIs(w, e.encryptedMPI1)
   129  	case PubKeyAlgoElGamal:
   130  		writeMPIs(w, e.encryptedMPI1, e.encryptedMPI2)
   131  	default:
   132  		panic("internal error")
   133  	}
   134  
   135  	return nil
   136  }
   137  
   138  // SerializeEncryptedKey serializes an encrypted key packet to w that contains
   139  // key, encrypted to pub.
   140  // If config is nil, sensible defaults will be used.
   141  func SerializeEncryptedKey(w io.Writer, pub *PublicKey, cipherFunc CipherFunction, key []byte, config *Config) error {
   142  	var buf [10]byte
   143  	buf[0] = encryptedKeyVersion
   144  	binary.BigEndian.PutUint64(buf[1:9], pub.KeyId)
   145  	buf[9] = byte(pub.PubKeyAlgo)
   146  
   147  	keyBlock := make([]byte, 1 /* cipher type */ +len(key)+2 /* checksum */)
   148  	keyBlock[0] = byte(cipherFunc)
   149  	copy(keyBlock[1:], key)
   150  	checksum := checksumKeyMaterial(key)
   151  	keyBlock[1+len(key)] = byte(checksum >> 8)
   152  	keyBlock[1+len(key)+1] = byte(checksum)
   153  
   154  	switch pub.PubKeyAlgo {
   155  	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
   156  		return serializeEncryptedKeyRSA(w, config.Random(), buf, pub.PublicKey.(*rsa.PublicKey), keyBlock)
   157  	case PubKeyAlgoElGamal:
   158  		return serializeEncryptedKeyElGamal(w, config.Random(), buf, pub.PublicKey.(*elgamal.PublicKey), keyBlock)
   159  	case PubKeyAlgoDSA, PubKeyAlgoRSASignOnly:
   160  		return errors.InvalidArgumentError("cannot encrypt to public key of type " + strconv.Itoa(int(pub.PubKeyAlgo)))
   161  	}
   162  
   163  	return errors.UnsupportedError("encrypting a key to public key of type " + strconv.Itoa(int(pub.PubKeyAlgo)))
   164  }
   165  
   166  func serializeEncryptedKeyRSA(w io.Writer, rand io.Reader, header [10]byte, pub *rsa.PublicKey, keyBlock []byte) error {
   167  	cipherText, err := rsa.EncryptPKCS1v15(rand, pub, keyBlock)
   168  	if err != nil {
   169  		return errors.InvalidArgumentError("RSA encryption failed: " + err.Error())
   170  	}
   171  
   172  	packetLen := 10 /* header length */ + 2 /* mpi size */ + len(cipherText)
   173  
   174  	err = serializeHeader(w, packetTypeEncryptedKey, packetLen)
   175  	if err != nil {
   176  		return err
   177  	}
   178  	_, err = w.Write(header[:])
   179  	if err != nil {
   180  		return err
   181  	}
   182  	return writeMPI(w, 8*uint16(len(cipherText)), cipherText)
   183  }
   184  
   185  func serializeEncryptedKeyElGamal(w io.Writer, rand io.Reader, header [10]byte, pub *elgamal.PublicKey, keyBlock []byte) error {
   186  	c1, c2, err := elgamal.Encrypt(rand, pub, keyBlock)
   187  	if err != nil {
   188  		return errors.InvalidArgumentError("ElGamal encryption failed: " + err.Error())
   189  	}
   190  
   191  	packetLen := 10 /* header length */
   192  	packetLen += 2 /* mpi size */ + (c1.BitLen()+7)/8
   193  	packetLen += 2 /* mpi size */ + (c2.BitLen()+7)/8
   194  
   195  	err = serializeHeader(w, packetTypeEncryptedKey, packetLen)
   196  	if err != nil {
   197  		return err
   198  	}
   199  	_, err = w.Write(header[:])
   200  	if err != nil {
   201  		return err
   202  	}
   203  	err = writeBig(w, c1)
   204  	if err != nil {
   205  		return err
   206  	}
   207  	return writeBig(w, c2)
   208  }
   209  

View as plain text