github.com/mad-day/Yawning-crypto@v0.0.0-20190711051033-5a5f8cca32ec/morus/morus.go (about)

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