main
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
5package packet
6
7import (
8 "bytes"
9 "crypto"
10 "crypto/rsa"
11 "encoding/binary"
12 "encoding/hex"
13 "io"
14 "math/big"
15 "strconv"
16
17 "github.com/ProtonMail/go-crypto/openpgp/ecdh"
18 "github.com/ProtonMail/go-crypto/openpgp/elgamal"
19 "github.com/ProtonMail/go-crypto/openpgp/errors"
20 "github.com/ProtonMail/go-crypto/openpgp/internal/encoding"
21 "github.com/ProtonMail/go-crypto/openpgp/x25519"
22 "github.com/ProtonMail/go-crypto/openpgp/x448"
23)
24
25// EncryptedKey represents a public-key encrypted session key. See RFC 4880,
26// section 5.1.
27type EncryptedKey struct {
28 Version int
29 KeyId uint64
30 KeyVersion int // v6
31 KeyFingerprint []byte // v6
32 Algo PublicKeyAlgorithm
33 CipherFunc CipherFunction // only valid after a successful Decrypt for a v3 packet
34 Key []byte // only valid after a successful Decrypt
35
36 encryptedMPI1, encryptedMPI2 encoding.Field
37 ephemeralPublicX25519 *x25519.PublicKey // used for x25519
38 ephemeralPublicX448 *x448.PublicKey // used for x448
39 encryptedSession []byte // used for x25519 and x448
40}
41
42func (e *EncryptedKey) parse(r io.Reader) (err error) {
43 var buf [8]byte
44 _, err = readFull(r, buf[:versionSize])
45 if err != nil {
46 return
47 }
48 e.Version = int(buf[0])
49 if e.Version != 3 && e.Version != 6 {
50 return errors.UnsupportedError("unknown EncryptedKey version " + strconv.Itoa(int(buf[0])))
51 }
52 if e.Version == 6 {
53 //Read a one-octet size of the following two fields.
54 if _, err = readFull(r, buf[:1]); err != nil {
55 return
56 }
57 // The size may also be zero, and the key version and
58 // fingerprint omitted for an "anonymous recipient"
59 if buf[0] != 0 {
60 // non-anonymous case
61 _, err = readFull(r, buf[:versionSize])
62 if err != nil {
63 return
64 }
65 e.KeyVersion = int(buf[0])
66 if e.KeyVersion != 4 && e.KeyVersion != 6 {
67 return errors.UnsupportedError("unknown public key version " + strconv.Itoa(e.KeyVersion))
68 }
69 var fingerprint []byte
70 if e.KeyVersion == 6 {
71 fingerprint = make([]byte, fingerprintSizeV6)
72 } else if e.KeyVersion == 4 {
73 fingerprint = make([]byte, fingerprintSize)
74 }
75 _, err = readFull(r, fingerprint)
76 if err != nil {
77 return
78 }
79 e.KeyFingerprint = fingerprint
80 if e.KeyVersion == 6 {
81 e.KeyId = binary.BigEndian.Uint64(e.KeyFingerprint[:keyIdSize])
82 } else if e.KeyVersion == 4 {
83 e.KeyId = binary.BigEndian.Uint64(e.KeyFingerprint[fingerprintSize-keyIdSize : fingerprintSize])
84 }
85 }
86 } else {
87 _, err = readFull(r, buf[:8])
88 if err != nil {
89 return
90 }
91 e.KeyId = binary.BigEndian.Uint64(buf[:keyIdSize])
92 }
93
94 _, err = readFull(r, buf[:1])
95 if err != nil {
96 return
97 }
98 e.Algo = PublicKeyAlgorithm(buf[0])
99 var cipherFunction byte
100 switch e.Algo {
101 case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
102 e.encryptedMPI1 = new(encoding.MPI)
103 if _, err = e.encryptedMPI1.ReadFrom(r); err != nil {
104 return
105 }
106 case PubKeyAlgoElGamal:
107 e.encryptedMPI1 = new(encoding.MPI)
108 if _, err = e.encryptedMPI1.ReadFrom(r); err != nil {
109 return
110 }
111
112 e.encryptedMPI2 = new(encoding.MPI)
113 if _, err = e.encryptedMPI2.ReadFrom(r); err != nil {
114 return
115 }
116 case PubKeyAlgoECDH:
117 e.encryptedMPI1 = new(encoding.MPI)
118 if _, err = e.encryptedMPI1.ReadFrom(r); err != nil {
119 return
120 }
121
122 e.encryptedMPI2 = new(encoding.OID)
123 if _, err = e.encryptedMPI2.ReadFrom(r); err != nil {
124 return
125 }
126 case PubKeyAlgoX25519:
127 e.ephemeralPublicX25519, e.encryptedSession, cipherFunction, err = x25519.DecodeFields(r, e.Version == 6)
128 if err != nil {
129 return
130 }
131 case PubKeyAlgoX448:
132 e.ephemeralPublicX448, e.encryptedSession, cipherFunction, err = x448.DecodeFields(r, e.Version == 6)
133 if err != nil {
134 return
135 }
136 }
137 if e.Version < 6 {
138 switch e.Algo {
139 case PubKeyAlgoX25519, PubKeyAlgoX448:
140 e.CipherFunc = CipherFunction(cipherFunction)
141 // Check for validiy is in the Decrypt method
142 }
143 }
144
145 _, err = consumeAll(r)
146 return
147}
148
149// Decrypt decrypts an encrypted session key with the given private key. The
150// private key must have been decrypted first.
151// If config is nil, sensible defaults will be used.
152func (e *EncryptedKey) Decrypt(priv *PrivateKey, config *Config) error {
153 if e.Version < 6 && e.KeyId != 0 && e.KeyId != priv.KeyId {
154 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))
155 }
156 if e.Version == 6 && e.KeyVersion != 0 && !bytes.Equal(e.KeyFingerprint, priv.Fingerprint) {
157 return errors.InvalidArgumentError("cannot decrypt encrypted session key for key fingerprint " + hex.EncodeToString(e.KeyFingerprint) + " with private key fingerprint " + hex.EncodeToString(priv.Fingerprint))
158 }
159 if e.Algo != priv.PubKeyAlgo {
160 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)))
161 }
162 if priv.Dummy() {
163 return errors.ErrDummyPrivateKey("dummy key found")
164 }
165
166 var err error
167 var b []byte
168
169 // TODO(agl): use session key decryption routines here to avoid
170 // padding oracle attacks.
171 switch priv.PubKeyAlgo {
172 case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
173 // Supports both *rsa.PrivateKey and crypto.Decrypter
174 k := priv.PrivateKey.(crypto.Decrypter)
175 b, err = k.Decrypt(config.Random(), padToKeySize(k.Public().(*rsa.PublicKey), e.encryptedMPI1.Bytes()), nil)
176 case PubKeyAlgoElGamal:
177 c1 := new(big.Int).SetBytes(e.encryptedMPI1.Bytes())
178 c2 := new(big.Int).SetBytes(e.encryptedMPI2.Bytes())
179 b, err = elgamal.Decrypt(priv.PrivateKey.(*elgamal.PrivateKey), c1, c2)
180 case PubKeyAlgoECDH:
181 vsG := e.encryptedMPI1.Bytes()
182 m := e.encryptedMPI2.Bytes()
183 oid := priv.PublicKey.oid.EncodedBytes()
184 fp := priv.PublicKey.Fingerprint[:]
185 if priv.PublicKey.Version == 5 {
186 // For v5 the, the fingerprint must be restricted to 20 bytes
187 fp = fp[:20]
188 }
189 b, err = ecdh.Decrypt(priv.PrivateKey.(*ecdh.PrivateKey), vsG, m, oid, fp)
190 case PubKeyAlgoX25519:
191 b, err = x25519.Decrypt(priv.PrivateKey.(*x25519.PrivateKey), e.ephemeralPublicX25519, e.encryptedSession)
192 case PubKeyAlgoX448:
193 b, err = x448.Decrypt(priv.PrivateKey.(*x448.PrivateKey), e.ephemeralPublicX448, e.encryptedSession)
194 default:
195 err = errors.InvalidArgumentError("cannot decrypt encrypted session key with private key of type " + strconv.Itoa(int(priv.PubKeyAlgo)))
196 }
197 if err != nil {
198 return err
199 }
200
201 var key []byte
202 switch priv.PubKeyAlgo {
203 case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoElGamal, PubKeyAlgoECDH:
204 keyOffset := 0
205 if e.Version < 6 {
206 e.CipherFunc = CipherFunction(b[0])
207 keyOffset = 1
208 if !e.CipherFunc.IsSupported() {
209 return errors.UnsupportedError("unsupported encryption function")
210 }
211 }
212 key, err = decodeChecksumKey(b[keyOffset:])
213 if err != nil {
214 return err
215 }
216 case PubKeyAlgoX25519, PubKeyAlgoX448:
217 if e.Version < 6 {
218 switch e.CipherFunc {
219 case CipherAES128, CipherAES192, CipherAES256:
220 break
221 default:
222 return errors.StructuralError("v3 PKESK mandates AES as cipher function for x25519 and x448")
223 }
224 }
225 key = b[:]
226 default:
227 return errors.UnsupportedError("unsupported algorithm for decryption")
228 }
229 e.Key = key
230 return nil
231}
232
233// Serialize writes the encrypted key packet, e, to w.
234func (e *EncryptedKey) Serialize(w io.Writer) error {
235 var encodedLength int
236 switch e.Algo {
237 case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
238 encodedLength = int(e.encryptedMPI1.EncodedLength())
239 case PubKeyAlgoElGamal:
240 encodedLength = int(e.encryptedMPI1.EncodedLength()) + int(e.encryptedMPI2.EncodedLength())
241 case PubKeyAlgoECDH:
242 encodedLength = int(e.encryptedMPI1.EncodedLength()) + int(e.encryptedMPI2.EncodedLength())
243 case PubKeyAlgoX25519:
244 encodedLength = x25519.EncodedFieldsLength(e.encryptedSession, e.Version == 6)
245 case PubKeyAlgoX448:
246 encodedLength = x448.EncodedFieldsLength(e.encryptedSession, e.Version == 6)
247 default:
248 return errors.InvalidArgumentError("don't know how to serialize encrypted key type " + strconv.Itoa(int(e.Algo)))
249 }
250
251 packetLen := versionSize /* version */ + keyIdSize /* key id */ + algorithmSize /* algo */ + encodedLength
252 if e.Version == 6 {
253 packetLen = versionSize /* version */ + algorithmSize /* algo */ + encodedLength + keyVersionSize /* key version */
254 if e.KeyVersion == 6 {
255 packetLen += fingerprintSizeV6
256 } else if e.KeyVersion == 4 {
257 packetLen += fingerprintSize
258 }
259 }
260
261 err := serializeHeader(w, packetTypeEncryptedKey, packetLen)
262 if err != nil {
263 return err
264 }
265
266 _, err = w.Write([]byte{byte(e.Version)})
267 if err != nil {
268 return err
269 }
270 if e.Version == 6 {
271 _, err = w.Write([]byte{byte(e.KeyVersion)})
272 if err != nil {
273 return err
274 }
275 // The key version number may also be zero,
276 // and the fingerprint omitted
277 if e.KeyVersion != 0 {
278 _, err = w.Write(e.KeyFingerprint)
279 if err != nil {
280 return err
281 }
282 }
283 } else {
284 // Write KeyID
285 err = binary.Write(w, binary.BigEndian, e.KeyId)
286 if err != nil {
287 return err
288 }
289 }
290 _, err = w.Write([]byte{byte(e.Algo)})
291 if err != nil {
292 return err
293 }
294
295 switch e.Algo {
296 case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
297 _, err := w.Write(e.encryptedMPI1.EncodedBytes())
298 return err
299 case PubKeyAlgoElGamal:
300 if _, err := w.Write(e.encryptedMPI1.EncodedBytes()); err != nil {
301 return err
302 }
303 _, err := w.Write(e.encryptedMPI2.EncodedBytes())
304 return err
305 case PubKeyAlgoECDH:
306 if _, err := w.Write(e.encryptedMPI1.EncodedBytes()); err != nil {
307 return err
308 }
309 _, err := w.Write(e.encryptedMPI2.EncodedBytes())
310 return err
311 case PubKeyAlgoX25519:
312 err := x25519.EncodeFields(w, e.ephemeralPublicX25519, e.encryptedSession, byte(e.CipherFunc), e.Version == 6)
313 return err
314 case PubKeyAlgoX448:
315 err := x448.EncodeFields(w, e.ephemeralPublicX448, e.encryptedSession, byte(e.CipherFunc), e.Version == 6)
316 return err
317 default:
318 panic("internal error")
319 }
320}
321
322// SerializeEncryptedKeyAEAD serializes an encrypted key packet to w that contains
323// key, encrypted to pub.
324// If aeadSupported is set, PKESK v6 is used, otherwise v3.
325// Note: aeadSupported MUST match the value passed to SerializeSymmetricallyEncrypted.
326// If config is nil, sensible defaults will be used.
327func SerializeEncryptedKeyAEAD(w io.Writer, pub *PublicKey, cipherFunc CipherFunction, aeadSupported bool, key []byte, config *Config) error {
328 return SerializeEncryptedKeyAEADwithHiddenOption(w, pub, cipherFunc, aeadSupported, key, false, config)
329}
330
331// SerializeEncryptedKeyAEADwithHiddenOption serializes an encrypted key packet to w that contains
332// key, encrypted to pub.
333// Offers the hidden flag option to indicated if the PKESK packet should include a wildcard KeyID.
334// If aeadSupported is set, PKESK v6 is used, otherwise v3.
335// Note: aeadSupported MUST match the value passed to SerializeSymmetricallyEncrypted.
336// If config is nil, sensible defaults will be used.
337func SerializeEncryptedKeyAEADwithHiddenOption(w io.Writer, pub *PublicKey, cipherFunc CipherFunction, aeadSupported bool, key []byte, hidden bool, config *Config) error {
338 var buf [36]byte // max possible header size is v6
339 lenHeaderWritten := versionSize
340 version := 3
341
342 if aeadSupported {
343 version = 6
344 }
345 // An implementation MUST NOT generate ElGamal v6 PKESKs.
346 if version == 6 && pub.PubKeyAlgo == PubKeyAlgoElGamal {
347 return errors.InvalidArgumentError("ElGamal v6 PKESK are not allowed")
348 }
349 // In v3 PKESKs, for x25519 and x448, mandate using AES
350 if version == 3 && (pub.PubKeyAlgo == PubKeyAlgoX25519 || pub.PubKeyAlgo == PubKeyAlgoX448) {
351 switch cipherFunc {
352 case CipherAES128, CipherAES192, CipherAES256:
353 break
354 default:
355 return errors.InvalidArgumentError("v3 PKESK mandates AES for x25519 and x448")
356 }
357 }
358
359 buf[0] = byte(version)
360
361 // If hidden is set, the key should be hidden
362 // An implementation MAY accept or use a Key ID of all zeros,
363 // or a key version of zero and no key fingerprint, to hide the intended decryption key.
364 // See Section 5.1.8. in the open pgp crypto refresh
365 if version == 6 {
366 if !hidden {
367 // A one-octet size of the following two fields.
368 buf[1] = byte(keyVersionSize + len(pub.Fingerprint))
369 // A one octet key version number.
370 buf[2] = byte(pub.Version)
371 lenHeaderWritten += keyVersionSize + 1
372 // The fingerprint of the public key
373 copy(buf[lenHeaderWritten:lenHeaderWritten+len(pub.Fingerprint)], pub.Fingerprint)
374 lenHeaderWritten += len(pub.Fingerprint)
375 } else {
376 // The size may also be zero, and the key version
377 // and fingerprint omitted for an "anonymous recipient"
378 buf[1] = 0
379 lenHeaderWritten += 1
380 }
381 } else {
382 if !hidden {
383 binary.BigEndian.PutUint64(buf[versionSize:(versionSize+keyIdSize)], pub.KeyId)
384 }
385 lenHeaderWritten += keyIdSize
386 }
387 buf[lenHeaderWritten] = byte(pub.PubKeyAlgo)
388 lenHeaderWritten += algorithmSize
389
390 var keyBlock []byte
391 switch pub.PubKeyAlgo {
392 case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoElGamal, PubKeyAlgoECDH:
393 lenKeyBlock := len(key) + 2
394 if version < 6 {
395 lenKeyBlock += 1 // cipher type included
396 }
397 keyBlock = make([]byte, lenKeyBlock)
398 keyOffset := 0
399 if version < 6 {
400 keyBlock[0] = byte(cipherFunc)
401 keyOffset = 1
402 }
403 encodeChecksumKey(keyBlock[keyOffset:], key)
404 case PubKeyAlgoX25519, PubKeyAlgoX448:
405 // algorithm is added in plaintext below
406 keyBlock = key
407 }
408
409 switch pub.PubKeyAlgo {
410 case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
411 return serializeEncryptedKeyRSA(w, config.Random(), buf[:lenHeaderWritten], pub.PublicKey.(*rsa.PublicKey), keyBlock)
412 case PubKeyAlgoElGamal:
413 return serializeEncryptedKeyElGamal(w, config.Random(), buf[:lenHeaderWritten], pub.PublicKey.(*elgamal.PublicKey), keyBlock)
414 case PubKeyAlgoECDH:
415 return serializeEncryptedKeyECDH(w, config.Random(), buf[:lenHeaderWritten], pub.PublicKey.(*ecdh.PublicKey), keyBlock, pub.oid, pub.Fingerprint)
416 case PubKeyAlgoX25519:
417 return serializeEncryptedKeyX25519(w, config.Random(), buf[:lenHeaderWritten], pub.PublicKey.(*x25519.PublicKey), keyBlock, byte(cipherFunc), version)
418 case PubKeyAlgoX448:
419 return serializeEncryptedKeyX448(w, config.Random(), buf[:lenHeaderWritten], pub.PublicKey.(*x448.PublicKey), keyBlock, byte(cipherFunc), version)
420 case PubKeyAlgoDSA, PubKeyAlgoRSASignOnly:
421 return errors.InvalidArgumentError("cannot encrypt to public key of type " + strconv.Itoa(int(pub.PubKeyAlgo)))
422 }
423
424 return errors.UnsupportedError("encrypting a key to public key of type " + strconv.Itoa(int(pub.PubKeyAlgo)))
425}
426
427// SerializeEncryptedKey serializes an encrypted key packet to w that contains
428// key, encrypted to pub.
429// PKESKv6 is used if config.AEAD() is not nil.
430// If config is nil, sensible defaults will be used.
431// Deprecated: Use SerializeEncryptedKeyAEAD instead.
432func SerializeEncryptedKey(w io.Writer, pub *PublicKey, cipherFunc CipherFunction, key []byte, config *Config) error {
433 return SerializeEncryptedKeyAEAD(w, pub, cipherFunc, config.AEAD() != nil, key, config)
434}
435
436// SerializeEncryptedKeyWithHiddenOption serializes an encrypted key packet to w that contains
437// key, encrypted to pub. PKESKv6 is used if config.AEAD() is not nil.
438// The hidden option controls if the packet should be anonymous, i.e., omit key metadata.
439// If config is nil, sensible defaults will be used.
440// Deprecated: Use SerializeEncryptedKeyAEADwithHiddenOption instead.
441func SerializeEncryptedKeyWithHiddenOption(w io.Writer, pub *PublicKey, cipherFunc CipherFunction, key []byte, hidden bool, config *Config) error {
442 return SerializeEncryptedKeyAEADwithHiddenOption(w, pub, cipherFunc, config.AEAD() != nil, key, hidden, config)
443}
444
445func serializeEncryptedKeyRSA(w io.Writer, rand io.Reader, header []byte, pub *rsa.PublicKey, keyBlock []byte) error {
446 cipherText, err := rsa.EncryptPKCS1v15(rand, pub, keyBlock)
447 if err != nil {
448 return errors.InvalidArgumentError("RSA encryption failed: " + err.Error())
449 }
450
451 cipherMPI := encoding.NewMPI(cipherText)
452 packetLen := len(header) /* header length */ + int(cipherMPI.EncodedLength())
453
454 err = serializeHeader(w, packetTypeEncryptedKey, packetLen)
455 if err != nil {
456 return err
457 }
458 _, err = w.Write(header[:])
459 if err != nil {
460 return err
461 }
462 _, err = w.Write(cipherMPI.EncodedBytes())
463 return err
464}
465
466func serializeEncryptedKeyElGamal(w io.Writer, rand io.Reader, header []byte, pub *elgamal.PublicKey, keyBlock []byte) error {
467 c1, c2, err := elgamal.Encrypt(rand, pub, keyBlock)
468 if err != nil {
469 return errors.InvalidArgumentError("ElGamal encryption failed: " + err.Error())
470 }
471
472 packetLen := len(header) /* header length */
473 packetLen += 2 /* mpi size */ + (c1.BitLen()+7)/8
474 packetLen += 2 /* mpi size */ + (c2.BitLen()+7)/8
475
476 err = serializeHeader(w, packetTypeEncryptedKey, packetLen)
477 if err != nil {
478 return err
479 }
480 _, err = w.Write(header[:])
481 if err != nil {
482 return err
483 }
484 if _, err = w.Write(new(encoding.MPI).SetBig(c1).EncodedBytes()); err != nil {
485 return err
486 }
487 _, err = w.Write(new(encoding.MPI).SetBig(c2).EncodedBytes())
488 return err
489}
490
491func serializeEncryptedKeyECDH(w io.Writer, rand io.Reader, header []byte, pub *ecdh.PublicKey, keyBlock []byte, oid encoding.Field, fingerprint []byte) error {
492 vsG, c, err := ecdh.Encrypt(rand, pub, keyBlock, oid.EncodedBytes(), fingerprint)
493 if err != nil {
494 return errors.InvalidArgumentError("ECDH encryption failed: " + err.Error())
495 }
496
497 g := encoding.NewMPI(vsG)
498 m := encoding.NewOID(c)
499
500 packetLen := len(header) /* header length */
501 packetLen += int(g.EncodedLength()) + int(m.EncodedLength())
502
503 err = serializeHeader(w, packetTypeEncryptedKey, packetLen)
504 if err != nil {
505 return err
506 }
507
508 _, err = w.Write(header[:])
509 if err != nil {
510 return err
511 }
512 if _, err = w.Write(g.EncodedBytes()); err != nil {
513 return err
514 }
515 _, err = w.Write(m.EncodedBytes())
516 return err
517}
518
519func serializeEncryptedKeyX25519(w io.Writer, rand io.Reader, header []byte, pub *x25519.PublicKey, keyBlock []byte, cipherFunc byte, version int) error {
520 ephemeralPublicX25519, ciphertext, err := x25519.Encrypt(rand, pub, keyBlock)
521 if err != nil {
522 return errors.InvalidArgumentError("x25519 encryption failed: " + err.Error())
523 }
524
525 packetLen := len(header) /* header length */
526 packetLen += x25519.EncodedFieldsLength(ciphertext, version == 6)
527
528 err = serializeHeader(w, packetTypeEncryptedKey, packetLen)
529 if err != nil {
530 return err
531 }
532
533 _, err = w.Write(header[:])
534 if err != nil {
535 return err
536 }
537 return x25519.EncodeFields(w, ephemeralPublicX25519, ciphertext, cipherFunc, version == 6)
538}
539
540func serializeEncryptedKeyX448(w io.Writer, rand io.Reader, header []byte, pub *x448.PublicKey, keyBlock []byte, cipherFunc byte, version int) error {
541 ephemeralPublicX448, ciphertext, err := x448.Encrypt(rand, pub, keyBlock)
542 if err != nil {
543 return errors.InvalidArgumentError("x448 encryption failed: " + err.Error())
544 }
545
546 packetLen := len(header) /* header length */
547 packetLen += x448.EncodedFieldsLength(ciphertext, version == 6)
548
549 err = serializeHeader(w, packetTypeEncryptedKey, packetLen)
550 if err != nil {
551 return err
552 }
553
554 _, err = w.Write(header[:])
555 if err != nil {
556 return err
557 }
558 return x448.EncodeFields(w, ephemeralPublicX448, ciphertext, cipherFunc, version == 6)
559}
560
561func checksumKeyMaterial(key []byte) uint16 {
562 var checksum uint16
563 for _, v := range key {
564 checksum += uint16(v)
565 }
566 return checksum
567}
568
569func decodeChecksumKey(msg []byte) (key []byte, err error) {
570 key = msg[:len(msg)-2]
571 expectedChecksum := uint16(msg[len(msg)-2])<<8 | uint16(msg[len(msg)-1])
572 checksum := checksumKeyMaterial(key)
573 if checksum != expectedChecksum {
574 err = errors.StructuralError("session key checksum is incorrect")
575 }
576 return
577}
578
579func encodeChecksumKey(buffer []byte, key []byte) {
580 copy(buffer, key)
581 checksum := checksumKeyMaterial(key)
582 buffer[len(key)] = byte(checksum >> 8)
583 buffer[len(key)+1] = byte(checksum)
584}