lioness.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. // lioness.go - A LIONESS-BLAKE2b-ChaCha20 implementation.
  2. //
  3. // To the extent possible under law, Yawning Angel has waived all copyright
  4. // and related or neighboring rights to lioness, using the Creative
  5. // Commons "CC0" public domain dedication. See LICENSE or
  6. // <http://creativecommons.org/publicdomain/zero/1.0/> for full details.
  7. package lioness
  8. import (
  9. "errors"
  10. "git.schwanenlied.me/yawning/chacha20.git"
  11. "github.com/minio/blake2b-simd"
  12. )
  13. const (
  14. // KeySize is the key size in bytes.
  15. KeySize = 128
  16. // IVSize is the initialization vector size in bytes.
  17. IVSize = 48
  18. // MinBlockSize is the minimum block size in bytes.
  19. MinBlockSize = 32 + 1
  20. // MaxBlockSize is the maximum block size in bytes.
  21. MaxBlockSize = 32 + (64 * (1 << 32))
  22. lSize = chacha20.KeySize
  23. )
  24. var (
  25. // ErrBlockSize is the error returned when the block size is invalid.
  26. ErrBlockSize = errors.New("lioness: invalid block size")
  27. xorBytes32 = xorBytes32Ref
  28. )
  29. // Encrypt encrypts a block. dst and src may overlap.
  30. func Encrypt(key [KeySize]byte, iv [IVSize]byte, dst, src []byte) error {
  31. // XXX: In theory I should enforce MaxBlockSize, but it's > sizeof(int)
  32. // on 32 bit systems.
  33. if len(src) < MinBlockSize || len(dst) < len(src) {
  34. return ErrBlockSize
  35. }
  36. var l [lSize]byte
  37. r := make([]byte, len(dst)-lSize)
  38. var tmp [lSize + IVSize/4]byte
  39. defer zeroBytes(tmp[:])
  40. k1 := key[0:32]
  41. k2 := key[32:64]
  42. k3 := key[64:96]
  43. k4 := key[96:128]
  44. iv1 := iv[0:12]
  45. iv2 := iv[12:24]
  46. iv3 := iv[24:36]
  47. iv4 := iv[36:48]
  48. var s chacha20.Cipher
  49. defer s.Reset()
  50. var hCfg blake2b.Config
  51. hCfg.Size = lSize
  52. hCfg.Key = tmp[:]
  53. // R = ChaCha20(L ^ k1, iv1, R)
  54. xorBytes32(tmp[:lSize], src[0:lSize], k1)
  55. if err := s.ReKey(tmp[:lSize], iv1); err != nil {
  56. return err
  57. }
  58. s.XORKeyStream(r, src[lSize:])
  59. // L = L ^ BLAKE2b(k2 | iv2, R)
  60. copy(tmp[:lSize], k2)
  61. copy(tmp[lSize:], iv2)
  62. h, err := blake2b.New(&hCfg)
  63. if err != nil {
  64. return err
  65. }
  66. defer h.Reset()
  67. h.Write(r)
  68. htmp := h.Sum(nil)
  69. defer zeroBytes(htmp)
  70. xorBytes32(l[:], src[0:lSize], htmp)
  71. // R = ChaCha20(L ^ k3, iv3, R)
  72. xorBytes32(tmp[:lSize], l[:], k3)
  73. if err := s.ReKey(tmp[:lSize], iv3); err != nil {
  74. return err
  75. }
  76. s.XORKeyStream(r, r)
  77. // L ^ BLAKE2b(k4 | iv4, R)
  78. copy(tmp[:lSize], k4)
  79. copy(tmp[lSize:], iv4)
  80. hh, err := blake2b.New(&hCfg) // I wish blake2b-simd supported rekeying.
  81. if err != nil {
  82. return err
  83. }
  84. defer hh.Reset()
  85. hh.Write(r)
  86. htmp = htmp[:0]
  87. htmp = hh.Sum(htmp)
  88. xorBytes32(l[:], l[:], htmp)
  89. copy(dst, l[:])
  90. copy(dst[lSize:], r)
  91. return nil
  92. }
  93. // Decrypt decrypts a block. dst and src may overlap.
  94. func Decrypt(key [KeySize]byte, iv [IVSize]byte, dst, src []byte) error {
  95. // XXX: In theory I should enforce MaxBlockSize, but it's > sizeof(int)
  96. // on 32 bit systems.
  97. if len(src) < MinBlockSize || len(dst) < len(src) {
  98. return ErrBlockSize
  99. }
  100. k1 := key[0:32]
  101. k2 := key[32:64]
  102. k3 := key[64:96]
  103. k4 := key[96:128]
  104. iv1 := iv[0:12]
  105. iv2 := iv[12:24]
  106. iv3 := iv[24:36]
  107. iv4 := iv[36:48]
  108. var l [lSize]byte
  109. r := make([]byte, len(dst)-lSize)
  110. var tmp [lSize + IVSize/4]byte
  111. defer zeroBytes(tmp[:])
  112. var s chacha20.Cipher
  113. defer s.Reset()
  114. var hCfg blake2b.Config
  115. hCfg.Size = lSize
  116. hCfg.Key = tmp[:]
  117. // L = L ^ BLAKE2b(k4 | iv4, R)
  118. copy(tmp[:lSize], k4)
  119. copy(tmp[lSize:], iv4)
  120. h, err := blake2b.New(&hCfg)
  121. if err != nil {
  122. return err
  123. }
  124. defer h.Reset()
  125. h.Write(src[lSize:])
  126. htmp := h.Sum(nil)
  127. defer zeroBytes(htmp)
  128. xorBytes32(l[:], src[0:lSize], htmp)
  129. // R = ChaCha20(L ^ k3, iv3, R)
  130. xorBytes32(tmp[:lSize], l[:], k3)
  131. if err := s.ReKey(tmp[:lSize], iv3); err != nil {
  132. return err
  133. }
  134. s.XORKeyStream(r, src[lSize:])
  135. // L = L ^ BLAKE2b(k2 | iv2, R)
  136. copy(tmp[:lSize], k2)
  137. copy(tmp[lSize:], iv2)
  138. hh, err := blake2b.New(&hCfg) // I wish blake2b-simd supported rekeying.
  139. if err != nil {
  140. return err
  141. }
  142. defer hh.Reset()
  143. hh.Write(r)
  144. htmp = htmp[:0]
  145. htmp = hh.Sum(htmp)
  146. xorBytes32(l[:], l[:], htmp)
  147. // R = ChaCha20(L ^ k1, iv1, R)
  148. xorBytes32(tmp[:lSize], l[:], k1)
  149. if err := s.ReKey(tmp[:lSize], iv1); err != nil {
  150. return err
  151. }
  152. s.XORKeyStream(r, r)
  153. copy(dst, l[:])
  154. copy(dst[lSize:], r)
  155. return nil
  156. }
  157. func xorBytes32Ref(dst, a, b []byte) {
  158. // Note: Before you freak the fuck out and try to optimize this,
  159. // for more platforms, take note that it's 32 bytes. Performance
  160. // here is only meaningful for extremely small messages.
  161. if len(dst) != 32 {
  162. panic("lioness: xorBytes32Ref() len != 32")
  163. }
  164. for i, v := range a {
  165. dst[i] = v ^ b[i]
  166. }
  167. }
  168. func zeroBytes(a []byte) {
  169. // Note: Before you freak the fuck out and try to optimize this,
  170. // the compiler has a special case for it.
  171. //
  172. // See: https://github.com/golang/go/issues/5373
  173. for i := range a {
  174. a[i] = 0
  175. }
  176. }