You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

82 lines
2.6 KiB

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