github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/crypto/openpgp/packet/encrypted_key.go (about)

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