poly1305.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. //
  2. // poly1305.go: Poly1305 MAC.
  3. //
  4. // To the extent possible under law, Yawning Angel waived all copyright
  5. // and related or neighboring rights to poly1305, using the creative
  6. // commons "CC0" public domain dedication. See LICENSE or
  7. // <http://creativecommons.org/publicdomain/zero/1.0/> for full details.
  8. // Package poly1305 is a Poly1305 MAC implementation. It is different from the
  9. // golang.org/x/crypto implementation in that it exports a hash.Hash interface
  10. // to support incremental updates.
  11. //
  12. // The implementation is based on Andrew Moon's poly1305-donna.
  13. package poly1305
  14. import (
  15. "crypto/subtle"
  16. "errors"
  17. "hash"
  18. "runtime"
  19. "unsafe"
  20. )
  21. const (
  22. // KeySize is the Poly1305 key size in bytes.
  23. KeySize = 32
  24. // Size is the Poly1305 MAC size in bytes.
  25. Size = 16
  26. // BlockSize is the Poly1305 block size in bytes.
  27. BlockSize = 16
  28. )
  29. var (
  30. // ErrInvalidKeySize is the error returned when an invalid sized key is
  31. // encountered.
  32. ErrInvalidKeySize = errors.New("poly1305: invalid key size")
  33. // ErrInvalidMacSize is the error returned when an invalid sized MAC is
  34. // encountered.
  35. ErrInvalidMacSize = errors.New("poly1305: invalid mac size")
  36. isLittleEndian = false
  37. )
  38. type implInterface interface {
  39. init(key []byte)
  40. clear()
  41. blocks(m []byte, bytes int, isFinal bool)
  42. finish(mac *[Size]byte)
  43. }
  44. // Poly1305 is an instance of the Poly1305 MAC algorithm.
  45. type Poly1305 struct {
  46. impl implState
  47. leftover int
  48. buffer [BlockSize]byte
  49. }
  50. // Write adds more data to the running hash. It never returns an error.
  51. func (st *Poly1305) Write(p []byte) (n int, err error) {
  52. //
  53. // poly1305-donna.c:poly1305_update()
  54. //
  55. m := p
  56. bytes := len(m)
  57. // handle leftover
  58. if st.leftover > 0 {
  59. want := BlockSize - st.leftover
  60. if want > bytes {
  61. want = bytes
  62. }
  63. for i := 0; i < want; i++ {
  64. st.buffer[st.leftover+i] = m[i]
  65. }
  66. bytes -= want
  67. m = m[want:]
  68. st.leftover += want
  69. if st.leftover < BlockSize {
  70. return len(p), nil
  71. }
  72. st.impl.blocks(st.buffer[:], BlockSize, false)
  73. st.leftover = 0
  74. }
  75. // process full blocks
  76. if bytes >= BlockSize {
  77. want := bytes & (^(BlockSize - 1))
  78. st.impl.blocks(m, want, false)
  79. m = m[want:]
  80. bytes -= want
  81. }
  82. // store leftover
  83. if bytes > 0 {
  84. for i := 0; i < bytes; i++ {
  85. st.buffer[st.leftover+i] = m[i]
  86. }
  87. st.leftover += bytes
  88. }
  89. return len(p), nil
  90. }
  91. // Sum appends the current hash to b and returns the resulting slice. It does
  92. // not change the underlying hash state.
  93. func (st *Poly1305) Sum(b []byte) []byte {
  94. var mac [Size]byte
  95. tmp := *st
  96. tmp.finish(&mac)
  97. return append(b, mac[:]...)
  98. }
  99. // Reset clears the internal hash state and panic()s, because calling this is a
  100. // sign that the user is doing something unadvisable.
  101. func (st *Poly1305) Reset() {
  102. st.Clear() // Obliterate the state before panic().
  103. // Poly1305 keys are one time use only.
  104. panic("poly1305: Reset() is not supported")
  105. }
  106. // Size returns the number of bytes Sum will return.
  107. func (st *Poly1305) Size() int {
  108. return Size
  109. }
  110. // BlockSize returns the hash's underlying block size.
  111. func (st *Poly1305) BlockSize() int {
  112. return BlockSize
  113. }
  114. // Init (re-)initializes the hash instance with a given key.
  115. func (st *Poly1305) Init(key []byte) {
  116. if len(key) != KeySize {
  117. panic(ErrInvalidKeySize)
  118. }
  119. st.impl.init(key)
  120. st.leftover = 0
  121. }
  122. // Clear purges the sensitive material in hash's internal state.
  123. func (st *Poly1305) Clear() {
  124. st.impl.clear()
  125. }
  126. func (st *Poly1305) finish(mac *[Size]byte) {
  127. // process the remaining block
  128. if st.leftover > 0 {
  129. st.buffer[st.leftover] = 1
  130. for i := st.leftover + 1; i < BlockSize; i++ {
  131. st.buffer[i] = 0
  132. }
  133. st.impl.blocks(st.buffer[:], BlockSize, true)
  134. }
  135. st.impl.finish(mac)
  136. st.impl.clear()
  137. }
  138. // New returns a new Poly1305 instance keyed with the supplied key.
  139. func New(key []byte) (*Poly1305, error) {
  140. if len(key) != KeySize {
  141. return nil, ErrInvalidKeySize
  142. }
  143. h := &Poly1305{}
  144. h.Init(key)
  145. return h, nil
  146. }
  147. // Sum does exactly what golang.org/x/crypto/poly1305.Sum() does.
  148. func Sum(mac *[Size]byte, m []byte, key *[KeySize]byte) {
  149. var h Poly1305
  150. h.Init(key[:])
  151. h.Write(m)
  152. h.finish(mac)
  153. }
  154. // Verify does exactly what golang.org/x/crypto/poly1305.Verify does.
  155. func Verify(mac *[Size]byte, m []byte, key *[KeySize]byte) bool {
  156. var m2 [Size]byte
  157. Sum(&m2, m, key)
  158. return subtle.ConstantTimeCompare(mac[:], m2[:]) == 1
  159. }
  160. func init() {
  161. // Use the UTF-32 (UCS-4) Byte Order Mark to detect host byte order,
  162. // which enables the further use of 'unsafe' for added performance.
  163. const bomLE = 0x0000feff
  164. bom := [4]byte{0xff, 0xfe, 0x00, 0x00}
  165. // ARM doesn't get the spiffy fast code since it's picky wrt alignment
  166. // and I doubt Go does the right thing.
  167. if runtime.GOARCH != "arm" {
  168. bomHost := *(*uint32)(unsafe.Pointer(&bom[0]))
  169. if bomHost == 0x0000feff { // Little endian, use unsafe.
  170. isLittleEndian = true
  171. }
  172. }
  173. }
  174. var _ hash.Hash = (*Poly1305)(nil)