...

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

Documentation: github.com/ProtonMail/go-crypto/openpgp/packet

     1  // Copyright (C) 2019 ProtonTech AG
     2  
     3  package packet
     4  
     5  import (
     6  	"io"
     7  
     8  	"github.com/ProtonMail/go-crypto/openpgp/errors"
     9  	"github.com/ProtonMail/go-crypto/openpgp/internal/algorithm"
    10  )
    11  
    12  // AEADEncrypted represents an AEAD Encrypted Packet.
    13  // See https://www.ietf.org/archive/id/draft-koch-openpgp-2015-rfc4880bis-00.html#name-aead-encrypted-data-packet-t
    14  type AEADEncrypted struct {
    15  	cipher        CipherFunction
    16  	mode          AEADMode
    17  	chunkSizeByte byte
    18  	Contents      io.Reader // Encrypted chunks and tags
    19  	initialNonce  []byte    // Referred to as IV in RFC4880-bis
    20  }
    21  
    22  // Only currently defined version
    23  const aeadEncryptedVersion = 1
    24  
    25  func (ae *AEADEncrypted) parse(buf io.Reader) error {
    26  	headerData := make([]byte, 4)
    27  	if n, err := io.ReadFull(buf, headerData); n < 4 {
    28  		return errors.AEADError("could not read aead header:" + err.Error())
    29  	}
    30  	// Read initial nonce
    31  	mode := AEADMode(headerData[2])
    32  	nonceLen := mode.IvLength()
    33  
    34  	// This packet supports only EAX and OCB
    35  	// https://www.ietf.org/archive/id/draft-koch-openpgp-2015-rfc4880bis-00.html#name-aead-encrypted-data-packet-t
    36  	if nonceLen == 0 || mode > AEADModeOCB {
    37  		return errors.AEADError("unknown mode")
    38  	}
    39  
    40  	initialNonce := make([]byte, nonceLen)
    41  	if n, err := io.ReadFull(buf, initialNonce); n < nonceLen {
    42  		return errors.AEADError("could not read aead nonce:" + err.Error())
    43  	}
    44  	ae.Contents = buf
    45  	ae.initialNonce = initialNonce
    46  	c := headerData[1]
    47  	if _, ok := algorithm.CipherById[c]; !ok {
    48  		return errors.UnsupportedError("unknown cipher: " + string(c))
    49  	}
    50  	ae.cipher = CipherFunction(c)
    51  	ae.mode = mode
    52  	ae.chunkSizeByte = headerData[3]
    53  	return nil
    54  }
    55  
    56  // Decrypt returns a io.ReadCloser from which decrypted bytes can be read, or
    57  // an error.
    58  func (ae *AEADEncrypted) Decrypt(ciph CipherFunction, key []byte) (io.ReadCloser, error) {
    59  	return ae.decrypt(key)
    60  }
    61  
    62  // decrypt prepares an aeadCrypter and returns a ReadCloser from which
    63  // decrypted bytes can be read (see aeadDecrypter.Read()).
    64  func (ae *AEADEncrypted) decrypt(key []byte) (io.ReadCloser, error) {
    65  	blockCipher := ae.cipher.new(key)
    66  	aead := ae.mode.new(blockCipher)
    67  	// Carry the first tagLen bytes
    68  	tagLen := ae.mode.TagLength()
    69  	peekedBytes := make([]byte, tagLen)
    70  	n, err := io.ReadFull(ae.Contents, peekedBytes)
    71  	if n < tagLen || (err != nil && err != io.EOF) {
    72  		return nil, errors.AEADError("Not enough data to decrypt:" + err.Error())
    73  	}
    74  	chunkSize := decodeAEADChunkSize(ae.chunkSizeByte)
    75  	return &aeadDecrypter{
    76  		aeadCrypter: aeadCrypter{
    77  			aead:           aead,
    78  			chunkSize:      chunkSize,
    79  			initialNonce:   ae.initialNonce,
    80  			associatedData: ae.associatedData(),
    81  			chunkIndex:     make([]byte, 8),
    82  			packetTag:      packetTypeAEADEncrypted,
    83  		},
    84  		reader:      ae.Contents,
    85  		peekedBytes: peekedBytes}, nil
    86  }
    87  
    88  // associatedData for chunks: tag, version, cipher, mode, chunk size byte
    89  func (ae *AEADEncrypted) associatedData() []byte {
    90  	return []byte{
    91  		0xD4,
    92  		aeadEncryptedVersion,
    93  		byte(ae.cipher),
    94  		byte(ae.mode),
    95  		ae.chunkSizeByte}
    96  }
    97  

View as plain text