1
2
3
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
18
19 const maxSessionKeySizeInBytes = 64
20
21
22
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
30 }
31
32
33
34 func (ske *SymmetricKeyEncrypted) parse(r io.Reader) error {
35 var buf [1]byte
36
37
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
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
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
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
84
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
100
101
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
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
151
152
153
154
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
174
175
176
177
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
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
195
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 + len(s2kBytes) + 1 + 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
217 buf := []byte{byte(version)}
218
219
220 buf = append(buf, byte(cipherFunc))
221
222 if version == 5 {
223
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
252 iv := make([]byte, config.AEAD().Mode().IvLength())
253 _, err = io.ReadFull(config.Random(), iv)
254 if err != nil {
255 return
256 }
257
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