secretbox.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. // Copyright 2012 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. /*
  5. Package secretbox encrypts and authenticates small messages.
  6. Secretbox uses XSalsa20 and Poly1305 to encrypt and authenticate messages with
  7. secret-key cryptography. The length of messages is not hidden.
  8. It is the caller's responsibility to ensure the uniqueness of nonces—for
  9. example, by using nonce 1 for the first message, nonce 2 for the second
  10. message, etc. Nonces are long enough that randomly generated nonces have
  11. negligible risk of collision.
  12. This package is interoperable with NaCl: http://nacl.cr.yp.to/secretbox.html.
  13. */
  14. package secretbox
  15. import (
  16. "code.google.com/p/go.crypto/poly1305"
  17. "code.google.com/p/go.crypto/salsa20/salsa"
  18. )
  19. // Overhead is the number of bytes of overhead when boxing a message.
  20. const Overhead = poly1305.TagSize
  21. // setup produces a sub-key and Salsa20 counter given a nonce and key.
  22. func setup(subKey *[32]byte, counter *[16]byte, nonce *[24]byte, key *[32]byte) {
  23. // We use XSalsa20 for encryption so first we need to generate a
  24. // key and nonce with HSalsa20.
  25. var hNonce [16]byte
  26. copy(hNonce[:], nonce[:])
  27. salsa.HSalsa20(subKey, &hNonce, key, &salsa.Sigma)
  28. // The final 8 bytes of the original nonce form the new nonce.
  29. copy(counter[:], nonce[16:])
  30. }
  31. // Seal appends an encrypted and authenticated copy of message to out, which
  32. // must not overlap message. The key and nonce pair must be unique for each
  33. // distinct message and the output will be Overhead bytes longer than message.
  34. func Seal(out, message []byte, nonce *[24]byte, key *[32]byte) []byte {
  35. var subKey [32]byte
  36. var counter [16]byte
  37. setup(&subKey, &counter, nonce, key)
  38. // The Poly1305 key is generated by encrypting 32 bytes of zeros. Since
  39. // Salsa20 works with 64-byte blocks, we also generate 32 bytes of
  40. // keystream as a side effect.
  41. var firstBlock [64]byte
  42. salsa.XORKeyStream(firstBlock[:], firstBlock[:], &counter, &subKey)
  43. var poly1305Key [32]byte
  44. copy(poly1305Key[:], firstBlock[:])
  45. out = out[len(out):]
  46. outLen := len(message) + poly1305.TagSize
  47. if cap(out) >= outLen {
  48. out = out[:outLen]
  49. } else if out == nil {
  50. out = make([]byte, outLen)
  51. } else {
  52. for i := 0; i < outLen; i++ {
  53. out = append(out, 0)
  54. }
  55. }
  56. // We XOR up to 32 bytes of message with the keystream generated from
  57. // the first block.
  58. firstMessageBlock := message
  59. if len(firstMessageBlock) > 32 {
  60. firstMessageBlock = firstMessageBlock[:32]
  61. }
  62. tagOut := out
  63. out = out[poly1305.TagSize:]
  64. for i, x := range firstMessageBlock {
  65. out[i] = firstBlock[32+i] ^ x
  66. }
  67. message = message[len(firstMessageBlock):]
  68. ciphertext := out
  69. out = out[len(firstMessageBlock):]
  70. // Now encrypt the rest.
  71. counter[8] = 1
  72. salsa.XORKeyStream(out, message, &counter, &subKey)
  73. var tag [poly1305.TagSize]byte
  74. poly1305.Sum(&tag, ciphertext, &poly1305Key)
  75. copy(tagOut, tag[:])
  76. return tagOut
  77. }
  78. // Open authenticates and decrypts a box produced by Seal and appends the
  79. // message to out, which must not overlap box. The output will be Overhead
  80. // bytes smaller than box.
  81. func Open(out []byte, box []byte, nonce *[24]byte, key *[32]byte) ([]byte, bool) {
  82. if len(box) < Overhead {
  83. return nil, false
  84. }
  85. var subKey [32]byte
  86. var counter [16]byte
  87. setup(&subKey, &counter, nonce, key)
  88. // The Poly1305 key is generated by encrypting 32 bytes of zeros. Since
  89. // Salsa20 works with 64-byte blocks, we also generate 32 bytes of
  90. // keystream as a side effect.
  91. var firstBlock [64]byte
  92. salsa.XORKeyStream(firstBlock[:], firstBlock[:], &counter, &subKey)
  93. var poly1305Key [32]byte
  94. copy(poly1305Key[:], firstBlock[:])
  95. var tag [poly1305.TagSize]byte
  96. copy(tag[:], box)
  97. if !poly1305.Verify(&tag, box[poly1305.TagSize:], &poly1305Key) {
  98. return nil, false
  99. }
  100. out = out[len(out):]
  101. outLen := len(box) - Overhead
  102. if cap(out) >= outLen {
  103. out = out[:outLen]
  104. } else if out == nil {
  105. out = make([]byte, outLen)
  106. } else {
  107. for i := 0; i < outLen; i++ {
  108. out = append(out, 0)
  109. }
  110. }
  111. // We XOR up to 32 bytes of box with the keystream generated from
  112. // the first block.
  113. box = box[Overhead:]
  114. firstMessageBlock := box
  115. if len(firstMessageBlock) > 32 {
  116. firstMessageBlock = firstMessageBlock[:32]
  117. }
  118. for i, x := range firstMessageBlock {
  119. out[i] = firstBlock[32+i] ^ x
  120. }
  121. box = box[len(firstMessageBlock):]
  122. plaintext := out
  123. out = out[len(firstMessageBlock):]
  124. // Now decrypt the rest.
  125. counter[8] = 1
  126. salsa.XORKeyStream(out, box, &counter, &subKey)
  127. return plaintext, true
  128. }