chacha20poly1305_generic.go 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. // Copyright 2016 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. package chacha20poly1305
  5. import (
  6. "encoding/binary"
  7. "golang.org/x/crypto/internal/chacha20"
  8. "golang.org/x/crypto/poly1305"
  9. )
  10. func roundTo16(n int) int {
  11. return 16 * ((n + 15) / 16)
  12. }
  13. func (c *chacha20poly1305) sealGeneric(dst, nonce, plaintext, additionalData []byte) []byte {
  14. ret, out := sliceForAppend(dst, len(plaintext)+poly1305.TagSize)
  15. var polyKey [32]byte
  16. s := chacha20.New(c.key, [3]uint32{
  17. binary.LittleEndian.Uint32(nonce[0:4]),
  18. binary.LittleEndian.Uint32(nonce[4:8]),
  19. binary.LittleEndian.Uint32(nonce[8:12]),
  20. })
  21. s.XORKeyStream(polyKey[:], polyKey[:])
  22. s.Advance() // skip the next 32 bytes
  23. s.XORKeyStream(out, plaintext)
  24. polyInput := make([]byte, roundTo16(len(additionalData))+roundTo16(len(plaintext))+8+8)
  25. copy(polyInput, additionalData)
  26. copy(polyInput[roundTo16(len(additionalData)):], out[:len(plaintext)])
  27. binary.LittleEndian.PutUint64(polyInput[len(polyInput)-16:], uint64(len(additionalData)))
  28. binary.LittleEndian.PutUint64(polyInput[len(polyInput)-8:], uint64(len(plaintext)))
  29. var tag [poly1305.TagSize]byte
  30. poly1305.Sum(&tag, polyInput, &polyKey)
  31. copy(out[len(plaintext):], tag[:])
  32. return ret
  33. }
  34. func (c *chacha20poly1305) openGeneric(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
  35. var tag [poly1305.TagSize]byte
  36. copy(tag[:], ciphertext[len(ciphertext)-16:])
  37. ciphertext = ciphertext[:len(ciphertext)-16]
  38. var polyKey [32]byte
  39. s := chacha20.New(c.key, [3]uint32{
  40. binary.LittleEndian.Uint32(nonce[0:4]),
  41. binary.LittleEndian.Uint32(nonce[4:8]),
  42. binary.LittleEndian.Uint32(nonce[8:12]),
  43. })
  44. s.XORKeyStream(polyKey[:], polyKey[:])
  45. s.Advance() // skip the next 32 bytes
  46. polyInput := make([]byte, roundTo16(len(additionalData))+roundTo16(len(ciphertext))+8+8)
  47. copy(polyInput, additionalData)
  48. copy(polyInput[roundTo16(len(additionalData)):], ciphertext)
  49. binary.LittleEndian.PutUint64(polyInput[len(polyInput)-16:], uint64(len(additionalData)))
  50. binary.LittleEndian.PutUint64(polyInput[len(polyInput)-8:], uint64(len(ciphertext)))
  51. ret, out := sliceForAppend(dst, len(ciphertext))
  52. if !poly1305.Verify(&tag, polyInput, &polyKey) {
  53. for i := range out {
  54. out[i] = 0
  55. }
  56. return nil, errOpen
  57. }
  58. s.XORKeyStream(out, ciphertext)
  59. return ret, nil
  60. }