/miscreant.go

Go implementation of Miscreant: misuse-resistant encryption library with AES-SIV (RFC 5297) and AES-PMAC-SIV support

Primary LanguageGoOtherNOASSERTION

miscreant.go Build Status GoDoc MIT licensed Gitter Chat

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

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