...

Source file src/github.com/ProtonMail/go-crypto/openpgp/packet/symmetric_key_encrypted.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  	"bytes"
     9  	"crypto/cipher"
    10  	"io"
    11  	"strconv"
    12  
    13  	"github.com/ProtonMail/go-crypto/openpgp/errors"
    14  	"github.com/ProtonMail/go-crypto/openpgp/s2k"
    15  )
    16  
    17  // This is the largest session key that we'll support. Since at most 256-bit cipher
    18  // is supported in OpenPGP, this is large enough to contain also the auth tag.
    19  const maxSessionKeySizeInBytes = 64
    20  
    21  // SymmetricKeyEncrypted represents a passphrase protected session key. See RFC
    22  // 4880, section 5.3.
    23  type SymmetricKeyEncrypted struct {
    24  	Version      int
    25  	CipherFunc   CipherFunction
    26  	Mode         AEADMode
    27  	s2k          func(out, in []byte)
    28  	iv           []byte
    29  	encryptedKey []byte // Contains also the authentication tag for AEAD
    30  }
    31  
    32  // parse parses an SymmetricKeyEncrypted packet as specified in
    33  // https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-07.html#name-symmetric-key-encrypted-ses
    34  func (ske *SymmetricKeyEncrypted) parse(r io.Reader) error {
    35  	var buf [1]byte
    36  
    37  	// Version
    38  	if _, err := readFull(r, buf[:]); err != nil {
    39  		return err
    40  	}
    41  	ske.Version = int(buf[0])
    42  	if ske.Version != 4 && ske.Version != 5 {
    43  		return errors.UnsupportedError("unknown SymmetricKeyEncrypted version")
    44  	}
    45  
    46  	// Cipher function
    47  	if _, err := readFull(r, buf[:]); err != nil {
    48  		return err
    49  	}
    50  	ske.CipherFunc = CipherFunction(buf[0])
    51  	if !ske.CipherFunc.IsSupported() {
    52  		return errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(buf[0])))
    53  	}
    54  
    55  	if ske.Version == 5 {
    56  		// AEAD mode
    57  		if _, err := readFull(r, buf[:]); err != nil {
    58  			return errors.StructuralError("cannot read AEAD octet from packet")
    59  		}
    60  		ske.Mode = AEADMode(buf[0])
    61  	}
    62  
    63  	var err error
    64  	if ske.s2k, err = s2k.Parse(r); err != nil {
    65  		if _, ok := err.(errors.ErrDummyPrivateKey); ok {
    66  			return errors.UnsupportedError("missing key GNU extension in session key")
    67  		}
    68  		return err
    69  	}
    70  
    71  	if ske.Version == 5 {
    72  		// AEAD IV
    73  		iv := make([]byte, ske.Mode.IvLength())
    74  		_, err := readFull(r, iv)
    75  		if err != nil {
    76  			return errors.StructuralError("cannot read AEAD IV")
    77  		}
    78  
    79  		ske.iv = iv
    80  	}
    81  
    82  	encryptedKey := make([]byte, maxSessionKeySizeInBytes)
    83  	// The session key may follow. We just have to try and read to find
    84  	// out. If it exists then we limit it to maxSessionKeySizeInBytes.
    85  	n, err := readFull(r, encryptedKey)
    86  	if err != nil && err != io.ErrUnexpectedEOF {
    87  		return err
    88  	}
    89  
    90  	if n != 0 {
    91  		if n == maxSessionKeySizeInBytes {
    92  			return errors.UnsupportedError("oversized encrypted session key")
    93  		}
    94  		ske.encryptedKey = encryptedKey[:n]
    95  	}
    96  	return nil
    97  }
    98  
    99  // Decrypt attempts to decrypt an encrypted session key and returns the key and
   100  // the cipher to use when decrypting a subsequent Symmetrically Encrypted Data
   101  // packet.
   102  func (ske *SymmetricKeyEncrypted) Decrypt(passphrase []byte) ([]byte, CipherFunction, error) {
   103  	key := make([]byte, ske.CipherFunc.KeySize())
   104  	ske.s2k(key, passphrase)
   105  	if len(ske.encryptedKey) == 0 {
   106  		return key, ske.CipherFunc, nil
   107  	}
   108  	switch ske.Version {
   109  	case 4:
   110  		plaintextKey, cipherFunc, err := ske.decryptV4(key)
   111  		return plaintextKey, cipherFunc, err
   112  	case 5:
   113  		plaintextKey, err := ske.decryptV5(key)
   114  		return plaintextKey, CipherFunction(0), err
   115  	}
   116  	err := errors.UnsupportedError("unknown SymmetricKeyEncrypted version")
   117  	return nil, CipherFunction(0), err
   118  }
   119  
   120  func (ske *SymmetricKeyEncrypted) decryptV4(key []byte) ([]byte, CipherFunction, error) {
   121  	// the IV is all zeros
   122  	iv := make([]byte, ske.CipherFunc.blockSize())
   123  	c := cipher.NewCFBDecrypter(ske.CipherFunc.new(key), iv)
   124  	plaintextKey := make([]byte, len(ske.encryptedKey))
   125  	c.XORKeyStream(plaintextKey, ske.encryptedKey)
   126  	cipherFunc := CipherFunction(plaintextKey[0])
   127  	if cipherFunc.blockSize() == 0 {
   128  		return nil, ske.CipherFunc, errors.UnsupportedError(
   129  			"unknown cipher: " + strconv.Itoa(int(cipherFunc)))
   130  	}
   131  	plaintextKey = plaintextKey[1:]
   132  	if len(plaintextKey) != cipherFunc.KeySize() {
   133  		return nil, cipherFunc, errors.StructuralError(
   134  			"length of decrypted key not equal to cipher keysize")
   135  	}
   136  	return plaintextKey, cipherFunc, nil
   137  }
   138  
   139  func (ske *SymmetricKeyEncrypted) decryptV5(key []byte) ([]byte, error) {
   140  	adata := []byte{0xc3, byte(5), byte(ske.CipherFunc), byte(ske.Mode)}
   141  	aead := getEncryptedKeyAeadInstance(ske.CipherFunc, ske.Mode, key, adata)
   142  
   143  	plaintextKey, err := aead.Open(nil, ske.iv, ske.encryptedKey, adata)
   144  	if err != nil {
   145  		return nil, err
   146  	}
   147  	return plaintextKey, nil
   148  }
   149  
   150  // SerializeSymmetricKeyEncrypted serializes a symmetric key packet to w.
   151  // The packet contains a random session key, encrypted by a key derived from
   152  // the given passphrase. The session key is returned and must be passed to
   153  // SerializeSymmetricallyEncrypted.
   154  // If config is nil, sensible defaults will be used.
   155  func SerializeSymmetricKeyEncrypted(w io.Writer, passphrase []byte, config *Config) (key []byte, err error) {
   156  	cipherFunc := config.Cipher()
   157  
   158  	sessionKey := make([]byte, cipherFunc.KeySize())
   159  	_, err = io.ReadFull(config.Random(), sessionKey)
   160  	if err != nil {
   161  		return
   162  	}
   163  
   164  	err = SerializeSymmetricKeyEncryptedReuseKey(w, sessionKey, passphrase, config)
   165  	if err != nil {
   166  		return
   167  	}
   168  
   169  	key = sessionKey
   170  	return
   171  }
   172  
   173  // SerializeSymmetricKeyEncryptedReuseKey serializes a symmetric key packet to w.
   174  // The packet contains the given session key, encrypted by a key derived from
   175  // the given passphrase. The returned session key must be passed to
   176  // SerializeSymmetricallyEncrypted.
   177  // If config is nil, sensible defaults will be used.
   178  func SerializeSymmetricKeyEncryptedReuseKey(w io.Writer, sessionKey []byte, passphrase []byte, config *Config) (err error) {
   179  	var version int
   180  	if config.AEAD() != nil {
   181  		version = 5
   182  	} else {
   183  		version = 4
   184  	}
   185  	cipherFunc := config.Cipher()
   186  	// cipherFunc must be AES
   187  	if !cipherFunc.IsSupported() || cipherFunc < CipherAES128 || cipherFunc > CipherAES256 {
   188  		return errors.UnsupportedError("unsupported cipher: " + strconv.Itoa(int(cipherFunc)))
   189  	}
   190  
   191  	keySize := cipherFunc.KeySize()
   192  	s2kBuf := new(bytes.Buffer)
   193  	keyEncryptingKey := make([]byte, keySize)
   194  	// s2k.Serialize salts and stretches the passphrase, and writes the
   195  	// resulting key to keyEncryptingKey and the s2k descriptor to s2kBuf.
   196  	err = s2k.Serialize(s2kBuf, keyEncryptingKey, config.Random(), passphrase, config.S2K())
   197  	if err != nil {
   198  		return
   199  	}
   200  	s2kBytes := s2kBuf.Bytes()
   201  
   202  	var packetLength int
   203  	switch version {
   204  	case 4:
   205  		packetLength = 2 /* header */ + len(s2kBytes) + 1 /* cipher type */ + keySize
   206  	case 5:
   207  		ivLen := config.AEAD().Mode().IvLength()
   208  		tagLen := config.AEAD().Mode().TagLength()
   209  		packetLength = 3 + len(s2kBytes) + ivLen + keySize + tagLen
   210  	}
   211  	err = serializeHeader(w, packetTypeSymmetricKeyEncrypted, packetLength)
   212  	if err != nil {
   213  		return
   214  	}
   215  
   216  	// Symmetric Key Encrypted Version
   217  	buf := []byte{byte(version)}
   218  
   219  	// Cipher function
   220  	buf = append(buf, byte(cipherFunc))
   221  
   222  	if version == 5 {
   223  		// AEAD mode
   224  		buf = append(buf, byte(config.AEAD().Mode()))
   225  	}
   226  	_, err = w.Write(buf)
   227  	if err != nil {
   228  		return
   229  	}
   230  	_, err = w.Write(s2kBytes)
   231  	if err != nil {
   232  		return
   233  	}
   234  
   235  	switch version {
   236  	case 4:
   237  		iv := make([]byte, cipherFunc.blockSize())
   238  		c := cipher.NewCFBEncrypter(cipherFunc.new(keyEncryptingKey), iv)
   239  		encryptedCipherAndKey := make([]byte, keySize+1)
   240  		c.XORKeyStream(encryptedCipherAndKey, buf[1:])
   241  		c.XORKeyStream(encryptedCipherAndKey[1:], sessionKey)
   242  		_, err = w.Write(encryptedCipherAndKey)
   243  		if err != nil {
   244  			return
   245  		}
   246  	case 5:
   247  		mode := config.AEAD().Mode()
   248  		adata := []byte{0xc3, byte(5), byte(cipherFunc), byte(mode)}
   249  		aead := getEncryptedKeyAeadInstance(cipherFunc, mode, keyEncryptingKey, adata)
   250  
   251  		// Sample iv using random reader
   252  		iv := make([]byte, config.AEAD().Mode().IvLength())
   253  		_, err = io.ReadFull(config.Random(), iv)
   254  		if err != nil {
   255  			return
   256  		}
   257  		// Seal and write (encryptedData includes auth. tag)
   258  
   259  		encryptedData := aead.Seal(nil, iv, sessionKey, adata)
   260  		_, err = w.Write(iv)
   261  		if err != nil {
   262  			return
   263  		}
   264  		_, err = w.Write(encryptedData)
   265  		if err != nil {
   266  			return
   267  		}
   268  	}
   269  
   270  	return
   271  }
   272  
   273  func getEncryptedKeyAeadInstance(c CipherFunction, mode AEADMode, inputKey, associatedData []byte) (aead cipher.AEAD) {
   274  	blockCipher := c.new(inputKey)
   275  	return mode.new(blockCipher)
   276  }
   277  

View as plain text