JDK-8153028 : JEP 329: ChaCha20 and Poly1305 Cryptographic Algorithms
  • Type: JEP
  • Component: security-libs
  • Sub-Component: javax.crypto
  • Priority: P3
  • Status: Closed
  • Resolution: Delivered
  • Fix Versions: 11
  • Submitted: 2016-03-29
  • Updated: 2018-09-13
  • Resolved: 2018-09-13
Related Reports
Blocks :  
Blocks :  
Blocks :  
Relates :  
Relates :  
Sub Tasks
JDK-8153029 :  
JDK-8153030 :  
JDK-8199388 :  
JDK-8210795 :  
Description
Summary
-------

Implement the ChaCha20 and ChaCha20-Poly1305 ciphers as specified in [RFC 7539][rfc7539].  ChaCha20 is a relatively new stream cipher that can replace the older, insecure RC4 stream cipher.

[rfc7539]: https://tools.ietf.org/html/rfc7539

Goals
-----

- Provide ChaCha20 and ChaCha20-Poly1305 `Cipher` implementations.  These algorithms will be implemented in the SunJCE provider.
- Provide a `KeyGenerator` implementation that creates keys suitable for ChaCha20 and ChaCha20-Poly1305 algorithms.
- Provide an `AlgorithmParameters` implementation for use with the ChaCha20-Poly1305 algorithm.

Non-Goals
-----------

TLS cipher suite support will not be part of this JEP.  TLS support for these ciphers will be part of a follow-on enhancement.

Motivation
----------

The only other widely adopted stream cipher, RC4, has long been deemed insecure. The industry consensus is that ChaCha20-Poly1305 is secure at this point in time, and it has seen fairly wide adoption across TLS implementations as well as in other cryptographic protocols. The JDK needs to be on par with other cryptographic toolkits and TLS implementations.

Additionally, TLS 1.3 only allows the use of AEAD-based cipher suites.  Implementing the ChaCha20-Poly1305 algorithm is the first step in implementing different cipher suites that run in AEAD mode in case there were ever weaknesses to be found in AES or GCM.

Description
-----------

The ChaCha20 and ChaCha20-Poly1305 algorithms will implement the `javax.crypto.CipherSpi` API  within the SunJCE provider.  Ciphers will be instantiated in the same way as other ciphers, using the `Cipher.getInstance()` method.  For both ciphers, two acceptable transforms are allowed.  The single-name transform is the preferred approach, `"ChaCha20"` for ChaCha20 as a simple stream cipher with no authentication, and `"ChaCha20-Poly1305"` for ChaCha20 as an AEAD cipher using Poly1305 as the authenticator.  `"ChaCha20/None/NoPadding"` and `"ChaCha20-Poly1305/None/NoPadding"` are also acceptable transform strings, though no other mode or padding values besides `"None"` and `"NoPadding"` will be accepted.  Use of other mode or padding values will cause an exception to be thrown.

Initialization of the ChaCha20 cipher will accept a new `AlgorithmParameterSpec` implementation, `javax.crypto.spec.ChaCha20ParameterSpec`:

```
ChaCha20ParameterSpec(byte[] nonce, int counter);     // Constructor
public byte[] getNonce();     // Obtains a copy of the nonce value
public int getCounter();     // Obtains the initial counter value
```

The nonce value must be 96 bits in length (12 bytes).  Any other length will cause an exception to be thrown.  The integer counter value may be any integer value, even negative, in order to allow the full range of unsigned 32-bit values.

Initialization of this algorithm without a `ChaCha20ParameterSpec` will cause the cipher to generate its own 12-byte nonce internally and set the counter value to 1.  The counter bytes may be obtained by invoking the `Cipher.getIV()` method.

Initialization for ChaCha20-Poly1305 may be accomplished by providing an instance of the current `javax.crypto.spec.IvParameterSpec` class which contains the 12-byte nonce.  The decision to use `IvParameterSpec` over `ChaCha20ParameterSpec` allows ChaCha20-Poly1305 to be backported to earlier releases without making any API changes.  Because `IvParameterSpec` does not set length requirements on the bytes it holds, the cipher object itself will enforce the 12-byte length requirement during initialization.

As with ChaCha20, ChaCha20-Poly1305 may be initialized without an `IvParameterSpec`, in which case the nonce will be randomly generated and may be obtained with `Cipher.getIV()`.

Key objects provided through any of the `init` methods must have an algorithm type of "ChaCha20".  A new `KeyGenerator` implementation will be created to support this.  As with existing `KeyGenerator` implementations for other algorithms such as AES, RC2, ARCFOUR and the HmacSHA2 family, this `KeyGenerator` may not be initialized with an `AlgorithmParameterSpec`.  If forms of the `init` method are invoked that allow an adjustable key length, that parameter must be set to 256 or an `InvalidParameterException` will be thrown.

Use of the ChaCha20 algorithm follows the existing `Cipher` API used for other stream ciphers.  A simple single-part encryption could be written as follows:

```
// Get a Cipher instance and set up the parameters
// Assume SecretKey "key", 12-byte nonce "nonceBytes" and plaintext "pText"
// are coming from outside this code snippet
Cipher mambo = Cipher.getInstance("ChaCha20");
ChaCha20ParameterSpec mamboSpec
    = new ChaCha20ParameterSpec(nonceBytes, 7);   // Use a starting counter value of "7"
// Encrypt our input
mambo.init(Cipher.ENCRYPT_MODE, key, mamboSpec);
byte[] encryptedResult = mambo.doFinal(pText);
```

For ChaCha20 running in AEAD mode with the Poly1305 authenticator, only the nonce is required since RFC 7539 defines the initial counter value for data to begin at 1.  In order to allow this Cipher implementation to be backportable and facilitate its use within our JSSE provider, `javax.crypto.spec.IvParameterSpec` will be used to provide the nonce.

When running in AEAD mode, output sizes may be different than inputs due to either the addition of the authentication tag (for encryption) or the consumption and verification of the tag (for decryption).  Where allocation of an output buffer before encryption/decryption is desired the `getOutputSize()` method should be used.  A sample single-part encryption follows:

```
// Get a Cipher instance and set up the parameters
// Assume SecretKey "key", 12-byte nonce "nonceBytes" and plaintext "pText"
// are coming from outside this code snippet
Cipher mambo = Cipher.getInstance("ChaCha20-Poly1305");
AlgorithmParameterSpec mamboSpec = new IvParameterSpec(nonceBytes);

// Encrypt our input
mambo.init(Cipher.ENCRYPT_MODE, key, mamboSpec);
byte[] encryptedResult = new byte[mambo.getOutputSize(pText.length)];
mambo.doFinal(pText, 0, pText.length, encryptedResult);
```

An important requirement for both ChaCha20 and ChaCha20-Poly1305 ciphers is that following a `doFinal()` call, a new `init()` call must be made which provides a different nonce from the one currently configured.  This is similar to the requirement on encryption for AES-GCM, but in the cases of these two ciphers the init requirement must happen after both encryption and decryption operations.  Subsequent calls to `Cipher.update()`, `Cipher.updateAAD()` or `Cipher.doFinal()` after a previous `doFinal()` and no `init()` call in-between will result in an `IllegalStateException` being thrown.

Testing
------

Testing will cover the following areas:

- Verify that the ChaCha20 and ChaCha20-Poly1305 ciphers pass all known-answer tests
- Verify the ChaCha20 key generator accepts the proper initialization forms and generates keys of the appropriate size
- Verify that the ciphers handle restrictions on initialization (no nonce reuse, etc.)
- Verify that the ciphers execute the proper re-initialization requirements between complete encryption/decryption operations
- Verify that our implementation interoperates with at least one other implementation
- Verfy the ChaCha20-Poly1305 AlgorithmParameters implementation accepts nonce data in the proper format.

Dependencies
------------

The only significant dependency is the constant-time math APIs.  These will be provided as part of [JEP 324](http://openjdk.java.net/jeps/324).