chacha.go 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. package internal
  2. //go:generate go run chacha_core_gen.go
  3. import (
  4. "encoding/binary"
  5. )
  6. const (
  7. wordSize = 4 // the size of ChaCha20's words
  8. stateSize = 16 // the size of ChaCha20's state, in words
  9. blockSize = stateSize * wordSize // the size of ChaCha20's block, in bytes
  10. )
  11. type ChaCha20Stream struct {
  12. state [stateSize]uint32 // the state as an array of 16 32-bit words
  13. block [blockSize]byte // the keystream as an array of 64 bytes
  14. offset int // the offset of used bytes in block
  15. rounds int
  16. }
  17. func NewChaCha20Stream(key []byte, nonce []byte, rounds int) *ChaCha20Stream {
  18. s := new(ChaCha20Stream)
  19. // the magic constants for 256-bit keys
  20. s.state[0] = 0x61707865
  21. s.state[1] = 0x3320646e
  22. s.state[2] = 0x79622d32
  23. s.state[3] = 0x6b206574
  24. for i := 0; i < 8; i++ {
  25. s.state[i+4] = binary.LittleEndian.Uint32(key[i*4 : i*4+4])
  26. }
  27. switch len(nonce) {
  28. case 8:
  29. s.state[14] = binary.LittleEndian.Uint32(nonce[0:])
  30. s.state[15] = binary.LittleEndian.Uint32(nonce[4:])
  31. case 12:
  32. s.state[13] = binary.LittleEndian.Uint32(nonce[0:4])
  33. s.state[14] = binary.LittleEndian.Uint32(nonce[4:8])
  34. s.state[15] = binary.LittleEndian.Uint32(nonce[8:12])
  35. default:
  36. panic("bad nonce length")
  37. }
  38. s.rounds = rounds
  39. ChaCha20Block(&s.state, s.block[:], s.rounds)
  40. return s
  41. }
  42. func (s *ChaCha20Stream) XORKeyStream(dst, src []byte) {
  43. // Stride over the input in 64-byte blocks, minus the amount of keystream
  44. // previously used. This will produce best results when processing blocks
  45. // of a size evenly divisible by 64.
  46. i := 0
  47. max := len(src)
  48. for i < max {
  49. gap := blockSize - s.offset
  50. limit := i + gap
  51. if limit > max {
  52. limit = max
  53. }
  54. o := s.offset
  55. for j := i; j < limit; j++ {
  56. dst[j] = src[j] ^ s.block[o]
  57. o++
  58. }
  59. i += gap
  60. s.offset = o
  61. if o == blockSize {
  62. s.offset = 0
  63. s.state[12]++
  64. ChaCha20Block(&s.state, s.block[:], s.rounds)
  65. }
  66. }
  67. }