...

Source file src/github.com/ProtonMail/go-crypto/openpgp/packet/encrypted_key.go

Documentation: github.com/ProtonMail/go-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  	"github.com/ProtonMail/go-crypto/openpgp/ecdh"
    16  	"github.com/ProtonMail/go-crypto/openpgp/elgamal"
    17  	"github.com/ProtonMail/go-crypto/openpgp/errors"
    18  	"github.com/ProtonMail/go-crypto/openpgp/internal/encoding"
    19  )
    20  
    21  const encryptedKeyVersion = 3
    22  
    23  // EncryptedKey represents a public-key encrypted session key. See RFC 4880,
    24  // section 5.1.
    25  type EncryptedKey struct {
    26  	KeyId      uint64
    27  	Algo       PublicKeyAlgorithm
    28  	CipherFunc CipherFunction // only valid after a successful Decrypt for a v3 packet
    29  	Key        []byte         // only valid after a successful Decrypt
    30  
    31  	encryptedMPI1, encryptedMPI2 encoding.Field
    32  }
    33  
    34  func (e *EncryptedKey) parse(r io.Reader) (err error) {
    35  	var buf [10]byte
    36  	_, err = readFull(r, buf[:])
    37  	if err != nil {
    38  		return
    39  	}
    40  	if buf[0] != encryptedKeyVersion {
    41  		return errors.UnsupportedError("unknown EncryptedKey version " + strconv.Itoa(int(buf[0])))
    42  	}
    43  	e.KeyId = binary.BigEndian.Uint64(buf[1:9])
    44  	e.Algo = PublicKeyAlgorithm(buf[9])
    45  	switch e.Algo {
    46  	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
    47  		e.encryptedMPI1 = new(encoding.MPI)
    48  		if _, err = e.encryptedMPI1.ReadFrom(r); err != nil {
    49  			return
    50  		}
    51  	case PubKeyAlgoElGamal:
    52  		e.encryptedMPI1 = new(encoding.MPI)
    53  		if _, err = e.encryptedMPI1.ReadFrom(r); err != nil {
    54  			return
    55  		}
    56  
    57  		e.encryptedMPI2 = new(encoding.MPI)
    58  		if _, err = e.encryptedMPI2.ReadFrom(r); err != nil {
    59  			return
    60  		}
    61  	case PubKeyAlgoECDH:
    62  		e.encryptedMPI1 = new(encoding.MPI)
    63  		if _, err = e.encryptedMPI1.ReadFrom(r); err != nil {
    64  			return
    65  		}
    66  
    67  		e.encryptedMPI2 = new(encoding.OID)
    68  		if _, err = e.encryptedMPI2.ReadFrom(r); err != nil {
    69  			return
    70  		}
    71  	}
    72  	_, err = consumeAll(r)
    73  	return
    74  }
    75  
    76  func checksumKeyMaterial(key []byte) uint16 {
    77  	var checksum uint16
    78  	for _, v := range key {
    79  		checksum += uint16(v)
    80  	}
    81  	return checksum
    82  }
    83  
    84  // Decrypt decrypts an encrypted session key with the given private key. The
    85  // private key must have been decrypted first.
    86  // If config is nil, sensible defaults will be used.
    87  func (e *EncryptedKey) Decrypt(priv *PrivateKey, config *Config) error {
    88  	if e.KeyId != 0 && e.KeyId != priv.KeyId {
    89  		return errors.InvalidArgumentError("cannot decrypt encrypted session key for key id " + strconv.FormatUint(e.KeyId, 16) + " with private key id " + strconv.FormatUint(priv.KeyId, 16))
    90  	}
    91  	if e.Algo != priv.PubKeyAlgo {
    92  		return errors.InvalidArgumentError("cannot decrypt encrypted session key of type " + strconv.Itoa(int(e.Algo)) + " with private key of type " + strconv.Itoa(int(priv.PubKeyAlgo)))
    93  	}
    94  	if priv.Dummy() {
    95  		return errors.ErrDummyPrivateKey("dummy key found")
    96  	}
    97  
    98  	var err error
    99  	var b []byte
   100  
   101  	// TODO(agl): use session key decryption routines here to avoid
   102  	// padding oracle attacks.
   103  	switch priv.PubKeyAlgo {
   104  	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
   105  		// Supports both *rsa.PrivateKey and crypto.Decrypter
   106  		k := priv.PrivateKey.(crypto.Decrypter)
   107  		b, err = k.Decrypt(config.Random(), padToKeySize(k.Public().(*rsa.PublicKey), e.encryptedMPI1.Bytes()), nil)
   108  	case PubKeyAlgoElGamal:
   109  		c1 := new(big.Int).SetBytes(e.encryptedMPI1.Bytes())
   110  		c2 := new(big.Int).SetBytes(e.encryptedMPI2.Bytes())
   111  		b, err = elgamal.Decrypt(priv.PrivateKey.(*elgamal.PrivateKey), c1, c2)
   112  	case PubKeyAlgoECDH:
   113  		vsG := e.encryptedMPI1.Bytes()
   114  		m := e.encryptedMPI2.Bytes()
   115  		oid := priv.PublicKey.oid.EncodedBytes()
   116  		b, err = ecdh.Decrypt(priv.PrivateKey.(*ecdh.PrivateKey), vsG, m, oid, priv.PublicKey.Fingerprint[:])
   117  	default:
   118  		err = errors.InvalidArgumentError("cannot decrypt encrypted session key with private key of type " + strconv.Itoa(int(priv.PubKeyAlgo)))
   119  	}
   120  
   121  	if err != nil {
   122  		return err
   123  	}
   124  
   125  	e.CipherFunc = CipherFunction(b[0])
   126  	if !e.CipherFunc.IsSupported() {
   127  		return errors.UnsupportedError("unsupported encryption function")
   128  	}
   129  
   130  	e.Key = b[1 : len(b)-2]
   131  	expectedChecksum := uint16(b[len(b)-2])<<8 | uint16(b[len(b)-1])
   132  	checksum := checksumKeyMaterial(e.Key)
   133  	if checksum != expectedChecksum {
   134  		return errors.StructuralError("EncryptedKey checksum incorrect")
   135  	}
   136  
   137  	return nil
   138  }
   139  
   140  // Serialize writes the encrypted key packet, e, to w.
   141  func (e *EncryptedKey) Serialize(w io.Writer) error {
   142  	var mpiLen int
   143  	switch e.Algo {
   144  	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
   145  		mpiLen = int(e.encryptedMPI1.EncodedLength())
   146  	case PubKeyAlgoElGamal:
   147  		mpiLen = int(e.encryptedMPI1.EncodedLength()) + int(e.encryptedMPI2.EncodedLength())
   148  	case PubKeyAlgoECDH:
   149  		mpiLen = int(e.encryptedMPI1.EncodedLength()) + int(e.encryptedMPI2.EncodedLength())
   150  	default:
   151  		return errors.InvalidArgumentError("don't know how to serialize encrypted key type " + strconv.Itoa(int(e.Algo)))
   152  	}
   153  
   154  	err := serializeHeader(w, packetTypeEncryptedKey, 1 /* version */ +8 /* key id */ +1 /* algo */ +mpiLen)
   155  	if err != nil {
   156  		return err
   157  	}
   158  
   159  	w.Write([]byte{encryptedKeyVersion})
   160  	binary.Write(w, binary.BigEndian, e.KeyId)
   161  	w.Write([]byte{byte(e.Algo)})
   162  
   163  	switch e.Algo {
   164  	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
   165  		_, err := w.Write(e.encryptedMPI1.EncodedBytes())
   166  		return err
   167  	case PubKeyAlgoElGamal:
   168  		if _, err := w.Write(e.encryptedMPI1.EncodedBytes()); err != nil {
   169  			return err
   170  		}
   171  		_, err := w.Write(e.encryptedMPI2.EncodedBytes())
   172  		return err
   173  	case PubKeyAlgoECDH:
   174  		if _, err := w.Write(e.encryptedMPI1.EncodedBytes()); err != nil {
   175  			return err
   176  		}
   177  		_, err := w.Write(e.encryptedMPI2.EncodedBytes())
   178  		return err
   179  	default:
   180  		panic("internal error")
   181  	}
   182  }
   183  
   184  // SerializeEncryptedKey serializes an encrypted key packet to w that contains
   185  // key, encrypted to pub.
   186  // If config is nil, sensible defaults will be used.
   187  func SerializeEncryptedKey(w io.Writer, pub *PublicKey, cipherFunc CipherFunction, key []byte, config *Config) error {
   188  	var buf [10]byte
   189  	buf[0] = encryptedKeyVersion
   190  	binary.BigEndian.PutUint64(buf[1:9], pub.KeyId)
   191  	buf[9] = byte(pub.PubKeyAlgo)
   192  
   193  	keyBlock := make([]byte, 1 /* cipher type */ +len(key)+2 /* checksum */)
   194  	keyBlock[0] = byte(cipherFunc)
   195  	copy(keyBlock[1:], key)
   196  	checksum := checksumKeyMaterial(key)
   197  	keyBlock[1+len(key)] = byte(checksum >> 8)
   198  	keyBlock[1+len(key)+1] = byte(checksum)
   199  
   200  	switch pub.PubKeyAlgo {
   201  	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
   202  		return serializeEncryptedKeyRSA(w, config.Random(), buf, pub.PublicKey.(*rsa.PublicKey), keyBlock)
   203  	case PubKeyAlgoElGamal:
   204  		return serializeEncryptedKeyElGamal(w, config.Random(), buf, pub.PublicKey.(*elgamal.PublicKey), keyBlock)
   205  	case PubKeyAlgoECDH:
   206  		return serializeEncryptedKeyECDH(w, config.Random(), buf, pub.PublicKey.(*ecdh.PublicKey), keyBlock, pub.oid, pub.Fingerprint)
   207  	case PubKeyAlgoDSA, PubKeyAlgoRSASignOnly:
   208  		return errors.InvalidArgumentError("cannot encrypt to public key of type " + strconv.Itoa(int(pub.PubKeyAlgo)))
   209  	}
   210  
   211  	return errors.UnsupportedError("encrypting a key to public key of type " + strconv.Itoa(int(pub.PubKeyAlgo)))
   212  }
   213  
   214  func serializeEncryptedKeyRSA(w io.Writer, rand io.Reader, header [10]byte, pub *rsa.PublicKey, keyBlock []byte) error {
   215  	cipherText, err := rsa.EncryptPKCS1v15(rand, pub, keyBlock)
   216  	if err != nil {
   217  		return errors.InvalidArgumentError("RSA encryption failed: " + err.Error())
   218  	}
   219  
   220  	cipherMPI := encoding.NewMPI(cipherText)
   221  	packetLen := 10 /* header length */ + int(cipherMPI.EncodedLength())
   222  
   223  	err = serializeHeader(w, packetTypeEncryptedKey, packetLen)
   224  	if err != nil {
   225  		return err
   226  	}
   227  	_, err = w.Write(header[:])
   228  	if err != nil {
   229  		return err
   230  	}
   231  	_, err = w.Write(cipherMPI.EncodedBytes())
   232  	return err
   233  }
   234  
   235  func serializeEncryptedKeyElGamal(w io.Writer, rand io.Reader, header [10]byte, pub *elgamal.PublicKey, keyBlock []byte) error {
   236  	c1, c2, err := elgamal.Encrypt(rand, pub, keyBlock)
   237  	if err != nil {
   238  		return errors.InvalidArgumentError("ElGamal encryption failed: " + err.Error())
   239  	}
   240  
   241  	packetLen := 10 /* header length */
   242  	packetLen += 2 /* mpi size */ + (c1.BitLen()+7)/8
   243  	packetLen += 2 /* mpi size */ + (c2.BitLen()+7)/8
   244  
   245  	err = serializeHeader(w, packetTypeEncryptedKey, packetLen)
   246  	if err != nil {
   247  		return err
   248  	}
   249  	_, err = w.Write(header[:])
   250  	if err != nil {
   251  		return err
   252  	}
   253  	if _, err = w.Write(new(encoding.MPI).SetBig(c1).EncodedBytes()); err != nil {
   254  		return err
   255  	}
   256  	_, err = w.Write(new(encoding.MPI).SetBig(c2).EncodedBytes())
   257  	return err
   258  }
   259  
   260  func serializeEncryptedKeyECDH(w io.Writer, rand io.Reader, header [10]byte, pub *ecdh.PublicKey, keyBlock []byte, oid encoding.Field, fingerprint []byte) error {
   261  	vsG, c, err := ecdh.Encrypt(rand, pub, keyBlock, oid.EncodedBytes(), fingerprint)
   262  	if err != nil {
   263  		return errors.InvalidArgumentError("ECDH encryption failed: " + err.Error())
   264  	}
   265  
   266  	g := encoding.NewMPI(vsG)
   267  	m := encoding.NewOID(c)
   268  
   269  	packetLen := 10 /* header length */
   270  	packetLen += int(g.EncodedLength()) + int(m.EncodedLength())
   271  
   272  	err = serializeHeader(w, packetTypeEncryptedKey, packetLen)
   273  	if err != nil {
   274  		return err
   275  	}
   276  
   277  	_, err = w.Write(header[:])
   278  	if err != nil {
   279  		return err
   280  	}
   281  	if _, err = w.Write(g.EncodedBytes()); err != nil {
   282  		return err
   283  	}
   284  	_, err = w.Write(m.EncodedBytes())
   285  	return err
   286  }
   287  

View as plain text