1
2
3
4
5 package packet
6
7 import (
8 "crypto/cipher"
9 "crypto/sha256"
10 "io"
11
12 "github.com/ProtonMail/go-crypto/openpgp/errors"
13 "golang.org/x/crypto/hkdf"
14 )
15
16
17
18 func (se *SymmetricallyEncrypted) parseAead(r io.Reader) error {
19 headerData := make([]byte, 3)
20 if n, err := io.ReadFull(r, headerData); n < 3 {
21 return errors.StructuralError("could not read aead header: " + err.Error())
22 }
23
24
25 se.Cipher = CipherFunction(headerData[0])
26
27 if se.Cipher.blockSize() != 16 {
28 return errors.UnsupportedError("invalid aead cipher: " + string(se.Cipher))
29 }
30
31
32 se.Mode = AEADMode(headerData[1])
33 if se.Mode.TagLength() == 0 {
34 return errors.UnsupportedError("unknown aead mode: " + string(se.Mode))
35 }
36
37
38 se.ChunkSizeByte = headerData[2]
39 if se.ChunkSizeByte > 16 {
40 return errors.UnsupportedError("invalid aead chunk size byte: " + string(se.ChunkSizeByte))
41 }
42
43
44 if n, err := io.ReadFull(r, se.Salt[:]); n < aeadSaltSize {
45 return errors.StructuralError("could not read aead salt: " + err.Error())
46 }
47
48 return nil
49 }
50
51
52 func (se *SymmetricallyEncrypted) associatedData() []byte {
53 return []byte{
54 0xD2,
55 symmetricallyEncryptedVersionAead,
56 byte(se.Cipher),
57 byte(se.Mode),
58 se.ChunkSizeByte,
59 }
60 }
61
62
63
64 func (se *SymmetricallyEncrypted) decryptAead(inputKey []byte) (io.ReadCloser, error) {
65 aead, nonce := getSymmetricallyEncryptedAeadInstance(se.Cipher, se.Mode, inputKey, se.Salt[:], se.associatedData())
66
67
68 tagLen := se.Mode.TagLength()
69 peekedBytes := make([]byte, tagLen)
70 n, err := io.ReadFull(se.Contents, peekedBytes)
71 if n < tagLen || (err != nil && err != io.EOF) {
72 return nil, errors.StructuralError("not enough data to decrypt:" + err.Error())
73 }
74
75 return &aeadDecrypter{
76 aeadCrypter: aeadCrypter{
77 aead: aead,
78 chunkSize: decodeAEADChunkSize(se.ChunkSizeByte),
79 initialNonce: nonce,
80 associatedData: se.associatedData(),
81 chunkIndex: make([]byte, 8),
82 packetTag: packetTypeSymmetricallyEncryptedIntegrityProtected,
83 },
84 reader: se.Contents,
85 peekedBytes: peekedBytes,
86 }, nil
87 }
88
89
90
91 func serializeSymmetricallyEncryptedAead(ciphertext io.WriteCloser, cipherSuite CipherSuite, chunkSizeByte byte, rand io.Reader, inputKey []byte) (Contents io.WriteCloser, err error) {
92
93 if cipherSuite.Cipher.blockSize() != 16 {
94 return nil, errors.InvalidArgumentError("invalid aead cipher function")
95 }
96
97 if cipherSuite.Cipher.KeySize() != len(inputKey) {
98 return nil, errors.InvalidArgumentError("error in aead serialization: bad key length")
99 }
100
101
102 prefix := []byte{
103 0xD2,
104 symmetricallyEncryptedVersionAead,
105 byte(cipherSuite.Cipher),
106 byte(cipherSuite.Mode),
107 chunkSizeByte,
108 }
109
110
111 n, err := ciphertext.Write(prefix[1:])
112 if err != nil || n < 4 {
113 return nil, err
114 }
115
116
117 salt := make([]byte, aeadSaltSize)
118 if _, err := rand.Read(salt); err != nil {
119 return nil, err
120 }
121
122 if _, err := ciphertext.Write(salt); err != nil {
123 return nil, err
124 }
125
126 aead, nonce := getSymmetricallyEncryptedAeadInstance(cipherSuite.Cipher, cipherSuite.Mode, inputKey, salt, prefix)
127
128 return &aeadEncrypter{
129 aeadCrypter: aeadCrypter{
130 aead: aead,
131 chunkSize: decodeAEADChunkSize(chunkSizeByte),
132 associatedData: prefix,
133 chunkIndex: make([]byte, 8),
134 initialNonce: nonce,
135 packetTag: packetTypeSymmetricallyEncryptedIntegrityProtected,
136 },
137 writer: ciphertext,
138 }, nil
139 }
140
141 func getSymmetricallyEncryptedAeadInstance(c CipherFunction, mode AEADMode, inputKey, salt, associatedData []byte) (aead cipher.AEAD, nonce []byte) {
142 hkdfReader := hkdf.New(sha256.New, inputKey, salt, associatedData)
143
144 encryptionKey := make([]byte, c.KeySize())
145 _, _ = readFull(hkdfReader, encryptionKey)
146
147
148 nonce = make([]byte, mode.IvLength()-8)
149
150 _, _ = readFull(hkdfReader, nonce)
151
152 blockCipher := c.new(encryptionKey)
153 aead = mode.new(blockCipher)
154
155 return
156 }
157
View as plain text