Add support for random nonce generation to ring::aead
.
This commit is contained in:
parent
63c0364bd3
commit
88d5aa7fd0
117
src/aead.rs
117
src/aead.rs
@ -22,7 +22,7 @@
|
||||
//! [`crypto.cipher.AEAD`]: https://golang.org/pkg/crypto/cipher/#AEAD
|
||||
|
||||
use self::block::{Block, BLOCK_LEN};
|
||||
use crate::{constant_time, cpu, error, hkdf, polyfill};
|
||||
use crate::{constant_time, cpu, error, hkdf, polyfill, rand};
|
||||
use core::ops::RangeFrom;
|
||||
|
||||
pub use self::{
|
||||
@ -445,18 +445,58 @@ impl hkdf::KeyType for &'static Algorithm {
|
||||
}
|
||||
}
|
||||
|
||||
mod sealed {
|
||||
pub trait NonceGeneration {
|
||||
const VALUE: Self;
|
||||
}
|
||||
}
|
||||
|
||||
/// A nonce generation strategy for `LesssSafeKey`; either `ExplicitNonces` or
|
||||
/// `RandomNonces`.
|
||||
pub trait NonceGeneration: sealed::NonceGeneration {}
|
||||
impl<T> NonceGeneration for T where T: sealed::NonceGeneration {}
|
||||
|
||||
/// A nonce generation strategy where random nonces are used.
|
||||
///
|
||||
/// These algorithms are *NOT* nonce-misuse-resistant. They use nonces small
|
||||
/// enough where birthday collisions need to be considered, so even ensuring
|
||||
/// perfectly-random generation of nonces isn't sufficient to prevent nonce
|
||||
/// reuse.
|
||||
pub struct RandomNonces(());
|
||||
impl sealed::NonceGeneration for RandomNonces {
|
||||
const VALUE: Self = Self(());
|
||||
}
|
||||
|
||||
/// A nonce generation strategy where explicitly-constructed nonces are used.
|
||||
pub struct ExplicitNonces(());
|
||||
impl sealed::NonceGeneration for ExplicitNonces {
|
||||
const VALUE: Self = Self(());
|
||||
}
|
||||
|
||||
/// Immutable keys for use in situations where `OpeningKey`/`SealingKey` and
|
||||
/// `NonceSequence` cannot reasonably be used.
|
||||
///
|
||||
/// Prefer to use `OpeningKey`/`SealingKey` and `NonceSequence` when practical.
|
||||
pub struct LessSafeKey {
|
||||
/// These algorithms are *NOT* nonce-misuse-resistant. They use nonces small
|
||||
/// enough where the likelihood of collisions must be carefully considered.
|
||||
pub struct LessSafeKey<N = ExplicitNonces>
|
||||
where
|
||||
N: NonceGeneration,
|
||||
{
|
||||
key: UnboundKey,
|
||||
_nonce_generation: N,
|
||||
}
|
||||
|
||||
impl LessSafeKey {
|
||||
impl<N> LessSafeKey<N>
|
||||
where
|
||||
N: NonceGeneration,
|
||||
{
|
||||
/// Constructs a `LessSafeKey` from an `UnboundKey`.
|
||||
#[inline]
|
||||
pub fn new(key: UnboundKey) -> Self {
|
||||
Self { key }
|
||||
Self {
|
||||
key,
|
||||
_nonce_generation: N::VALUE,
|
||||
}
|
||||
}
|
||||
|
||||
/// Like [`OpeningKey::open_in_place()`], except it accepts an arbitrary nonce.
|
||||
@ -492,6 +532,14 @@ impl LessSafeKey {
|
||||
open_within_(&self.key, nonce, aad, in_out, ciphertext_and_tag)
|
||||
}
|
||||
|
||||
/// The key's AEAD algorithm.
|
||||
#[inline]
|
||||
pub fn algorithm(&self) -> &'static Algorithm {
|
||||
&self.key.algorithm
|
||||
}
|
||||
}
|
||||
|
||||
impl LessSafeKey<ExplicitNonces> {
|
||||
/// Deprecated. Renamed to [`seal_in_place_append_tag()`].
|
||||
#[deprecated(note = "Renamed to `seal_in_place_append_tag`.")]
|
||||
#[inline]
|
||||
@ -523,6 +571,9 @@ impl LessSafeKey {
|
||||
A: AsRef<[u8]>,
|
||||
InOut: AsMut<[u8]> + for<'in_out> Extend<&'in_out u8>,
|
||||
{
|
||||
// Overwrite the plaintext with the ciphertext before extending `in_out`
|
||||
// so that if the `extend()` causes a reallocation, the ciphertext (not
|
||||
// the plaintext) will be in the old deallocated buffer.
|
||||
self.seal_in_place_separate_tag(nonce, aad, in_out.as_mut())
|
||||
.map(|tag| in_out.extend(tag.as_ref()))
|
||||
}
|
||||
@ -543,15 +594,63 @@ impl LessSafeKey {
|
||||
{
|
||||
seal_in_place_separate_tag_(&self.key, nonce, Aad::from(aad.as_ref()), in_out)
|
||||
}
|
||||
}
|
||||
|
||||
/// The key's AEAD algorithm.
|
||||
impl LessSafeKey<RandomNonces> {
|
||||
/// Like [`SealingKey::seal_in_place_append_tag()`], except the nonce is
|
||||
/// randomly generated.
|
||||
///
|
||||
/// The randomly-generated nonce is returned on success.
|
||||
#[inline]
|
||||
pub fn algorithm(&self) -> &'static Algorithm {
|
||||
&self.key.algorithm
|
||||
pub fn seal_with_random_nonce_in_place_append_tag<A, InOut>(
|
||||
&self,
|
||||
aad: Aad<A>,
|
||||
in_out: &mut InOut,
|
||||
rng: &dyn rand::SecureRandom,
|
||||
) -> Result<Nonce, error::Unspecified>
|
||||
where
|
||||
A: AsRef<[u8]>,
|
||||
InOut: AsMut<[u8]> + for<'in_out> Extend<&'in_out u8>,
|
||||
{
|
||||
// Overwrite the plaintext with the ciphertext before extending `in_out`
|
||||
// so that if the `extend()` causes a reallocation, the ciphertext (not
|
||||
// the plaintext) will be in the old deallocated buffer.
|
||||
self.seal_with_random_nonce_in_place_separate_tag(aad, in_out.as_mut(), rng)
|
||||
.map(|(nonce, tag)| {
|
||||
in_out.extend(tag.as_ref());
|
||||
nonce
|
||||
})
|
||||
}
|
||||
|
||||
/// Like [`SealingKey::seal_in_place_separate_tag()`], except the nonce is
|
||||
/// randomly generated.
|
||||
///
|
||||
/// The randomly-generated nonce and the tag are returned on success.
|
||||
#[inline]
|
||||
pub fn seal_with_random_nonce_in_place_separate_tag<A>(
|
||||
&self,
|
||||
aad: Aad<A>,
|
||||
in_out: &mut [u8],
|
||||
rng: &dyn rand::SecureRandom,
|
||||
) -> Result<(Nonce, Tag), error::Unspecified>
|
||||
where
|
||||
A: AsRef<[u8]>,
|
||||
{
|
||||
let nonce = Nonce::assume_unique_for_key(rand::generate(rng)?.expose());
|
||||
seal_in_place_separate_tag_(
|
||||
&self.key,
|
||||
Nonce::assume_unique_for_key(*nonce.as_ref()),
|
||||
Aad::from(aad.as_ref()),
|
||||
in_out,
|
||||
)
|
||||
.map(|tag| (nonce, tag))
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::Debug for LessSafeKey {
|
||||
impl<N> core::fmt::Debug for LessSafeKey<N>
|
||||
where
|
||||
N: NonceGeneration,
|
||||
{
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
|
||||
f.debug_struct("LessSafeKey")
|
||||
.field("algorithm", self.algorithm())
|
||||
|
@ -97,7 +97,7 @@ pub(crate) mod sealed {
|
||||
}
|
||||
}
|
||||
|
||||
impl_random_arrays![4 8 16 32 48 64];
|
||||
impl_random_arrays![4 8 12 16 24 32 48 64];
|
||||
}
|
||||
|
||||
/// A type that can be returned by `ring::rand::generate()`.
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2015-2016 Brian Smith.
|
||||
// Copyright 2015-2019 Brian Smith.
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
@ -48,6 +48,12 @@ fn aead_aes_gcm_128() {
|
||||
open_with_less_safe_key,
|
||||
test_file!("aead_aes_128_gcm_tests.txt"),
|
||||
);
|
||||
test_aead(
|
||||
&aead::AES_128_GCM,
|
||||
seal_with_less_safe_random_nonce_key,
|
||||
open_with_less_safe_random_nonce_key,
|
||||
test_file!("aead_aes_128_gcm_tests.txt"),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -64,6 +70,12 @@ fn aead_aes_gcm_256() {
|
||||
open_with_less_safe_key,
|
||||
test_file!("aead_aes_256_gcm_tests.txt"),
|
||||
);
|
||||
test_aead(
|
||||
&aead::AES_256_GCM,
|
||||
seal_with_less_safe_random_nonce_key,
|
||||
open_with_less_safe_random_nonce_key,
|
||||
test_file!("aead_aes_256_gcm_tests.txt"),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -80,6 +92,12 @@ fn aead_chacha20_poly1305() {
|
||||
open_with_less_safe_key,
|
||||
test_file!("aead_chacha20_poly1305_tests.txt"),
|
||||
);
|
||||
test_aead(
|
||||
&aead::CHACHA20_POLY1305,
|
||||
seal_with_less_safe_random_nonce_key,
|
||||
open_with_less_safe_random_nonce_key,
|
||||
test_file!("aead_chacha20_poly1305_tests.txt"),
|
||||
);
|
||||
}
|
||||
|
||||
fn test_aead<Seal, Open>(
|
||||
@ -263,6 +281,33 @@ fn open_with_key<'a>(
|
||||
o_key.open_within(aad, in_out, ciphertext_and_tag)
|
||||
}
|
||||
|
||||
fn seal_with_less_safe_random_nonce_key(
|
||||
algorithm: &'static aead::Algorithm,
|
||||
key: &[u8],
|
||||
nonce: aead::Nonce,
|
||||
aad: aead::Aad<&[u8]>,
|
||||
in_out: &mut Vec<u8>,
|
||||
) -> Result<(), error::Unspecified> {
|
||||
let rng = test::rand::FixedSliceRandom {
|
||||
bytes: nonce.as_ref(),
|
||||
};
|
||||
let key = make_less_safe_random_nonce_key(algorithm, key);
|
||||
key.seal_with_random_nonce_in_place_append_tag(aad, in_out, &rng)
|
||||
.map(|_: aead::Nonce| ())
|
||||
}
|
||||
|
||||
fn open_with_less_safe_random_nonce_key<'a>(
|
||||
algorithm: &'static aead::Algorithm,
|
||||
key: &[u8],
|
||||
nonce: aead::Nonce,
|
||||
aad: aead::Aad<&[u8]>,
|
||||
in_out: &'a mut [u8],
|
||||
ciphertext_and_tag: RangeFrom<usize>,
|
||||
) -> Result<&'a mut [u8], error::Unspecified> {
|
||||
let key = make_less_safe_random_nonce_key(algorithm, key);
|
||||
key.open_within(nonce, aad, in_out, ciphertext_and_tag)
|
||||
}
|
||||
|
||||
fn seal_with_less_safe_key(
|
||||
algorithm: &'static aead::Algorithm,
|
||||
key: &[u8],
|
||||
@ -419,6 +464,13 @@ fn test_aead_key_debug() {
|
||||
"LessSafeKey { algorithm: CHACHA20_POLY1305 }",
|
||||
format!("{:?}", key)
|
||||
);
|
||||
|
||||
let key: aead::LessSafeKey<aead::RandomNonces> =
|
||||
make_less_safe_random_nonce_key(&aead::CHACHA20_POLY1305, &key_bytes);
|
||||
assert_eq!(
|
||||
"LessSafeKey { algorithm: CHACHA20_POLY1305 }",
|
||||
format!("{:?}", key)
|
||||
);
|
||||
}
|
||||
|
||||
fn make_key<K: aead::BoundKey<OneNonceSequence>>(
|
||||
@ -431,6 +483,14 @@ fn make_key<K: aead::BoundKey<OneNonceSequence>>(
|
||||
K::new(key, nonce_sequence)
|
||||
}
|
||||
|
||||
fn make_less_safe_random_nonce_key(
|
||||
algorithm: &'static aead::Algorithm,
|
||||
key: &[u8],
|
||||
) -> aead::LessSafeKey<aead::RandomNonces> {
|
||||
let key = aead::UnboundKey::new(algorithm, key).unwrap();
|
||||
aead::LessSafeKey::new(key)
|
||||
}
|
||||
|
||||
fn make_less_safe_key(algorithm: &'static aead::Algorithm, key: &[u8]) -> aead::LessSafeKey {
|
||||
let key = aead::UnboundKey::new(algorithm, key).unwrap();
|
||||
aead::LessSafeKey::new(key)
|
||||
|
Loading…
x
Reference in New Issue
Block a user