morus.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. // morus.go - High-level interface
  2. //
  3. // To the extent possible under law, Yawning Angel has waived all copyright
  4. // and related or neighboring rights to the software, 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 morus implements the MORUS-1280-256 Authenticated Cipher.
  8. //
  9. // This implementation is derived from the reference implementation by
  10. // Hongjun Wu and Tao Huang.
  11. package morus
  12. import (
  13. "encoding/binary"
  14. "errors"
  15. )
  16. const (
  17. // KeySize is the size of a key in bytes.
  18. KeySize = 32
  19. // NonceSize is the size of a nonce in bytes.
  20. NonceSize = 16
  21. // TagSize is the size of an authentication tag in bytes.
  22. TagSize = 16
  23. // Version is the version of the MORUS specification implemented.
  24. Version = "2.0"
  25. )
  26. var (
  27. // ErrInvalidKeySize is the error thrown via a panic when a key is an
  28. // invalid size.
  29. ErrInvalidKeySize = errors.New("morus: invalid key size")
  30. // ErrInvalidNonceSize is the error thrown via a panic when a nonce is
  31. // an invalid size.
  32. ErrInvalidNonceSize = errors.New("morus: invalid nonce size")
  33. // ErrOpen is the error returned when the message authentication fails
  34. // during an Open call.
  35. ErrOpen = errors.New("morus: message authentication failed")
  36. rawInitializationConstant = [32]byte{
  37. 0x0, 0x1, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d,
  38. 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62,
  39. 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1,
  40. 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd,
  41. }
  42. initializationConstants [4]uint64
  43. // Neither the specification document nor the portable reference
  44. // implementations define how this should be handled. However the
  45. // AVX2 implementation isn't byte swapping, so it's likely safe to
  46. // assume little endian.
  47. byteOrder = binary.LittleEndian
  48. )
  49. // AEAD is a MORUS instance, implementing crypto/cipher.AEAD.
  50. type AEAD struct {
  51. key []byte
  52. }
  53. // NonceSize returns the size of the nonce that must be passed to Seal and
  54. // Open.
  55. func (ae *AEAD) NonceSize() int {
  56. return NonceSize
  57. }
  58. // Overhead returns the maximum difference between the lengths of a plaintext
  59. // and its ciphertext.
  60. func (ae *AEAD) Overhead() int {
  61. return TagSize
  62. }
  63. // Seal encrypts and authenticates plaintext, authenticates the
  64. // additional data and appends the result to dst, returning the updated
  65. // slice. The nonce must be NonceSize() bytes long and unique for all
  66. // time, for a given key.
  67. //
  68. // The plaintext and dst must overlap exactly or not at all. To reuse
  69. // plaintext's storage for the encrypted output, use plaintext[:0] as dst.
  70. func (ae *AEAD) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
  71. if len(nonce) != NonceSize {
  72. panic(ErrInvalidNonceSize)
  73. }
  74. dst = hardwareAccelImpl.aeadEncryptFn(dst, plaintext, additionalData, nonce, ae.key)
  75. return dst
  76. }
  77. // Open decrypts and authenticates ciphertext, authenticates the
  78. // additional data and, if successful, appends the resulting plaintext
  79. // to dst, returning the updated slice. The nonce must be NonceSize()
  80. // bytes long and both it and the additional data must match the
  81. // value passed to Seal.
  82. //
  83. // The ciphertext and dst must overlap exactly or not at all. To reuse
  84. // ciphertext's storage for the decrypted output, use ciphertext[:0] as dst.
  85. //
  86. // Even if the function fails, the contents of dst, up to its capacity,
  87. // may be overwritten.
  88. func (ae *AEAD) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
  89. var err error
  90. var ok bool
  91. if len(nonce) != NonceSize {
  92. panic(ErrInvalidNonceSize)
  93. }
  94. dst, ok = hardwareAccelImpl.aeadDecryptFn(dst, ciphertext, additionalData, nonce, ae.key)
  95. if !ok {
  96. err = ErrOpen
  97. }
  98. return dst, err
  99. }
  100. // Reset securely purges stored sensitive data from the AEAD instance.
  101. func (ae *AEAD) Reset() {
  102. burnBytes(ae.key)
  103. }
  104. // New returns a new keyed MORUS-1280-256 instance.
  105. func New(key []byte) *AEAD {
  106. if len(key) != KeySize {
  107. panic(ErrInvalidKeySize)
  108. }
  109. return &AEAD{key: append([]byte{}, key...)}
  110. }
  111. // Shamelessly stolen from the Go runtime library.
  112. func sliceForAppend(in []byte, n int) (head, tail []byte) {
  113. if total := len(in) + n; cap(in) >= total {
  114. head = in[:total]
  115. } else {
  116. head = make([]byte, total)
  117. copy(head, in)
  118. }
  119. tail = head[len(in):]
  120. return
  121. }
  122. func init() {
  123. initializationConstants[0] = byteOrder.Uint64(rawInitializationConstant[0:])
  124. initializationConstants[1] = byteOrder.Uint64(rawInitializationConstant[8:])
  125. initializationConstants[2] = byteOrder.Uint64(rawInitializationConstant[16:])
  126. initializationConstants[3] = byteOrder.Uint64(rawInitializationConstant[24:])
  127. }