README

The best crypto you've never heard of, brought to you by Phil Rogaway

Go implementation of Miscreant: Advanced symmetric encryption library which provides the AES-SIV (RFC 5297), AES-PMAC-SIV, and STREAM constructions. These algorithms are easy-to-use (or rather, hard-to-misuse) and support encryption of individual messages or message streams.

import "github.com/miscreant/miscreant.go/"

All types are designed to be thread-compatible: Methods of an instance shared between multiple threads (or goroutines) must not be accessed concurrently. Callers are responsible for implementing their own mutual exclusion.

About AES-SIV and AES-PMAC-SIV

AES-SIV and AES-PMAC-SIV provide nonce-reuse misuse-resistance (NRMR): accidentally reusing a nonce with this construction is not a security catastrophe, unlike more popular AES encryption modes like AES-GCM where nonce reuse leaks both the authentication key and the XOR of both plaintexts, both of which can potentially be leveraged for full plaintext recovery attacks.

With AES-SIV, the worst outcome of reusing a nonce is an attacker can see you've sent the same plaintext twice, as opposed to almost all other AES modes where it can facilitate chosen ciphertext attacks and/or full plaintext recovery.

Help and Discussion

Have questions? Want to suggest a feature or change?

API

Miscreant implements the cipher.AEAD interface which provides Authenticated Encryption with Associated Data. This is the main API you should use for most purposes unless you have highly specific needs that are covered more specifically by one of the other APIs described below.

Creating a cipher instance: NewAEAD()

To initialize a cipher.AEAD, you will need to select one of the ciphers below to initialize it with:

  • "AES-SIV": CMAC-based construction described in RFC 5297. Slower but standardized and more common.
  • "AES-PMAC-SIV": PMAC-based construction. Faster but non-standardized and only available in the Miscreant libraries.

For performance reasons we recommend AES-PMAC-SIV but please be aware it is only presently implemented by the Miscreant libraries.

After selecting a cipher, pass in a 32-byte or 64-byte key. Note that these options are twice the size of what you might be expecting (AES-SIV uses two AES keys).

You can generate a random key using the miscreant.generateKey() method, and then instantiate a cipher instance by calling miscreant.newAEAD(). You will also need to supply a nonce size. We recommend 16-bytes if you would like to use random nonces:

// Create a 32-byte AES-SIV key
k := miscreant.GenerateKey(32)

// Create a new cipher.AEAD instance
c := miscreant.NewAEAD("AES-PMAC-SIV", k, 16)
Encrypting data: Seal()

The Seal() method encrypts a message and authenticates a bytestring of associated data under a given key and nonce.

The miscreant.GenerateNonce() function can be used to randomly generate a nonce for the message to be encrypted under. If you wish to use this approach (alternatively you can use a counter for the nonce), please make sure to pass a nonceSize of 16-bytes or greater to newAEAD().

Example:

import "github.com/miscreant/miscreant.go/"

// Create a 32-byte AES-SIV key
k := miscreant.GenerateKey(32)

// Create a new cipher.AEAD instance with PMAC as the MAC
c := miscreant.NewAEAD("AES-PMAC-SIV", k, 16)

// Plaintext to be encrypted
pt := []byte("Hello, world!")

// Nonce to encrypt it under
n := miscreant.GenerateNonce(c)

// Associated data to authenticate along with the message
// (or nil if we don't care)
ad := nil

// Create a destination buffer to hold the ciphertext. We need it to be the
// length of the plaintext plus `c.Overhead()` to hold the IV/tag
ct := make([]byte, len(pt) + c.Overhead())

// Perform encryption by calling 'Seal'. The encrypted ciphertext will be
// written into the `ct` buffer
c.Seal(ct, n, pt, ad)
Decryption (#open)

The Open() method decrypts a ciphertext with the given key.

Example:

import "github.com/miscreant/miscreant.go/"

// Load an existing cryptographic key
k := ...

// Create a new cipher.AEAD instance
c := miscreant.NewAEAD("AES-PMAC-SIV", k, 16)

// Ciphertext to be decrypted
ct := ...

// Nonce under which the ciphertext was originally encrypted
n := ...

// Associated data to authenticate along with the message
// (or nil if we don't care)
ad := nil

// Create a destination buffer to hold the resulting plaintext.
// We need it to be the length of the ciphertext less `c.Overhead()`
l := len(ct) - c.Overhead()
if l < 0 {
    panic("ciphertext too short!")
}
pt := make([]byte, l)

// Perform decryption by calling 'Open'. The decrypted plaintext will be
// written into the `pt` buffer
_, err := c.Open(pt, n, ct, ad)
if err != nil {
    panic(err)
}

Security Notice

Though this library is written by cryptographic professionals, it has not undergone a thorough security audit, and cryptographic professionals are still humans that make mistakes.

This library makes an effort to use constant time operations throughout its implementation, however actual constant time behavior has not been verified.

Use this library at your own risk.

Code of Conduct

We abide by the Contributor Covenant and ask that you do as well.

For more information, please see CODE_OF_CONDUCT.md.

Contributing

Bug reports and pull requests are welcome on GitHub at:

https://github.com/miscreant/miscreant.go

Copyright (c) 2017-2019 The Miscreant Developers. See LICENSE.txt for further details.

Documentation

Index

Constants

View Source
const MaxAssociatedDataItems = 126

MaxAssociatedDataItems is the maximum number of associated data items

Variables

View Source
var (
	// ErrKeySize indicates the given key size is not supported
	ErrKeySize = errors.New("siv: bad key size")

	// ErrNotAuthentic indicates a ciphertext is malformed or corrupt
	ErrNotAuthentic = errors.New("siv: authentication failed")

	// ErrTooManyAssociatedDataItems indicates more than MaxAssociatedDataItems were given
	ErrTooManyAssociatedDataItems = errors.New("siv: too many associated data items")
)

Functions

func GenerateKey

func GenerateKey(length int) []byte

GenerateKey generates a random 32-byte or 64-byte encryption key. Panics if the key size is unsupported or source of randomness fails.

func GenerateNonce

func GenerateNonce(c cipher.AEAD) []byte

GenerateNonce generates a random nonce for the given `cipher.AEAD`. Panics if the configured nonce size is less than 16-bytes (128-bits)

func NewAEAD

func NewAEAD(alg string, key []byte, nonceSize int) (cipher.AEAD, error)

NewAEAD returns an AES-SIV instance implementing cipher.AEAD interface, with the given cipher, nonce size, and a key which must be twice as long as an AES key, either 32 or 64 bytes to select AES-128 (AES-SIV-256) or AES-256 (AES-SIV-512).

Unless the given nonce size is less than zero, Seal and Open will panic when passed nonce of a different size.

Types

type Cipher

type Cipher struct {
	// contains filtered or unexported fields
}

Cipher is an instance of AES-SIV, configured with either AES-CMAC or AES-PMAC as a message authentication code.

func NewAESCMACSIV

func NewAESCMACSIV(key []byte) (c *Cipher, err error)

NewAESCMACSIV returns a new AES-SIV cipher with the given key, which must be twice as long as an AES key, either 32 or 64 bytes to select AES-128 (AES-CMAC-SIV-256), or AES-256 (AES-CMAC-SIV-512).

func NewAESPMACSIV

func NewAESPMACSIV(key []byte) (c *Cipher, err error)

NewAESPMACSIV returns a new AES-SIV cipher with the given key, which must be twice as long as an AES key, either 32 or 64 bytes to select AES-128 (AES-PMAC-SIV-256), or AES-256 (AES-PMAC-SIV-512).

func (*Cipher) Open

func (c *Cipher) Open(dst []byte, ciphertext []byte, data ...[]byte) ([]byte, error)

Open decrypts ciphertext, authenticates the decrypted plaintext and the given associated data items and, if successful, appends the resulting plaintext to dst, returning the updated slice. The additional data items must match the items passed to Seal.

The ciphertext and dst may alias exactly or not at all.

For nonce-based encryption, the nonce should be the last associated data item.

func (*Cipher) Overhead

func (c *Cipher) Overhead() int

Overhead returns the difference between plaintext and ciphertext lengths.

func (*Cipher) Seal

func (c *Cipher) Seal(dst []byte, plaintext []byte, data ...[]byte) ([]byte, error)

Seal encrypts and authenticates plaintext, authenticates the given associated data items, and appends the result to dst, returning the updated slice.

The plaintext and dst may alias exactly or not at all.

For nonce-based encryption, the nonce should be the last associated data item.

type StreamDecryptor

type StreamDecryptor struct {
	// contains filtered or unexported fields
}

StreamDecryptor decrypts message streams, selecting the nonces using a 32-bit counter, generalized for any cipher.AEAD algorithm

This construction corresponds to the ℰ stream encryptor object as defined in the paper Online Authenticated-Encryption and its Nonce-Reuse Misuse-Resistance

func NewStreamDecryptor

func NewStreamDecryptor(alg string, key, nonce []byte) (*StreamDecryptor, error)

NewStreamDecryptor returns a STREAM encryptor instance with the given cipher, nonce, and a key which must be twice as long as an AES key, either 32 or 64 bytes to select AES-128 (AES-SIV-256) or AES-256 (AES-SIV-512).

func (*StreamDecryptor) NonceSize

func (d *StreamDecryptor) NonceSize() int

NonceSize returns the size of the nonce that must be passed to NewStreamDecryptor

func (*StreamDecryptor) Open

func (d *StreamDecryptor) Open(dst, ciphertext, aData []byte, lastBlock bool) ([]byte, error)

Open decrypts and authenticates the next ciphertext in the STREAM, and also authenticates the additional data, ensuring it matches the value passed to Seal.

If successful, it appends the resulting plaintext to dst and returns the updated slice.

The ciphertext and dst may alias exactly or not at all. To reuse ciphertext's storage for the decrypted output, use ciphertext[:0] as dst.

Even if the function fails, the contents of dst, up to its capacity, may be overwritten.

func (*StreamDecryptor) Overhead

func (d *StreamDecryptor) Overhead() int

Overhead returns the maximum difference between the lengths of a plaintext and its ciphertext, which in the case of AES-SIV modes is the size of the initialization vector

type StreamEncryptor

type StreamEncryptor struct {
	// contains filtered or unexported fields
}

StreamEncryptor encrypts message streams, selecting the nonces using a 32-bit counter, generalized for any cipher.AEAD algorithm

This construction corresponds to the ℰ stream encryptor object as defined in the paper Online Authenticated-Encryption and its Nonce-Reuse Misuse-Resistance

func NewStreamEncryptor

func NewStreamEncryptor(alg string, key, nonce []byte) (*StreamEncryptor, error)

NewStreamEncryptor returns a STREAM encryptor instance with the given cipher, nonce, and a key which must be twice as long as an AES key, either 32 or 64 bytes to select AES-128 (AES-SIV-256) or AES-256 (AES-SIV-512).

func (*StreamEncryptor) NonceSize

func (e *StreamEncryptor) NonceSize() int

NonceSize returns the size of the nonce that must be passed to NewStreamEncryptor

func (*StreamEncryptor) Overhead

func (e *StreamEncryptor) Overhead() int

Overhead returns the maximum difference between the lengths of a plaintext and its ciphertext, which in the case of AES-SIV modes is the size of the initialization vector

func (*StreamEncryptor) Seal

func (e *StreamEncryptor) Seal(dst, plaintext, aData []byte, lastBlock bool) []byte

Seal the next message in the STREAM, which encrypts and authenticates plaintext, authenticates the additional data and appends the result to dst, returning the updated slice.

The plaintext and dst may alias exactly or not at all. To reuse plaintext's storage for the encrypted output, use plaintext[:0] as dst.

The lastBlock argument should be set to true if this is the last message in the STREAM. No further messages can be encrypted after the last one

Directories

Path Synopsis