chore: checkpoint before Python removal

This commit is contained in:
2026-03-26 22:33:59 +00:00
parent 683cec9307
commit e568ddf82a
29972 changed files with 11269302 additions and 2 deletions

186
vendor/ring/src/aead.rs vendored Normal file
View File

@@ -0,0 +1,186 @@
// Copyright 2015-2024 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//! Authenticated Encryption with Associated Data (AEAD).
//!
//! See [Authenticated encryption: relations among notions and analysis of the
//! generic composition paradigm][AEAD] for an introduction to the concept of
//! AEADs.
//!
//! [AEAD]: https://eprint.iacr.org/2000/025.pdf
//! [`crypto.cipher.AEAD`]: https://golang.org/pkg/crypto/cipher/#AEAD
use crate::{
cpu, error,
polyfill::{u64_from_usize, usize_from_u64_saturated},
};
pub use self::{
algorithm::{Algorithm, AES_128_GCM, AES_256_GCM, CHACHA20_POLY1305},
less_safe_key::LessSafeKey,
nonce::{Nonce, NONCE_LEN},
opening_key::OpeningKey,
sealing_key::SealingKey,
unbound_key::UnboundKey,
};
/// A sequences of unique nonces.
///
/// A given `NonceSequence` must never return the same `Nonce` twice from
/// `advance()`.
///
/// A simple counter is a reasonable (but probably not ideal) `NonceSequence`.
///
/// Intentionally not `Clone` or `Copy` since cloning would allow duplication
/// of the sequence.
pub trait NonceSequence {
/// Returns the next nonce in the sequence.
///
/// This may fail if "too many" nonces have been requested, where how many
/// is too many is up to the implementation of `NonceSequence`. An
/// implementation may that enforce a maximum number of records are
/// sent/received under a key this way. Once `advance()` fails, it must
/// fail for all subsequent calls.
fn advance(&mut self) -> Result<Nonce, error::Unspecified>;
}
/// An AEAD key bound to a nonce sequence.
pub trait BoundKey<N: NonceSequence>: core::fmt::Debug {
/// Constructs a new key from the given `UnboundKey` and `NonceSequence`.
fn new(key: UnboundKey, nonce_sequence: N) -> Self;
/// The key's AEAD algorithm.
fn algorithm(&self) -> &'static Algorithm;
}
/// The additionally authenticated data (AAD) for an opening or sealing
/// operation. This data is authenticated but is **not** encrypted.
///
/// The type `A` could be a byte slice `&[u8]`, a byte array `[u8; N]`
/// for some constant `N`, `Vec<u8>`, etc.
#[derive(Clone, Copy)]
pub struct Aad<A>(A);
impl<A: AsRef<[u8]>> Aad<A> {
/// Construct the `Aad` from the given bytes.
#[inline]
pub fn from(aad: A) -> Self {
Self(aad)
}
}
impl<A> AsRef<[u8]> for Aad<A>
where
A: AsRef<[u8]>,
{
fn as_ref(&self) -> &[u8] {
self.0.as_ref()
}
}
impl Aad<[u8; 0]> {
/// Construct an empty `Aad`.
pub fn empty() -> Self {
Self::from([])
}
}
impl<A> core::fmt::Debug for Aad<A>
where
A: core::fmt::Debug,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_tuple("Aad").field(&self.0).finish()
}
}
impl<A> PartialEq for Aad<A>
where
A: PartialEq,
{
#[inline]
fn eq(&self, other: &Self) -> bool {
self.0.eq(&other.0)
}
}
impl<A> Eq for Aad<A> where A: Eq {}
#[allow(clippy::large_enum_variant, variant_size_differences)]
#[derive(Clone)]
enum KeyInner {
AesGcm(aes_gcm::Key),
ChaCha20Poly1305(chacha20_poly1305::Key),
}
const fn max_input_len(block_len: usize, overhead_blocks_per_nonce: usize) -> usize {
// Each of our AEADs use a 32-bit block counter so the maximum is the
// largest input that will not overflow the counter.
usize_from_u64_saturated(
((1u64 << 32) - u64_from_usize(overhead_blocks_per_nonce)) * u64_from_usize(block_len),
)
}
/// A possibly valid authentication tag.
#[must_use]
#[repr(C)]
#[derive(Clone, Copy)]
pub struct Tag([u8; TAG_LEN]);
impl AsRef<[u8]> for Tag {
fn as_ref(&self) -> &[u8] {
self.0.as_ref()
}
}
impl TryFrom<&[u8]> for Tag {
type Error = error::Unspecified;
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
let raw_tag: [u8; TAG_LEN] = value.try_into().map_err(|_| error::Unspecified)?;
Ok(Self::from(raw_tag))
}
}
impl From<[u8; TAG_LEN]> for Tag {
#[inline]
fn from(value: [u8; TAG_LEN]) -> Self {
Self(value)
}
}
const MAX_KEY_LEN: usize = 32;
// All the AEADs we support use 128-bit tags.
const TAG_LEN: usize = 16;
/// The maximum length of a tag for the algorithms in this module.
pub const MAX_TAG_LEN: usize = TAG_LEN;
mod aes;
mod aes_gcm;
mod algorithm;
mod chacha;
mod chacha20_poly1305;
pub mod chacha20_poly1305_openssh;
mod gcm;
mod less_safe_key;
mod nonce;
mod opening_key;
mod overlapping;
mod poly1305;
pub mod quic;
mod sealing_key;
mod shift;
mod unbound_key;

284
vendor/ring/src/aead/aes.rs vendored Normal file
View File

@@ -0,0 +1,284 @@
// Copyright 2018-2024 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use super::{nonce::Nonce, overlapping, quic::Sample, NONCE_LEN};
use crate::{
bb,
cpu::{self, GetFeature as _},
error,
polyfill::unwrap_const,
};
use cfg_if::cfg_if;
use core::num::NonZeroU32;
pub(super) use ffi::Counter;
#[macro_use]
mod ffi;
mod bs;
pub(super) mod fallback;
pub(super) mod hw;
pub(super) mod vp;
pub type Overlapping<'o> = overlapping::Overlapping<'o, u8>;
pub type OverlappingPartialBlock<'o> = overlapping::PartialBlock<'o, u8, BLOCK_LEN>;
cfg_if! {
if #[cfg(any(all(target_arch = "aarch64", target_endian = "little"), target_arch = "x86_64"))] {
pub(super) use ffi::AES_KEY;
} else {
use ffi::AES_KEY;
}
}
#[derive(Clone)]
pub(super) enum Key {
#[cfg(any(
all(target_arch = "aarch64", target_endian = "little"),
target_arch = "x86_64",
target_arch = "x86"
))]
Hw(hw::Key),
#[cfg(any(
all(target_arch = "aarch64", target_endian = "little"),
all(target_arch = "arm", target_endian = "little"),
target_arch = "x86",
target_arch = "x86_64"
))]
Vp(vp::Key),
Fallback(fallback::Key),
}
impl Key {
#[inline]
pub fn new(
bytes: KeyBytes<'_>,
cpu_features: cpu::Features,
) -> Result<Self, error::Unspecified> {
#[cfg(any(
all(target_arch = "aarch64", target_endian = "little"),
target_arch = "x86",
target_arch = "x86_64"
))]
if let Some(hw_features) = cpu_features.get_feature() {
return Ok(Self::Hw(hw::Key::new(
bytes,
hw_features,
cpu_features.get_feature(),
)?));
}
#[cfg(any(
all(target_arch = "aarch64", target_endian = "little"),
all(target_arch = "arm", target_endian = "little"),
target_arch = "x86_64",
target_arch = "x86"
))]
if let Some(vp_features) = cpu_features.get_feature() {
return Ok(Self::Vp(vp::Key::new(bytes, vp_features)?));
}
let _ = cpu_features;
Ok(Self::Fallback(fallback::Key::new(bytes)?))
}
#[inline]
fn encrypt_block(&self, a: Block) -> Block {
match self {
#[cfg(any(
all(target_arch = "aarch64", target_endian = "little"),
target_arch = "x86_64",
target_arch = "x86"
))]
Key::Hw(inner) => inner.encrypt_block(a),
#[cfg(any(
all(target_arch = "aarch64", target_endian = "little"),
all(target_arch = "arm", target_endian = "little"),
target_arch = "x86",
target_arch = "x86_64"
))]
Key::Vp(inner) => inner.encrypt_block(a),
Key::Fallback(inner) => inner.encrypt_block(a),
}
}
pub fn new_mask(&self, sample: Sample) -> [u8; 5] {
let [b0, b1, b2, b3, b4, ..] = self.encrypt_block(sample);
[b0, b1, b2, b3, b4]
}
}
pub const AES_128_KEY_LEN: usize = 128 / 8;
pub const AES_256_KEY_LEN: usize = 256 / 8;
pub enum KeyBytes<'a> {
AES_128(&'a [u8; AES_128_KEY_LEN]),
AES_256(&'a [u8; AES_256_KEY_LEN]),
}
// `Counter` is `ffi::Counter` as its representation is dictated by its use in
// the FFI.
impl Counter {
pub fn one(nonce: Nonce) -> Self {
let mut value = [0u8; BLOCK_LEN];
value[..NONCE_LEN].copy_from_slice(nonce.as_ref());
value[BLOCK_LEN - 1] = 1;
Self(value)
}
pub fn increment(&mut self) -> Iv {
const ONE: NonZeroU32 = unwrap_const(NonZeroU32::new(1));
let iv = Iv(self.0);
self.increment_by_less_safe(ONE);
iv
}
pub(super) fn increment_by_less_safe(&mut self, increment_by: NonZeroU32) {
let [.., c0, c1, c2, c3] = &mut self.0;
let old_value: u32 = u32::from_be_bytes([*c0, *c1, *c2, *c3]);
let new_value = old_value.wrapping_add(increment_by.get());
[*c0, *c1, *c2, *c3] = u32::to_be_bytes(new_value);
}
}
/// The IV for a single block encryption.
///
/// Intentionally not `Clone` to ensure each is used only once.
pub struct Iv(Block);
impl From<Counter> for Iv {
fn from(counter: Counter) -> Self {
Self(counter.0)
}
}
pub(super) type Block = [u8; BLOCK_LEN];
pub(super) const BLOCK_LEN: usize = 16;
pub(super) const ZERO_BLOCK: Block = [0u8; BLOCK_LEN];
pub(super) trait EncryptBlock {
fn encrypt_block(&self, block: Block) -> Block;
fn encrypt_iv_xor_block(&self, iv: Iv, block: Block) -> Block;
}
pub(super) trait EncryptCtr32 {
fn ctr32_encrypt_within(&self, in_out: Overlapping<'_>, ctr: &mut Counter);
}
#[allow(dead_code)]
fn encrypt_block_using_encrypt_iv_xor_block(key: &impl EncryptBlock, block: Block) -> Block {
key.encrypt_iv_xor_block(Iv(block), ZERO_BLOCK)
}
fn encrypt_iv_xor_block_using_encrypt_block(
key: &impl EncryptBlock,
iv: Iv,
block: Block,
) -> Block {
let encrypted_iv = key.encrypt_block(iv.0);
bb::xor_16(encrypted_iv, block)
}
#[allow(dead_code)]
fn encrypt_iv_xor_block_using_ctr32(key: &impl EncryptCtr32, iv: Iv, mut block: Block) -> Block {
let mut ctr = Counter(iv.0); // This is OK because we're only encrypting one block.
key.ctr32_encrypt_within(block.as_mut().into(), &mut ctr);
block
}
#[cfg(test)]
mod tests {
use super::*;
use crate::testutil as test;
#[test]
pub fn test_aes() {
test::run(test_vector_file!("aes_tests.txt"), |section, test_case| {
assert_eq!(section, "");
let key = consume_key(test_case, "Key");
let input = test_case.consume_bytes("Input");
let block: Block = input.as_slice().try_into()?;
let expected_output = test_case.consume_bytes("Output");
let output = key.encrypt_block(block);
assert_eq!(output.as_ref(), &expected_output[..]);
Ok(())
})
}
fn consume_key(test_case: &mut test::TestCase, name: &str) -> Key {
let key = test_case.consume_bytes(name);
let key = &key[..];
let key = match key.len() {
16 => KeyBytes::AES_128(key.try_into().unwrap()),
32 => KeyBytes::AES_256(key.try_into().unwrap()),
_ => unreachable!(),
};
Key::new(key, cpu::features()).unwrap()
}
}
// These AES-GCM-specific tests are here instead of in `aes_gcm` because
// `Counter`'s API isn't visible (enough) to aes_gcm.
#[cfg(test)]
mod aes_gcm_tests {
use super::{super::aes_gcm::MAX_IN_OUT_LEN, *};
use core::num::NonZeroU32;
#[test]
fn test_aes_gcm_counter_blocks_max() {
test_aes_gcm_counter_blocks(MAX_IN_OUT_LEN, &[0, 0, 0, 0]);
}
#[test]
fn test_aes_gcm_counter_blocks_max_minus_one() {
test_aes_gcm_counter_blocks(MAX_IN_OUT_LEN - BLOCK_LEN, &[0xff, 0xff, 0xff, 0xff]);
}
fn test_aes_gcm_counter_blocks(in_out_len: usize, expected_final_counter: &[u8; 4]) {
fn ctr32(ctr: &Counter) -> &[u8; 4] {
(&ctr.0[12..]).try_into().unwrap()
}
let rounded_down = in_out_len / BLOCK_LEN;
let blocks = rounded_down + (if in_out_len % BLOCK_LEN == 0 { 0 } else { 1 });
let blocks = u32::try_from(blocks)
.ok()
.and_then(NonZeroU32::new)
.unwrap();
let nonce = Nonce::assume_unique_for_key([1; 12]);
let mut ctr = Counter::one(nonce);
assert_eq!(ctr32(&ctr), &[0, 0, 0, 1]);
let _tag_iv = ctr.increment();
assert_eq!(ctr32(&ctr), &[0, 0, 0, 2]);
ctr.increment_by_less_safe(blocks);
// `MAX_IN_OUT_LEN` is less on 32-bit targets, so we don't even get
// close to wrapping, but run the tests on them anyway.
#[cfg(target_pointer_width = "64")]
assert_eq!(ctr32(&ctr), expected_final_counter);
#[cfg(target_pointer_width = "32")]
let _ = expected_final_counter;
}
}

60
vendor/ring/src/aead/aes/bs.rs vendored Normal file
View File

@@ -0,0 +1,60 @@
// Copyright 2018-2024 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#![cfg(all(target_arch = "arm", target_endian = "little"))]
use super::{Counter, Overlapping, AES_KEY};
/// SAFETY:
/// * The caller must ensure that if blocks > 0 then either `input` and
/// `output` do not overlap at all, or input == output.add(n) for some
/// (nonnegative) n.
/// * if blocks > 0, The caller must ensure `input` points to `blocks` blocks
/// and that `output` points to writable space for `blocks` blocks.
/// * The caller must ensure that `vpaes_key` was initialized with
/// `vpaes_set_encrypt_key`.
/// * Upon returning, `blocks` blocks will have been read from `input` and
/// written to `output`.
pub(super) unsafe fn ctr32_encrypt_blocks_with_vpaes_key(
in_out: Overlapping<'_>,
vpaes_key: &AES_KEY,
ctr: &mut Counter,
) {
prefixed_extern! {
// bsaes_ctr32_encrypt_blocks requires transformation of an existing
// VPAES key; there is no `bsaes_set_encrypt_key`.
fn vpaes_encrypt_key_to_bsaes(bsaes_key: *mut AES_KEY, vpaes_key: &AES_KEY);
}
// SAFETY:
// * The caller ensures `vpaes_key` was initialized by
// `vpaes_set_encrypt_key`.
// * `bsaes_key was zeroed above, and `vpaes_encrypt_key_to_bsaes`
// is assumed to initialize `bsaes_key`.
let bsaes_key = unsafe { AES_KEY::derive(vpaes_encrypt_key_to_bsaes, vpaes_key) };
// The code for `vpaes_encrypt_key_to_bsaes` notes "vpaes stores one
// fewer round count than bsaes, but the number of keys is the same,"
// so use this as a sanity check.
debug_assert_eq!(bsaes_key.rounds(), vpaes_key.rounds() + 1);
// SAFETY:
// * `bsaes_key` is in bsaes format after calling
// `vpaes_encrypt_key_to_bsaes`.
// * `bsaes_ctr32_encrypt_blocks` satisfies the contract for
// `ctr32_encrypt_blocks`.
unsafe {
ctr32_encrypt_blocks!(bsaes_ctr32_encrypt_blocks, in_out, &bsaes_key, ctr);
}
}

44
vendor/ring/src/aead/aes/fallback.rs vendored Normal file
View File

@@ -0,0 +1,44 @@
// Copyright 2018-2024 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use super::{Block, Counter, EncryptBlock, EncryptCtr32, Iv, KeyBytes, Overlapping, AES_KEY};
use crate::error;
#[derive(Clone)]
pub struct Key {
inner: AES_KEY,
}
impl Key {
pub(in super::super) fn new(bytes: KeyBytes<'_>) -> Result<Self, error::Unspecified> {
let inner = unsafe { set_encrypt_key!(aes_nohw_set_encrypt_key, bytes) }?;
Ok(Self { inner })
}
}
impl EncryptBlock for Key {
fn encrypt_block(&self, block: Block) -> Block {
unsafe { encrypt_block!(aes_nohw_encrypt, block, &self.inner) }
}
fn encrypt_iv_xor_block(&self, iv: Iv, block: Block) -> Block {
super::encrypt_iv_xor_block_using_encrypt_block(self, iv, block)
}
}
impl EncryptCtr32 for Key {
fn ctr32_encrypt_within(&self, in_out: Overlapping<'_>, ctr: &mut Counter) {
unsafe { ctr32_encrypt_blocks!(aes_nohw_ctr32_encrypt_blocks, in_out, &self.inner, ctr) }
}
}

206
vendor/ring/src/aead/aes/ffi.rs vendored Normal file
View File

@@ -0,0 +1,206 @@
// Copyright 2018-2024 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use super::{Block, KeyBytes, Overlapping, BLOCK_LEN};
use crate::{bits::BitLength, c, error};
use core::{
ffi::{c_int, c_uint},
num::{NonZeroU32, NonZeroUsize},
};
/// nonce || big-endian counter.
#[repr(transparent)]
pub(in super::super) struct Counter(pub(super) [u8; BLOCK_LEN]);
// Keep this in sync with AES_KEY in aes.h.
#[repr(C)]
#[derive(Clone)]
pub(in super::super) struct AES_KEY {
pub rd_key: [u32; 4 * (MAX_ROUNDS + 1)],
pub rounds: c_uint,
}
// Keep this in sync with `AES_MAXNR` in aes.h.
const MAX_ROUNDS: usize = 14;
impl AES_KEY {
#[inline]
pub(super) unsafe fn new(
f: unsafe extern "C" fn(*const u8, BitLength<c_int>, *mut AES_KEY) -> c_int,
bytes: KeyBytes<'_>,
) -> Result<Self, error::Unspecified> {
let mut key = Self {
rd_key: [0; 4 * (MAX_ROUNDS + 1)],
rounds: 0,
};
let (bytes, key_bits) = match bytes {
KeyBytes::AES_128(bytes) => (&bytes[..], BitLength::from_bits(128)),
KeyBytes::AES_256(bytes) => (&bytes[..], BitLength::from_bits(256)),
};
// Unusually, in this case zero means success and non-zero means failure.
if 0 == unsafe { f(bytes.as_ptr(), key_bits, &mut key) } {
debug_assert_ne!(key.rounds, 0); // Sanity check initialization.
Ok(key)
} else {
Err(error::Unspecified)
}
}
}
#[cfg(all(target_arch = "arm", target_endian = "little"))]
impl AES_KEY {
pub(super) unsafe fn derive(
f: for<'a> unsafe extern "C" fn(*mut AES_KEY, &'a AES_KEY),
src: &Self,
) -> Self {
let mut r = AES_KEY {
rd_key: [0u32; 4 * (MAX_ROUNDS + 1)],
rounds: 0,
};
unsafe { f(&mut r, src) };
r
}
pub(super) fn rounds(&self) -> u32 {
self.rounds
}
}
// SAFETY:
// * The function `$name` must read `bits` bits from `user_key`; `bits` will
// always be a valid AES key length, i.e. a whole number of bytes.
// * `$name` must set `key.rounds` to the value expected by the corresponding
// encryption/decryption functions and return 0, or otherwise must return
// non-zero to indicate failure.
// * `$name` may inspect CPU features.
//
// In BoringSSL, the C prototypes for these are in
// crypto/fipsmodule/aes/internal.h.
macro_rules! set_encrypt_key {
( $name:ident, $key_bytes:expr $(,)? ) => {{
use crate::bits::BitLength;
use core::ffi::c_int;
prefixed_extern! {
fn $name(user_key: *const u8, bits: BitLength<c_int>, key: *mut AES_KEY) -> c_int;
}
$crate::aead::aes::ffi::AES_KEY::new($name, $key_bytes)
}};
}
macro_rules! encrypt_block {
($name:ident, $block:expr, $key:expr) => {{
use crate::aead::aes::{ffi::AES_KEY, Block};
prefixed_extern! {
fn $name(a: &Block, r: *mut Block, key: &AES_KEY);
}
$key.encrypt_block($name, $block)
}};
}
impl AES_KEY {
#[inline]
pub(super) unsafe fn encrypt_block(
&self,
f: unsafe extern "C" fn(&Block, *mut Block, &AES_KEY),
a: Block,
) -> Block {
let mut result = core::mem::MaybeUninit::uninit();
unsafe {
f(&a, result.as_mut_ptr(), self);
result.assume_init()
}
}
}
/// SAFETY:
/// * The caller must ensure that `$key` was initialized with the
/// `set_encrypt_key!` invocation that `$name` requires.
/// * The caller must ensure that fhe function `$name` satisfies the conditions
/// for the `f` parameter to `ctr32_encrypt_blocks`.
macro_rules! ctr32_encrypt_blocks {
($name:ident, $in_out:expr, $key:expr, $ctr:expr $(,)? ) => {{
use crate::{
aead::aes::{ffi::AES_KEY, Counter, BLOCK_LEN},
c,
};
prefixed_extern! {
fn $name(
input: *const [u8; BLOCK_LEN],
output: *mut [u8; BLOCK_LEN],
blocks: c::NonZero_size_t,
key: &AES_KEY,
ivec: &Counter,
);
}
$key.ctr32_encrypt_blocks($name, $in_out, $ctr)
}};
}
impl AES_KEY {
/// SAFETY:
/// * `f` must not read more than `blocks` blocks from `input`.
/// * `f` must write exactly `block` blocks to `output`.
/// * In particular, `f` must handle blocks == 0 without reading from `input`
/// or writing to `output`.
/// * `f` must support the input overlapping with the output exactly or
/// with any nonnegative offset `n` (i.e. `input == output.add(n)`);
/// `f` does NOT need to support the cases where input < output.
/// * `key` must have been initialized with the `set_encrypt_key!` invocation
/// that corresponds to `f`.
/// * `f` may inspect CPU features.
#[inline]
pub(super) unsafe fn ctr32_encrypt_blocks(
&self,
f: unsafe extern "C" fn(
input: *const [u8; BLOCK_LEN],
output: *mut [u8; BLOCK_LEN],
blocks: c::NonZero_size_t,
key: &AES_KEY,
ivec: &Counter,
),
in_out: Overlapping<'_>,
ctr: &mut Counter,
) {
in_out.with_input_output_len(|input, output, len| {
debug_assert_eq!(len % BLOCK_LEN, 0);
let blocks = match NonZeroUsize::new(len / BLOCK_LEN) {
Some(blocks) => blocks,
None => {
return;
}
};
let input: *const [u8; BLOCK_LEN] = input.cast();
let output: *mut [u8; BLOCK_LEN] = output.cast();
let blocks_u32: NonZeroU32 = blocks.try_into().unwrap();
// SAFETY:
// * `input` points to `blocks` blocks.
// * `output` points to space for `blocks` blocks to be written.
// * input == output.add(n), where n == src.start, and the caller is
// responsible for ensuing this sufficient for `f` to work correctly.
// * `blocks` is non-zero so `f` doesn't have to work for empty slices.
// * The caller is responsible for ensuring `key` was initialized by the
// `set_encrypt_key!` invocation required by `f`.
unsafe {
f(input, output, blocks, self, ctr);
}
ctr.increment_by_less_safe(blocks_u32);
});
}
}

95
vendor/ring/src/aead/aes/hw.rs vendored Normal file
View File

@@ -0,0 +1,95 @@
// Copyright 2018-2024 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#![cfg(any(
all(target_arch = "aarch64", target_endian = "little"),
target_arch = "x86",
target_arch = "x86_64"
))]
use super::{Block, Counter, EncryptBlock, EncryptCtr32, Iv, KeyBytes, Overlapping, AES_KEY};
use crate::{cpu, error};
use cfg_if::cfg_if;
cfg_if! {
if #[cfg(all(target_arch = "aarch64", target_endian = "little"))] {
pub(in super::super) type RequiredCpuFeatures = cpu::arm::Aes;
pub(in super::super) type OptionalCpuFeatures = ();
} else if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
use cpu::intel::{Aes, Avx, Ssse3};
// Some functions seem to have been written to require only SSE/SSE2
// but there seem to be no SSSE3-less CPUs with AES-NI, and we don't
// have feature detection for SSE2.
pub(in super::super) type RequiredCpuFeatures = (Aes, Ssse3);
pub(in super::super) type OptionalCpuFeatures = Avx;
}
}
#[derive(Clone)]
pub struct Key {
inner: AES_KEY,
}
impl Key {
#[cfg(all(target_arch = "aarch64", target_endian = "little"))]
pub(in super::super) fn new(
bytes: KeyBytes<'_>,
_required_cpu_features: RequiredCpuFeatures,
_optional_cpu_features: Option<OptionalCpuFeatures>,
) -> Result<Self, error::Unspecified> {
let inner = unsafe { set_encrypt_key!(aes_hw_set_encrypt_key, bytes) }?;
Ok(Self { inner })
}
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
pub(in super::super) fn new(
bytes: KeyBytes<'_>,
(Aes { .. }, Ssse3 { .. }): RequiredCpuFeatures,
optional_cpu_features: Option<OptionalCpuFeatures>,
) -> Result<Self, error::Unspecified> {
// Ssse3 is required, but upstream only uses this if there is also Avx;
// presumably the base version is faster on pre-AVX CPUs.
let inner = if let Some(Avx { .. }) = optional_cpu_features {
unsafe { set_encrypt_key!(aes_hw_set_encrypt_key_alt, bytes) }?
} else {
unsafe { set_encrypt_key!(aes_hw_set_encrypt_key_base, bytes) }?
};
Ok(Self { inner })
}
#[cfg(any(
all(target_arch = "aarch64", target_endian = "little"),
target_arch = "x86_64"
))]
#[must_use]
pub(in super::super) fn inner_less_safe(&self) -> &AES_KEY {
&self.inner
}
}
impl EncryptBlock for Key {
fn encrypt_block(&self, block: Block) -> Block {
super::encrypt_block_using_encrypt_iv_xor_block(self, block)
}
fn encrypt_iv_xor_block(&self, iv: Iv, block: Block) -> Block {
super::encrypt_iv_xor_block_using_ctr32(self, iv, block)
}
}
impl EncryptCtr32 for Key {
fn ctr32_encrypt_within(&self, in_out: Overlapping<'_>, ctr: &mut Counter) {
unsafe { ctr32_encrypt_blocks!(aes_hw_ctr32_encrypt_blocks, in_out, &self.inner, ctr) }
}
}

139
vendor/ring/src/aead/aes/vp.rs vendored Normal file
View File

@@ -0,0 +1,139 @@
// Copyright 2018-2024 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#![cfg(any(
all(target_arch = "aarch64", target_endian = "little"),
all(target_arch = "arm", target_endian = "little"),
target_arch = "x86",
target_arch = "x86_64"
))]
use super::{Block, Counter, EncryptBlock, EncryptCtr32, Iv, KeyBytes, Overlapping, AES_KEY};
use crate::{cpu, error};
#[cfg(any(
all(target_arch = "aarch64", target_endian = "little"),
all(target_arch = "arm", target_endian = "little")
))]
type RequiredCpuFeatures = cpu::arm::Neon;
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
pub(in super::super) type RequiredCpuFeatures = cpu::intel::Ssse3;
#[derive(Clone)]
pub(in super::super) struct Key {
inner: AES_KEY,
}
impl Key {
pub(in super::super) fn new(
bytes: KeyBytes<'_>,
_cpu: RequiredCpuFeatures,
) -> Result<Self, error::Unspecified> {
let inner = unsafe { set_encrypt_key!(vpaes_set_encrypt_key, bytes) }?;
Ok(Self { inner })
}
}
#[cfg(any(
all(target_arch = "aarch64", target_endian = "little"),
all(target_arch = "arm", target_endian = "little"),
target_arch = "x86_64"
))]
impl EncryptBlock for Key {
fn encrypt_block(&self, block: Block) -> Block {
super::encrypt_block_using_encrypt_iv_xor_block(self, block)
}
fn encrypt_iv_xor_block(&self, iv: Iv, block: Block) -> Block {
super::encrypt_iv_xor_block_using_ctr32(self, iv, block)
}
}
#[cfg(any(
all(target_arch = "aarch64", target_endian = "little"),
target_arch = "x86_64"
))]
impl EncryptCtr32 for Key {
fn ctr32_encrypt_within(&self, in_out: Overlapping<'_>, ctr: &mut Counter) {
unsafe { ctr32_encrypt_blocks!(vpaes_ctr32_encrypt_blocks, in_out, &self.inner, ctr) }
}
}
#[cfg(all(target_arch = "arm", target_endian = "little"))]
impl EncryptCtr32 for Key {
fn ctr32_encrypt_within(&self, in_out: Overlapping<'_>, ctr: &mut Counter) {
use super::{super::overlapping::IndexError, bs, BLOCK_LEN};
let in_out = {
let (in_out, src) = in_out.into_slice_src_mut();
let blocks = in_out[src.clone()].len() / BLOCK_LEN;
// bsaes operates in batches of 8 blocks.
let bsaes_blocks = if blocks >= 8 && (blocks % 8) < 6 {
// It's faster to use bsaes for all the full batches and then
// switch to vpaes for the last partial batch (if any).
blocks - (blocks % 8)
} else if blocks >= 8 {
// It's faster to let bsaes handle everything including
// the last partial batch.
blocks
} else {
// It's faster to let vpaes handle everything.
0
};
let bsaes_in_out_len = bsaes_blocks * BLOCK_LEN;
let bs_in_out =
Overlapping::new(&mut in_out[..(src.start + bsaes_in_out_len)], src.clone())
.unwrap_or_else(|IndexError { .. }| unreachable!());
// SAFETY:
// * self.inner was initialized with `vpaes_set_encrypt_key` above,
// as required by `bsaes_ctr32_encrypt_blocks_with_vpaes_key`.
unsafe {
bs::ctr32_encrypt_blocks_with_vpaes_key(bs_in_out, &self.inner, ctr);
}
Overlapping::new(&mut in_out[bsaes_in_out_len..], src)
.unwrap_or_else(|IndexError { .. }| unreachable!())
};
// SAFETY:
// * self.inner was initialized with `vpaes_set_encrypt_key` above,
// as required by `vpaes_ctr32_encrypt_blocks`.
// * `vpaes_ctr32_encrypt_blocks` satisfies the contract for
// `ctr32_encrypt_blocks`.
unsafe { ctr32_encrypt_blocks!(vpaes_ctr32_encrypt_blocks, in_out, &self.inner, ctr) }
}
}
#[cfg(target_arch = "x86")]
impl EncryptBlock for Key {
fn encrypt_block(&self, block: Block) -> Block {
unsafe { encrypt_block!(vpaes_encrypt, block, &self.inner) }
}
fn encrypt_iv_xor_block(&self, iv: Iv, block: Block) -> Block {
super::encrypt_iv_xor_block_using_encrypt_block(self, iv, block)
}
}
#[cfg(target_arch = "x86")]
impl EncryptCtr32 for Key {
fn ctr32_encrypt_within(&self, in_out: Overlapping<'_>, ctr: &mut Counter) {
super::super::shift::shift_full_blocks(in_out, |input| {
self.encrypt_iv_xor_block(ctr.increment(), *input)
});
}
}

505
vendor/ring/src/aead/aes_gcm.rs vendored Normal file
View File

@@ -0,0 +1,505 @@
// Copyright 2015-2025 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use super::{
aes::{self, Counter, Overlapping, OverlappingPartialBlock, BLOCK_LEN, ZERO_BLOCK},
gcm,
overlapping::IndexError,
Aad, Nonce, Tag,
};
use crate::{
cpu,
error::{self, InputTooLongError},
polyfill::{slice, sliceutil::overwrite_at_start, usize_from_u64_saturated},
};
use core::ops::RangeFrom;
#[cfg(any(
all(target_arch = "aarch64", target_endian = "little"),
all(target_arch = "arm", target_endian = "little"),
target_arch = "x86",
target_arch = "x86_64"
))]
use cpu::GetFeature as _;
mod aarch64;
mod aeshwclmulmovbe;
mod vaesclmulavx2;
#[derive(Clone)]
pub(super) struct Key(DynKey);
impl Key {
pub(super) fn new(
key: aes::KeyBytes,
cpu_features: cpu::Features,
) -> Result<Self, error::Unspecified> {
Ok(Self(DynKey::new(key, cpu_features)?))
}
}
#[derive(Clone)]
enum DynKey {
#[cfg(target_arch = "x86_64")]
VAesClMulAvx2(Combo<aes::hw::Key, gcm::vclmulavx2::Key>),
#[cfg(target_arch = "x86_64")]
AesHwClMulAvxMovbe(Combo<aes::hw::Key, gcm::clmulavxmovbe::Key>),
#[cfg(any(
all(target_arch = "aarch64", target_endian = "little"),
target_arch = "x86",
target_arch = "x86_64"
))]
AesHwClMul(Combo<aes::hw::Key, gcm::clmul::Key>),
#[cfg(any(
all(target_arch = "aarch64", target_endian = "little"),
all(target_arch = "arm", target_endian = "little")
))]
Simd(Combo<aes::vp::Key, gcm::neon::Key>),
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
Simd(Combo<aes::vp::Key, gcm::fallback::Key>),
Fallback(Combo<aes::fallback::Key, gcm::fallback::Key>),
}
impl DynKey {
fn new(key: aes::KeyBytes, cpu: cpu::Features) -> Result<Self, error::Unspecified> {
let cpu = cpu.values();
#[cfg(target_arch = "x86_64")]
if let Some((aes, gcm)) = cpu.get_feature() {
// 14.3.1 Detection of VEX-Encoded AES and VPCLMULQDQ
let aes_key = aes::hw::Key::new(key, aes, cpu.get_feature())?;
let gcm_key_value = derive_gcm_key_value(&aes_key);
let combo = if let Some(cpu) = cpu.get_feature() {
let gcm_key = gcm::vclmulavx2::Key::new(gcm_key_value, cpu);
Self::VAesClMulAvx2(Combo { aes_key, gcm_key })
} else if let Some(cpu) = cpu.get_feature() {
let gcm_key = gcm::clmulavxmovbe::Key::new(gcm_key_value, cpu);
Self::AesHwClMulAvxMovbe(Combo { aes_key, gcm_key })
} else {
let gcm_key = gcm::clmul::Key::new(gcm_key_value, gcm);
Self::AesHwClMul(Combo { aes_key, gcm_key })
};
return Ok(combo);
}
// x86_64 is handled above.
#[cfg(any(
all(target_arch = "aarch64", target_endian = "little"),
target_arch = "x86"
))]
if let (Some(aes), Some(gcm)) = (cpu.get_feature(), cpu.get_feature()) {
let aes_key = aes::hw::Key::new(key, aes, cpu.get_feature())?;
let gcm_key_value = derive_gcm_key_value(&aes_key);
let gcm_key = gcm::clmul::Key::new(gcm_key_value, gcm);
return Ok(Self::AesHwClMul(Combo { aes_key, gcm_key }));
}
#[cfg(any(
all(target_arch = "aarch64", target_endian = "little"),
all(target_arch = "arm", target_endian = "little")
))]
if let Some(cpu) = cpu.get_feature() {
return Self::new_neon(key, cpu);
}
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
if let Some(cpu) = cpu.get_feature() {
return Self::new_ssse3(key, cpu);
}
let _ = cpu;
Self::new_fallback(key)
}
#[cfg(any(
all(target_arch = "aarch64", target_endian = "little"),
all(target_arch = "arm", target_endian = "little")
))]
#[cfg_attr(target_arch = "aarch64", inline(never))]
fn new_neon(key: aes::KeyBytes, cpu: cpu::arm::Neon) -> Result<Self, error::Unspecified> {
let aes_key = aes::vp::Key::new(key, cpu)?;
let gcm_key_value = derive_gcm_key_value(&aes_key);
let gcm_key = gcm::neon::Key::new(gcm_key_value, cpu);
Ok(Self::Simd(Combo { aes_key, gcm_key }))
}
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
#[inline(never)]
fn new_ssse3(
key: aes::KeyBytes,
cpu: aes::vp::RequiredCpuFeatures,
) -> Result<Self, error::Unspecified> {
let aes_key = aes::vp::Key::new(key, cpu)?;
let gcm_key_value = derive_gcm_key_value(&aes_key);
let gcm_key = gcm::fallback::Key::new(gcm_key_value);
Ok(Self::Simd(Combo { aes_key, gcm_key }))
}
#[cfg_attr(
any(
all(target_arch = "aarch64", target_endian = "little"),
all(target_arch = "arm", target_endian = "little"),
target_arch = "x86",
target_arch = "x86_64",
),
inline(never)
)]
fn new_fallback(key: aes::KeyBytes) -> Result<Self, error::Unspecified> {
let aes_key = aes::fallback::Key::new(key)?;
let gcm_key_value = derive_gcm_key_value(&aes_key);
let gcm_key = gcm::fallback::Key::new(gcm_key_value);
Ok(Self::Fallback(Combo { aes_key, gcm_key }))
}
}
fn derive_gcm_key_value(aes_key: &impl aes::EncryptBlock) -> gcm::KeyValue {
gcm::KeyValue::new(aes_key.encrypt_block(ZERO_BLOCK))
}
const CHUNK_BLOCKS: usize = 3 * 1024 / 16;
#[inline(never)]
pub(super) fn seal(
Key(key): &Key,
nonce: Nonce,
aad: Aad<&[u8]>,
in_out: &mut [u8],
) -> Result<Tag, error::Unspecified> {
let mut ctr = Counter::one(nonce);
let tag_iv = ctr.increment();
match key {
#[cfg(all(target_arch = "aarch64", target_endian = "little"))]
DynKey::AesHwClMul(c) => {
seal_whole_partial(c, aad, in_out, ctr, tag_iv, aarch64::seal_whole)
}
#[cfg(target_arch = "x86_64")]
DynKey::VAesClMulAvx2(c) => seal_whole_partial(
c,
aad,
in_out,
ctr,
tag_iv,
vaesclmulavx2::seal_whole_vaes_clmul_avx2,
),
#[cfg(target_arch = "x86_64")]
DynKey::AesHwClMulAvxMovbe(Combo { aes_key, gcm_key }) => {
aeshwclmulmovbe::seal(aes_key, gcm_key, ctr, tag_iv, aad, in_out)
}
#[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
DynKey::AesHwClMul(c) => seal_strided(c, aad, in_out, ctr, tag_iv),
#[cfg(any(
all(target_arch = "aarch64", target_endian = "little"),
all(target_arch = "arm", target_endian = "little"),
target_arch = "x86_64",
target_arch = "x86"
))]
DynKey::Simd(c) => seal_strided(c, aad, in_out, ctr, tag_iv),
DynKey::Fallback(c) => seal_strided(c, aad, in_out, ctr, tag_iv),
}
}
#[cfg(any(
all(target_arch = "aarch64", target_endian = "little"),
target_arch = "x86_64"
))]
fn seal_whole_partial<A: aes::EncryptBlock, G: gcm::UpdateBlock>(
Combo { aes_key, gcm_key }: &Combo<A, G>,
aad: Aad<&[u8]>,
in_out: &mut [u8],
mut ctr: Counter,
tag_iv: aes::Iv,
seal_whole: impl FnOnce(&A, &mut gcm::Context<G>, &mut Counter, slice::AsChunksMut<u8, BLOCK_LEN>),
) -> Result<Tag, error::Unspecified> {
let mut auth = gcm::Context::new(gcm_key, aad, in_out.len())?;
let (whole, remainder) = slice::as_chunks_mut(in_out);
seal_whole(aes_key, &mut auth, &mut ctr, whole);
let remainder = OverlappingPartialBlock::new(remainder.into())
.unwrap_or_else(|InputTooLongError { .. }| unreachable!());
seal_finish(aes_key, auth, remainder, ctr, tag_iv)
}
#[cfg_attr(
any(
all(target_arch = "aarch64", target_endian = "little"),
all(target_arch = "arm", target_endian = "little"),
target_arch = "x86",
target_arch = "x86_64"
),
inline(never)
)]
#[cfg_attr(
any(
all(target_arch = "aarch64", target_endian = "little"),
target_arch = "x86_64"
),
cold
)]
fn seal_strided<
A: aes::EncryptBlock + aes::EncryptCtr32,
G: gcm::UpdateBlock + gcm::UpdateBlocks,
>(
Combo { aes_key, gcm_key }: &Combo<A, G>,
aad: Aad<&[u8]>,
in_out: &mut [u8],
mut ctr: Counter,
tag_iv: aes::Iv,
) -> Result<Tag, error::Unspecified> {
let mut auth = gcm::Context::new(gcm_key, aad, in_out.len())?;
let (mut whole, remainder) = slice::as_chunks_mut(in_out);
for mut chunk in whole.chunks_mut::<CHUNK_BLOCKS>() {
aes_key.ctr32_encrypt_within(chunk.as_flattened_mut().into(), &mut ctr);
auth.update_blocks(chunk.as_ref());
}
let remainder = OverlappingPartialBlock::new(remainder.into())
.unwrap_or_else(|InputTooLongError { .. }| unreachable!());
seal_finish(aes_key, auth, remainder, ctr, tag_iv)
}
fn seal_finish<A: aes::EncryptBlock, G: gcm::UpdateBlock>(
aes_key: &A,
mut auth: gcm::Context<G>,
remainder: OverlappingPartialBlock<'_>,
ctr: Counter,
tag_iv: aes::Iv,
) -> Result<Tag, error::Unspecified> {
let remainder_len = remainder.len();
if remainder_len > 0 {
let mut input = ZERO_BLOCK;
overwrite_at_start(&mut input, remainder.input());
let mut output = aes_key.encrypt_iv_xor_block(ctr.into(), input);
output[remainder_len..].fill(0);
auth.update_block(output);
remainder.overwrite_at_start(output);
}
Ok(finish(aes_key, auth, tag_iv))
}
#[inline(never)]
pub(super) fn open(
Key(key): &Key,
nonce: Nonce,
aad: Aad<&[u8]>,
in_out_slice: &mut [u8],
src: RangeFrom<usize>,
) -> Result<Tag, error::Unspecified> {
let mut ctr = Counter::one(nonce);
let tag_iv = ctr.increment();
match key {
#[cfg(all(target_arch = "aarch64", target_endian = "little"))]
DynKey::AesHwClMul(c) => {
open_whole_partial(c, aad, in_out_slice, src, ctr, tag_iv, aarch64::open_whole)
}
#[cfg(target_arch = "x86_64")]
DynKey::VAesClMulAvx2(c) => open_whole_partial(
c,
aad,
in_out_slice,
src,
ctr,
tag_iv,
vaesclmulavx2::open_whole_vaes_clmul_avx2,
),
#[cfg(target_arch = "x86_64")]
DynKey::AesHwClMulAvxMovbe(Combo { aes_key, gcm_key }) => {
aeshwclmulmovbe::open(aes_key, gcm_key, ctr, tag_iv, aad, in_out_slice, src)
}
#[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
DynKey::AesHwClMul(c) => open_strided(c, aad, in_out_slice, src, ctr, tag_iv),
#[cfg(any(
all(target_arch = "aarch64", target_endian = "little"),
all(target_arch = "arm", target_endian = "little"),
target_arch = "x86_64",
target_arch = "x86"
))]
DynKey::Simd(c) => open_strided(c, aad, in_out_slice, src, ctr, tag_iv),
DynKey::Fallback(c) => open_strided(c, aad, in_out_slice, src, ctr, tag_iv),
}
}
#[cfg(any(
all(target_arch = "aarch64", target_endian = "little"),
target_arch = "x86_64"
))]
fn open_whole_partial<A: aes::EncryptBlock, G: gcm::UpdateBlock>(
Combo { aes_key, gcm_key }: &Combo<A, G>,
aad: Aad<&[u8]>,
in_out_slice: &mut [u8],
src: RangeFrom<usize>,
mut ctr: Counter,
tag_iv: aes::Iv,
open_whole: impl FnOnce(&A, &mut gcm::Context<G>, Overlapping, &mut Counter),
) -> Result<Tag, error::Unspecified> {
let in_out = Overlapping::new(in_out_slice, src.clone()).map_err(error::erase::<IndexError>)?;
let mut auth = gcm::Context::new(gcm_key, aad, in_out.len())?;
let remainder_len = in_out.len() % BLOCK_LEN;
let in_out_slice_len = in_out_slice.len();
let whole_in_out_slice = &mut in_out_slice[..(in_out_slice_len - remainder_len)];
let whole = Overlapping::new(whole_in_out_slice, src.clone())
.unwrap_or_else(|IndexError { .. }| unreachable!());
let whole_len = whole.len();
open_whole(aes_key, &mut auth, whole, &mut ctr);
let remainder = &mut in_out_slice[whole_len..];
let remainder =
Overlapping::new(remainder, src).unwrap_or_else(|IndexError { .. }| unreachable!());
let remainder = OverlappingPartialBlock::new(remainder)
.unwrap_or_else(|InputTooLongError { .. }| unreachable!());
open_finish(aes_key, auth, remainder, ctr, tag_iv)
}
#[cfg_attr(
any(
all(
any(
all(target_arch = "aarch64", target_endian = "little"),
all(target_arch = "arm", target_endian = "little")
),
target_feature = "neon"
),
all(
any(target_arch = "x86", target_arch = "x86_64"),
target_feature = "sse"
)
),
inline(never)
)]
#[cfg_attr(
any(
all(target_arch = "aarch64", target_endian = "little"),
target_arch = "x86_64"
),
cold
)]
fn open_strided<
A: aes::EncryptBlock + aes::EncryptCtr32,
G: gcm::UpdateBlock + gcm::UpdateBlocks,
>(
Combo { aes_key, gcm_key }: &Combo<A, G>,
aad: Aad<&[u8]>,
in_out_slice: &mut [u8],
src: RangeFrom<usize>,
mut ctr: Counter,
tag_iv: aes::Iv,
) -> Result<Tag, error::Unspecified> {
let in_out = Overlapping::new(in_out_slice, src.clone()).map_err(error::erase::<IndexError>)?;
let input = in_out.input();
let input_len = input.len();
let mut auth = gcm::Context::new(gcm_key, aad, input_len)?;
let remainder_len = input_len % BLOCK_LEN;
let whole_len = input_len - remainder_len;
let in_prefix_len = src.start;
{
let mut chunk_len = CHUNK_BLOCKS * BLOCK_LEN;
let mut output = 0;
let mut input = in_prefix_len;
loop {
if whole_len - output < chunk_len {
chunk_len = whole_len - output;
}
let ciphertext = &in_out_slice[input..][..chunk_len];
let (ciphertext, leftover) = slice::as_chunks(ciphertext);
debug_assert_eq!(leftover.len(), 0);
if ciphertext.is_empty() {
break;
}
auth.update_blocks(ciphertext);
let chunk = Overlapping::new(
&mut in_out_slice[output..][..(chunk_len + in_prefix_len)],
in_prefix_len..,
)
.map_err(error::erase::<IndexError>)?;
aes_key.ctr32_encrypt_within(chunk, &mut ctr);
output += chunk_len;
input += chunk_len;
}
}
let in_out = Overlapping::new(&mut in_out_slice[whole_len..], src)
.unwrap_or_else(|IndexError { .. }| unreachable!());
let in_out = OverlappingPartialBlock::new(in_out)
.unwrap_or_else(|InputTooLongError { .. }| unreachable!());
open_finish(aes_key, auth, in_out, ctr, tag_iv)
}
fn open_finish<A: aes::EncryptBlock, G: gcm::UpdateBlock>(
aes_key: &A,
mut auth: gcm::Context<G>,
remainder: OverlappingPartialBlock<'_>,
ctr: Counter,
tag_iv: aes::Iv,
) -> Result<Tag, error::Unspecified> {
if remainder.len() > 0 {
let mut input = ZERO_BLOCK;
overwrite_at_start(&mut input, remainder.input());
auth.update_block(input);
remainder.overwrite_at_start(aes_key.encrypt_iv_xor_block(ctr.into(), input));
}
Ok(finish(aes_key, auth, tag_iv))
}
fn finish<A: aes::EncryptBlock, G: gcm::UpdateBlock>(
aes_key: &A,
gcm_ctx: gcm::Context<G>,
tag_iv: aes::Iv,
) -> Tag {
// Finalize the tag and return it.
gcm_ctx.pre_finish(|pre_tag| Tag(aes_key.encrypt_iv_xor_block(tag_iv, pre_tag)))
}
pub(super) const MAX_IN_OUT_LEN: usize = super::max_input_len(BLOCK_LEN, 2);
// [NIST SP800-38D] Section 5.2.1.1. Note that [RFC 5116 Section 5.1] and
// [RFC 5116 Section 5.2] have an off-by-one error in `P_MAX`.
//
// [NIST SP800-38D]:
// http://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf
// [RFC 5116 Section 5.1]: https://tools.ietf.org/html/rfc5116#section-5.1
// [RFC 5116 Section 5.2]: https://tools.ietf.org/html/rfc5116#section-5.2
const _MAX_INPUT_LEN_BOUNDED_BY_NIST: () =
assert!(MAX_IN_OUT_LEN == usize_from_u64_saturated(((1u64 << 39) - 256) / 8));
#[derive(Copy, Clone)]
pub(super) struct Combo<Aes, Gcm> {
pub(super) aes_key: Aes,
pub(super) gcm_key: Gcm,
}

95
vendor/ring/src/aead/aes_gcm/aarch64.rs vendored Normal file
View File

@@ -0,0 +1,95 @@
// Copyright 2015-2025 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#![cfg(all(target_arch = "aarch64", target_endian = "little"))]
use super::{aes, gcm, Counter, BLOCK_LEN};
use crate::{aead::aes::Overlapping, bits::BitLength, polyfill::slice::AsChunksMut};
use core::num::NonZeroU64;
pub(super) fn seal_whole(
aes_key: &aes::hw::Key,
auth: &mut gcm::Context<gcm::clmul::Key>,
ctr: &mut Counter,
mut in_out: AsChunksMut<u8, BLOCK_LEN>,
) {
let whole_block_bits = auth.in_out_whole_block_bits();
let whole_block_bits_u64: BitLength<u64> = whole_block_bits.into();
if let Ok(whole_block_bits) = whole_block_bits_u64.try_into() {
let (htable, xi) = auth.inner();
prefixed_extern! {
fn aes_gcm_enc_kernel(
input: *const [u8; BLOCK_LEN],
in_bits: BitLength<NonZeroU64>,
output: *mut [u8; BLOCK_LEN],
Xi: &mut gcm::Xi,
ivec: &mut Counter,
key: &aes::AES_KEY,
Htable: &gcm::HTable);
}
unsafe {
aes_gcm_enc_kernel(
in_out.as_ptr(),
whole_block_bits,
in_out.as_mut_ptr(),
xi,
ctr,
aes_key.inner_less_safe(),
htable,
)
}
}
}
pub(super) fn open_whole(
aes_key: &aes::hw::Key,
auth: &mut gcm::Context<gcm::clmul::Key>,
in_out: Overlapping,
ctr: &mut Counter,
) {
// Precondition. TODO: Create an overlapping::AsChunks for this.
assert_eq!(in_out.len() % BLOCK_LEN, 0);
in_out.with_input_output_len(|input, output, _len| {
let whole_block_bits = auth.in_out_whole_block_bits();
let whole_block_bits_u64: BitLength<u64> = whole_block_bits.into();
if let Ok(whole_block_bits) = whole_block_bits_u64.try_into() {
let (htable, xi) = auth.inner();
prefixed_extern! {
fn aes_gcm_dec_kernel(
input: *const u8,
in_bits: BitLength<NonZeroU64>,
output: *mut u8,
Xi: &mut gcm::Xi,
ivec: &mut Counter,
key: &aes::AES_KEY,
Htable: &gcm::HTable);
}
unsafe {
aes_gcm_dec_kernel(
input,
whole_block_bits,
output,
xi,
ctr,
aes_key.inner_less_safe(),
htable,
)
}
}
})
}

View File

@@ -0,0 +1,154 @@
// Copyright 2015-2025 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#![cfg(target_arch = "x86_64")]
use super::{
super::overlapping::IndexError,
aes::{self, Counter, EncryptCtr32, Overlapping, OverlappingPartialBlock},
gcm, Aad, Tag,
};
use crate::{
c,
error::{self, InputTooLongError},
polyfill::slice,
};
use core::ops::RangeFrom;
#[inline(never)]
pub(super) fn seal(
aes_key: &aes::hw::Key,
gcm_key: &gcm::clmulavxmovbe::Key,
mut ctr: Counter,
tag_iv: aes::Iv,
aad: Aad<&[u8]>,
in_out: &mut [u8],
) -> Result<Tag, error::Unspecified> {
prefixed_extern! {
// `HTable` and `Xi` should be 128-bit aligned. TODO: Can we shrink `HTable`? The
// assembly says it needs just nine values in that array.
fn aesni_gcm_encrypt(
input: *const u8,
output: *mut u8,
len: c::size_t,
key: &aes::AES_KEY,
ivec: &mut Counter,
Htable: &gcm::HTable,
Xi: &mut gcm::Xi) -> c::size_t;
}
let mut auth = gcm::Context::new(gcm_key, aad, in_out.len())?;
let (htable, xi) = auth.inner();
let processed = unsafe {
aesni_gcm_encrypt(
in_out.as_ptr(),
in_out.as_mut_ptr(),
in_out.len(),
aes_key.inner_less_safe(),
&mut ctr,
htable,
xi,
)
};
let ramaining = match in_out.get_mut(processed..) {
Some(remaining) => remaining,
None => {
// This can't happen. If it did, then the assembly already
// caused a buffer overflow.
unreachable!()
}
};
let (mut whole, remainder) = slice::as_chunks_mut(ramaining);
aes_key.ctr32_encrypt_within(whole.as_flattened_mut().into(), &mut ctr);
auth.update_blocks(whole.as_ref());
let remainder = OverlappingPartialBlock::new(remainder.into())
.unwrap_or_else(|InputTooLongError { .. }| unreachable!());
super::seal_finish(aes_key, auth, remainder, ctr, tag_iv)
}
#[inline(never)]
pub(super) fn open(
aes_key: &aes::hw::Key,
gcm_key: &gcm::clmulavxmovbe::Key,
mut ctr: Counter,
tag_iv: aes::Iv,
aad: Aad<&[u8]>,
in_out_slice: &mut [u8],
src: RangeFrom<usize>,
) -> Result<Tag, error::Unspecified> {
prefixed_extern! {
// `HTable` and `Xi` should be 128-bit aligned. TODO: Can we shrink `HTable`? The
// assembly says it needs just nine values in that array.
fn aesni_gcm_decrypt(
input: *const u8,
output: *mut u8,
len: c::size_t,
key: &aes::AES_KEY,
ivec: &mut Counter,
Htable: &gcm::HTable,
Xi: &mut gcm::Xi) -> c::size_t;
}
let in_out = Overlapping::new(in_out_slice, src.clone()).map_err(error::erase::<IndexError>)?;
let mut auth = gcm::Context::new(gcm_key, aad, in_out.len())?;
let processed = in_out.with_input_output_len(|input, output, len| {
let (htable, xi) = auth.inner();
unsafe {
aesni_gcm_decrypt(
input,
output,
len,
aes_key.inner_less_safe(),
&mut ctr,
htable,
xi,
)
}
});
let in_out_slice = in_out_slice.get_mut(processed..).unwrap_or_else(|| {
// This can't happen. If it did, then the assembly already
// caused a buffer overflow.
unreachable!()
});
// Authenticate any remaining whole blocks.
let in_out =
Overlapping::new(in_out_slice, src.clone()).unwrap_or_else(|IndexError { .. }| {
// This can't happen. If it did, then the assembly already
// overwrote part of the remaining input.
unreachable!()
});
let (whole, _) = slice::as_chunks(in_out.input());
auth.update_blocks(whole);
let whole_len = whole.as_flattened().len();
// Decrypt any remaining whole blocks.
let whole = Overlapping::new(&mut in_out_slice[..(src.start + whole_len)], src.clone())
.map_err(error::erase::<IndexError>)?;
aes_key.ctr32_encrypt_within(whole, &mut ctr);
let in_out_slice = match in_out_slice.get_mut(whole_len..) {
Some(partial) => partial,
None => unreachable!(),
};
let in_out =
Overlapping::new(in_out_slice, src).unwrap_or_else(|IndexError { .. }| unreachable!());
let in_out = OverlappingPartialBlock::new(in_out)
.unwrap_or_else(|InputTooLongError { .. }| unreachable!());
super::open_finish(aes_key, auth, in_out, ctr, tag_iv)
}

View File

@@ -0,0 +1,86 @@
// Copyright 2015-2025 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#![cfg(target_arch = "x86_64")]
use super::{aes, gcm, Counter, BLOCK_LEN};
use crate::{aead::aes::Overlapping, c, polyfill::slice::AsChunksMut};
use core::num::NonZeroU32;
pub(super) fn seal_whole_vaes_clmul_avx2(
aes_key: &aes::hw::Key,
auth: &mut gcm::Context<gcm::vclmulavx2::Key>,
ctr: &mut Counter,
mut in_out: AsChunksMut<u8, BLOCK_LEN>,
) {
prefixed_extern! {
fn aes_gcm_enc_update_vaes_avx2(
input: *const u8,
output: *mut u8,
len: c::size_t,
key: &aes::AES_KEY,
ivec: &Counter,
Htable: &gcm::HTable,
Xi: &mut gcm::Xi);
}
let in_out = in_out.as_flattened_mut();
// Precondition: Since we have a `gcm::Context` then the number of blocks
// must fit in `u32`.
let blocks = u32::try_from(in_out.len() / BLOCK_LEN).unwrap();
if let Some(blocks) = NonZeroU32::new(blocks) {
let aes_key = aes_key.inner_less_safe();
let (htable, xi) = auth.inner();
let input = in_out.as_ptr();
let output = in_out.as_mut_ptr();
let len = in_out.len();
unsafe { aes_gcm_enc_update_vaes_avx2(input, output, len, aes_key, ctr, htable, xi) };
ctr.increment_by_less_safe(blocks);
}
}
pub(super) fn open_whole_vaes_clmul_avx2(
aes_key: &aes::hw::Key,
auth: &mut gcm::Context<gcm::vclmulavx2::Key>,
in_out: Overlapping,
ctr: &mut Counter,
) {
prefixed_extern! {
fn aes_gcm_dec_update_vaes_avx2(
input: *const u8,
output: *mut u8,
len: c::size_t,
key: &aes::AES_KEY,
ivec: &mut Counter,
Htable: &gcm::HTable,
Xi: &mut gcm::Xi);
}
// Precondition. TODO: Create an overlapping::AsChunks for this.
assert_eq!(in_out.len() % BLOCK_LEN, 0);
// Precondition: Since we have a `gcm::Context` then the number of blocks
// must fit in `u32`.
let blocks = u32::try_from(in_out.len() / BLOCK_LEN).unwrap();
if let Some(blocks) = NonZeroU32::new(blocks) {
let aes_key = aes_key.inner_less_safe();
let (htable, xi) = auth.inner();
in_out.with_input_output_len(|input, output, len| unsafe {
aes_gcm_dec_update_vaes_avx2(input, output, len, aes_key, ctr, htable, xi)
});
ctr.increment_by_less_safe(blocks);
}
}

269
vendor/ring/src/aead/algorithm.rs vendored Normal file
View File

@@ -0,0 +1,269 @@
// Copyright 2015-2021 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use crate::{
bb, cpu,
error::{self, InputTooLongError},
hkdf,
};
use core::ops::RangeFrom;
use super::{
aes, aes_gcm, chacha20_poly1305,
nonce::{Nonce, NONCE_LEN},
overlapping::{IndexError, Overlapping},
Aad, KeyInner, Tag, TAG_LEN,
};
impl hkdf::KeyType for &'static Algorithm {
#[inline]
fn len(&self) -> usize {
self.key_len()
}
}
/// An AEAD Algorithm.
pub struct Algorithm {
init: fn(key: &[u8], cpu_features: cpu::Features) -> Result<KeyInner, error::Unspecified>,
seal: fn(
key: &KeyInner,
nonce: Nonce,
aad: Aad<&[u8]>,
in_out: &mut [u8],
cpu_features: cpu::Features,
) -> Result<Tag, error::Unspecified>,
open: fn(
key: &KeyInner,
nonce: Nonce,
aad: Aad<&[u8]>,
in_out: &mut [u8],
src: RangeFrom<usize>,
cpu_features: cpu::Features,
) -> Result<Tag, error::Unspecified>,
key_len: usize,
id: AlgorithmID,
}
impl Algorithm {
/// The length of the key.
#[inline(always)]
pub fn key_len(&self) -> usize {
self.key_len
}
/// The length of a tag.
///
/// See also `MAX_TAG_LEN`.
#[inline(always)]
pub fn tag_len(&self) -> usize {
TAG_LEN
}
/// The length of the nonces.
#[inline(always)]
pub fn nonce_len(&self) -> usize {
NONCE_LEN
}
pub(super) fn new_key(
&self,
key_bytes: &[u8],
cpu_features: cpu::Features,
) -> Result<KeyInner, error::Unspecified> {
(self.init)(key_bytes, cpu_features)
}
pub(super) fn open_within<'io>(
&self,
key: &KeyInner,
nonce: Nonce,
aad: Aad<&[u8]>,
received_tag: Tag,
in_out: &'io mut [u8],
src: RangeFrom<usize>,
cpu_features: cpu::Features,
) -> Result<&'io mut [u8], error::Unspecified> {
let ciphertext_len = in_out.get(src.clone()).ok_or(error::Unspecified)?.len();
let Tag(calculated_tag) = (self.open)(key, nonce, aad, in_out, src, cpu_features)?;
if bb::verify_slices_are_equal(calculated_tag.as_ref(), received_tag.as_ref()).is_err() {
// Zero out the plaintext so that it isn't accidentally leaked or used
// after verification fails. It would be safest if we could check the
// tag before decrypting, but some `open` implementations interleave
// authentication with decryption for performance.
for b in &mut in_out[..ciphertext_len] {
*b = 0;
}
return Err(error::Unspecified);
}
// `ciphertext_len` is also the plaintext length.
Ok(&mut in_out[..ciphertext_len])
}
#[inline]
pub(super) fn seal(
&self,
key: &KeyInner,
nonce: Nonce,
aad: Aad<&[u8]>,
in_out: &mut [u8],
cpu_features: cpu::Features,
) -> Result<Tag, error::Unspecified> {
(self.seal)(key, nonce, aad, in_out, cpu_features)
}
}
derive_debug_via_id!(Algorithm);
#[derive(Debug, Eq, PartialEq)]
pub(super) enum AlgorithmID {
AES_128_GCM,
AES_256_GCM,
CHACHA20_POLY1305,
}
impl PartialEq for Algorithm {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
impl Eq for Algorithm {}
/// AES-128 in GCM mode with 128-bit tags and 96 bit nonces.
pub static AES_128_GCM: Algorithm = Algorithm {
key_len: aes::AES_128_KEY_LEN,
init: aes_gcm_init_128,
seal: aes_gcm_seal,
open: aes_gcm_open,
id: AlgorithmID::AES_128_GCM,
};
/// AES-256 in GCM mode with 128-bit tags and 96 bit nonces.
pub static AES_256_GCM: Algorithm = Algorithm {
key_len: aes::AES_256_KEY_LEN,
init: aes_gcm_init_256,
seal: aes_gcm_seal,
open: aes_gcm_open,
id: AlgorithmID::AES_256_GCM,
};
fn aes_gcm_init_128(
key: &[u8],
cpu_features: cpu::Features,
) -> Result<KeyInner, error::Unspecified> {
let key = key.try_into().map_err(|_| error::Unspecified)?;
Ok(KeyInner::AesGcm(aes_gcm::Key::new(
aes::KeyBytes::AES_128(key),
cpu_features,
)?))
}
fn aes_gcm_init_256(
key: &[u8],
cpu_features: cpu::Features,
) -> Result<KeyInner, error::Unspecified> {
let key = key.try_into().map_err(|_| error::Unspecified)?;
Ok(KeyInner::AesGcm(aes_gcm::Key::new(
aes::KeyBytes::AES_256(key),
cpu_features,
)?))
}
fn aes_gcm_seal(
key: &KeyInner,
nonce: Nonce,
aad: Aad<&[u8]>,
in_out: &mut [u8],
_cpu_features: cpu::Features,
) -> Result<Tag, error::Unspecified> {
let key = match key {
KeyInner::AesGcm(key) => key,
_ => unreachable!(),
};
aes_gcm::seal(key, nonce, aad, in_out)
}
pub(super) fn aes_gcm_open(
key: &KeyInner,
nonce: Nonce,
aad: Aad<&[u8]>,
in_out: &mut [u8],
src: RangeFrom<usize>,
_cpu_features: cpu::Features,
) -> Result<Tag, error::Unspecified> {
let key = match key {
KeyInner::AesGcm(key) => key,
_ => unreachable!(),
};
aes_gcm::open(key, nonce, aad, in_out, src)
}
/// ChaCha20-Poly1305 as described in [RFC 8439].
///
/// The keys are 256 bits long and the nonces are 96 bits long.
///
/// [RFC 8439]: https://tools.ietf.org/html/rfc8439
pub static CHACHA20_POLY1305: Algorithm = Algorithm {
key_len: chacha20_poly1305::KEY_LEN,
init: chacha20_poly1305_init,
seal: chacha20_poly1305_seal,
open: chacha20_poly1305_open,
id: AlgorithmID::CHACHA20_POLY1305,
};
/// Copies |key| into |ctx_buf|.
fn chacha20_poly1305_init(
key: &[u8],
_cpu_features: cpu::Features,
) -> Result<KeyInner, error::Unspecified> {
let key: [u8; chacha20_poly1305::KEY_LEN] = key.try_into()?;
Ok(KeyInner::ChaCha20Poly1305(chacha20_poly1305::Key::new(key)))
}
fn chacha20_poly1305_seal(
key: &KeyInner,
nonce: Nonce,
aad: Aad<&[u8]>,
in_out: &mut [u8],
cpu_features: cpu::Features,
) -> Result<Tag, error::Unspecified> {
let key = match key {
KeyInner::ChaCha20Poly1305(key) => key,
_ => unreachable!(),
};
chacha20_poly1305::seal(key, nonce, aad, in_out, cpu_features)
.map_err(error::erase::<InputTooLongError>)
}
fn chacha20_poly1305_open(
key: &KeyInner,
nonce: Nonce,
aad: Aad<&[u8]>,
in_out: &mut [u8],
src: RangeFrom<usize>,
cpu_features: cpu::Features,
) -> Result<Tag, error::Unspecified> {
let key = match key {
KeyInner::ChaCha20Poly1305(key) => key,
_ => unreachable!(),
};
let in_out = Overlapping::new(in_out, src).map_err(error::erase::<IndexError>)?;
chacha20_poly1305::open(key, nonce, aad, in_out, cpu_features)
.map_err(error::erase::<InputTooLongError>)
}

327
vendor/ring/src/aead/chacha.rs vendored Normal file
View File

@@ -0,0 +1,327 @@
// Copyright 2016 Brian Smith.
// Portions Copyright (c) 2016, Google Inc.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use super::{overlapping, quic::Sample, Nonce};
use crate::cpu;
use cfg_if::cfg_if;
cfg_if! {
if #[cfg(any(
all(target_arch = "aarch64", target_endian = "little"),
all(target_arch = "arm", target_endian = "little"),
target_arch = "x86",
target_arch = "x86_64"
))] {
#[macro_use]
mod ffi;
#[cfg(any(target_arch = "x86", test))]
mod fallback;
} else {
mod fallback;
}
}
use crate::polyfill::ArraySplitMap;
pub type Overlapping<'o> = overlapping::Overlapping<'o, u8>;
#[derive(Clone)]
pub struct Key {
words: [u32; KEY_LEN / 4],
}
impl Key {
pub(super) fn new(value: [u8; KEY_LEN]) -> Self {
Self {
words: value.array_split_map(u32::from_le_bytes),
}
}
}
impl Key {
// Encrypts `in_out` with the counter 0 and returns counter 1,
// where the counter is derived from the nonce `nonce`.
#[inline]
pub(super) fn encrypt_single_block_with_ctr_0<const N: usize>(
&self,
nonce: Nonce,
in_out: &mut [u8; N],
cpu: cpu::Features,
) -> Counter {
assert!(N <= BLOCK_LEN);
let (zero, one) = Counter::zero_one_less_safe(nonce);
self.encrypt(zero, in_out.as_mut().into(), cpu);
one
}
#[inline]
pub fn new_mask(&self, sample: Sample) -> [u8; 5] {
let cpu = cpu::features(); // TODO: Remove this.
let (ctr, nonce) = sample.split_at(4);
let ctr = u32::from_le_bytes(ctr.try_into().unwrap());
let nonce = Nonce::assume_unique_for_key(nonce.try_into().unwrap());
let ctr = Counter::from_nonce_and_ctr(nonce, ctr);
let mut out: [u8; 5] = [0; 5];
self.encrypt(ctr, out.as_mut().into(), cpu);
out
}
#[inline(always)]
pub(super) fn encrypt(&self, counter: Counter, in_out: Overlapping<'_>, cpu: cpu::Features) {
cfg_if! {
if #[cfg(all(target_arch = "aarch64", target_endian = "little"))] {
use cpu::{GetFeature as _, arm::Neon};
const NEON_MIN_LEN: usize = 192 + 1;
if in_out.len() >= NEON_MIN_LEN {
if let Some(cpu) = cpu.get_feature() {
return chacha20_ctr32_ffi!(
unsafe { (NEON_MIN_LEN, Neon, Overlapping<'_>) => ChaCha20_ctr32_neon },
self, counter, in_out, cpu);
}
}
if in_out.len() >= 1 {
chacha20_ctr32_ffi!(
unsafe { (1, (), Overlapping<'_>) => ChaCha20_ctr32_nohw },
self, counter, in_out, ())
}
} else if #[cfg(all(target_arch = "arm", target_endian = "little"))] {
use cpu::{GetFeature as _, arm::Neon};
const NEON_MIN_LEN: usize = 192 + 1;
if in_out.len() >= NEON_MIN_LEN {
if let Some(cpu) = cpu.get_feature() {
return chacha20_ctr32_ffi!(
unsafe { (NEON_MIN_LEN, Neon, &mut [u8]) => ChaCha20_ctr32_neon },
self, counter, in_out.copy_within(), cpu);
}
}
if in_out.len() >= 1 {
chacha20_ctr32_ffi!(
unsafe { (1, (), &mut [u8]) => ChaCha20_ctr32_nohw },
self, counter, in_out.copy_within(), ())
}
} else if #[cfg(target_arch = "x86")] {
use cpu::{GetFeature as _, intel::Ssse3};
if in_out.len() >= 1 {
if let Some(cpu) = cpu.get_feature() {
chacha20_ctr32_ffi!(
unsafe { (1, Ssse3, &mut [u8]) => ChaCha20_ctr32_ssse3 },
self, counter, in_out.copy_within(), cpu)
} else {
let _: cpu::Features = cpu;
fallback::ChaCha20_ctr32(self, counter, in_out)
}
}
} else if #[cfg(target_arch = "x86_64")] {
use cpu::{GetFeature, intel::{Avx2, Ssse3}};
const SSE_MIN_LEN: usize = 128 + 1; // Also AVX2, SSSE3_4X, SSSE3
if in_out.len() >= SSE_MIN_LEN {
let values = cpu.values();
if let Some(cpu) = values.get_feature() {
return chacha20_ctr32_ffi!(
unsafe { (SSE_MIN_LEN, Avx2, Overlapping<'_>) => ChaCha20_ctr32_avx2 },
self, counter, in_out, cpu);
}
if let Some(cpu) = values.get_feature() {
return chacha20_ctr32_ffi!(
unsafe { (SSE_MIN_LEN, Ssse3, Overlapping<'_>) =>
ChaCha20_ctr32_ssse3_4x },
self, counter, in_out, cpu);
}
}
if in_out.len() >= 1 {
chacha20_ctr32_ffi!(
unsafe { (1, (), Overlapping<'_>) => ChaCha20_ctr32_nohw },
self, counter, in_out, ())
}
} else {
let _: cpu::Features = cpu;
fallback::ChaCha20_ctr32(self, counter, in_out)
}
}
}
#[inline]
pub(super) fn words_less_safe(&self) -> &[u32; KEY_LEN / 4] {
&self.words
}
}
/// Counter || Nonce, all native endian.
#[repr(transparent)]
pub struct Counter([u32; 4]);
impl Counter {
// Nonce-reuse: the caller must only use the first counter (0) for at most
// a single block.
fn zero_one_less_safe(nonce: Nonce) -> (Self, Self) {
let ctr0 @ Self([_, n0, n1, n2]) = Self::from_nonce_and_ctr(nonce, 0);
let ctr1 = Self([1, n0, n1, n2]);
(ctr0, ctr1)
}
fn from_nonce_and_ctr(nonce: Nonce, ctr: u32) -> Self {
let [n0, n1, n2] = nonce.as_ref().array_split_map(u32::from_le_bytes);
Self([ctr, n0, n1, n2])
}
/// This is "less safe" because it hands off management of the counter to
/// the caller.
#[cfg(any(
test,
not(any(
all(target_arch = "aarch64", target_endian = "little"),
all(target_arch = "arm", target_endian = "little"),
target_arch = "x86_64"
))
))]
fn into_words_less_safe(self) -> [u32; 4] {
self.0
}
}
pub const KEY_LEN: usize = 32;
const BLOCK_LEN: usize = 64;
#[cfg(test)]
mod tests {
extern crate alloc;
use super::{super::overlapping::IndexError, *};
use crate::error;
use crate::testutil as test;
use alloc::vec;
const MAX_ALIGNMENT_AND_OFFSET: (usize, usize) = (15, 259);
const MAX_ALIGNMENT_AND_OFFSET_SUBSET: (usize, usize) =
if cfg!(any(not(debug_assertions), feature = "slow_tests")) {
MAX_ALIGNMENT_AND_OFFSET
} else {
(0, 0)
};
#[test]
fn chacha20_test_default() {
// Always use `MAX_OFFSET` if we hav assembly code.
let max_offset = if cfg!(any(
all(target_arch = "aarch64", target_endian = "little"),
all(target_arch = "arm", target_endian = "little"),
target_arch = "x86",
target_arch = "x86_64"
)) {
MAX_ALIGNMENT_AND_OFFSET
} else {
MAX_ALIGNMENT_AND_OFFSET_SUBSET
};
chacha20_test(max_offset, Key::encrypt);
}
// Smoketest the fallback implementation.
#[test]
fn chacha20_test_fallback() {
chacha20_test(MAX_ALIGNMENT_AND_OFFSET_SUBSET, |key, ctr, in_out, _cpu| {
fallback::ChaCha20_ctr32(key, ctr, in_out)
});
}
// Verifies the encryption is successful when done on overlapping buffers.
//
// On some branches of the 32-bit x86 and ARM assembly code the in-place
// operation fails in some situations where the input/output buffers are
// not exactly overlapping. Such failures are dependent not only on the
// degree of overlapping but also the length of the data. `encrypt_within`
// works around that.
fn chacha20_test(
max_alignment_and_offset: (usize, usize),
f: impl for<'k, 'o> Fn(&'k Key, Counter, Overlapping<'o>, cpu::Features),
) {
let cpu = cpu::features();
// Reuse a buffer to avoid slowing down the tests with allocations.
let mut buf = vec![0u8; 1300];
test::run(
test_vector_file!("chacha_tests.txt"),
move |section, test_case| {
assert_eq!(section, "");
let key = test_case.consume_bytes("Key");
let key: &[u8; KEY_LEN] = key.as_slice().try_into()?;
let key = Key::new(*key);
let ctr = test_case.consume_usize("Ctr");
let nonce = test_case.consume_bytes("Nonce");
let input = test_case.consume_bytes("Input");
let output = test_case.consume_bytes("Output");
// Run the test case over all prefixes of the input because the
// behavior of ChaCha20 implementation changes dependent on the
// length of the input.
for len in 0..=input.len() {
#[allow(clippy::cast_possible_truncation)]
chacha20_test_case_inner(
&key,
&nonce,
ctr as u32,
&input[..len],
&output[..len],
&mut buf,
max_alignment_and_offset,
cpu,
&f,
);
}
Ok(())
},
);
}
fn chacha20_test_case_inner(
key: &Key,
nonce: &[u8],
ctr: u32,
input: &[u8],
expected: &[u8],
buf: &mut [u8],
(max_alignment, max_offset): (usize, usize),
cpu: cpu::Features,
f: &impl for<'k, 'o> Fn(&'k Key, Counter, Overlapping<'o>, cpu::Features),
) {
const ARBITRARY: u8 = 123;
for alignment in 0..=max_alignment {
buf[..alignment].fill(ARBITRARY);
let buf = &mut buf[alignment..];
for offset in 0..=max_offset {
let buf = &mut buf[..(offset + input.len())];
buf[..offset].fill(ARBITRARY);
let src = offset..;
buf[src.clone()].copy_from_slice(input);
let ctr = Counter::from_nonce_and_ctr(
Nonce::try_assume_unique_for_key(nonce).unwrap(),
ctr,
);
let in_out = Overlapping::new(buf, src)
.map_err(error::erase::<IndexError>)
.unwrap();
f(key, ctr, in_out, cpu);
assert_eq!(&buf[..input.len()], expected)
}
}
}
}

108
vendor/ring/src/aead/chacha/fallback.rs vendored Normal file
View File

@@ -0,0 +1,108 @@
// Copyright 2021 Brian Smith.
// Portions Copyright (c) 2014, Google Inc.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
// Adapted from the public domain, estream code by D. Bernstein.
// Adapted from the BoringSSL crypto/chacha/chacha.c.
use super::{super::overlapping::IndexError, Counter, Key, Overlapping, BLOCK_LEN};
use crate::{bb, polyfill::sliceutil};
use core::mem::size_of;
pub(super) fn ChaCha20_ctr32(key: &Key, counter: Counter, mut in_out: Overlapping<'_>) {
const SIGMA: [u32; 4] = [
u32::from_le_bytes(*b"expa"),
u32::from_le_bytes(*b"nd 3"),
u32::from_le_bytes(*b"2-by"),
u32::from_le_bytes(*b"te k"),
];
let key = key.words_less_safe();
let counter = counter.into_words_less_safe();
let mut state = [
SIGMA[0], SIGMA[1], SIGMA[2], SIGMA[3], key[0], key[1], key[2], key[3], key[4], key[5],
key[6], key[7], counter[0], counter[1], counter[2], counter[3],
];
let mut in_out_len = in_out.len();
let mut buf = [0u8; BLOCK_LEN];
while in_out_len > 0 {
chacha_core(&mut buf, &state);
state[12] += 1;
debug_assert_eq!(in_out_len, in_out.len());
// Both branches do the same thing, but the duplication helps the
// compiler optimize (vectorize) the `BLOCK_LEN` case.
if in_out_len >= BLOCK_LEN {
in_out = in_out
.split_first_chunk::<BLOCK_LEN>(|in_out| {
bb::xor_assign_at_start(&mut buf, in_out.input());
sliceutil::overwrite_at_start(in_out.into_unwritten_output(), &buf);
})
.unwrap_or_else(|IndexError { .. }| {
// Since `in_out_len == in_out.len() && in_out_len >= BLOCK_LEN`.
unreachable!()
});
} else {
bb::xor_assign_at_start(&mut buf, in_out.input());
sliceutil::overwrite_at_start(in_out.into_unwritten_output(), &buf);
break;
}
in_out_len -= BLOCK_LEN;
}
}
// Performs 20 rounds of ChaCha on `input`, storing the result in `output`.
#[inline(always)]
fn chacha_core(output: &mut [u8; BLOCK_LEN], input: &State) {
let mut x = *input;
for _ in (0..20).step_by(2) {
quarterround(&mut x, 0, 4, 8, 12);
quarterround(&mut x, 1, 5, 9, 13);
quarterround(&mut x, 2, 6, 10, 14);
quarterround(&mut x, 3, 7, 11, 15);
quarterround(&mut x, 0, 5, 10, 15);
quarterround(&mut x, 1, 6, 11, 12);
quarterround(&mut x, 2, 7, 8, 13);
quarterround(&mut x, 3, 4, 9, 14);
}
for (x, input) in x.iter_mut().zip(input.iter()) {
*x = x.wrapping_add(*input);
}
output
.chunks_exact_mut(size_of::<u32>())
.zip(x.iter())
.for_each(|(output, &x)| output.copy_from_slice(&x.to_le_bytes()));
}
#[inline(always)]
fn quarterround(x: &mut State, a: usize, b: usize, c: usize, d: usize) {
#[inline(always)]
fn step(x: &mut State, a: usize, b: usize, c: usize, rotation: u32) {
x[a] = x[a].wrapping_add(x[b]);
x[c] = (x[c] ^ x[a]).rotate_left(rotation);
}
step(x, a, b, d, 16);
step(x, c, d, b, 12);
step(x, a, b, d, 8);
step(x, c, d, b, 7);
}
type State = [u32; BLOCK_LEN / 4];

66
vendor/ring/src/aead/chacha/ffi.rs vendored Normal file
View File

@@ -0,0 +1,66 @@
// Copyright 2016-2025 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use super::{super::overlapping::Overlapping, Counter, Key};
// `unsafe { (N, C, InOut) => f }` means that the function `f` is safe to call
// iff the in/out length is at least `N`, the CPU features `C` are available,
// and the input type is `InOut`. If `f` supports overlapping input/output then
// `InOut` should be `Overlapping<'_, u8>`; otherwise it should be `&mut [u8]`.
macro_rules! chacha20_ctr32_ffi {
( unsafe { ($MIN_LEN:expr, $Cpu:ty, $InOut:ty) => $f:ident },
$key:expr, $counter:expr, $in_out:expr, $cpu:expr ) => {{
prefixed_extern! {
fn $f(
out: *mut u8,
in_: *const u8,
in_len: crate::c::size_t,
key: &[u32; 8],
counter: &crate::aead::chacha::Counter,
);
}
// SAFETY: The user asserts that $f has the signature above and is safe
// to call if additionally we have a value of type `$Cpu` and an in/out
// value of the indicated type, which we do.
unsafe {
crate::aead::chacha::ffi::chacha20_ctr32_ffi::<$InOut, $Cpu, $MIN_LEN>(
$key, $counter, $in_out, $cpu, $f,
)
}
}};
}
// Panics if `in_out.len() < MIN_LEN`. The caller should have guarded against
// that so that the assertion gets optimized away.
pub(super) unsafe fn chacha20_ctr32_ffi<
'o,
InOut: 'o + Into<Overlapping<'o, u8>>,
Cpu,
const MIN_LEN: usize,
>(
key: &Key,
counter: Counter,
in_out: InOut,
cpu: Cpu,
f: unsafe extern "C" fn(*mut u8, *const u8, crate::c::size_t, &[u32; 8], &Counter),
) {
assert!(MIN_LEN > 0);
let in_out: Overlapping<'_, u8> = in_out.into();
in_out.with_input_output_len(|input, output, len| {
assert!(len >= MIN_LEN);
let key = key.words_less_safe();
let _: Cpu = cpu;
unsafe { f(output, input, len, key, &counter) }
});
}

View File

@@ -0,0 +1,230 @@
// Copyright 2015-2025 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use super::{
super::{NONCE_LEN, TAG_LEN},
chacha::Overlapping,
check_input_lengths, Aad, InputTooLongError, Key, Nonce, Tag, KEY_LEN,
};
use cfg_if::cfg_if;
macro_rules! declare_open {
( $name:ident ) => {
prefixed_extern! {
fn $name(
out_plaintext: *mut u8,
ciphertext: *const u8,
plaintext_len: usize,
ad: *const u8,
ad_len: usize,
data: &mut InOut<open_data_in>,
);
}
};
}
macro_rules! declare_seal {
( $name:ident ) => {
prefixed_extern! {
fn $name(
out_ciphertext: *mut u8,
plaintext: *const u8,
plaintext_len: usize,
ad: *const u8,
ad_len: usize,
data: &mut InOut<seal_data_in>,
);
}
};
}
cfg_if! {
if #[cfg(all(target_arch = "aarch64", target_endian = "little"))] {
use crate::cpu::arm::Neon;
type RequiredCpuFeatures = Neon;
type OptionalCpuFeatures = ();
} else {
use crate::cpu::intel::{Avx2, Bmi2, Sse41};
type RequiredCpuFeatures = Sse41;
type OptionalCpuFeatures = (Avx2, Bmi2);
}
}
pub(super) fn seal(
Key(key): &Key,
nonce: Nonce,
aad: Aad<&[u8]>,
in_out: &mut [u8],
required_cpu_features: RequiredCpuFeatures,
optional_cpu_features: Option<OptionalCpuFeatures>,
) -> Result<Tag, InputTooLongError> {
check_input_lengths(aad, in_out)?;
// XXX: BoringSSL uses `alignas(16)` on `key` instead of on the
// structure, but Rust can't do that yet; see
// https://github.com/rust-lang/rust/issues/73557.
//
// Keep in sync with the anonymous struct of BoringSSL's
// `chacha20_poly1305_seal_data`.
#[repr(align(16), C)]
#[derive(Clone, Copy)]
struct seal_data_in {
key: [u32; KEY_LEN / 4],
counter: u32,
nonce: [u8; NONCE_LEN],
extra_ciphertext: *const u8,
extra_ciphertext_len: usize,
}
let mut data = InOut {
input: seal_data_in {
key: *key.words_less_safe(),
counter: 0,
nonce: *nonce.as_ref(),
extra_ciphertext: core::ptr::null(),
extra_ciphertext_len: 0,
},
};
// Encrypts `plaintext_len` bytes from `plaintext` and writes them to `out_ciphertext`.
let output = in_out.as_mut_ptr();
let input = in_out.as_ptr();
let len = in_out.len();
let ad = aad.as_ref().as_ptr();
let ad_len = aad.as_ref().len();
#[allow(clippy::needless_late_init)]
let tag;
cfg_if! {
if #[cfg(all(target_arch = "aarch64", target_endian = "little"))] {
declare_seal! { chacha20_poly1305_seal }
let _: Neon = required_cpu_features;
let _: Option<()> = optional_cpu_features;
tag = unsafe {
chacha20_poly1305_seal(output, input, len, ad, ad_len, &mut data);
&data.out.tag
};
} else {
let _: Sse41 = required_cpu_features;
if matches!(optional_cpu_features, Some((Avx2 { .. }, Bmi2 { .. }))) {
declare_seal! { chacha20_poly1305_seal_avx2 }
tag = unsafe {
chacha20_poly1305_seal_avx2(output, input, len, ad, ad_len, &mut data);
&data.out.tag
};
} else {
declare_seal! { chacha20_poly1305_seal_sse41 }
tag = unsafe {
chacha20_poly1305_seal_sse41(output, input, len, ad, ad_len, &mut data);
&data.out.tag
};
}
}
}
Ok(Tag(*tag))
}
pub(super) fn open(
Key(key): &Key,
nonce: Nonce,
aad: Aad<&[u8]>,
in_out: Overlapping<'_>,
required_cpu_features: RequiredCpuFeatures,
optional_cpu_features: Option<OptionalCpuFeatures>,
) -> Result<Tag, InputTooLongError> {
check_input_lengths(aad, in_out.input())?;
// XXX: BoringSSL uses `alignas(16)` on `key` instead of on the
// structure, but Rust can't do that yet; see
// https://github.com/rust-lang/rust/issues/73557.
//
// Keep in sync with the anonymous struct of BoringSSL's
// `chacha20_poly1305_open_data`.
#[derive(Copy, Clone)]
#[repr(align(16), C)]
struct open_data_in {
key: [u32; KEY_LEN / 4],
counter: u32,
nonce: [u8; NONCE_LEN],
}
let mut data = InOut {
input: open_data_in {
key: *key.words_less_safe(),
counter: 0,
nonce: *nonce.as_ref(),
},
};
in_out.with_input_output_len(|input, output, len| {
let ad = aad.as_ref().as_ptr();
let ad_len = aad.as_ref().len();
#[allow(clippy::needless_late_init)]
let tag;
cfg_if! {
if #[cfg(all(target_arch = "aarch64", target_endian = "little"))] {
declare_open! { chacha20_poly1305_open }
let _: Neon = required_cpu_features;
let _: Option<()> = optional_cpu_features;
tag = unsafe {
chacha20_poly1305_open(output, input, len, ad, ad_len, &mut data);
&data.out.tag
};
} else {
let _: Sse41 = required_cpu_features;
if matches!(optional_cpu_features, Some((Avx2 { .. }, Bmi2 { .. }))) {
declare_open! { chacha20_poly1305_open_avx2 }
tag = unsafe {
chacha20_poly1305_open_avx2(output, input, len, ad, ad_len, &mut data);
&data.out.tag
};
} else {
declare_open! { chacha20_poly1305_open_sse41 }
tag = unsafe {
chacha20_poly1305_open_sse41(output, input, len, ad, ad_len, &mut data);
&data.out.tag
};
}
}
}
Ok(Tag(*tag))
})
}
// Keep in sync with BoringSSL's `chacha20_poly1305_open_data` and
// `chacha20_poly1305_seal_data`.
#[repr(C)]
pub(super) union InOut<T>
where
T: Copy,
{
pub(super) input: T,
pub(super) out: Out,
}
// It isn't obvious whether the assembly code works for tags that aren't
// 16-byte aligned. In practice it will always be 16-byte aligned because it
// is embedded in a union where the other member of the union is 16-byte
// aligned.
#[derive(Clone, Copy)]
#[repr(align(16), C)]
pub(super) struct Out {
pub(super) tag: [u8; TAG_LEN],
}

View File

@@ -0,0 +1,167 @@
// Copyright 2015-2025 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use super::{
chacha::{self, Counter, Overlapping},
poly1305, Aad, Nonce, Tag,
};
use crate::{
cpu,
error::InputTooLongError,
polyfill::{slice, sliceutil, u64_from_usize, usize_from_u64_saturated},
};
use cfg_if::cfg_if;
cfg_if! {
if #[cfg(any(
all(target_arch = "aarch64", target_endian = "little"),
target_arch = "x86_64"))] {
use cpu::GetFeature as _;
mod integrated;
}
}
pub(super) const KEY_LEN: usize = chacha::KEY_LEN;
const MAX_IN_OUT_LEN: usize = super::max_input_len(64, 1);
// https://tools.ietf.org/html/rfc8439#section-2.8
const _MAX_IN_OUT_LEN_BOUNDED_BY_RFC: () =
assert!(MAX_IN_OUT_LEN == usize_from_u64_saturated(274_877_906_880u64));
#[derive(Clone)]
pub(super) struct Key(chacha::Key);
impl Key {
pub(super) fn new(value: [u8; KEY_LEN]) -> Self {
Self(chacha::Key::new(value))
}
}
pub(super) fn seal(
key: &Key,
nonce: Nonce,
aad: Aad<&[u8]>,
in_out: &mut [u8],
cpu: cpu::Features,
) -> Result<Tag, InputTooLongError> {
#[cfg(any(
all(target_arch = "aarch64", target_endian = "little"),
target_arch = "x86_64"
))]
if let Some(required) = cpu.get_feature() {
return integrated::seal(key, nonce, aad, in_out, required, cpu.get_feature());
}
seal_fallback(key, nonce, aad, in_out, cpu)
}
pub(super) fn seal_fallback(
Key(chacha20_key): &Key,
nonce: Nonce,
aad: Aad<&[u8]>,
in_out: &mut [u8],
cpu: cpu::Features,
) -> Result<Tag, InputTooLongError> {
let (counter, poly1305_key) = begin(chacha20_key, nonce, aad, in_out, cpu)?;
let mut auth = poly1305::Context::from_key(poly1305_key, cpu);
poly1305_update_padded_16(&mut auth, aad.as_ref());
chacha20_key.encrypt(counter, in_out.into(), cpu);
poly1305_update_padded_16(&mut auth, in_out);
Ok(finish(auth, aad.as_ref().len(), in_out.len()))
}
pub(super) fn open(
key: &Key,
nonce: Nonce,
aad: Aad<&[u8]>,
in_out: Overlapping<'_>,
cpu: cpu::Features,
) -> Result<Tag, InputTooLongError> {
#[cfg(any(
all(target_arch = "aarch64", target_endian = "little"),
target_arch = "x86_64"
))]
if let Some(required) = cpu.get_feature() {
return integrated::open(key, nonce, aad, in_out, required, cpu.get_feature());
}
open_fallback(key, nonce, aad, in_out, cpu)
}
pub(super) fn open_fallback(
Key(chacha20_key): &Key,
nonce: Nonce,
aad: Aad<&[u8]>,
in_out: Overlapping<'_>,
cpu: cpu::Features,
) -> Result<Tag, InputTooLongError> {
let (counter, poly1305_key) = begin(chacha20_key, nonce, aad, in_out.input(), cpu)?;
let mut auth = poly1305::Context::from_key(poly1305_key, cpu);
poly1305_update_padded_16(&mut auth, aad.as_ref());
poly1305_update_padded_16(&mut auth, in_out.input());
let in_out_len = in_out.len();
chacha20_key.encrypt(counter, in_out, cpu);
Ok(finish(auth, aad.as_ref().len(), in_out_len))
}
fn check_input_lengths(aad: Aad<&[u8]>, input: &[u8]) -> Result<(), InputTooLongError> {
if input.len() > MAX_IN_OUT_LEN {
return Err(InputTooLongError::new(input.len()));
}
// RFC 8439 Section 2.8 says the maximum AAD length is 2**64 - 1, which is
// never larger than usize::MAX, so we don't need an explicit length
// check.
const _USIZE_BOUNDED_BY_U64: u64 = u64_from_usize(usize::MAX);
let _ = aad;
Ok(())
}
// Also used by chacha20_poly1305_openssh.
pub(super) fn begin(
key: &chacha::Key,
nonce: Nonce,
aad: Aad<&[u8]>,
input: &[u8],
cpu: cpu::Features,
) -> Result<(Counter, poly1305::Key), InputTooLongError> {
check_input_lengths(aad, input)?;
let mut key_bytes = [0u8; poly1305::KEY_LEN];
let counter = key.encrypt_single_block_with_ctr_0(nonce, &mut key_bytes, cpu);
let poly1305_key = poly1305::Key::new(key_bytes);
Ok((counter, poly1305_key))
}
fn finish(auth: poly1305::Context, aad_len: usize, in_out_len: usize) -> Tag {
let mut block = [0u8; poly1305::BLOCK_LEN];
let (alen, clen) = block.split_at_mut(poly1305::BLOCK_LEN / 2);
alen.copy_from_slice(&u64::to_le_bytes(u64_from_usize(aad_len)));
clen.copy_from_slice(&u64::to_le_bytes(u64_from_usize(in_out_len)));
auth.finish(&block)
}
#[inline]
fn poly1305_update_padded_16(ctx: &mut poly1305::Context, input: &[u8]) {
let (whole, remainder) = slice::as_chunks(input);
ctx.update(whole);
if !remainder.is_empty() {
let mut block = [0u8; poly1305::BLOCK_LEN];
sliceutil::overwrite_at_start(&mut block, remainder);
ctx.update_block(block);
}
}

View File

@@ -0,0 +1,212 @@
// Copyright 2016 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//! The [chacha20-poly1305@openssh.com] AEAD-ish construct.
//!
//! This should only be used by SSH implementations. It has a similar, but
//! different API from `ring::aead` because the construct cannot use the same
//! API as `ring::aead` due to the way the construct handles the encrypted
//! packet length.
//!
//! The concatenation of a and b is denoted `a||b`. `K_1` and `K_2` are defined
//! in the [chacha20-poly1305@openssh.com] specification. `packet_length`,
//! `padding_length`, `payload`, and `random padding` are defined in
//! [RFC 4253]. The term `plaintext` is used as a shorthand for
//! `padding_length||payload||random padding`.
//!
//! [chacha20-poly1305@openssh.com]:
//! http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.chacha20poly1305?annotate=HEAD
//! [RFC 4253]: https://tools.ietf.org/html/rfc4253
use super::{
chacha::{self, *},
chacha20_poly1305, cpu, poly1305, Aad, Nonce, Tag,
};
use crate::{
bb,
error::{self, InputTooLongError},
polyfill::slice,
};
/// A key for sealing packets.
pub struct SealingKey {
key: Key,
}
impl SealingKey {
/// Constructs a new `SealingKey`.
pub fn new(key_material: &[u8; KEY_LEN]) -> Self {
Self {
key: Key::new(key_material),
}
}
/// Seals (encrypts and signs) a packet.
///
/// On input, `plaintext_in_ciphertext_out` must contain the unencrypted
/// `packet_length||plaintext` where `plaintext` is the
/// `padding_length||payload||random padding`. It will be overwritten by
/// `encrypted_packet_length||ciphertext`, where `encrypted_packet_length`
/// is encrypted with `K_1` and `ciphertext` is encrypted by `K_2`.
///
/// # Panics
///
/// Panics if `plaintext_in_ciphertext_out.len() < PACKET_LENGTH_LEN`.
///
/// Panics if `plaintext_in_ciphertext_out` is longer than the maximum
/// input size for ChaCha20-Poly1305. Note that this limit is much,
/// much larger than SSH's 256KB maximum record size.
pub fn seal_in_place(
&self,
sequence_number: u32,
plaintext_in_ciphertext_out: &mut [u8],
tag_out: &mut [u8; TAG_LEN],
) {
// XXX/TODO(SemVer): Refactor API to return an error.
let (len_in_out, data_and_padding_in_out): (&mut [u8; PACKET_LENGTH_LEN], _) =
slice::split_first_chunk_mut(plaintext_in_ciphertext_out).unwrap();
let cpu = cpu::features();
// XXX/TODO(SemVer): Refactor API to return an error.
let (counter, poly_key) = chacha20_poly1305::begin(
&self.key.k_2,
make_nonce(sequence_number),
Aad::from(len_in_out),
data_and_padding_in_out,
cpu,
)
.map_err(error::erase::<InputTooLongError>)
.unwrap();
let _: Counter = self.key.k_1.encrypt_single_block_with_ctr_0(
make_nonce(sequence_number),
len_in_out,
cpu,
);
self.key
.k_2
.encrypt(counter, data_and_padding_in_out.into(), cpu);
let Tag(tag) = poly1305::sign(poly_key, plaintext_in_ciphertext_out, cpu);
*tag_out = tag;
}
}
/// A key for opening packets.
pub struct OpeningKey {
key: Key,
}
impl OpeningKey {
/// Constructs a new `OpeningKey`.
pub fn new(key_material: &[u8; KEY_LEN]) -> Self {
Self {
key: Key::new(key_material),
}
}
/// Returns the decrypted, but unauthenticated, packet length.
///
/// Importantly, the result won't be authenticated until `open_in_place` is
/// called.
pub fn decrypt_packet_length(
&self,
sequence_number: u32,
encrypted_packet_length: [u8; PACKET_LENGTH_LEN],
) -> [u8; PACKET_LENGTH_LEN] {
let cpu = cpu::features();
let mut packet_length = encrypted_packet_length;
let _: Counter = self.key.k_1.encrypt_single_block_with_ctr_0(
make_nonce(sequence_number),
&mut packet_length,
cpu,
);
packet_length
}
/// Opens (authenticates and decrypts) a packet.
///
/// `ciphertext_in_plaintext_out` must be of the form
/// `encrypted_packet_length||ciphertext` where `ciphertext` is the
/// encrypted `plaintext`. When the function succeeds the ciphertext is
/// replaced by the plaintext and the result is `Ok(plaintext)`, where
/// `plaintext` is `&ciphertext_in_plaintext_out[PACKET_LENGTH_LEN..]`;
/// otherwise the contents of `ciphertext_in_plaintext_out` are unspecified
/// and must not be used.
pub fn open_in_place<'a>(
&self,
sequence_number: u32,
ciphertext_in_plaintext_out: &'a mut [u8],
tag: &[u8; TAG_LEN],
) -> Result<&'a [u8], error::Unspecified> {
let (packet_length, after_packet_length): (&mut [u8; PACKET_LENGTH_LEN], _) =
slice::split_first_chunk_mut(ciphertext_in_plaintext_out).ok_or(error::Unspecified)?;
let cpu = cpu::features();
let (counter, poly_key) = chacha20_poly1305::begin(
&self.key.k_2,
make_nonce(sequence_number),
Aad::from(packet_length),
after_packet_length,
cpu,
)
.map_err(error::erase::<InputTooLongError>)?;
// We must verify the tag before decrypting so that
// `ciphertext_in_plaintext_out` is unmodified if verification fails.
// This is beyond what we guarantee.
let calculated_tag = poly1305::sign(poly_key, ciphertext_in_plaintext_out, cpu);
bb::verify_slices_are_equal(calculated_tag.as_ref(), tag)?;
// Won't panic because the length was checked above.
let after_packet_length = &mut ciphertext_in_plaintext_out[PACKET_LENGTH_LEN..];
self.key
.k_2
.encrypt(counter, after_packet_length.into(), cpu);
Ok(after_packet_length)
}
}
struct Key {
k_1: chacha::Key,
k_2: chacha::Key,
}
impl Key {
fn new(key_material: &[u8; KEY_LEN]) -> Self {
// The first half becomes K_2 and the second half becomes K_1.
let (k_2, k_1) = key_material.split_at(chacha::KEY_LEN);
Self {
k_1: chacha::Key::new(k_1.try_into().unwrap()),
k_2: chacha::Key::new(k_2.try_into().unwrap()),
}
}
}
fn make_nonce(sequence_number: u32) -> Nonce {
let [s0, s1, s2, s3] = sequence_number.to_be_bytes();
let nonce = [0, 0, 0, 0, 0, 0, 0, 0, s0, s1, s2, s3];
Nonce::assume_unique_for_key(nonce)
}
/// The length of key.
pub const KEY_LEN: usize = chacha::KEY_LEN * 2;
/// The length in bytes of the `packet_length` field in a SSH packet.
pub const PACKET_LENGTH_LEN: usize = 4; // 32 bits
/// The length in bytes of an authentication tag.
pub const TAG_LEN: usize = super::TAG_LEN;

163
vendor/ring/src/aead/gcm.rs vendored Normal file
View File

@@ -0,0 +1,163 @@
// Copyright 2018-2024 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use self::ffi::{Block, BLOCK_LEN, ZERO_BLOCK};
use super::{aes_gcm, Aad};
use crate::{
bits::{BitLength, FromByteLen as _},
error::{self, InputTooLongError},
polyfill::{slice::AsChunks, sliceutil::overwrite_at_start, NotSend},
};
use cfg_if::cfg_if;
pub(super) use ffi::KeyValue;
cfg_if! {
if #[cfg(any(all(target_arch = "aarch64", target_endian = "little"), target_arch = "x86_64"))] {
pub(super) use self::ffi::{HTable, Xi};
} else {
use self::ffi::{HTable, Xi};
}
}
#[macro_use]
mod ffi;
pub(super) mod clmul;
pub(super) mod clmulavxmovbe;
pub(super) mod fallback;
pub(super) mod neon;
pub(super) mod vclmulavx2;
pub(super) struct Context<'key, K> {
Xi: Xi,
key: &'key K,
aad_len: BitLength<u64>,
in_out_len: BitLength<u64>,
_not_send: NotSend,
}
impl<'key, K: UpdateBlock> Context<'key, K> {
#[inline(always)]
pub(crate) fn new(
key: &'key K,
aad: Aad<&[u8]>,
in_out_len: usize,
) -> Result<Self, error::Unspecified> {
if in_out_len > aes_gcm::MAX_IN_OUT_LEN {
return Err(error::Unspecified);
}
let in_out_len =
BitLength::from_byte_len(in_out_len).map_err(error::erase::<InputTooLongError>)?;
let aad_len = BitLength::from_byte_len(aad.as_ref().len())
.map_err(error::erase::<InputTooLongError>)?;
// NIST SP800-38D Section 5.2.1.1 says that the maximum AAD length is
// 2**64 - 1 bits, i.e. BitLength<u64>::MAX, so we don't need to do an
// explicit check here.
let mut ctx = Self {
Xi: Xi(ZERO_BLOCK),
key,
aad_len,
in_out_len,
_not_send: NotSend::VALUE,
};
for ad in aad.0.chunks(BLOCK_LEN) {
let mut block = ZERO_BLOCK;
overwrite_at_start(&mut block, ad);
ctx.update_block(block);
}
Ok(ctx)
}
}
#[cfg(all(
target_arch = "aarch64",
target_endian = "little",
target_pointer_width = "64"
))]
impl<K> Context<'_, K> {
pub(super) fn in_out_whole_block_bits(&self) -> BitLength<usize> {
use crate::polyfill::usize_from_u64;
const WHOLE_BLOCK_BITS_MASK: usize = !0b111_1111;
#[allow(clippy::assertions_on_constants)]
const _WHOLE_BLOCK_BITS_MASK_CORRECT: () =
assert!(WHOLE_BLOCK_BITS_MASK == !((BLOCK_LEN * 8) - 1));
BitLength::from_bits(usize_from_u64(self.in_out_len.as_bits()) & WHOLE_BLOCK_BITS_MASK)
}
}
#[cfg(all(target_arch = "aarch64", target_endian = "little"))]
/// Access to `inner` for the integrated AES-GCM implementations only.
impl Context<'_, clmul::Key> {
#[inline]
pub(super) fn inner(&mut self) -> (&HTable, &mut Xi) {
(&self.key.inner(), &mut self.Xi)
}
}
#[cfg(target_arch = "x86_64")]
impl Context<'_, clmulavxmovbe::Key> {
/// Access to `inner` for the integrated AES-GCM implementations only.
#[inline]
pub(super) fn inner(&mut self) -> (&HTable, &mut Xi) {
(self.key.inner(), &mut self.Xi)
}
}
#[cfg(target_arch = "x86_64")]
impl Context<'_, vclmulavx2::Key> {
/// Access to `inner` for the integrated AES-GCM implementations only.
#[inline]
pub(super) fn inner(&mut self) -> (&HTable, &mut Xi) {
(self.key.inner(), &mut self.Xi)
}
}
impl<K: UpdateBlocks> Context<'_, K> {
#[inline(always)]
pub fn update_blocks(&mut self, input: AsChunks<u8, BLOCK_LEN>) {
self.key.update_blocks(&mut self.Xi, input);
}
}
impl<K: UpdateBlock> Context<'_, K> {
pub fn update_block(&mut self, a: Block) {
self.key.update_block(&mut self.Xi, a);
}
#[inline(always)]
pub(super) fn pre_finish<F>(mut self, f: F) -> super::Tag
where
F: FnOnce(Block) -> super::Tag,
{
let mut block = [0u8; BLOCK_LEN];
let (alen, clen) = block.split_at_mut(BLOCK_LEN / 2);
alen.copy_from_slice(&BitLength::<u64>::to_be_bytes(self.aad_len));
clen.copy_from_slice(&BitLength::<u64>::to_be_bytes(self.in_out_len));
self.update_block(block);
f(self.Xi.0)
}
}
pub(super) trait UpdateBlock {
fn update_block(&self, xi: &mut Xi, a: Block);
}
pub(super) trait UpdateBlocks {
fn update_blocks(&self, xi: &mut Xi, input: AsChunks<u8, BLOCK_LEN>);
}

73
vendor/ring/src/aead/gcm/clmul.rs vendored Normal file
View File

@@ -0,0 +1,73 @@
// Copyright 2018-2024 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#![cfg(any(
all(target_arch = "aarch64", target_endian = "little"),
target_arch = "x86",
target_arch = "x86_64"
))]
use super::{ffi::KeyValue, HTable, UpdateBlock, Xi};
use crate::aead::gcm::ffi::BLOCK_LEN;
use crate::cpu;
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
use {super::UpdateBlocks, crate::polyfill::slice::AsChunks};
#[cfg(all(target_arch = "aarch64", target_endian = "little"))]
pub(in super::super) type RequiredCpuFeatures = cpu::arm::PMull;
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
pub(in super::super) type RequiredCpuFeatures = (cpu::intel::ClMul, cpu::intel::Ssse3);
#[derive(Clone)]
pub struct Key {
h_table: HTable,
}
impl Key {
#[cfg_attr(target_arch = "x86_64", inline(never))]
pub(in super::super) fn new(value: KeyValue, _cpu: RequiredCpuFeatures) -> Self {
Self {
h_table: unsafe { htable_new!(gcm_init_clmul, value) },
}
}
#[cfg(target_arch = "aarch64")]
pub(super) fn inner(&self) -> &HTable {
&self.h_table
}
}
impl UpdateBlock for Key {
#[cfg(target_arch = "aarch64")]
fn update_block(&self, xi: &mut Xi, a: [u8; BLOCK_LEN]) {
prefixed_extern! {
fn gcm_gmult_clmul(xi: &mut Xi, Htable: &HTable);
}
xi.bitxor_assign(a);
unsafe { self.h_table.gmult(gcm_gmult_clmul, xi) };
}
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
fn update_block(&self, xi: &mut Xi, a: [u8; BLOCK_LEN]) {
self.update_blocks(xi, (&a).into())
}
}
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
impl UpdateBlocks for Key {
fn update_blocks(&self, xi: &mut Xi, input: AsChunks<u8, { BLOCK_LEN }>) {
unsafe { ghash!(gcm_ghash_clmul, xi, &self.h_table, input) }
}
}

View File

@@ -0,0 +1,51 @@
// Copyright 2018-2024 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#![cfg(target_arch = "x86_64")]
use super::{HTable, KeyValue, UpdateBlock, UpdateBlocks, Xi, BLOCK_LEN};
use crate::{cpu::intel, polyfill::slice::AsChunks};
#[derive(Clone)]
pub struct Key {
h_table: HTable,
}
impl Key {
#[inline(never)]
pub(in super::super) fn new(
value: KeyValue,
_required_cpu_features: (intel::ClMul, intel::Avx, intel::Movbe),
) -> Self {
Self {
h_table: unsafe { htable_new!(gcm_init_avx, value) },
}
}
pub(super) fn inner(&self) -> &HTable {
&self.h_table
}
}
impl UpdateBlock for Key {
fn update_block(&self, xi: &mut Xi, a: [u8; BLOCK_LEN]) {
self.update_blocks(xi, (&a).into())
}
}
impl UpdateBlocks for Key {
fn update_blocks(&self, xi: &mut Xi, input: AsChunks<u8, BLOCK_LEN>) {
unsafe { ghash!(gcm_ghash_avx, xi, self.inner(), input) }
}
}

271
vendor/ring/src/aead/gcm/fallback.rs vendored Normal file
View File

@@ -0,0 +1,271 @@
// Copyright (c) 2019, Google Inc.
// Portions Copyright 2020-2024 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
// This file is based on BoringSSL's gcm_nohw.c.
// This file contains a implementation of GHASH based on the notes
// in https://bearssl.org/constanttime.html#ghash-for-gcm and the reduction
// algorithm described in
// https://crypto.stanford.edu/RealWorldCrypto/slides/gueron.pdf.
//
// Unlike the BearSSL notes, we use u128 in the 64-bit implementation.
use super::{ffi::U128, KeyValue, UpdateBlock, UpdateBlocks, Xi, BLOCK_LEN};
use crate::polyfill::{slice::AsChunks, ArraySplitMap as _};
#[derive(Clone)]
pub struct Key {
h: U128,
}
impl Key {
pub(in super::super) fn new(value: KeyValue) -> Self {
Self { h: init(value) }
}
}
impl UpdateBlock for Key {
fn update_block(&self, xi: &mut Xi, a: [u8; BLOCK_LEN]) {
xi.bitxor_assign(a);
gmult(xi, self.h);
}
}
impl UpdateBlocks for Key {
fn update_blocks(&self, xi: &mut Xi, input: AsChunks<u8, BLOCK_LEN>) {
ghash(xi, self.h, input);
}
}
#[cfg(target_pointer_width = "64")]
fn gcm_mul64_nohw(a: u64, b: u64) -> (u64, u64) {
#[allow(clippy::cast_possible_truncation)]
#[inline(always)]
fn lo(a: u128) -> u64 {
a as u64
}
#[inline(always)]
fn hi(a: u128) -> u64 {
lo(a >> 64)
}
#[inline(always)]
fn mul(a: u64, b: u64) -> u128 {
u128::from(a) * u128::from(b)
}
// One term every four bits means the largest term is 64/4 = 16, which barely
// overflows into the next term. Using one term every five bits would cost 25
// multiplications instead of 16. It is faster to mask off the bottom four
// bits of |a|, giving a largest term of 60/4 = 15, and apply the bottom bits
// separately.
let a0 = a & 0x1111111111111110;
let a1 = a & 0x2222222222222220;
let a2 = a & 0x4444444444444440;
let a3 = a & 0x8888888888888880;
let b0 = b & 0x1111111111111111;
let b1 = b & 0x2222222222222222;
let b2 = b & 0x4444444444444444;
let b3 = b & 0x8888888888888888;
let c0 = mul(a0, b0) ^ mul(a1, b3) ^ mul(a2, b2) ^ mul(a3, b1);
let c1 = mul(a0, b1) ^ mul(a1, b0) ^ mul(a2, b3) ^ mul(a3, b2);
let c2 = mul(a0, b2) ^ mul(a1, b1) ^ mul(a2, b0) ^ mul(a3, b3);
let c3 = mul(a0, b3) ^ mul(a1, b2) ^ mul(a2, b1) ^ mul(a3, b0);
// Multiply the bottom four bits of |a| with |b|.
let a0_mask = 0u64.wrapping_sub(a & 1);
let a1_mask = 0u64.wrapping_sub((a >> 1) & 1);
let a2_mask = 0u64.wrapping_sub((a >> 2) & 1);
let a3_mask = 0u64.wrapping_sub((a >> 3) & 1);
let extra = u128::from(a0_mask & b)
^ (u128::from(a1_mask & b) << 1)
^ (u128::from(a2_mask & b) << 2)
^ (u128::from(a3_mask & b) << 3);
let lo = (lo(c0) & 0x1111111111111111)
^ (lo(c1) & 0x2222222222222222)
^ (lo(c2) & 0x4444444444444444)
^ (lo(c3) & 0x8888888888888888)
^ lo(extra);
let hi = (hi(c0) & 0x1111111111111111)
^ (hi(c1) & 0x2222222222222222)
^ (hi(c2) & 0x4444444444444444)
^ (hi(c3) & 0x8888888888888888)
^ hi(extra);
(lo, hi)
}
#[cfg(not(target_pointer_width = "64"))]
fn gcm_mul32_nohw(a: u32, b: u32) -> u64 {
#[inline(always)]
fn mul(a: u32, b: u32) -> u64 {
u64::from(a) * u64::from(b)
}
// One term every four bits means the largest term is 32/4 = 8, which does not
// overflow into the next term.
let a0 = a & 0x11111111;
let a1 = a & 0x22222222;
let a2 = a & 0x44444444;
let a3 = a & 0x88888888;
let b0 = b & 0x11111111;
let b1 = b & 0x22222222;
let b2 = b & 0x44444444;
let b3 = b & 0x88888888;
let c0 = mul(a0, b0) ^ mul(a1, b3) ^ mul(a2, b2) ^ mul(a3, b1);
let c1 = mul(a0, b1) ^ mul(a1, b0) ^ mul(a2, b3) ^ mul(a3, b2);
let c2 = mul(a0, b2) ^ mul(a1, b1) ^ mul(a2, b0) ^ mul(a3, b3);
let c3 = mul(a0, b3) ^ mul(a1, b2) ^ mul(a2, b1) ^ mul(a3, b0);
(c0 & 0x1111111111111111)
| (c1 & 0x2222222222222222)
| (c2 & 0x4444444444444444)
| (c3 & 0x8888888888888888)
}
#[cfg(not(target_pointer_width = "64"))]
fn gcm_mul64_nohw(a: u64, b: u64) -> (u64, u64) {
#[inline(always)]
fn lo(a: u64) -> u32 {
a as u32
}
#[inline(always)]
fn hi(a: u64) -> u32 {
lo(a >> 32)
}
let a0 = lo(a);
let a1 = hi(a);
let b0 = lo(b);
let b1 = hi(b);
// Karatsuba multiplication.
let lo = gcm_mul32_nohw(a0, b0);
let hi = gcm_mul32_nohw(a1, b1);
let mid = gcm_mul32_nohw(a0 ^ a1, b0 ^ b1) ^ lo ^ hi;
(lo ^ (mid << 32), hi ^ (mid >> 32))
}
fn init(value: KeyValue) -> U128 {
let xi = value.into_inner();
// We implement GHASH in terms of POLYVAL, as described in RFC 8452. This
// avoids a shift by 1 in the multiplication, needed to account for bit
// reversal losing a bit after multiplication, that is,
// rev128(X) * rev128(Y) = rev255(X*Y).
//
// Per Appendix A, we run mulX_POLYVAL. Note this is the same transformation
// applied by |gcm_init_clmul|, etc. Note |Xi| has already been byteswapped.
//
// See also slide 16 of
// https://crypto.stanford.edu/RealWorldCrypto/slides/gueron.pdf
let mut lo = xi[1];
let mut hi = xi[0];
let mut carry = hi >> 63;
carry = 0u64.wrapping_sub(carry);
hi <<= 1;
hi |= lo >> 63;
lo <<= 1;
// The irreducible polynomial is 1 + x^121 + x^126 + x^127 + x^128, so we
// conditionally add 0xc200...0001.
lo ^= carry & 1;
hi ^= carry & 0xc200000000000000;
// This implementation does not use the rest of |Htable|.
U128 { hi, lo }
}
fn gcm_polyval_nohw(xi: &mut [u64; 2], h: U128) {
// Karatsuba multiplication. The product of |Xi| and |H| is stored in |r0|
// through |r3|. Note there is no byte or bit reversal because we are
// evaluating POLYVAL.
let (r0, mut r1) = gcm_mul64_nohw(xi[0], h.lo);
let (mut r2, mut r3) = gcm_mul64_nohw(xi[1], h.hi);
let (mut mid0, mut mid1) = gcm_mul64_nohw(xi[0] ^ xi[1], h.hi ^ h.lo);
mid0 ^= r0 ^ r2;
mid1 ^= r1 ^ r3;
r2 ^= mid1;
r1 ^= mid0;
// Now we multiply our 256-bit result by x^-128 and reduce. |r2| and
// |r3| shifts into position and we must multiply |r0| and |r1| by x^-128. We
// have:
//
// 1 = x^121 + x^126 + x^127 + x^128
// x^-128 = x^-7 + x^-2 + x^-1 + 1
//
// This is the GHASH reduction step, but with bits flowing in reverse.
// The x^-7, x^-2, and x^-1 terms shift bits past x^0, which would require
// another reduction steps. Instead, we gather the excess bits, incorporate
// them into |r0| and |r1| and reduce once. See slides 17-19
// of https://crypto.stanford.edu/RealWorldCrypto/slides/gueron.pdf.
r1 ^= (r0 << 63) ^ (r0 << 62) ^ (r0 << 57);
// 1
r2 ^= r0;
r3 ^= r1;
// x^-1
r2 ^= r0 >> 1;
r2 ^= r1 << 63;
r3 ^= r1 >> 1;
// x^-2
r2 ^= r0 >> 2;
r2 ^= r1 << 62;
r3 ^= r1 >> 2;
// x^-7
r2 ^= r0 >> 7;
r2 ^= r1 << 57;
r3 ^= r1 >> 7;
*xi = [r2, r3];
}
fn gmult(xi: &mut Xi, h: U128) {
with_swapped_xi(xi, |swapped| {
gcm_polyval_nohw(swapped, h);
})
}
fn ghash(xi: &mut Xi, h: U128, input: AsChunks<u8, BLOCK_LEN>) {
with_swapped_xi(xi, |swapped| {
input.into_iter().for_each(|&input| {
let input = input.array_split_map(u64::from_be_bytes);
swapped[0] ^= input[1];
swapped[1] ^= input[0];
gcm_polyval_nohw(swapped, h);
});
});
}
#[inline]
fn with_swapped_xi(Xi(xi): &mut Xi, f: impl FnOnce(&mut [u64; 2])) {
let unswapped: [u64; 2] = xi.array_split_map(u64::from_be_bytes);
let mut swapped: [u64; 2] = [unswapped[1], unswapped[0]];
f(&mut swapped);
let (xi_0, xi_1) = xi.split_at_mut(BLOCK_LEN / 2);
xi_0.copy_from_slice(&u64::to_be_bytes(swapped[1]));
xi_1.copy_from_slice(&u64::to_be_bytes(swapped[0]));
}

165
vendor/ring/src/aead/gcm/ffi.rs vendored Normal file
View File

@@ -0,0 +1,165 @@
// Copyright 2018 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use crate::{
bb,
polyfill::{slice::AsChunks, ArraySplitMap},
};
pub(in super::super) const BLOCK_LEN: usize = 16;
pub(in super::super) type Block = [u8; BLOCK_LEN];
pub(super) const ZERO_BLOCK: Block = [0u8; BLOCK_LEN];
#[cfg(any(
all(target_arch = "aarch64", target_endian = "little"),
all(target_arch = "arm", target_endian = "little"),
target_arch = "x86",
target_arch = "x86_64"
))]
macro_rules! htable_new {
( $name:ident, $value:expr $(,)? ) => {{
use crate::aead::gcm::ffi::HTable;
prefixed_extern! {
fn $name(HTable: &mut HTable, h: &[u64; 2]);
}
HTable::new($name, $value)
}};
}
/// SAFETY:
/// * The function `$name` must meet the contract of the `f` paramweter of
/// `ghash()`.
#[cfg(any(
all(target_arch = "aarch64", target_endian = "little"),
all(target_arch = "arm", target_endian = "little"),
target_arch = "x86",
target_arch = "x86_64"
))]
macro_rules! ghash {
( $name:ident, $xi:expr, $h_table:expr, $input:expr $(,)? ) => {{
use crate::aead::gcm::ffi::{HTable, Xi};
prefixed_extern! {
fn $name(
xi: &mut Xi,
Htable: &HTable,
inp: *const u8,
len: crate::c::NonZero_size_t,
);
}
$h_table.ghash($name, $xi, $input)
}};
}
pub(in super::super) struct KeyValue([u64; 2]);
impl KeyValue {
pub(in super::super) fn new(value: Block) -> Self {
Self(value.array_split_map(u64::from_be_bytes))
}
pub(super) fn into_inner(self) -> [u64; 2] {
self.0
}
}
/// SAFETY:
/// * `f` must read `len` bytes from `inp`; it may assume
/// that `len` is a (non-zero) multiple of `BLOCK_LEN`.
/// * `f` may inspect CPU features.
#[cfg(any(
all(target_arch = "aarch64", target_endian = "little"),
all(target_arch = "arm", target_endian = "little"),
target_arch = "x86",
target_arch = "x86_64"
))]
impl HTable {
pub(super) unsafe fn new(
init: unsafe extern "C" fn(HTable: &mut HTable, &[u64; 2]),
value: KeyValue,
) -> Self {
let mut r = Self {
Htable: [U128 { hi: 0, lo: 0 }; HTABLE_LEN],
};
unsafe { init(&mut r, &value.0) };
r
}
#[cfg(any(
all(target_arch = "aarch64", target_endian = "little"),
all(target_arch = "arm", target_endian = "little")
))]
pub(super) unsafe fn gmult(
&self,
f: unsafe extern "C" fn(xi: &mut Xi, h_table: &HTable),
xi: &mut Xi,
) {
unsafe { f(xi, self) }
}
pub(super) unsafe fn ghash(
&self,
f: unsafe extern "C" fn(
xi: &mut Xi,
Htable: &HTable,
inp: *const u8,
len: crate::c::NonZero_size_t,
),
xi: &mut Xi,
input: AsChunks<u8, BLOCK_LEN>,
) {
use core::num::NonZeroUsize;
let input = input.as_flattened();
let input_len = match NonZeroUsize::new(input.len()) {
Some(len) => len,
None => {
return;
}
};
// SAFETY:
// * There are `input_len: NonZeroUsize` bytes available at `input` for
// `f` to read.
unsafe {
f(xi, self, input.as_ptr(), input_len);
}
}
}
// The alignment is required by some assembly code, such as `ghash-ssse3-*`.
#[derive(Clone)]
#[repr(C, align(16))]
pub(in super::super) struct HTable {
Htable: [U128; HTABLE_LEN],
}
#[derive(Clone, Copy)]
#[repr(C)]
pub(super) struct U128 {
pub(super) hi: u64,
pub(super) lo: u64,
}
const HTABLE_LEN: usize = 16;
#[repr(transparent)]
pub(in super::super) struct Xi(pub(super) Block);
impl Xi {
#[inline]
pub(super) fn bitxor_assign(&mut self, a: Block) {
self.0 = bb::xor_16(self.0, a)
}
}

52
vendor/ring/src/aead/gcm/neon.rs vendored Normal file
View File

@@ -0,0 +1,52 @@
// Copyright 2018-2024 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#![cfg(any(
all(target_arch = "aarch64", target_endian = "little"),
all(target_arch = "arm", target_endian = "little")
))]
use super::{HTable, KeyValue, UpdateBlock, UpdateBlocks, Xi, BLOCK_LEN};
use crate::{cpu, polyfill::slice::AsChunks};
pub(in super::super) type RequiredCpuFeatures = cpu::arm::Neon;
#[derive(Clone)]
pub struct Key {
h_table: HTable,
}
impl Key {
pub(in super::super) fn new(value: KeyValue, _cpu: RequiredCpuFeatures) -> Self {
Self {
h_table: unsafe { htable_new!(gcm_init_neon, value) },
}
}
}
impl UpdateBlock for Key {
fn update_block(&self, xi: &mut Xi, a: [u8; BLOCK_LEN]) {
prefixed_extern! {
fn gcm_gmult_neon(xi: &mut Xi, Htable: &HTable);
}
xi.bitxor_assign(a);
unsafe { self.h_table.gmult(gcm_gmult_neon, xi) };
}
}
impl UpdateBlocks for Key {
fn update_blocks(&self, xi: &mut Xi, input: AsChunks<u8, BLOCK_LEN>) {
unsafe { ghash!(gcm_ghash_neon, xi, &self.h_table, input) }
}
}

46
vendor/ring/src/aead/gcm/vclmulavx2.rs vendored Normal file
View File

@@ -0,0 +1,46 @@
// Copyright 2018-2025 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#![cfg(target_arch = "x86_64")]
use super::{ffi::KeyValue, HTable, UpdateBlock, Xi};
use crate::{
aead::gcm::ffi::BLOCK_LEN,
cpu::intel::{Avx2, VAesClmul},
polyfill::slice::AsChunks,
};
#[derive(Clone)]
pub struct Key {
h_table: HTable,
}
impl Key {
pub(in super::super) fn new(value: KeyValue, _cpu: (Avx2, VAesClmul)) -> Self {
Self {
h_table: unsafe { htable_new!(gcm_init_vpclmulqdq_avx2, value) },
}
}
pub(super) fn inner(&self) -> &HTable {
&self.h_table
}
}
impl UpdateBlock for Key {
fn update_block(&self, xi: &mut Xi, a: [u8; BLOCK_LEN]) {
let input: AsChunks<u8, BLOCK_LEN> = (&a).into();
unsafe { ghash!(gcm_ghash_vpclmulqdq_avx2_1, xi, &self.h_table, input) }
}
}

181
vendor/ring/src/aead/less_safe_key.rs vendored Normal file
View File

@@ -0,0 +1,181 @@
// Copyright 2015-2021 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use super::{Aad, Algorithm, KeyInner, Nonce, Tag, UnboundKey, TAG_LEN};
use crate::{cpu, error};
use core::ops::RangeFrom;
/// Immutable keys for use in situations where `OpeningKey`/`SealingKey` and
/// `NonceSequence` cannot reasonably be used.
///
/// Prefer to use `OpeningKey`/`SealingKey` and `NonceSequence` when practical.
#[derive(Clone)]
pub struct LessSafeKey {
inner: KeyInner,
algorithm: &'static Algorithm,
}
impl LessSafeKey {
/// Constructs a `LessSafeKey`.
#[inline]
pub fn new(key: UnboundKey) -> Self {
key.into_inner()
}
pub(super) fn new_(
algorithm: &'static Algorithm,
key_bytes: &[u8],
cpu_features: cpu::Features,
) -> Result<Self, error::Unspecified> {
Ok(Self {
inner: algorithm.new_key(key_bytes, cpu_features)?,
algorithm,
})
}
/// Like [open_in_place](Self::open_in_place), except the authentication tag is
/// passed separately.
#[inline]
pub fn open_in_place_separate_tag<'in_out, A>(
&self,
nonce: Nonce,
aad: Aad<A>,
tag: Tag,
in_out: &'in_out mut [u8],
ciphertext: RangeFrom<usize>,
) -> Result<&'in_out mut [u8], error::Unspecified>
where
A: AsRef<[u8]>,
{
let aad = Aad::from(aad.as_ref());
self.algorithm.open_within(
&self.inner,
nonce,
aad,
tag,
in_out,
ciphertext,
cpu::features(),
)
}
/// Like [`super::OpeningKey::open_in_place()`], except it accepts an
/// arbitrary nonce.
///
/// `nonce` must be unique for every use of the key to open data.
#[inline]
pub fn open_in_place<'in_out, A>(
&self,
nonce: Nonce,
aad: Aad<A>,
in_out: &'in_out mut [u8],
) -> Result<&'in_out mut [u8], error::Unspecified>
where
A: AsRef<[u8]>,
{
self.open_within(nonce, aad, in_out, 0..)
}
/// Like [`super::OpeningKey::open_within()`], except it accepts an
/// arbitrary nonce.
///
/// `nonce` must be unique for every use of the key to open data.
#[inline]
pub fn open_within<'in_out, A>(
&self,
nonce: Nonce,
aad: Aad<A>,
in_out: &'in_out mut [u8],
ciphertext_and_tag: RangeFrom<usize>,
) -> Result<&'in_out mut [u8], error::Unspecified>
where
A: AsRef<[u8]>,
{
let tag_offset = in_out
.len()
.checked_sub(TAG_LEN)
.ok_or(error::Unspecified)?;
// Split the tag off the end of `in_out`.
let (in_out, received_tag) = in_out.split_at_mut(tag_offset);
let received_tag = (*received_tag).try_into()?;
let ciphertext = ciphertext_and_tag;
self.open_in_place_separate_tag(nonce, aad, received_tag, in_out, ciphertext)
}
/// Like [`super::SealingKey::seal_in_place_append_tag()`], except it
/// accepts an arbitrary nonce.
///
/// `nonce` must be unique for every use of the key to seal data.
#[inline]
pub fn seal_in_place_append_tag<A, InOut>(
&self,
nonce: Nonce,
aad: Aad<A>,
in_out: &mut InOut,
) -> Result<(), error::Unspecified>
where
A: AsRef<[u8]>,
InOut: AsMut<[u8]> + for<'in_out> Extend<&'in_out u8>,
{
self.seal_in_place_separate_tag(nonce, aad, in_out.as_mut())
.map(|tag| in_out.extend(tag.as_ref()))
}
/// Like `super::SealingKey::seal_in_place_separate_tag()`, except it
/// accepts an arbitrary nonce.
///
/// `nonce` must be unique for every use of the key to seal data.
#[inline]
pub fn seal_in_place_separate_tag<A>(
&self,
nonce: Nonce,
aad: Aad<A>,
in_out: &mut [u8],
) -> Result<Tag, error::Unspecified>
where
A: AsRef<[u8]>,
{
self.algorithm.seal(
&self.inner,
nonce,
Aad::from(aad.as_ref()),
in_out,
cpu::features(),
)
}
/// The key's AEAD algorithm.
#[inline]
pub fn algorithm(&self) -> &'static Algorithm {
self.algorithm
}
pub(super) fn fmt_debug(
&self,
type_name: &'static str,
f: &mut core::fmt::Formatter,
) -> Result<(), core::fmt::Error> {
f.debug_struct(type_name)
.field("algorithm", &self.algorithm())
.finish()
}
}
impl core::fmt::Debug for LessSafeKey {
fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
self.fmt_debug("LessSafeKey", f)
}
}

51
vendor/ring/src/aead/nonce.rs vendored Normal file
View File

@@ -0,0 +1,51 @@
// Copyright 2018 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use crate::error;
/// A nonce for a single AEAD opening or sealing operation.
///
/// The user must ensure, for a particular key, that each nonce is unique.
///
/// `Nonce` intentionally doesn't implement `Clone` to ensure that each one is
/// consumed at most once.
pub struct Nonce([u8; NONCE_LEN]);
impl Nonce {
/// Constructs a `Nonce` with the given value, assuming that the value is
/// unique for the lifetime of the key it is being used with.
///
/// Fails if `value` isn't `NONCE_LEN` bytes long.
#[inline]
pub fn try_assume_unique_for_key(value: &[u8]) -> Result<Self, error::Unspecified> {
let value: &[u8; NONCE_LEN] = value.try_into()?;
Ok(Self::assume_unique_for_key(*value))
}
/// Constructs a `Nonce` with the given value, assuming that the value is
/// unique for the lifetime of the key it is being used with.
#[inline]
pub fn assume_unique_for_key(value: [u8; NONCE_LEN]) -> Self {
Self(value)
}
}
impl AsRef<[u8; NONCE_LEN]> for Nonce {
fn as_ref(&self) -> &[u8; NONCE_LEN] {
&self.0
}
}
/// All the AEADs we support use 96-bit nonces.
pub const NONCE_LEN: usize = 96 / 8;

143
vendor/ring/src/aead/opening_key.rs vendored Normal file
View File

@@ -0,0 +1,143 @@
// Copyright 2015-2021 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//! Authenticated Encryption with Associated Data (AEAD).
//!
//! See [Authenticated encryption: relations among notions and analysis of the
//! generic composition paradigm][AEAD] for an introduction to the concept of
//! AEADs.
//!
//! [AEAD]: https://eprint.iacr.org/2000/025.pdf
//! [`crypto.cipher.AEAD`]: https://golang.org/pkg/crypto/cipher/#AEAD
use super::{Aad, Algorithm, BoundKey, LessSafeKey, NonceSequence, UnboundKey};
use crate::error;
use core::ops::RangeFrom;
/// An AEAD key for authenticating and decrypting ("opening"), bound to a nonce
/// sequence.
///
/// Intentionally not `Clone` or `Copy` since cloning would allow duplication
/// of the nonce sequence.
pub struct OpeningKey<N: NonceSequence> {
key: LessSafeKey,
nonce_sequence: N,
}
impl<N: NonceSequence> BoundKey<N> for OpeningKey<N> {
fn new(key: UnboundKey, nonce_sequence: N) -> Self {
Self {
key: key.into_inner(),
nonce_sequence,
}
}
#[inline]
fn algorithm(&self) -> &'static Algorithm {
self.key.algorithm()
}
}
impl<N: NonceSequence> core::fmt::Debug for OpeningKey<N> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
self.key.fmt_debug("OpeningKey", f)
}
}
impl<N: NonceSequence> OpeningKey<N> {
/// Authenticates and decrypts (“opens”) data in place.
///
/// `aad` is the additional authenticated data (AAD), if any.
///
/// On input, `in_out` must be the ciphertext followed by the tag. When
/// `open_in_place()` returns `Ok(plaintext)`, the input ciphertext
/// has been overwritten by the plaintext; `plaintext` will refer to the
/// plaintext without the tag.
///
/// When `open_in_place()` returns `Err(..)`, `in_out` may have been
/// overwritten in an unspecified way.
#[inline]
pub fn open_in_place<'in_out, A>(
&mut self,
aad: Aad<A>,
in_out: &'in_out mut [u8],
) -> Result<&'in_out mut [u8], error::Unspecified>
where
A: AsRef<[u8]>,
{
self.key
.open_in_place(self.nonce_sequence.advance()?, aad, in_out)
}
/// Authenticates and decrypts (“opens”) data in place, with a shift.
///
/// `aad` is the additional authenticated data (AAD), if any.
///
/// On input, `in_out[ciphertext_and_tag]` must be the ciphertext followed
/// by the tag. When `open_within()` returns `Ok(plaintext)`, the plaintext
/// will be at `in_out[0..plaintext.len()]`. In other words, the following
/// two code fragments are equivalent for valid values of
/// `ciphertext_and_tag`, except `open_within` will often be more efficient:
///
///
/// ```skip
/// let plaintext = key.open_within(aad, in_out, cipertext_and_tag)?;
/// ```
///
/// ```skip
/// let ciphertext_and_tag_len = in_out[ciphertext_and_tag].len();
/// in_out.copy_within(ciphertext_and_tag, 0);
/// let plaintext = key.open_in_place(aad, &mut in_out[..ciphertext_and_tag_len])?;
/// ```
///
/// Similarly, `key.open_within(aad, in_out, 0..)` is equivalent to
/// `key.open_in_place(aad, in_out)`.
///
/// When `open_in_place()` returns `Err(..)`, `in_out` may have been
/// overwritten in an unspecified way.
///
/// The shifting feature is useful in the case where multiple packets are
/// being reassembled in place. Consider this example where the peer has
/// sent the message “Split stream reassembled in place” split into
/// three sealed packets:
///
/// ```ascii-art
/// Packet 1 Packet 2 Packet 3
/// Input: [Header][Ciphertext][Tag][Header][Ciphertext][Tag][Header][Ciphertext][Tag]
/// | +--------------+ |
/// +------+ +-----+ +----------------------------------+
/// v v v
/// Output: [Plaintext][Plaintext][Plaintext]
/// “Split stream reassembled in place”
/// ```
///
/// This reassembly can be accomplished with three calls to `open_within()`.
#[inline]
pub fn open_within<'in_out, A>(
&mut self,
aad: Aad<A>,
in_out: &'in_out mut [u8],
ciphertext_and_tag: RangeFrom<usize>,
) -> Result<&'in_out mut [u8], error::Unspecified>
where
A: AsRef<[u8]>,
{
self.key.open_within(
self.nonce_sequence.advance()?,
aad,
in_out,
ciphertext_and_tag,
)
}
}

View File

@@ -0,0 +1,60 @@
// Copyright 2024 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#![cfg_attr(not(test), allow(dead_code))]
use super::Overlapping;
use crate::error::LenMismatchError;
use core::array::TryFromSliceError;
pub struct Array<'o, T, const N: usize> {
// Invariant: N != 0.
// Invariant: `self.in_out.len() == N`.
in_out: Overlapping<'o, T>,
}
impl<'o, T, const N: usize> Array<'o, T, N> {
pub(super) fn new(in_out: Overlapping<'o, T>) -> Result<Self, LenMismatchError> {
if N == 0 || in_out.len() != N {
return Err(LenMismatchError::new(N));
}
Ok(Self { in_out })
}
pub fn into_unwritten_output(self) -> &'o mut [T; N]
where
&'o mut [T]: TryInto<&'o mut [T; N], Error = TryFromSliceError>,
{
self.in_out
.into_unwritten_output()
.try_into()
.unwrap_or_else(|TryFromSliceError { .. }| {
unreachable!() // Due to invariant
})
}
}
impl<T, const N: usize> Array<'_, T, N> {
pub fn input<'s>(&'s self) -> &'s [T; N]
where
&'s [T]: TryInto<&'s [T; N], Error = TryFromSliceError>,
{
self.in_out
.input()
.try_into()
.unwrap_or_else(|TryFromSliceError { .. }| {
unreachable!() // Due to invariant
})
}
}

152
vendor/ring/src/aead/overlapping/base.rs vendored Normal file
View File

@@ -0,0 +1,152 @@
// Copyright 2024 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
pub use self::index_error::IndexError;
use super::Array;
use crate::error::LenMismatchError;
use core::{mem, ops::RangeFrom};
pub struct Overlapping<'o, T> {
// Invariant: self.src.start <= in_out.len().
in_out: &'o mut [T],
src: RangeFrom<usize>,
}
impl<'o, T> From<&'o mut [T]> for Overlapping<'o, T> {
fn from(in_out: &'o mut [T]) -> Self {
Self { in_out, src: 0.. }
}
}
impl<'o, T> Overlapping<'o, T> {
pub fn new(in_out: &'o mut [T], src: RangeFrom<usize>) -> Result<Self, IndexError> {
match in_out.get(src.clone()) {
Some(_) => Ok(Self { in_out, src }),
None => Err(IndexError::new(src.start)),
}
}
#[cfg(any(
all(target_arch = "arm", target_endian = "little"),
target_arch = "x86"
))]
pub fn copy_within(self) -> &'o mut [T]
where
T: Copy,
{
if self.src.start == 0 {
self.in_out
} else {
let len = self.len();
self.in_out.copy_within(self.src, 0);
&mut self.in_out[..len]
}
}
#[cfg(any(
all(target_arch = "arm", target_endian = "little"),
target_arch = "x86"
))]
pub fn into_slice_src_mut(self) -> (&'o mut [T], RangeFrom<usize>) {
(self.in_out, self.src)
}
pub fn into_unwritten_output(self) -> &'o mut [T] {
let len = self.len();
self.in_out.get_mut(..len).unwrap_or_else(|| {
// The invariant ensures this succeeds.
unreachable!()
})
}
}
impl<T> Overlapping<'_, T> {
pub fn len(&self) -> usize {
self.input().len()
}
pub fn input(&self) -> &[T] {
self.in_out.get(self.src.clone()).unwrap_or_else(|| {
// Ensured by invariant.
unreachable!()
})
}
pub fn with_input_output_len<R>(self, f: impl FnOnce(*const T, *mut T, usize) -> R) -> R {
let len = self.len();
let output = self.in_out.as_mut_ptr();
// TODO: MSRV(1.65): use `output.cast_const()`
let output_const: *const T = output;
// SAFETY: The constructor ensures that `src` is a valid range.
// Equivalent to `self.in_out[src.clone()].as_ptr()` but without
// worries about compatibility with the stacked borrows model.
// TODO(MSRV-1.80, probably): Avoid special casing 0; see
// https://github.com/rust-lang/rust/pull/117329
// https://github.com/rust-lang/rustc_codegen_gcc/issues/516
let input = if self.src.start == 0 {
output_const
} else {
unsafe { output_const.add(self.src.start) }
};
f(input, output, len)
}
// Perhaps unlike `slice::split_first_chunk_mut`, this is biased,
// performance-wise, against the case where `N > self.len()`, so callers
// should be structured to avoid that.
//
// If the result is `Err` then nothing was written to `self`; if anything
// was written then the result will not be `Err`.
#[cfg_attr(not(test), allow(dead_code))]
pub fn split_first_chunk<const N: usize>(
mut self,
f: impl for<'a> FnOnce(Array<'a, T, N>),
) -> Result<Self, IndexError> {
let src = self.src.clone();
let end = self
.src
.start
.checked_add(N)
.ok_or_else(|| IndexError::new(N))?;
let first = self
.in_out
.get_mut(..end)
.ok_or_else(|| IndexError::new(N))?;
let first = Overlapping::new(first, src).unwrap_or_else(|IndexError { .. }| {
// Since `end == src.start + N`.
unreachable!()
});
let first = Array::new(first).unwrap_or_else(|LenMismatchError { .. }| {
// Since `end == src.start + N`.
unreachable!()
});
// Once we call `f`, we must return `Ok` because `f` may have written
// over (part of) the input.
Ok({
f(first);
let tail = mem::take(&mut self.in_out).get_mut(N..).unwrap_or_else(|| {
// There are at least `N` elements since `end == src.start + N`.
unreachable!()
});
Self::new(tail, self.src).unwrap_or_else(|IndexError { .. }| {
// Follows from `end == src.start + N`.
unreachable!()
})
})
}
}
cold_exhaustive_error! {
struct index_error::IndexError { index: usize }
}

23
vendor/ring/src/aead/overlapping/mod.rs vendored Normal file
View File

@@ -0,0 +1,23 @@
// Copyright 2024 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
pub use self::{
array::Array,
base::{IndexError, Overlapping},
partial_block::PartialBlock,
};
mod array;
mod base;
mod partial_block;

View File

@@ -0,0 +1,59 @@
// Copyright 2024 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use super::Overlapping;
use crate::error::InputTooLongError;
pub struct PartialBlock<'i, T, const BLOCK_LEN: usize> {
// invariant: `self.in_out.len() < BLOCK_LEN`.
in_out: Overlapping<'i, T>,
}
impl<'i, T, const BLOCK_LEN: usize> PartialBlock<'i, T, BLOCK_LEN> {
pub fn new(in_out: Overlapping<'i, T>) -> Result<Self, InputTooLongError> {
let len = in_out.len();
if len >= BLOCK_LEN {
return Err(InputTooLongError::new(len));
}
Ok(Self { in_out })
}
pub fn overwrite_at_start(self, padded: [T; BLOCK_LEN])
where
T: Copy,
{
let len = self.len();
let output = self.in_out.into_unwritten_output();
assert!(output.len() <= padded.len());
output.copy_from_slice(&padded[..len]);
}
}
impl<T, const BLOCK_LEN: usize> PartialBlock<'_, T, BLOCK_LEN> {
#[inline(always)]
pub fn input(&self) -> &[T] {
let r = self.in_out.input();
// Help the optimizer optimize the caller using the invariant.
// TODO: Does this actually help?
if r.len() >= BLOCK_LEN {
unreachable!()
}
r
}
#[inline(always)]
pub fn len(&self) -> usize {
self.input().len()
}
}

117
vendor/ring/src/aead/poly1305.rs vendored Normal file
View File

@@ -0,0 +1,117 @@
// Copyright 2015-2025 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
// TODO: enforce maximum input length.
use super::{Tag, TAG_LEN};
#[cfg(all(target_arch = "arm", target_endian = "little"))]
use crate::cpu::GetFeature as _;
use crate::{cpu, polyfill::slice::AsChunks};
mod ffi_arm_neon;
mod ffi_fallback;
/// A Poly1305 key.
pub(super) struct Key {
key_and_nonce: [u8; KEY_LEN],
}
pub(super) const BLOCK_LEN: usize = 16;
pub(super) const KEY_LEN: usize = 2 * BLOCK_LEN;
impl Key {
#[inline]
pub(super) fn new(key_and_nonce: [u8; KEY_LEN]) -> Self {
Self { key_and_nonce }
}
}
pub(super) enum Context {
#[cfg(all(target_arch = "arm", target_endian = "little"))]
ArmNeon(ffi_arm_neon::State),
Fallback(ffi_fallback::State),
}
impl Context {
#[inline]
pub(super) fn from_key(key: Key, cpu: cpu::Features) -> Self {
#[cfg(all(target_arch = "arm", target_endian = "little"))]
if let Some(cpu) = cpu.get_feature() {
return ffi_arm_neon::State::new_context(key, cpu);
}
let _: cpu::Features = cpu;
ffi_fallback::State::new_context(key)
}
pub fn update_block(&mut self, input: [u8; BLOCK_LEN]) {
self.update(AsChunks::from_ref(&input))
}
pub fn update(&mut self, input: AsChunks<u8, BLOCK_LEN>) {
self.update_internal(input.as_flattened());
}
fn update_internal(&mut self, input: &[u8]) {
match self {
#[cfg(all(target_arch = "arm", target_endian = "little"))]
Self::ArmNeon(state) => state.update_internal(input),
Self::Fallback(state) => state.update_internal(input),
}
}
pub(super) fn finish(mut self, input: &[u8]) -> Tag {
self.update_internal(input);
match self {
#[cfg(all(target_arch = "arm", target_endian = "little"))]
Self::ArmNeon(state) => state.finish(),
Self::Fallback(state) => state.finish(),
}
}
}
/// Implements the original, non-IETF padding semantics.
///
/// This is used by chacha20_poly1305_openssh and the standalone
/// poly1305 test vectors.
pub(super) fn sign(key: Key, input: &[u8], cpu_features: cpu::Features) -> Tag {
let ctx = Context::from_key(key, cpu_features);
ctx.finish(input)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::testutil as test;
// Adapted from BoringSSL's crypto/poly1305/poly1305_test.cc.
#[test]
pub fn test_poly1305() {
let cpu_features = cpu::features();
test::run(
test_vector_file!("poly1305_test.txt"),
|section, test_case| {
assert_eq!(section, "");
let key = test_case.consume_bytes("Key");
let key: &[u8; KEY_LEN] = key.as_slice().try_into().unwrap();
let input = test_case.consume_bytes("Input");
let expected_mac = test_case.consume_bytes("MAC");
let key = Key::new(*key);
let Tag(actual_mac) = sign(key, &input, cpu_features);
assert_eq!(expected_mac, actual_mac.as_ref());
Ok(())
},
)
}
}

View File

@@ -0,0 +1,98 @@
// Copyright 2015-2025 Brian Smith.
// Portions Copyright (c) 2014, 2015, Google Inc.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#![cfg(all(target_arch = "arm", target_endian = "little"))]
use super::{Key, Tag, KEY_LEN, TAG_LEN};
use crate::{c, cpu::arm::Neon};
use core::num::NonZeroUsize;
// XXX/TODO(MSRV): change to `pub(super)`.
pub(in super::super) struct State {
state: poly1305_state_st,
neon: Neon,
}
// TODO: Is 16 enough?
#[repr(C, align(16))]
struct poly1305_state_st {
r: fe1305x2,
h: fe1305x2,
c: fe1305x2,
precomp: [fe1305x2; 2],
data: [u8; data_len()],
buf: [u8; 32],
buf_used: c::size_t,
key: [u8; 16],
}
const fn data_len() -> usize {
128
}
#[derive(Clone, Copy)]
#[repr(C)]
struct fe1305x2 {
v: [u32; 12], // for alignment; only using 10
}
impl State {
pub(super) fn new_context(Key { key_and_nonce }: Key, neon: Neon) -> super::Context {
prefixed_extern! {
fn CRYPTO_poly1305_init_neon(state: &mut poly1305_state_st, key: &[u8; KEY_LEN]);
}
let mut r = Self {
state: poly1305_state_st {
r: fe1305x2 { v: [0; 12] },
h: fe1305x2 { v: [0; 12] },
c: fe1305x2 { v: [0; 12] },
precomp: [fe1305x2 { v: [0; 12] }; 2],
data: [0u8; data_len()],
buf: Default::default(),
buf_used: 0,
key: [0u8; 16],
},
neon,
};
unsafe { CRYPTO_poly1305_init_neon(&mut r.state, &key_and_nonce) }
super::Context::ArmNeon(r)
}
pub(super) fn update_internal(&mut self, input: &[u8]) {
prefixed_extern! {
fn CRYPTO_poly1305_update_neon(
st: &mut poly1305_state_st,
input: *const u8,
in_len: c::NonZero_size_t);
}
if let Some(len) = NonZeroUsize::new(input.len()) {
let _: Neon = self.neon;
let input = input.as_ptr();
unsafe { CRYPTO_poly1305_update_neon(&mut self.state, input, len) }
}
}
pub(super) fn finish(mut self) -> Tag {
prefixed_extern! {
fn CRYPTO_poly1305_finish_neon(st: &mut poly1305_state_st, mac: &mut [u8; TAG_LEN]);
}
let mut tag = Tag([0u8; TAG_LEN]);
unsafe { CRYPTO_poly1305_finish_neon(&mut self.state, &mut tag.0) }
tag
}
}

View File

@@ -0,0 +1,96 @@
// Copyright 2015-2025 Brian Smith.
// Portions Copyright (c) 2014, 2015, Google Inc.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use super::{Key, Tag, KEY_LEN, TAG_LEN};
use crate::c;
use core::num::NonZeroUsize;
// XXX/TODO(MSRV): change to `pub(super)`.
pub(in super::super) struct State {
state: poly1305_state_st,
}
// Keep in sync with `poly1305_state_st` in poly1305.c
#[repr(C, align(64))]
struct poly1305_state_st {
r0: u32,
r1: u32,
r2: u32,
r3: u32,
r4: u32,
s1: u32,
s2: u32,
s3: u32,
s4: u32,
h0: u32,
h1: u32,
h2: u32,
h3: u32,
h4: u32,
key: [u8; 16],
}
impl State {
pub(super) fn new_context(Key { key_and_nonce }: Key) -> super::Context {
prefixed_extern! {
fn CRYPTO_poly1305_init(state: &mut poly1305_state_st, key: &[u8; KEY_LEN]);
}
let mut r = Self {
state: poly1305_state_st {
r0: 0,
r1: 0,
r2: 0,
r3: 0,
r4: 0,
s1: 0,
s2: 0,
s3: 0,
s4: 0,
h0: 0,
h1: 0,
h2: 0,
h3: 0,
h4: 0,
key: [0u8; 16],
},
};
unsafe { CRYPTO_poly1305_init(&mut r.state, &key_and_nonce) }
super::Context::Fallback(r)
}
// `input.len % BLOCK_LEN == 0` must be true for every call except the
// final one.
pub(super) fn update_internal(&mut self, input: &[u8]) {
prefixed_extern! {
fn CRYPTO_poly1305_update(
state: &mut poly1305_state_st,
input: *const u8,
in_len: c::NonZero_size_t);
}
if let Some(len) = NonZeroUsize::new(input.len()) {
let input = input.as_ptr();
unsafe { CRYPTO_poly1305_update(&mut self.state, input, len) }
}
}
pub(super) fn finish(mut self) -> Tag {
prefixed_extern! {
fn CRYPTO_poly1305_finish(statep: &mut poly1305_state_st, mac: &mut [u8; TAG_LEN]);
}
let mut tag = Tag([0u8; TAG_LEN]);
unsafe { CRYPTO_poly1305_finish(&mut self.state, &mut tag.0) }
tag
}
}

170
vendor/ring/src/aead/poly1305_test.txt vendored Normal file
View File

@@ -0,0 +1,170 @@
# Test Vectors from OpenSSL commit bbe9769ba66ab2512678a87b0d9b266ba970db05.
Key = 2d773be37adb1e4d683bf0075e79c4ee037918535a7f99ccb7040fb5f5f43aea
Input = 89dab80b7717c1db5db437860a3f70218e93e1b8f461fb677f16f35f6f87e2a91c99bc3a47ace47640cc95c345be5ecca5a3523c35cc01893af0b64a620334270372ec12482d1b1e363561698a578b359803495bb4e2ef1930b17a5190b580f141300df30adbeca28f6427a8bc1a999fd51c554a017d095d8c3e3127daf9f595
MAC = c85d15ed44c378d6b00e23064c7bcd51
Key = 99e5822dd4173c995e3dae0ddefb97743fde3b080134b39f76e9bf8d0e88d546
Input = 000000000000000b170303020000000006db1f1f368d696a810a349c0c714c9a5e7850c2407d721acded95e018d7a85266a6e1289cdb4aeb18da5ac8a2b0026d24a59ad485227f3eaedbb2e7e35e1c66cd60f9abf716dcc9ac42682dd7dab287a7024c4eefc321cc0574e16793e37cec03c5bda42b54c114a80b57af26416c7be742005e20855c73e21dc8e2edc9d435cb6f6059280011c270b71570051c1c9b3052126620bc1e2730fa066c7a509d53c60e5ae1b40aa6e39e49669228c90eecb4a50db32a50bc49e90b4f4b359a1dfd11749cd3867fcf2fb7bb6cd4738f6a4ad6f7ca5058f7618845af9f020f6c3b967b8f4cd4a91e2813b507ae66f2d35c18284f7292186062e10fd5510d18775351ef334e7634ab4743f5b68f49adcab384d3fd75f7390f4006ef2a295c8c7a076ad54546cd25d2107fbe1436c840924aaebe5b370893cd63d1325b8616fc4810886bc152c53221b6df373119393255ee72bcaa880174f1717f9184fa91646f17a24ac55d16bfddca9581a92eda479201f0edbf633600d6066d1ab36d5d2415d71351bbcd608a25108d25641992c1f26c531cf9f90203bc4cc19f5927d834b0a47116d3884bbb164b8ec883d1ac832e56b3918a98601a08d171881541d594db399c6ae6151221745aec814c45b0b05b565436fd6f137aa10a0c0b643761dbd6f9a9dcb99b1a6e690854ce0769cde39761d82fcdec15f0d92d7d8e94ade8eb83fbe0
MAC = 2637408fe13086ea73f971e3425e2820
# RFC 8439, section 2.5.2.
Key = 85d6be7857556d337f4452fe42d506a80103808afb0db2fd4abff6af4149f51b
Input = "Cryptographic Forum Research Group"
MAC = a8061dc1305136c6c22b8baf0c0127a9
# RFC 8439, section A.3.
Key = 0000000000000000000000000000000000000000000000000000000000000000
Input = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
MAC = 00000000000000000000000000000000
Key = 0000000000000000000000000000000036e5f6b5c5e06070f0efca96227a863e
Input = 416e79207375626d697373696f6e20746f20746865204945544620696e74656e6465642062792074686520436f6e7472696275746f7220666f72207075626c69636174696f6e20617320616c6c206f722070617274206f6620616e204945544620496e7465726e65742d4472616674206f722052464320616e6420616e792073746174656d656e74206d6164652077697468696e2074686520636f6e74657874206f6620616e204945544620616374697669747920697320636f6e7369646572656420616e20224945544620436f6e747269627574696f6e222e20537563682073746174656d656e747320696e636c756465206f72616c2073746174656d656e747320696e20494554462073657373696f6e732c2061732077656c6c206173207772697474656e20616e6420656c656374726f6e696320636f6d6d756e69636174696f6e73206d61646520617420616e792074696d65206f7220706c6163652c207768696368206172652061646472657373656420746f
MAC = 36e5f6b5c5e06070f0efca96227a863e
Key = 36e5f6b5c5e06070f0efca96227a863e00000000000000000000000000000000
Input = 416e79207375626d697373696f6e20746f20746865204945544620696e74656e6465642062792074686520436f6e7472696275746f7220666f72207075626c69636174696f6e20617320616c6c206f722070617274206f6620616e204945544620496e7465726e65742d4472616674206f722052464320616e6420616e792073746174656d656e74206d6164652077697468696e2074686520636f6e74657874206f6620616e204945544620616374697669747920697320636f6e7369646572656420616e20224945544620436f6e747269627574696f6e222e20537563682073746174656d656e747320696e636c756465206f72616c2073746174656d656e747320696e20494554462073657373696f6e732c2061732077656c6c206173207772697474656e20616e6420656c656374726f6e696320636f6d6d756e69636174696f6e73206d61646520617420616e792074696d65206f7220706c6163652c207768696368206172652061646472657373656420746f
MAC = f3477e7cd95417af89a6b8794c310cf0
Key = 1c9240a5eb55d38af333888604f6b5f0473917c1402b80099dca5cbc207075c0
Input = 2754776173206272696c6c69672c20616e642074686520736c6974687920746f7665730a446964206779726520616e642067696d626c6520696e2074686520776162653a0a416c6c206d696d737920776572652074686520626f726f676f7665732c0a416e6420746865206d6f6d65207261746873206f757467726162652e
MAC = 4541669a7eaaee61e708dc7cbcc5eb62
Key = 0200000000000000000000000000000000000000000000000000000000000000
Input = ffffffffffffffffffffffffffffffff
MAC = 03000000000000000000000000000000
Key = 02000000000000000000000000000000ffffffffffffffffffffffffffffffff
Input = 02000000000000000000000000000000
MAC = 03000000000000000000000000000000
Key = 0100000000000000000000000000000000000000000000000000000000000000
Input = fffffffffffffffffffffffffffffffff0ffffffffffffffffffffffffffffff11000000000000000000000000000000
MAC = 05000000000000000000000000000000
Key = 0100000000000000000000000000000000000000000000000000000000000000
Input = fffffffffffffffffffffffffffffffffbfefefefefefefefefefefefefefefe01010101010101010101010101010101
MAC = 00000000000000000000000000000000
Key = 0200000000000000000000000000000000000000000000000000000000000000
Input = fdffffffffffffffffffffffffffffff
MAC = faffffffffffffffffffffffffffffff
Key = 0100000000000000040000000000000000000000000000000000000000000000
Input = e33594d7505e43b900000000000000003394d7505e4379cd01000000000000000000000000000000000000000000000001000000000000000000000000000000
MAC = 14000000000000005500000000000000
Key = 0100000000000000040000000000000000000000000000000000000000000000
Input = e33594d7505e43b900000000000000003394d7505e4379cd010000000000000000000000000000000000000000000000
MAC = 13000000000000000000000000000000
# Additional test vectors that are long enough to ensure OpenSSL's SIMD
# assembly is fully tested.
# Length 2048.
Key = 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
Input = 248ac31085b6c2adaaa38259a0d7192c5c35d1bb4ef39ad94c38d1c82479e2dd2159a077024b0589bc8a20101b506f0a1ad0bbab76e83a83f1b94be6beae74e874cab692c5963a75436b776121ec9f62399a3e66b2d22707dae81933b6277f3c8516bcbe26dbbd86f373103d7cf4cad1888c952118fbfbd0d7b4bedc4ae4936aff91157e7aa47c54442ea78d6ac251d324a0fbe49d89cc3521b66d16e9c66a3709894e4eb0a4eedc4ae19468e66b81f271351b1d921ea551047abcc6b87a901fde7db79fa1818c11336dbc07244a40eb14cf77bde35e78ae9ad7d3f57ed7e7f23926c9172f82d77684ea5ed7d74ebc6f142b997036bcb7cce8df1bbc0d5b35a46509c954fc9469d214d6238f166cbf872156b4c41d7aac5942cffb175023078252a3f36e315c5d4ce0e39928a018252862becacef96a19f03bdcf46d75584299d1f8b03c0169e9e407d937145b5e5024139e7022a1978f114f24cdfa23780a119735c41da8fb759bbb3f025c6ec30e6c6e9bce8615be68e392fce59fd26a8e6a6cc5c606e3848116e4d01d29565a1facfb524b6d29643b826eee1e42869fc76df229dd79b39a2b1df28bb335c3a5f15a855d0121e4a6da34b5e4d5b7b5d5746a03ecff70811e1516fcec1bf7462e8876a2d21710aa168c78f45a6a15015950e221da85d3ec822ad6d0a6931b25a06b7bb5f3c10bb36cd4d647f9561982fde9818de5d4bf8db7f86c53b4ff14928ac15f79023b61861e73e44216540bb302153770da2533de9795252ab5fb77ad924c9338c8144c23d4c90dab9a18feac1a1574d4545e1435eb405e6c4c439fc724fce992ae85badf345bad16d85fbd338f04433703614754d0e7e54c4ccde2670587d52ecfb5a70a14a501bacc727722649931d8515b13d020a78e511fe136d45fbf97f9c7f689fcc677cfb3683723878350ffe9d08130cc6e567b6179e01b7eb2b3bbcf0873e1308eec018edeb8cce946338e15d5bf68c71916a83a99358039ef071e009546a2df936879dffbba397a93925d229a469fd17d71b7f524e03a30da6ee927542f8b369bed4734fe25dbd63d24ffd2a222f5f84f75d858ab989be925af570ad6d45bd28ce61b5139e1dd2f0b7795fe072e6e83acbb5e7b777a70c641e4cab2af40eed69abc334cd2703c3273204fac580c6a3d6680427e5f7d051e8380a53f93a180f4556ecea4530b9a2d5948dad63d415b6874f6b90e767d6d265be86351b53ba690780bb57c21b57418c5b97559e840c68257f839e7583a4bf7c7645c5987d40cc1ba79a218c35edfacdabe581d950e4bb7a481ebe64d61d00e75b1f25f1ce5f5462334a5b9038a697aa0937a3f8017e05d2c9c05dcb05c0b02508dea619b137f5444b6f088eb3cb2c66788f88afdfbba8faa1c490485624c88ae11e57347a676902e7553f056188493209bdbb30acc63c9e41e16a9d6c009416b520a76ba38f57628170c43626b5cb46179dc5bf65de865085f84bf741c223fbe474d2d19d8f43914fbd6586351089e73babf344f988b7963fe44528457d7aad3c564f6bcbd0d772a4c9fd328e6022d1c7c9f86726f8d5a23797d309c0f653ab1ac687833eb2700f156296062a8b377078f45f6b68c3d07cae1913ba8d5a6f9bf7525a3439eb932d4cefc4bf8e1b07b48ca13ece366cbc3e0388915915d1757475103a9e9454e7e6355de2d6acbf4710f9a63e4f6d3cd70c2d6fca88dd8a14448fdb63ce9350fdaafbe0b8bd1c5d307dae76dfed799aef2d8f23d5608d37d1330dd38b94860905dbeebf78d7b7318b7d42aed40d3f9899e9f420cbd92a6eeae3026f7725694e0e4bee016ba346fed2c21172bdb4a461cebe0cfe38e76645226ac127a259c193264d735ce8c8a57e17dd3f0579e2e86dc295ad1f45ba2d85db35044da61f7d401274b31eefbeb34e8d2ae596e9b4541aae117bdac5ed0b324c20539c27c07a411d5288b0b5f6fa16e9a7df85dc319fa6b71cd08a859c06a3f7b0289e1750adbf182f9750fea96fea5ab7aa3473340607cd7ed2c626f5382491c26d5d5bea61401dee7319c94d418f297e61ceac8f258ee8c23831bda081591f5a918e96855774ddedffc51e5b180f1971806d42fc333020b734aeb45adb0bc47325d0cea5f6713a786558022afc39d573892aa3635efbfd8bcb11c57f306c72146afe8b45388125cb7bf9ecf965a7ba4f768c77be366470dcdcf214b7f6a5a9460ed4fe44ae559d85e2fdc2094de83fff12ea8804db1215c4ca865871bdd7f8ef32ab799bf923ffb02c1ded7d129beadad46c5eda31ab1a6f43da05ea08bff7ffa88d8966353d01830558c39b930b01d175e437124d8edd0d2698fd8932f2b2c9b14746e52879c57a395538150f390264f00e60d470711202f4194499ff79037ca9885dc8d695f7d917a3086ca88e8f8d0243efee09302cf39e039eb7cc8dd19d28120d5fe533b5727cd39133181c729ca6f90a015ed30be7668d5cb5ecc33a53ee69bf7d1a5ecbdb153803743c6adaaabd36bf84e5be38d3f04a5d5dbfd67bdcd3b176e65bd1391ade775cc32ce43a847fb6c672a3fe97a5d4081c4986959ec5fb898f42a9397ba2b3ec2c1018f8d76d057f2366bd0e4465514ad6560c599664fb85621fe771e00f43d39b591b2a6a321100f4d1ef23a376d5ae3eeedbfe23da73dff0ee4d16b34ebddd8f5f053db9824105fc7300dbee7ea6af56b112319e3e215a0fc79ae946f6b5227453ec7fcaf17cf7651f71499a50d81221404d5f129ac50ea7528ff0e0069ec4ab8acb7919d81749ab37a870c5ef2cc5a15cf96709d3c65b4addc77e7416847160bcabb94ea36377e0ef71be80b5cc53effd5444888044a353574c72c924bba2a8b4e8354188ebfed
MAC = 69d28f73dd09d39a92aa179da354b7ea
# Length 2049.
Key = 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
Input = 248ac31085b6c2adaaa38259a0d7192c5c35d1bb4ef39ad94c38d1c82479e2dd2159a077024b0589bc8a20101b506f0a1ad0bbab76e83a83f1b94be6beae74e874cab692c5963a75436b776121ec9f62399a3e66b2d22707dae81933b6277f3c8516bcbe26dbbd86f373103d7cf4cad1888c952118fbfbd0d7b4bedc4ae4936aff91157e7aa47c54442ea78d6ac251d324a0fbe49d89cc3521b66d16e9c66a3709894e4eb0a4eedc4ae19468e66b81f271351b1d921ea551047abcc6b87a901fde7db79fa1818c11336dbc07244a40eb14cf77bde35e78ae9ad7d3f57ed7e7f23926c9172f82d77684ea5ed7d74ebc6f142b997036bcb7cce8df1bbc0d5b35a46509c954fc9469d214d6238f166cbf872156b4c41d7aac5942cffb175023078252a3f36e315c5d4ce0e39928a018252862becacef96a19f03bdcf46d75584299d1f8b03c0169e9e407d937145b5e5024139e7022a1978f114f24cdfa23780a119735c41da8fb759bbb3f025c6ec30e6c6e9bce8615be68e392fce59fd26a8e6a6cc5c606e3848116e4d01d29565a1facfb524b6d29643b826eee1e42869fc76df229dd79b39a2b1df28bb335c3a5f15a855d0121e4a6da34b5e4d5b7b5d5746a03ecff70811e1516fcec1bf7462e8876a2d21710aa168c78f45a6a15015950e221da85d3ec822ad6d0a6931b25a06b7bb5f3c10bb36cd4d647f9561982fde9818de5d4bf8db7f86c53b4ff14928ac15f79023b61861e73e44216540bb302153770da2533de9795252ab5fb77ad924c9338c8144c23d4c90dab9a18feac1a1574d4545e1435eb405e6c4c439fc724fce992ae85badf345bad16d85fbd338f04433703614754d0e7e54c4ccde2670587d52ecfb5a70a14a501bacc727722649931d8515b13d020a78e511fe136d45fbf97f9c7f689fcc677cfb3683723878350ffe9d08130cc6e567b6179e01b7eb2b3bbcf0873e1308eec018edeb8cce946338e15d5bf68c71916a83a99358039ef071e009546a2df936879dffbba397a93925d229a469fd17d71b7f524e03a30da6ee927542f8b369bed4734fe25dbd63d24ffd2a222f5f84f75d858ab989be925af570ad6d45bd28ce61b5139e1dd2f0b7795fe072e6e83acbb5e7b777a70c641e4cab2af40eed69abc334cd2703c3273204fac580c6a3d6680427e5f7d051e8380a53f93a180f4556ecea4530b9a2d5948dad63d415b6874f6b90e767d6d265be86351b53ba690780bb57c21b57418c5b97559e840c68257f839e7583a4bf7c7645c5987d40cc1ba79a218c35edfacdabe581d950e4bb7a481ebe64d61d00e75b1f25f1ce5f5462334a5b9038a697aa0937a3f8017e05d2c9c05dcb05c0b02508dea619b137f5444b6f088eb3cb2c66788f88afdfbba8faa1c490485624c88ae11e57347a676902e7553f056188493209bdbb30acc63c9e41e16a9d6c009416b520a76ba38f57628170c43626b5cb46179dc5bf65de865085f84bf741c223fbe474d2d19d8f43914fbd6586351089e73babf344f988b7963fe44528457d7aad3c564f6bcbd0d772a4c9fd328e6022d1c7c9f86726f8d5a23797d309c0f653ab1ac687833eb2700f156296062a8b377078f45f6b68c3d07cae1913ba8d5a6f9bf7525a3439eb932d4cefc4bf8e1b07b48ca13ece366cbc3e0388915915d1757475103a9e9454e7e6355de2d6acbf4710f9a63e4f6d3cd70c2d6fca88dd8a14448fdb63ce9350fdaafbe0b8bd1c5d307dae76dfed799aef2d8f23d5608d37d1330dd38b94860905dbeebf78d7b7318b7d42aed40d3f9899e9f420cbd92a6eeae3026f7725694e0e4bee016ba346fed2c21172bdb4a461cebe0cfe38e76645226ac127a259c193264d735ce8c8a57e17dd3f0579e2e86dc295ad1f45ba2d85db35044da61f7d401274b31eefbeb34e8d2ae596e9b4541aae117bdac5ed0b324c20539c27c07a411d5288b0b5f6fa16e9a7df85dc319fa6b71cd08a859c06a3f7b0289e1750adbf182f9750fea96fea5ab7aa3473340607cd7ed2c626f5382491c26d5d5bea61401dee7319c94d418f297e61ceac8f258ee8c23831bda081591f5a918e96855774ddedffc51e5b180f1971806d42fc333020b734aeb45adb0bc47325d0cea5f6713a786558022afc39d573892aa3635efbfd8bcb11c57f306c72146afe8b45388125cb7bf9ecf965a7ba4f768c77be366470dcdcf214b7f6a5a9460ed4fe44ae559d85e2fdc2094de83fff12ea8804db1215c4ca865871bdd7f8ef32ab799bf923ffb02c1ded7d129beadad46c5eda31ab1a6f43da05ea08bff7ffa88d8966353d01830558c39b930b01d175e437124d8edd0d2698fd8932f2b2c9b14746e52879c57a395538150f390264f00e60d470711202f4194499ff79037ca9885dc8d695f7d917a3086ca88e8f8d0243efee09302cf39e039eb7cc8dd19d28120d5fe533b5727cd39133181c729ca6f90a015ed30be7668d5cb5ecc33a53ee69bf7d1a5ecbdb153803743c6adaaabd36bf84e5be38d3f04a5d5dbfd67bdcd3b176e65bd1391ade775cc32ce43a847fb6c672a3fe97a5d4081c4986959ec5fb898f42a9397ba2b3ec2c1018f8d76d057f2366bd0e4465514ad6560c599664fb85621fe771e00f43d39b591b2a6a321100f4d1ef23a376d5ae3eeedbfe23da73dff0ee4d16b34ebddd8f5f053db9824105fc7300dbee7ea6af56b112319e3e215a0fc79ae946f6b5227453ec7fcaf17cf7651f71499a50d81221404d5f129ac50ea7528ff0e0069ec4ab8acb7919d81749ab37a870c5ef2cc5a15cf96709d3c65b4addc77e7416847160bcabb94ea36377e0ef71be80b5cc53effd5444888044a353574c72c924bba2a8b4e8354188ebfedc8
MAC = d6a26654b88572e875d9661c83471c1b
# Length 2050.
Key = 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
Input = 248ac31085b6c2adaaa38259a0d7192c5c35d1bb4ef39ad94c38d1c82479e2dd2159a077024b0589bc8a20101b506f0a1ad0bbab76e83a83f1b94be6beae74e874cab692c5963a75436b776121ec9f62399a3e66b2d22707dae81933b6277f3c8516bcbe26dbbd86f373103d7cf4cad1888c952118fbfbd0d7b4bedc4ae4936aff91157e7aa47c54442ea78d6ac251d324a0fbe49d89cc3521b66d16e9c66a3709894e4eb0a4eedc4ae19468e66b81f271351b1d921ea551047abcc6b87a901fde7db79fa1818c11336dbc07244a40eb14cf77bde35e78ae9ad7d3f57ed7e7f23926c9172f82d77684ea5ed7d74ebc6f142b997036bcb7cce8df1bbc0d5b35a46509c954fc9469d214d6238f166cbf872156b4c41d7aac5942cffb175023078252a3f36e315c5d4ce0e39928a018252862becacef96a19f03bdcf46d75584299d1f8b03c0169e9e407d937145b5e5024139e7022a1978f114f24cdfa23780a119735c41da8fb759bbb3f025c6ec30e6c6e9bce8615be68e392fce59fd26a8e6a6cc5c606e3848116e4d01d29565a1facfb524b6d29643b826eee1e42869fc76df229dd79b39a2b1df28bb335c3a5f15a855d0121e4a6da34b5e4d5b7b5d5746a03ecff70811e1516fcec1bf7462e8876a2d21710aa168c78f45a6a15015950e221da85d3ec822ad6d0a6931b25a06b7bb5f3c10bb36cd4d647f9561982fde9818de5d4bf8db7f86c53b4ff14928ac15f79023b61861e73e44216540bb302153770da2533de9795252ab5fb77ad924c9338c8144c23d4c90dab9a18feac1a1574d4545e1435eb405e6c4c439fc724fce992ae85badf345bad16d85fbd338f04433703614754d0e7e54c4ccde2670587d52ecfb5a70a14a501bacc727722649931d8515b13d020a78e511fe136d45fbf97f9c7f689fcc677cfb3683723878350ffe9d08130cc6e567b6179e01b7eb2b3bbcf0873e1308eec018edeb8cce946338e15d5bf68c71916a83a99358039ef071e009546a2df936879dffbba397a93925d229a469fd17d71b7f524e03a30da6ee927542f8b369bed4734fe25dbd63d24ffd2a222f5f84f75d858ab989be925af570ad6d45bd28ce61b5139e1dd2f0b7795fe072e6e83acbb5e7b777a70c641e4cab2af40eed69abc334cd2703c3273204fac580c6a3d6680427e5f7d051e8380a53f93a180f4556ecea4530b9a2d5948dad63d415b6874f6b90e767d6d265be86351b53ba690780bb57c21b57418c5b97559e840c68257f839e7583a4bf7c7645c5987d40cc1ba79a218c35edfacdabe581d950e4bb7a481ebe64d61d00e75b1f25f1ce5f5462334a5b9038a697aa0937a3f8017e05d2c9c05dcb05c0b02508dea619b137f5444b6f088eb3cb2c66788f88afdfbba8faa1c490485624c88ae11e57347a676902e7553f056188493209bdbb30acc63c9e41e16a9d6c009416b520a76ba38f57628170c43626b5cb46179dc5bf65de865085f84bf741c223fbe474d2d19d8f43914fbd6586351089e73babf344f988b7963fe44528457d7aad3c564f6bcbd0d772a4c9fd328e6022d1c7c9f86726f8d5a23797d309c0f653ab1ac687833eb2700f156296062a8b377078f45f6b68c3d07cae1913ba8d5a6f9bf7525a3439eb932d4cefc4bf8e1b07b48ca13ece366cbc3e0388915915d1757475103a9e9454e7e6355de2d6acbf4710f9a63e4f6d3cd70c2d6fca88dd8a14448fdb63ce9350fdaafbe0b8bd1c5d307dae76dfed799aef2d8f23d5608d37d1330dd38b94860905dbeebf78d7b7318b7d42aed40d3f9899e9f420cbd92a6eeae3026f7725694e0e4bee016ba346fed2c21172bdb4a461cebe0cfe38e76645226ac127a259c193264d735ce8c8a57e17dd3f0579e2e86dc295ad1f45ba2d85db35044da61f7d401274b31eefbeb34e8d2ae596e9b4541aae117bdac5ed0b324c20539c27c07a411d5288b0b5f6fa16e9a7df85dc319fa6b71cd08a859c06a3f7b0289e1750adbf182f9750fea96fea5ab7aa3473340607cd7ed2c626f5382491c26d5d5bea61401dee7319c94d418f297e61ceac8f258ee8c23831bda081591f5a918e96855774ddedffc51e5b180f1971806d42fc333020b734aeb45adb0bc47325d0cea5f6713a786558022afc39d573892aa3635efbfd8bcb11c57f306c72146afe8b45388125cb7bf9ecf965a7ba4f768c77be366470dcdcf214b7f6a5a9460ed4fe44ae559d85e2fdc2094de83fff12ea8804db1215c4ca865871bdd7f8ef32ab799bf923ffb02c1ded7d129beadad46c5eda31ab1a6f43da05ea08bff7ffa88d8966353d01830558c39b930b01d175e437124d8edd0d2698fd8932f2b2c9b14746e52879c57a395538150f390264f00e60d470711202f4194499ff79037ca9885dc8d695f7d917a3086ca88e8f8d0243efee09302cf39e039eb7cc8dd19d28120d5fe533b5727cd39133181c729ca6f90a015ed30be7668d5cb5ecc33a53ee69bf7d1a5ecbdb153803743c6adaaabd36bf84e5be38d3f04a5d5dbfd67bdcd3b176e65bd1391ade775cc32ce43a847fb6c672a3fe97a5d4081c4986959ec5fb898f42a9397ba2b3ec2c1018f8d76d057f2366bd0e4465514ad6560c599664fb85621fe771e00f43d39b591b2a6a321100f4d1ef23a376d5ae3eeedbfe23da73dff0ee4d16b34ebddd8f5f053db9824105fc7300dbee7ea6af56b112319e3e215a0fc79ae946f6b5227453ec7fcaf17cf7651f71499a50d81221404d5f129ac50ea7528ff0e0069ec4ab8acb7919d81749ab37a870c5ef2cc5a15cf96709d3c65b4addc77e7416847160bcabb94ea36377e0ef71be80b5cc53effd5444888044a353574c72c924bba2a8b4e8354188ebfedc852
MAC = 9fbbb7f7adcd0cd5b46a4a520b22499a
# Length 2051.
Key = 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
Input = 248ac31085b6c2adaaa38259a0d7192c5c35d1bb4ef39ad94c38d1c82479e2dd2159a077024b0589bc8a20101b506f0a1ad0bbab76e83a83f1b94be6beae74e874cab692c5963a75436b776121ec9f62399a3e66b2d22707dae81933b6277f3c8516bcbe26dbbd86f373103d7cf4cad1888c952118fbfbd0d7b4bedc4ae4936aff91157e7aa47c54442ea78d6ac251d324a0fbe49d89cc3521b66d16e9c66a3709894e4eb0a4eedc4ae19468e66b81f271351b1d921ea551047abcc6b87a901fde7db79fa1818c11336dbc07244a40eb14cf77bde35e78ae9ad7d3f57ed7e7f23926c9172f82d77684ea5ed7d74ebc6f142b997036bcb7cce8df1bbc0d5b35a46509c954fc9469d214d6238f166cbf872156b4c41d7aac5942cffb175023078252a3f36e315c5d4ce0e39928a018252862becacef96a19f03bdcf46d75584299d1f8b03c0169e9e407d937145b5e5024139e7022a1978f114f24cdfa23780a119735c41da8fb759bbb3f025c6ec30e6c6e9bce8615be68e392fce59fd26a8e6a6cc5c606e3848116e4d01d29565a1facfb524b6d29643b826eee1e42869fc76df229dd79b39a2b1df28bb335c3a5f15a855d0121e4a6da34b5e4d5b7b5d5746a03ecff70811e1516fcec1bf7462e8876a2d21710aa168c78f45a6a15015950e221da85d3ec822ad6d0a6931b25a06b7bb5f3c10bb36cd4d647f9561982fde9818de5d4bf8db7f86c53b4ff14928ac15f79023b61861e73e44216540bb302153770da2533de9795252ab5fb77ad924c9338c8144c23d4c90dab9a18feac1a1574d4545e1435eb405e6c4c439fc724fce992ae85badf345bad16d85fbd338f04433703614754d0e7e54c4ccde2670587d52ecfb5a70a14a501bacc727722649931d8515b13d020a78e511fe136d45fbf97f9c7f689fcc677cfb3683723878350ffe9d08130cc6e567b6179e01b7eb2b3bbcf0873e1308eec018edeb8cce946338e15d5bf68c71916a83a99358039ef071e009546a2df936879dffbba397a93925d229a469fd17d71b7f524e03a30da6ee927542f8b369bed4734fe25dbd63d24ffd2a222f5f84f75d858ab989be925af570ad6d45bd28ce61b5139e1dd2f0b7795fe072e6e83acbb5e7b777a70c641e4cab2af40eed69abc334cd2703c3273204fac580c6a3d6680427e5f7d051e8380a53f93a180f4556ecea4530b9a2d5948dad63d415b6874f6b90e767d6d265be86351b53ba690780bb57c21b57418c5b97559e840c68257f839e7583a4bf7c7645c5987d40cc1ba79a218c35edfacdabe581d950e4bb7a481ebe64d61d00e75b1f25f1ce5f5462334a5b9038a697aa0937a3f8017e05d2c9c05dcb05c0b02508dea619b137f5444b6f088eb3cb2c66788f88afdfbba8faa1c490485624c88ae11e57347a676902e7553f056188493209bdbb30acc63c9e41e16a9d6c009416b520a76ba38f57628170c43626b5cb46179dc5bf65de865085f84bf741c223fbe474d2d19d8f43914fbd6586351089e73babf344f988b7963fe44528457d7aad3c564f6bcbd0d772a4c9fd328e6022d1c7c9f86726f8d5a23797d309c0f653ab1ac687833eb2700f156296062a8b377078f45f6b68c3d07cae1913ba8d5a6f9bf7525a3439eb932d4cefc4bf8e1b07b48ca13ece366cbc3e0388915915d1757475103a9e9454e7e6355de2d6acbf4710f9a63e4f6d3cd70c2d6fca88dd8a14448fdb63ce9350fdaafbe0b8bd1c5d307dae76dfed799aef2d8f23d5608d37d1330dd38b94860905dbeebf78d7b7318b7d42aed40d3f9899e9f420cbd92a6eeae3026f7725694e0e4bee016ba346fed2c21172bdb4a461cebe0cfe38e76645226ac127a259c193264d735ce8c8a57e17dd3f0579e2e86dc295ad1f45ba2d85db35044da61f7d401274b31eefbeb34e8d2ae596e9b4541aae117bdac5ed0b324c20539c27c07a411d5288b0b5f6fa16e9a7df85dc319fa6b71cd08a859c06a3f7b0289e1750adbf182f9750fea96fea5ab7aa3473340607cd7ed2c626f5382491c26d5d5bea61401dee7319c94d418f297e61ceac8f258ee8c23831bda081591f5a918e96855774ddedffc51e5b180f1971806d42fc333020b734aeb45adb0bc47325d0cea5f6713a786558022afc39d573892aa3635efbfd8bcb11c57f306c72146afe8b45388125cb7bf9ecf965a7ba4f768c77be366470dcdcf214b7f6a5a9460ed4fe44ae559d85e2fdc2094de83fff12ea8804db1215c4ca865871bdd7f8ef32ab799bf923ffb02c1ded7d129beadad46c5eda31ab1a6f43da05ea08bff7ffa88d8966353d01830558c39b930b01d175e437124d8edd0d2698fd8932f2b2c9b14746e52879c57a395538150f390264f00e60d470711202f4194499ff79037ca9885dc8d695f7d917a3086ca88e8f8d0243efee09302cf39e039eb7cc8dd19d28120d5fe533b5727cd39133181c729ca6f90a015ed30be7668d5cb5ecc33a53ee69bf7d1a5ecbdb153803743c6adaaabd36bf84e5be38d3f04a5d5dbfd67bdcd3b176e65bd1391ade775cc32ce43a847fb6c672a3fe97a5d4081c4986959ec5fb898f42a9397ba2b3ec2c1018f8d76d057f2366bd0e4465514ad6560c599664fb85621fe771e00f43d39b591b2a6a321100f4d1ef23a376d5ae3eeedbfe23da73dff0ee4d16b34ebddd8f5f053db9824105fc7300dbee7ea6af56b112319e3e215a0fc79ae946f6b5227453ec7fcaf17cf7651f71499a50d81221404d5f129ac50ea7528ff0e0069ec4ab8acb7919d81749ab37a870c5ef2cc5a15cf96709d3c65b4addc77e7416847160bcabb94ea36377e0ef71be80b5cc53effd5444888044a353574c72c924bba2a8b4e8354188ebfedc852f5
MAC = eb7cdceb97ade2a07622f8f5a4b1ce15
# Length 2052.
Key = 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
Input = 248ac31085b6c2adaaa38259a0d7192c5c35d1bb4ef39ad94c38d1c82479e2dd2159a077024b0589bc8a20101b506f0a1ad0bbab76e83a83f1b94be6beae74e874cab692c5963a75436b776121ec9f62399a3e66b2d22707dae81933b6277f3c8516bcbe26dbbd86f373103d7cf4cad1888c952118fbfbd0d7b4bedc4ae4936aff91157e7aa47c54442ea78d6ac251d324a0fbe49d89cc3521b66d16e9c66a3709894e4eb0a4eedc4ae19468e66b81f271351b1d921ea551047abcc6b87a901fde7db79fa1818c11336dbc07244a40eb14cf77bde35e78ae9ad7d3f57ed7e7f23926c9172f82d77684ea5ed7d74ebc6f142b997036bcb7cce8df1bbc0d5b35a46509c954fc9469d214d6238f166cbf872156b4c41d7aac5942cffb175023078252a3f36e315c5d4ce0e39928a018252862becacef96a19f03bdcf46d75584299d1f8b03c0169e9e407d937145b5e5024139e7022a1978f114f24cdfa23780a119735c41da8fb759bbb3f025c6ec30e6c6e9bce8615be68e392fce59fd26a8e6a6cc5c606e3848116e4d01d29565a1facfb524b6d29643b826eee1e42869fc76df229dd79b39a2b1df28bb335c3a5f15a855d0121e4a6da34b5e4d5b7b5d5746a03ecff70811e1516fcec1bf7462e8876a2d21710aa168c78f45a6a15015950e221da85d3ec822ad6d0a6931b25a06b7bb5f3c10bb36cd4d647f9561982fde9818de5d4bf8db7f86c53b4ff14928ac15f79023b61861e73e44216540bb302153770da2533de9795252ab5fb77ad924c9338c8144c23d4c90dab9a18feac1a1574d4545e1435eb405e6c4c439fc724fce992ae85badf345bad16d85fbd338f04433703614754d0e7e54c4ccde2670587d52ecfb5a70a14a501bacc727722649931d8515b13d020a78e511fe136d45fbf97f9c7f689fcc677cfb3683723878350ffe9d08130cc6e567b6179e01b7eb2b3bbcf0873e1308eec018edeb8cce946338e15d5bf68c71916a83a99358039ef071e009546a2df936879dffbba397a93925d229a469fd17d71b7f524e03a30da6ee927542f8b369bed4734fe25dbd63d24ffd2a222f5f84f75d858ab989be925af570ad6d45bd28ce61b5139e1dd2f0b7795fe072e6e83acbb5e7b777a70c641e4cab2af40eed69abc334cd2703c3273204fac580c6a3d6680427e5f7d051e8380a53f93a180f4556ecea4530b9a2d5948dad63d415b6874f6b90e767d6d265be86351b53ba690780bb57c21b57418c5b97559e840c68257f839e7583a4bf7c7645c5987d40cc1ba79a218c35edfacdabe581d950e4bb7a481ebe64d61d00e75b1f25f1ce5f5462334a5b9038a697aa0937a3f8017e05d2c9c05dcb05c0b02508dea619b137f5444b6f088eb3cb2c66788f88afdfbba8faa1c490485624c88ae11e57347a676902e7553f056188493209bdbb30acc63c9e41e16a9d6c009416b520a76ba38f57628170c43626b5cb46179dc5bf65de865085f84bf741c223fbe474d2d19d8f43914fbd6586351089e73babf344f988b7963fe44528457d7aad3c564f6bcbd0d772a4c9fd328e6022d1c7c9f86726f8d5a23797d309c0f653ab1ac687833eb2700f156296062a8b377078f45f6b68c3d07cae1913ba8d5a6f9bf7525a3439eb932d4cefc4bf8e1b07b48ca13ece366cbc3e0388915915d1757475103a9e9454e7e6355de2d6acbf4710f9a63e4f6d3cd70c2d6fca88dd8a14448fdb63ce9350fdaafbe0b8bd1c5d307dae76dfed799aef2d8f23d5608d37d1330dd38b94860905dbeebf78d7b7318b7d42aed40d3f9899e9f420cbd92a6eeae3026f7725694e0e4bee016ba346fed2c21172bdb4a461cebe0cfe38e76645226ac127a259c193264d735ce8c8a57e17dd3f0579e2e86dc295ad1f45ba2d85db35044da61f7d401274b31eefbeb34e8d2ae596e9b4541aae117bdac5ed0b324c20539c27c07a411d5288b0b5f6fa16e9a7df85dc319fa6b71cd08a859c06a3f7b0289e1750adbf182f9750fea96fea5ab7aa3473340607cd7ed2c626f5382491c26d5d5bea61401dee7319c94d418f297e61ceac8f258ee8c23831bda081591f5a918e96855774ddedffc51e5b180f1971806d42fc333020b734aeb45adb0bc47325d0cea5f6713a786558022afc39d573892aa3635efbfd8bcb11c57f306c72146afe8b45388125cb7bf9ecf965a7ba4f768c77be366470dcdcf214b7f6a5a9460ed4fe44ae559d85e2fdc2094de83fff12ea8804db1215c4ca865871bdd7f8ef32ab799bf923ffb02c1ded7d129beadad46c5eda31ab1a6f43da05ea08bff7ffa88d8966353d01830558c39b930b01d175e437124d8edd0d2698fd8932f2b2c9b14746e52879c57a395538150f390264f00e60d470711202f4194499ff79037ca9885dc8d695f7d917a3086ca88e8f8d0243efee09302cf39e039eb7cc8dd19d28120d5fe533b5727cd39133181c729ca6f90a015ed30be7668d5cb5ecc33a53ee69bf7d1a5ecbdb153803743c6adaaabd36bf84e5be38d3f04a5d5dbfd67bdcd3b176e65bd1391ade775cc32ce43a847fb6c672a3fe97a5d4081c4986959ec5fb898f42a9397ba2b3ec2c1018f8d76d057f2366bd0e4465514ad6560c599664fb85621fe771e00f43d39b591b2a6a321100f4d1ef23a376d5ae3eeedbfe23da73dff0ee4d16b34ebddd8f5f053db9824105fc7300dbee7ea6af56b112319e3e215a0fc79ae946f6b5227453ec7fcaf17cf7651f71499a50d81221404d5f129ac50ea7528ff0e0069ec4ab8acb7919d81749ab37a870c5ef2cc5a15cf96709d3c65b4addc77e7416847160bcabb94ea36377e0ef71be80b5cc53effd5444888044a353574c72c924bba2a8b4e8354188ebfedc852f590
MAC = d41c310927cd92e14784ea78b85503db
# Length 2053.
Key = 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
Input = 248ac31085b6c2adaaa38259a0d7192c5c35d1bb4ef39ad94c38d1c82479e2dd2159a077024b0589bc8a20101b506f0a1ad0bbab76e83a83f1b94be6beae74e874cab692c5963a75436b776121ec9f62399a3e66b2d22707dae81933b6277f3c8516bcbe26dbbd86f373103d7cf4cad1888c952118fbfbd0d7b4bedc4ae4936aff91157e7aa47c54442ea78d6ac251d324a0fbe49d89cc3521b66d16e9c66a3709894e4eb0a4eedc4ae19468e66b81f271351b1d921ea551047abcc6b87a901fde7db79fa1818c11336dbc07244a40eb14cf77bde35e78ae9ad7d3f57ed7e7f23926c9172f82d77684ea5ed7d74ebc6f142b997036bcb7cce8df1bbc0d5b35a46509c954fc9469d214d6238f166cbf872156b4c41d7aac5942cffb175023078252a3f36e315c5d4ce0e39928a018252862becacef96a19f03bdcf46d75584299d1f8b03c0169e9e407d937145b5e5024139e7022a1978f114f24cdfa23780a119735c41da8fb759bbb3f025c6ec30e6c6e9bce8615be68e392fce59fd26a8e6a6cc5c606e3848116e4d01d29565a1facfb524b6d29643b826eee1e42869fc76df229dd79b39a2b1df28bb335c3a5f15a855d0121e4a6da34b5e4d5b7b5d5746a03ecff70811e1516fcec1bf7462e8876a2d21710aa168c78f45a6a15015950e221da85d3ec822ad6d0a6931b25a06b7bb5f3c10bb36cd4d647f9561982fde9818de5d4bf8db7f86c53b4ff14928ac15f79023b61861e73e44216540bb302153770da2533de9795252ab5fb77ad924c9338c8144c23d4c90dab9a18feac1a1574d4545e1435eb405e6c4c439fc724fce992ae85badf345bad16d85fbd338f04433703614754d0e7e54c4ccde2670587d52ecfb5a70a14a501bacc727722649931d8515b13d020a78e511fe136d45fbf97f9c7f689fcc677cfb3683723878350ffe9d08130cc6e567b6179e01b7eb2b3bbcf0873e1308eec018edeb8cce946338e15d5bf68c71916a83a99358039ef071e009546a2df936879dffbba397a93925d229a469fd17d71b7f524e03a30da6ee927542f8b369bed4734fe25dbd63d24ffd2a222f5f84f75d858ab989be925af570ad6d45bd28ce61b5139e1dd2f0b7795fe072e6e83acbb5e7b777a70c641e4cab2af40eed69abc334cd2703c3273204fac580c6a3d6680427e5f7d051e8380a53f93a180f4556ecea4530b9a2d5948dad63d415b6874f6b90e767d6d265be86351b53ba690780bb57c21b57418c5b97559e840c68257f839e7583a4bf7c7645c5987d40cc1ba79a218c35edfacdabe581d950e4bb7a481ebe64d61d00e75b1f25f1ce5f5462334a5b9038a697aa0937a3f8017e05d2c9c05dcb05c0b02508dea619b137f5444b6f088eb3cb2c66788f88afdfbba8faa1c490485624c88ae11e57347a676902e7553f056188493209bdbb30acc63c9e41e16a9d6c009416b520a76ba38f57628170c43626b5cb46179dc5bf65de865085f84bf741c223fbe474d2d19d8f43914fbd6586351089e73babf344f988b7963fe44528457d7aad3c564f6bcbd0d772a4c9fd328e6022d1c7c9f86726f8d5a23797d309c0f653ab1ac687833eb2700f156296062a8b377078f45f6b68c3d07cae1913ba8d5a6f9bf7525a3439eb932d4cefc4bf8e1b07b48ca13ece366cbc3e0388915915d1757475103a9e9454e7e6355de2d6acbf4710f9a63e4f6d3cd70c2d6fca88dd8a14448fdb63ce9350fdaafbe0b8bd1c5d307dae76dfed799aef2d8f23d5608d37d1330dd38b94860905dbeebf78d7b7318b7d42aed40d3f9899e9f420cbd92a6eeae3026f7725694e0e4bee016ba346fed2c21172bdb4a461cebe0cfe38e76645226ac127a259c193264d735ce8c8a57e17dd3f0579e2e86dc295ad1f45ba2d85db35044da61f7d401274b31eefbeb34e8d2ae596e9b4541aae117bdac5ed0b324c20539c27c07a411d5288b0b5f6fa16e9a7df85dc319fa6b71cd08a859c06a3f7b0289e1750adbf182f9750fea96fea5ab7aa3473340607cd7ed2c626f5382491c26d5d5bea61401dee7319c94d418f297e61ceac8f258ee8c23831bda081591f5a918e96855774ddedffc51e5b180f1971806d42fc333020b734aeb45adb0bc47325d0cea5f6713a786558022afc39d573892aa3635efbfd8bcb11c57f306c72146afe8b45388125cb7bf9ecf965a7ba4f768c77be366470dcdcf214b7f6a5a9460ed4fe44ae559d85e2fdc2094de83fff12ea8804db1215c4ca865871bdd7f8ef32ab799bf923ffb02c1ded7d129beadad46c5eda31ab1a6f43da05ea08bff7ffa88d8966353d01830558c39b930b01d175e437124d8edd0d2698fd8932f2b2c9b14746e52879c57a395538150f390264f00e60d470711202f4194499ff79037ca9885dc8d695f7d917a3086ca88e8f8d0243efee09302cf39e039eb7cc8dd19d28120d5fe533b5727cd39133181c729ca6f90a015ed30be7668d5cb5ecc33a53ee69bf7d1a5ecbdb153803743c6adaaabd36bf84e5be38d3f04a5d5dbfd67bdcd3b176e65bd1391ade775cc32ce43a847fb6c672a3fe97a5d4081c4986959ec5fb898f42a9397ba2b3ec2c1018f8d76d057f2366bd0e4465514ad6560c599664fb85621fe771e00f43d39b591b2a6a321100f4d1ef23a376d5ae3eeedbfe23da73dff0ee4d16b34ebddd8f5f053db9824105fc7300dbee7ea6af56b112319e3e215a0fc79ae946f6b5227453ec7fcaf17cf7651f71499a50d81221404d5f129ac50ea7528ff0e0069ec4ab8acb7919d81749ab37a870c5ef2cc5a15cf96709d3c65b4addc77e7416847160bcabb94ea36377e0ef71be80b5cc53effd5444888044a353574c72c924bba2a8b4e8354188ebfedc852f59073
MAC = 16af133c423f783a14c49d9f526384cf
# Length 2054.
Key = 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
Input = 248ac31085b6c2adaaa38259a0d7192c5c35d1bb4ef39ad94c38d1c82479e2dd2159a077024b0589bc8a20101b506f0a1ad0bbab76e83a83f1b94be6beae74e874cab692c5963a75436b776121ec9f62399a3e66b2d22707dae81933b6277f3c8516bcbe26dbbd86f373103d7cf4cad1888c952118fbfbd0d7b4bedc4ae4936aff91157e7aa47c54442ea78d6ac251d324a0fbe49d89cc3521b66d16e9c66a3709894e4eb0a4eedc4ae19468e66b81f271351b1d921ea551047abcc6b87a901fde7db79fa1818c11336dbc07244a40eb14cf77bde35e78ae9ad7d3f57ed7e7f23926c9172f82d77684ea5ed7d74ebc6f142b997036bcb7cce8df1bbc0d5b35a46509c954fc9469d214d6238f166cbf872156b4c41d7aac5942cffb175023078252a3f36e315c5d4ce0e39928a018252862becacef96a19f03bdcf46d75584299d1f8b03c0169e9e407d937145b5e5024139e7022a1978f114f24cdfa23780a119735c41da8fb759bbb3f025c6ec30e6c6e9bce8615be68e392fce59fd26a8e6a6cc5c606e3848116e4d01d29565a1facfb524b6d29643b826eee1e42869fc76df229dd79b39a2b1df28bb335c3a5f15a855d0121e4a6da34b5e4d5b7b5d5746a03ecff70811e1516fcec1bf7462e8876a2d21710aa168c78f45a6a15015950e221da85d3ec822ad6d0a6931b25a06b7bb5f3c10bb36cd4d647f9561982fde9818de5d4bf8db7f86c53b4ff14928ac15f79023b61861e73e44216540bb302153770da2533de9795252ab5fb77ad924c9338c8144c23d4c90dab9a18feac1a1574d4545e1435eb405e6c4c439fc724fce992ae85badf345bad16d85fbd338f04433703614754d0e7e54c4ccde2670587d52ecfb5a70a14a501bacc727722649931d8515b13d020a78e511fe136d45fbf97f9c7f689fcc677cfb3683723878350ffe9d08130cc6e567b6179e01b7eb2b3bbcf0873e1308eec018edeb8cce946338e15d5bf68c71916a83a99358039ef071e009546a2df936879dffbba397a93925d229a469fd17d71b7f524e03a30da6ee927542f8b369bed4734fe25dbd63d24ffd2a222f5f84f75d858ab989be925af570ad6d45bd28ce61b5139e1dd2f0b7795fe072e6e83acbb5e7b777a70c641e4cab2af40eed69abc334cd2703c3273204fac580c6a3d6680427e5f7d051e8380a53f93a180f4556ecea4530b9a2d5948dad63d415b6874f6b90e767d6d265be86351b53ba690780bb57c21b57418c5b97559e840c68257f839e7583a4bf7c7645c5987d40cc1ba79a218c35edfacdabe581d950e4bb7a481ebe64d61d00e75b1f25f1ce5f5462334a5b9038a697aa0937a3f8017e05d2c9c05dcb05c0b02508dea619b137f5444b6f088eb3cb2c66788f88afdfbba8faa1c490485624c88ae11e57347a676902e7553f056188493209bdbb30acc63c9e41e16a9d6c009416b520a76ba38f57628170c43626b5cb46179dc5bf65de865085f84bf741c223fbe474d2d19d8f43914fbd6586351089e73babf344f988b7963fe44528457d7aad3c564f6bcbd0d772a4c9fd328e6022d1c7c9f86726f8d5a23797d309c0f653ab1ac687833eb2700f156296062a8b377078f45f6b68c3d07cae1913ba8d5a6f9bf7525a3439eb932d4cefc4bf8e1b07b48ca13ece366cbc3e0388915915d1757475103a9e9454e7e6355de2d6acbf4710f9a63e4f6d3cd70c2d6fca88dd8a14448fdb63ce9350fdaafbe0b8bd1c5d307dae76dfed799aef2d8f23d5608d37d1330dd38b94860905dbeebf78d7b7318b7d42aed40d3f9899e9f420cbd92a6eeae3026f7725694e0e4bee016ba346fed2c21172bdb4a461cebe0cfe38e76645226ac127a259c193264d735ce8c8a57e17dd3f0579e2e86dc295ad1f45ba2d85db35044da61f7d401274b31eefbeb34e8d2ae596e9b4541aae117bdac5ed0b324c20539c27c07a411d5288b0b5f6fa16e9a7df85dc319fa6b71cd08a859c06a3f7b0289e1750adbf182f9750fea96fea5ab7aa3473340607cd7ed2c626f5382491c26d5d5bea61401dee7319c94d418f297e61ceac8f258ee8c23831bda081591f5a918e96855774ddedffc51e5b180f1971806d42fc333020b734aeb45adb0bc47325d0cea5f6713a786558022afc39d573892aa3635efbfd8bcb11c57f306c72146afe8b45388125cb7bf9ecf965a7ba4f768c77be366470dcdcf214b7f6a5a9460ed4fe44ae559d85e2fdc2094de83fff12ea8804db1215c4ca865871bdd7f8ef32ab799bf923ffb02c1ded7d129beadad46c5eda31ab1a6f43da05ea08bff7ffa88d8966353d01830558c39b930b01d175e437124d8edd0d2698fd8932f2b2c9b14746e52879c57a395538150f390264f00e60d470711202f4194499ff79037ca9885dc8d695f7d917a3086ca88e8f8d0243efee09302cf39e039eb7cc8dd19d28120d5fe533b5727cd39133181c729ca6f90a015ed30be7668d5cb5ecc33a53ee69bf7d1a5ecbdb153803743c6adaaabd36bf84e5be38d3f04a5d5dbfd67bdcd3b176e65bd1391ade775cc32ce43a847fb6c672a3fe97a5d4081c4986959ec5fb898f42a9397ba2b3ec2c1018f8d76d057f2366bd0e4465514ad6560c599664fb85621fe771e00f43d39b591b2a6a321100f4d1ef23a376d5ae3eeedbfe23da73dff0ee4d16b34ebddd8f5f053db9824105fc7300dbee7ea6af56b112319e3e215a0fc79ae946f6b5227453ec7fcaf17cf7651f71499a50d81221404d5f129ac50ea7528ff0e0069ec4ab8acb7919d81749ab37a870c5ef2cc5a15cf96709d3c65b4addc77e7416847160bcabb94ea36377e0ef71be80b5cc53effd5444888044a353574c72c924bba2a8b4e8354188ebfedc852f59073f4
MAC = 00c75db8f0636b22f195645b03091f5f
# Length 2055.
Key = 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
Input = 248ac31085b6c2adaaa38259a0d7192c5c35d1bb4ef39ad94c38d1c82479e2dd2159a077024b0589bc8a20101b506f0a1ad0bbab76e83a83f1b94be6beae74e874cab692c5963a75436b776121ec9f62399a3e66b2d22707dae81933b6277f3c8516bcbe26dbbd86f373103d7cf4cad1888c952118fbfbd0d7b4bedc4ae4936aff91157e7aa47c54442ea78d6ac251d324a0fbe49d89cc3521b66d16e9c66a3709894e4eb0a4eedc4ae19468e66b81f271351b1d921ea551047abcc6b87a901fde7db79fa1818c11336dbc07244a40eb14cf77bde35e78ae9ad7d3f57ed7e7f23926c9172f82d77684ea5ed7d74ebc6f142b997036bcb7cce8df1bbc0d5b35a46509c954fc9469d214d6238f166cbf872156b4c41d7aac5942cffb175023078252a3f36e315c5d4ce0e39928a018252862becacef96a19f03bdcf46d75584299d1f8b03c0169e9e407d937145b5e5024139e7022a1978f114f24cdfa23780a119735c41da8fb759bbb3f025c6ec30e6c6e9bce8615be68e392fce59fd26a8e6a6cc5c606e3848116e4d01d29565a1facfb524b6d29643b826eee1e42869fc76df229dd79b39a2b1df28bb335c3a5f15a855d0121e4a6da34b5e4d5b7b5d5746a03ecff70811e1516fcec1bf7462e8876a2d21710aa168c78f45a6a15015950e221da85d3ec822ad6d0a6931b25a06b7bb5f3c10bb36cd4d647f9561982fde9818de5d4bf8db7f86c53b4ff14928ac15f79023b61861e73e44216540bb302153770da2533de9795252ab5fb77ad924c9338c8144c23d4c90dab9a18feac1a1574d4545e1435eb405e6c4c439fc724fce992ae85badf345bad16d85fbd338f04433703614754d0e7e54c4ccde2670587d52ecfb5a70a14a501bacc727722649931d8515b13d020a78e511fe136d45fbf97f9c7f689fcc677cfb3683723878350ffe9d08130cc6e567b6179e01b7eb2b3bbcf0873e1308eec018edeb8cce946338e15d5bf68c71916a83a99358039ef071e009546a2df936879dffbba397a93925d229a469fd17d71b7f524e03a30da6ee927542f8b369bed4734fe25dbd63d24ffd2a222f5f84f75d858ab989be925af570ad6d45bd28ce61b5139e1dd2f0b7795fe072e6e83acbb5e7b777a70c641e4cab2af40eed69abc334cd2703c3273204fac580c6a3d6680427e5f7d051e8380a53f93a180f4556ecea4530b9a2d5948dad63d415b6874f6b90e767d6d265be86351b53ba690780bb57c21b57418c5b97559e840c68257f839e7583a4bf7c7645c5987d40cc1ba79a218c35edfacdabe581d950e4bb7a481ebe64d61d00e75b1f25f1ce5f5462334a5b9038a697aa0937a3f8017e05d2c9c05dcb05c0b02508dea619b137f5444b6f088eb3cb2c66788f88afdfbba8faa1c490485624c88ae11e57347a676902e7553f056188493209bdbb30acc63c9e41e16a9d6c009416b520a76ba38f57628170c43626b5cb46179dc5bf65de865085f84bf741c223fbe474d2d19d8f43914fbd6586351089e73babf344f988b7963fe44528457d7aad3c564f6bcbd0d772a4c9fd328e6022d1c7c9f86726f8d5a23797d309c0f653ab1ac687833eb2700f156296062a8b377078f45f6b68c3d07cae1913ba8d5a6f9bf7525a3439eb932d4cefc4bf8e1b07b48ca13ece366cbc3e0388915915d1757475103a9e9454e7e6355de2d6acbf4710f9a63e4f6d3cd70c2d6fca88dd8a14448fdb63ce9350fdaafbe0b8bd1c5d307dae76dfed799aef2d8f23d5608d37d1330dd38b94860905dbeebf78d7b7318b7d42aed40d3f9899e9f420cbd92a6eeae3026f7725694e0e4bee016ba346fed2c21172bdb4a461cebe0cfe38e76645226ac127a259c193264d735ce8c8a57e17dd3f0579e2e86dc295ad1f45ba2d85db35044da61f7d401274b31eefbeb34e8d2ae596e9b4541aae117bdac5ed0b324c20539c27c07a411d5288b0b5f6fa16e9a7df85dc319fa6b71cd08a859c06a3f7b0289e1750adbf182f9750fea96fea5ab7aa3473340607cd7ed2c626f5382491c26d5d5bea61401dee7319c94d418f297e61ceac8f258ee8c23831bda081591f5a918e96855774ddedffc51e5b180f1971806d42fc333020b734aeb45adb0bc47325d0cea5f6713a786558022afc39d573892aa3635efbfd8bcb11c57f306c72146afe8b45388125cb7bf9ecf965a7ba4f768c77be366470dcdcf214b7f6a5a9460ed4fe44ae559d85e2fdc2094de83fff12ea8804db1215c4ca865871bdd7f8ef32ab799bf923ffb02c1ded7d129beadad46c5eda31ab1a6f43da05ea08bff7ffa88d8966353d01830558c39b930b01d175e437124d8edd0d2698fd8932f2b2c9b14746e52879c57a395538150f390264f00e60d470711202f4194499ff79037ca9885dc8d695f7d917a3086ca88e8f8d0243efee09302cf39e039eb7cc8dd19d28120d5fe533b5727cd39133181c729ca6f90a015ed30be7668d5cb5ecc33a53ee69bf7d1a5ecbdb153803743c6adaaabd36bf84e5be38d3f04a5d5dbfd67bdcd3b176e65bd1391ade775cc32ce43a847fb6c672a3fe97a5d4081c4986959ec5fb898f42a9397ba2b3ec2c1018f8d76d057f2366bd0e4465514ad6560c599664fb85621fe771e00f43d39b591b2a6a321100f4d1ef23a376d5ae3eeedbfe23da73dff0ee4d16b34ebddd8f5f053db9824105fc7300dbee7ea6af56b112319e3e215a0fc79ae946f6b5227453ec7fcaf17cf7651f71499a50d81221404d5f129ac50ea7528ff0e0069ec4ab8acb7919d81749ab37a870c5ef2cc5a15cf96709d3c65b4addc77e7416847160bcabb94ea36377e0ef71be80b5cc53effd5444888044a353574c72c924bba2a8b4e8354188ebfedc852f59073f434
MAC = 4a532bc740f581555831345f3b75bf33
# Length 2056.
Key = 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
Input = 248ac31085b6c2adaaa38259a0d7192c5c35d1bb4ef39ad94c38d1c82479e2dd2159a077024b0589bc8a20101b506f0a1ad0bbab76e83a83f1b94be6beae74e874cab692c5963a75436b776121ec9f62399a3e66b2d22707dae81933b6277f3c8516bcbe26dbbd86f373103d7cf4cad1888c952118fbfbd0d7b4bedc4ae4936aff91157e7aa47c54442ea78d6ac251d324a0fbe49d89cc3521b66d16e9c66a3709894e4eb0a4eedc4ae19468e66b81f271351b1d921ea551047abcc6b87a901fde7db79fa1818c11336dbc07244a40eb14cf77bde35e78ae9ad7d3f57ed7e7f23926c9172f82d77684ea5ed7d74ebc6f142b997036bcb7cce8df1bbc0d5b35a46509c954fc9469d214d6238f166cbf872156b4c41d7aac5942cffb175023078252a3f36e315c5d4ce0e39928a018252862becacef96a19f03bdcf46d75584299d1f8b03c0169e9e407d937145b5e5024139e7022a1978f114f24cdfa23780a119735c41da8fb759bbb3f025c6ec30e6c6e9bce8615be68e392fce59fd26a8e6a6cc5c606e3848116e4d01d29565a1facfb524b6d29643b826eee1e42869fc76df229dd79b39a2b1df28bb335c3a5f15a855d0121e4a6da34b5e4d5b7b5d5746a03ecff70811e1516fcec1bf7462e8876a2d21710aa168c78f45a6a15015950e221da85d3ec822ad6d0a6931b25a06b7bb5f3c10bb36cd4d647f9561982fde9818de5d4bf8db7f86c53b4ff14928ac15f79023b61861e73e44216540bb302153770da2533de9795252ab5fb77ad924c9338c8144c23d4c90dab9a18feac1a1574d4545e1435eb405e6c4c439fc724fce992ae85badf345bad16d85fbd338f04433703614754d0e7e54c4ccde2670587d52ecfb5a70a14a501bacc727722649931d8515b13d020a78e511fe136d45fbf97f9c7f689fcc677cfb3683723878350ffe9d08130cc6e567b6179e01b7eb2b3bbcf0873e1308eec018edeb8cce946338e15d5bf68c71916a83a99358039ef071e009546a2df936879dffbba397a93925d229a469fd17d71b7f524e03a30da6ee927542f8b369bed4734fe25dbd63d24ffd2a222f5f84f75d858ab989be925af570ad6d45bd28ce61b5139e1dd2f0b7795fe072e6e83acbb5e7b777a70c641e4cab2af40eed69abc334cd2703c3273204fac580c6a3d6680427e5f7d051e8380a53f93a180f4556ecea4530b9a2d5948dad63d415b6874f6b90e767d6d265be86351b53ba690780bb57c21b57418c5b97559e840c68257f839e7583a4bf7c7645c5987d40cc1ba79a218c35edfacdabe581d950e4bb7a481ebe64d61d00e75b1f25f1ce5f5462334a5b9038a697aa0937a3f8017e05d2c9c05dcb05c0b02508dea619b137f5444b6f088eb3cb2c66788f88afdfbba8faa1c490485624c88ae11e57347a676902e7553f056188493209bdbb30acc63c9e41e16a9d6c009416b520a76ba38f57628170c43626b5cb46179dc5bf65de865085f84bf741c223fbe474d2d19d8f43914fbd6586351089e73babf344f988b7963fe44528457d7aad3c564f6bcbd0d772a4c9fd328e6022d1c7c9f86726f8d5a23797d309c0f653ab1ac687833eb2700f156296062a8b377078f45f6b68c3d07cae1913ba8d5a6f9bf7525a3439eb932d4cefc4bf8e1b07b48ca13ece366cbc3e0388915915d1757475103a9e9454e7e6355de2d6acbf4710f9a63e4f6d3cd70c2d6fca88dd8a14448fdb63ce9350fdaafbe0b8bd1c5d307dae76dfed799aef2d8f23d5608d37d1330dd38b94860905dbeebf78d7b7318b7d42aed40d3f9899e9f420cbd92a6eeae3026f7725694e0e4bee016ba346fed2c21172bdb4a461cebe0cfe38e76645226ac127a259c193264d735ce8c8a57e17dd3f0579e2e86dc295ad1f45ba2d85db35044da61f7d401274b31eefbeb34e8d2ae596e9b4541aae117bdac5ed0b324c20539c27c07a411d5288b0b5f6fa16e9a7df85dc319fa6b71cd08a859c06a3f7b0289e1750adbf182f9750fea96fea5ab7aa3473340607cd7ed2c626f5382491c26d5d5bea61401dee7319c94d418f297e61ceac8f258ee8c23831bda081591f5a918e96855774ddedffc51e5b180f1971806d42fc333020b734aeb45adb0bc47325d0cea5f6713a786558022afc39d573892aa3635efbfd8bcb11c57f306c72146afe8b45388125cb7bf9ecf965a7ba4f768c77be366470dcdcf214b7f6a5a9460ed4fe44ae559d85e2fdc2094de83fff12ea8804db1215c4ca865871bdd7f8ef32ab799bf923ffb02c1ded7d129beadad46c5eda31ab1a6f43da05ea08bff7ffa88d8966353d01830558c39b930b01d175e437124d8edd0d2698fd8932f2b2c9b14746e52879c57a395538150f390264f00e60d470711202f4194499ff79037ca9885dc8d695f7d917a3086ca88e8f8d0243efee09302cf39e039eb7cc8dd19d28120d5fe533b5727cd39133181c729ca6f90a015ed30be7668d5cb5ecc33a53ee69bf7d1a5ecbdb153803743c6adaaabd36bf84e5be38d3f04a5d5dbfd67bdcd3b176e65bd1391ade775cc32ce43a847fb6c672a3fe97a5d4081c4986959ec5fb898f42a9397ba2b3ec2c1018f8d76d057f2366bd0e4465514ad6560c599664fb85621fe771e00f43d39b591b2a6a321100f4d1ef23a376d5ae3eeedbfe23da73dff0ee4d16b34ebddd8f5f053db9824105fc7300dbee7ea6af56b112319e3e215a0fc79ae946f6b5227453ec7fcaf17cf7651f71499a50d81221404d5f129ac50ea7528ff0e0069ec4ab8acb7919d81749ab37a870c5ef2cc5a15cf96709d3c65b4addc77e7416847160bcabb94ea36377e0ef71be80b5cc53effd5444888044a353574c72c924bba2a8b4e8354188ebfedc852f59073f4347a
MAC = 698c7d32c5923871d124a2479e521706
# Length 2057.
Key = 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
Input = 248ac31085b6c2adaaa38259a0d7192c5c35d1bb4ef39ad94c38d1c82479e2dd2159a077024b0589bc8a20101b506f0a1ad0bbab76e83a83f1b94be6beae74e874cab692c5963a75436b776121ec9f62399a3e66b2d22707dae81933b6277f3c8516bcbe26dbbd86f373103d7cf4cad1888c952118fbfbd0d7b4bedc4ae4936aff91157e7aa47c54442ea78d6ac251d324a0fbe49d89cc3521b66d16e9c66a3709894e4eb0a4eedc4ae19468e66b81f271351b1d921ea551047abcc6b87a901fde7db79fa1818c11336dbc07244a40eb14cf77bde35e78ae9ad7d3f57ed7e7f23926c9172f82d77684ea5ed7d74ebc6f142b997036bcb7cce8df1bbc0d5b35a46509c954fc9469d214d6238f166cbf872156b4c41d7aac5942cffb175023078252a3f36e315c5d4ce0e39928a018252862becacef96a19f03bdcf46d75584299d1f8b03c0169e9e407d937145b5e5024139e7022a1978f114f24cdfa23780a119735c41da8fb759bbb3f025c6ec30e6c6e9bce8615be68e392fce59fd26a8e6a6cc5c606e3848116e4d01d29565a1facfb524b6d29643b826eee1e42869fc76df229dd79b39a2b1df28bb335c3a5f15a855d0121e4a6da34b5e4d5b7b5d5746a03ecff70811e1516fcec1bf7462e8876a2d21710aa168c78f45a6a15015950e221da85d3ec822ad6d0a6931b25a06b7bb5f3c10bb36cd4d647f9561982fde9818de5d4bf8db7f86c53b4ff14928ac15f79023b61861e73e44216540bb302153770da2533de9795252ab5fb77ad924c9338c8144c23d4c90dab9a18feac1a1574d4545e1435eb405e6c4c439fc724fce992ae85badf345bad16d85fbd338f04433703614754d0e7e54c4ccde2670587d52ecfb5a70a14a501bacc727722649931d8515b13d020a78e511fe136d45fbf97f9c7f689fcc677cfb3683723878350ffe9d08130cc6e567b6179e01b7eb2b3bbcf0873e1308eec018edeb8cce946338e15d5bf68c71916a83a99358039ef071e009546a2df936879dffbba397a93925d229a469fd17d71b7f524e03a30da6ee927542f8b369bed4734fe25dbd63d24ffd2a222f5f84f75d858ab989be925af570ad6d45bd28ce61b5139e1dd2f0b7795fe072e6e83acbb5e7b777a70c641e4cab2af40eed69abc334cd2703c3273204fac580c6a3d6680427e5f7d051e8380a53f93a180f4556ecea4530b9a2d5948dad63d415b6874f6b90e767d6d265be86351b53ba690780bb57c21b57418c5b97559e840c68257f839e7583a4bf7c7645c5987d40cc1ba79a218c35edfacdabe581d950e4bb7a481ebe64d61d00e75b1f25f1ce5f5462334a5b9038a697aa0937a3f8017e05d2c9c05dcb05c0b02508dea619b137f5444b6f088eb3cb2c66788f88afdfbba8faa1c490485624c88ae11e57347a676902e7553f056188493209bdbb30acc63c9e41e16a9d6c009416b520a76ba38f57628170c43626b5cb46179dc5bf65de865085f84bf741c223fbe474d2d19d8f43914fbd6586351089e73babf344f988b7963fe44528457d7aad3c564f6bcbd0d772a4c9fd328e6022d1c7c9f86726f8d5a23797d309c0f653ab1ac687833eb2700f156296062a8b377078f45f6b68c3d07cae1913ba8d5a6f9bf7525a3439eb932d4cefc4bf8e1b07b48ca13ece366cbc3e0388915915d1757475103a9e9454e7e6355de2d6acbf4710f9a63e4f6d3cd70c2d6fca88dd8a14448fdb63ce9350fdaafbe0b8bd1c5d307dae76dfed799aef2d8f23d5608d37d1330dd38b94860905dbeebf78d7b7318b7d42aed40d3f9899e9f420cbd92a6eeae3026f7725694e0e4bee016ba346fed2c21172bdb4a461cebe0cfe38e76645226ac127a259c193264d735ce8c8a57e17dd3f0579e2e86dc295ad1f45ba2d85db35044da61f7d401274b31eefbeb34e8d2ae596e9b4541aae117bdac5ed0b324c20539c27c07a411d5288b0b5f6fa16e9a7df85dc319fa6b71cd08a859c06a3f7b0289e1750adbf182f9750fea96fea5ab7aa3473340607cd7ed2c626f5382491c26d5d5bea61401dee7319c94d418f297e61ceac8f258ee8c23831bda081591f5a918e96855774ddedffc51e5b180f1971806d42fc333020b734aeb45adb0bc47325d0cea5f6713a786558022afc39d573892aa3635efbfd8bcb11c57f306c72146afe8b45388125cb7bf9ecf965a7ba4f768c77be366470dcdcf214b7f6a5a9460ed4fe44ae559d85e2fdc2094de83fff12ea8804db1215c4ca865871bdd7f8ef32ab799bf923ffb02c1ded7d129beadad46c5eda31ab1a6f43da05ea08bff7ffa88d8966353d01830558c39b930b01d175e437124d8edd0d2698fd8932f2b2c9b14746e52879c57a395538150f390264f00e60d470711202f4194499ff79037ca9885dc8d695f7d917a3086ca88e8f8d0243efee09302cf39e039eb7cc8dd19d28120d5fe533b5727cd39133181c729ca6f90a015ed30be7668d5cb5ecc33a53ee69bf7d1a5ecbdb153803743c6adaaabd36bf84e5be38d3f04a5d5dbfd67bdcd3b176e65bd1391ade775cc32ce43a847fb6c672a3fe97a5d4081c4986959ec5fb898f42a9397ba2b3ec2c1018f8d76d057f2366bd0e4465514ad6560c599664fb85621fe771e00f43d39b591b2a6a321100f4d1ef23a376d5ae3eeedbfe23da73dff0ee4d16b34ebddd8f5f053db9824105fc7300dbee7ea6af56b112319e3e215a0fc79ae946f6b5227453ec7fcaf17cf7651f71499a50d81221404d5f129ac50ea7528ff0e0069ec4ab8acb7919d81749ab37a870c5ef2cc5a15cf96709d3c65b4addc77e7416847160bcabb94ea36377e0ef71be80b5cc53effd5444888044a353574c72c924bba2a8b4e8354188ebfedc852f59073f4347a8c
MAC = a677187dbf3c927aeeafb9ebce0f61dc
# Length 2058.
Key = 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
Input = 248ac31085b6c2adaaa38259a0d7192c5c35d1bb4ef39ad94c38d1c82479e2dd2159a077024b0589bc8a20101b506f0a1ad0bbab76e83a83f1b94be6beae74e874cab692c5963a75436b776121ec9f62399a3e66b2d22707dae81933b6277f3c8516bcbe26dbbd86f373103d7cf4cad1888c952118fbfbd0d7b4bedc4ae4936aff91157e7aa47c54442ea78d6ac251d324a0fbe49d89cc3521b66d16e9c66a3709894e4eb0a4eedc4ae19468e66b81f271351b1d921ea551047abcc6b87a901fde7db79fa1818c11336dbc07244a40eb14cf77bde35e78ae9ad7d3f57ed7e7f23926c9172f82d77684ea5ed7d74ebc6f142b997036bcb7cce8df1bbc0d5b35a46509c954fc9469d214d6238f166cbf872156b4c41d7aac5942cffb175023078252a3f36e315c5d4ce0e39928a018252862becacef96a19f03bdcf46d75584299d1f8b03c0169e9e407d937145b5e5024139e7022a1978f114f24cdfa23780a119735c41da8fb759bbb3f025c6ec30e6c6e9bce8615be68e392fce59fd26a8e6a6cc5c606e3848116e4d01d29565a1facfb524b6d29643b826eee1e42869fc76df229dd79b39a2b1df28bb335c3a5f15a855d0121e4a6da34b5e4d5b7b5d5746a03ecff70811e1516fcec1bf7462e8876a2d21710aa168c78f45a6a15015950e221da85d3ec822ad6d0a6931b25a06b7bb5f3c10bb36cd4d647f9561982fde9818de5d4bf8db7f86c53b4ff14928ac15f79023b61861e73e44216540bb302153770da2533de9795252ab5fb77ad924c9338c8144c23d4c90dab9a18feac1a1574d4545e1435eb405e6c4c439fc724fce992ae85badf345bad16d85fbd338f04433703614754d0e7e54c4ccde2670587d52ecfb5a70a14a501bacc727722649931d8515b13d020a78e511fe136d45fbf97f9c7f689fcc677cfb3683723878350ffe9d08130cc6e567b6179e01b7eb2b3bbcf0873e1308eec018edeb8cce946338e15d5bf68c71916a83a99358039ef071e009546a2df936879dffbba397a93925d229a469fd17d71b7f524e03a30da6ee927542f8b369bed4734fe25dbd63d24ffd2a222f5f84f75d858ab989be925af570ad6d45bd28ce61b5139e1dd2f0b7795fe072e6e83acbb5e7b777a70c641e4cab2af40eed69abc334cd2703c3273204fac580c6a3d6680427e5f7d051e8380a53f93a180f4556ecea4530b9a2d5948dad63d415b6874f6b90e767d6d265be86351b53ba690780bb57c21b57418c5b97559e840c68257f839e7583a4bf7c7645c5987d40cc1ba79a218c35edfacdabe581d950e4bb7a481ebe64d61d00e75b1f25f1ce5f5462334a5b9038a697aa0937a3f8017e05d2c9c05dcb05c0b02508dea619b137f5444b6f088eb3cb2c66788f88afdfbba8faa1c490485624c88ae11e57347a676902e7553f056188493209bdbb30acc63c9e41e16a9d6c009416b520a76ba38f57628170c43626b5cb46179dc5bf65de865085f84bf741c223fbe474d2d19d8f43914fbd6586351089e73babf344f988b7963fe44528457d7aad3c564f6bcbd0d772a4c9fd328e6022d1c7c9f86726f8d5a23797d309c0f653ab1ac687833eb2700f156296062a8b377078f45f6b68c3d07cae1913ba8d5a6f9bf7525a3439eb932d4cefc4bf8e1b07b48ca13ece366cbc3e0388915915d1757475103a9e9454e7e6355de2d6acbf4710f9a63e4f6d3cd70c2d6fca88dd8a14448fdb63ce9350fdaafbe0b8bd1c5d307dae76dfed799aef2d8f23d5608d37d1330dd38b94860905dbeebf78d7b7318b7d42aed40d3f9899e9f420cbd92a6eeae3026f7725694e0e4bee016ba346fed2c21172bdb4a461cebe0cfe38e76645226ac127a259c193264d735ce8c8a57e17dd3f0579e2e86dc295ad1f45ba2d85db35044da61f7d401274b31eefbeb34e8d2ae596e9b4541aae117bdac5ed0b324c20539c27c07a411d5288b0b5f6fa16e9a7df85dc319fa6b71cd08a859c06a3f7b0289e1750adbf182f9750fea96fea5ab7aa3473340607cd7ed2c626f5382491c26d5d5bea61401dee7319c94d418f297e61ceac8f258ee8c23831bda081591f5a918e96855774ddedffc51e5b180f1971806d42fc333020b734aeb45adb0bc47325d0cea5f6713a786558022afc39d573892aa3635efbfd8bcb11c57f306c72146afe8b45388125cb7bf9ecf965a7ba4f768c77be366470dcdcf214b7f6a5a9460ed4fe44ae559d85e2fdc2094de83fff12ea8804db1215c4ca865871bdd7f8ef32ab799bf923ffb02c1ded7d129beadad46c5eda31ab1a6f43da05ea08bff7ffa88d8966353d01830558c39b930b01d175e437124d8edd0d2698fd8932f2b2c9b14746e52879c57a395538150f390264f00e60d470711202f4194499ff79037ca9885dc8d695f7d917a3086ca88e8f8d0243efee09302cf39e039eb7cc8dd19d28120d5fe533b5727cd39133181c729ca6f90a015ed30be7668d5cb5ecc33a53ee69bf7d1a5ecbdb153803743c6adaaabd36bf84e5be38d3f04a5d5dbfd67bdcd3b176e65bd1391ade775cc32ce43a847fb6c672a3fe97a5d4081c4986959ec5fb898f42a9397ba2b3ec2c1018f8d76d057f2366bd0e4465514ad6560c599664fb85621fe771e00f43d39b591b2a6a321100f4d1ef23a376d5ae3eeedbfe23da73dff0ee4d16b34ebddd8f5f053db9824105fc7300dbee7ea6af56b112319e3e215a0fc79ae946f6b5227453ec7fcaf17cf7651f71499a50d81221404d5f129ac50ea7528ff0e0069ec4ab8acb7919d81749ab37a870c5ef2cc5a15cf96709d3c65b4addc77e7416847160bcabb94ea36377e0ef71be80b5cc53effd5444888044a353574c72c924bba2a8b4e8354188ebfedc852f59073f4347a8c8a
MAC = 201fed7eee981b31d2cc42ff6c38141a
# Length 2059.
Key = 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
Input = 248ac31085b6c2adaaa38259a0d7192c5c35d1bb4ef39ad94c38d1c82479e2dd2159a077024b0589bc8a20101b506f0a1ad0bbab76e83a83f1b94be6beae74e874cab692c5963a75436b776121ec9f62399a3e66b2d22707dae81933b6277f3c8516bcbe26dbbd86f373103d7cf4cad1888c952118fbfbd0d7b4bedc4ae4936aff91157e7aa47c54442ea78d6ac251d324a0fbe49d89cc3521b66d16e9c66a3709894e4eb0a4eedc4ae19468e66b81f271351b1d921ea551047abcc6b87a901fde7db79fa1818c11336dbc07244a40eb14cf77bde35e78ae9ad7d3f57ed7e7f23926c9172f82d77684ea5ed7d74ebc6f142b997036bcb7cce8df1bbc0d5b35a46509c954fc9469d214d6238f166cbf872156b4c41d7aac5942cffb175023078252a3f36e315c5d4ce0e39928a018252862becacef96a19f03bdcf46d75584299d1f8b03c0169e9e407d937145b5e5024139e7022a1978f114f24cdfa23780a119735c41da8fb759bbb3f025c6ec30e6c6e9bce8615be68e392fce59fd26a8e6a6cc5c606e3848116e4d01d29565a1facfb524b6d29643b826eee1e42869fc76df229dd79b39a2b1df28bb335c3a5f15a855d0121e4a6da34b5e4d5b7b5d5746a03ecff70811e1516fcec1bf7462e8876a2d21710aa168c78f45a6a15015950e221da85d3ec822ad6d0a6931b25a06b7bb5f3c10bb36cd4d647f9561982fde9818de5d4bf8db7f86c53b4ff14928ac15f79023b61861e73e44216540bb302153770da2533de9795252ab5fb77ad924c9338c8144c23d4c90dab9a18feac1a1574d4545e1435eb405e6c4c439fc724fce992ae85badf345bad16d85fbd338f04433703614754d0e7e54c4ccde2670587d52ecfb5a70a14a501bacc727722649931d8515b13d020a78e511fe136d45fbf97f9c7f689fcc677cfb3683723878350ffe9d08130cc6e567b6179e01b7eb2b3bbcf0873e1308eec018edeb8cce946338e15d5bf68c71916a83a99358039ef071e009546a2df936879dffbba397a93925d229a469fd17d71b7f524e03a30da6ee927542f8b369bed4734fe25dbd63d24ffd2a222f5f84f75d858ab989be925af570ad6d45bd28ce61b5139e1dd2f0b7795fe072e6e83acbb5e7b777a70c641e4cab2af40eed69abc334cd2703c3273204fac580c6a3d6680427e5f7d051e8380a53f93a180f4556ecea4530b9a2d5948dad63d415b6874f6b90e767d6d265be86351b53ba690780bb57c21b57418c5b97559e840c68257f839e7583a4bf7c7645c5987d40cc1ba79a218c35edfacdabe581d950e4bb7a481ebe64d61d00e75b1f25f1ce5f5462334a5b9038a697aa0937a3f8017e05d2c9c05dcb05c0b02508dea619b137f5444b6f088eb3cb2c66788f88afdfbba8faa1c490485624c88ae11e57347a676902e7553f056188493209bdbb30acc63c9e41e16a9d6c009416b520a76ba38f57628170c43626b5cb46179dc5bf65de865085f84bf741c223fbe474d2d19d8f43914fbd6586351089e73babf344f988b7963fe44528457d7aad3c564f6bcbd0d772a4c9fd328e6022d1c7c9f86726f8d5a23797d309c0f653ab1ac687833eb2700f156296062a8b377078f45f6b68c3d07cae1913ba8d5a6f9bf7525a3439eb932d4cefc4bf8e1b07b48ca13ece366cbc3e0388915915d1757475103a9e9454e7e6355de2d6acbf4710f9a63e4f6d3cd70c2d6fca88dd8a14448fdb63ce9350fdaafbe0b8bd1c5d307dae76dfed799aef2d8f23d5608d37d1330dd38b94860905dbeebf78d7b7318b7d42aed40d3f9899e9f420cbd92a6eeae3026f7725694e0e4bee016ba346fed2c21172bdb4a461cebe0cfe38e76645226ac127a259c193264d735ce8c8a57e17dd3f0579e2e86dc295ad1f45ba2d85db35044da61f7d401274b31eefbeb34e8d2ae596e9b4541aae117bdac5ed0b324c20539c27c07a411d5288b0b5f6fa16e9a7df85dc319fa6b71cd08a859c06a3f7b0289e1750adbf182f9750fea96fea5ab7aa3473340607cd7ed2c626f5382491c26d5d5bea61401dee7319c94d418f297e61ceac8f258ee8c23831bda081591f5a918e96855774ddedffc51e5b180f1971806d42fc333020b734aeb45adb0bc47325d0cea5f6713a786558022afc39d573892aa3635efbfd8bcb11c57f306c72146afe8b45388125cb7bf9ecf965a7ba4f768c77be366470dcdcf214b7f6a5a9460ed4fe44ae559d85e2fdc2094de83fff12ea8804db1215c4ca865871bdd7f8ef32ab799bf923ffb02c1ded7d129beadad46c5eda31ab1a6f43da05ea08bff7ffa88d8966353d01830558c39b930b01d175e437124d8edd0d2698fd8932f2b2c9b14746e52879c57a395538150f390264f00e60d470711202f4194499ff79037ca9885dc8d695f7d917a3086ca88e8f8d0243efee09302cf39e039eb7cc8dd19d28120d5fe533b5727cd39133181c729ca6f90a015ed30be7668d5cb5ecc33a53ee69bf7d1a5ecbdb153803743c6adaaabd36bf84e5be38d3f04a5d5dbfd67bdcd3b176e65bd1391ade775cc32ce43a847fb6c672a3fe97a5d4081c4986959ec5fb898f42a9397ba2b3ec2c1018f8d76d057f2366bd0e4465514ad6560c599664fb85621fe771e00f43d39b591b2a6a321100f4d1ef23a376d5ae3eeedbfe23da73dff0ee4d16b34ebddd8f5f053db9824105fc7300dbee7ea6af56b112319e3e215a0fc79ae946f6b5227453ec7fcaf17cf7651f71499a50d81221404d5f129ac50ea7528ff0e0069ec4ab8acb7919d81749ab37a870c5ef2cc5a15cf96709d3c65b4addc77e7416847160bcabb94ea36377e0ef71be80b5cc53effd5444888044a353574c72c924bba2a8b4e8354188ebfedc852f59073f4347a8c8a28
MAC = 0c3d3d01a37f347c4f7c5826bcafb3e1
# Length 2060.
Key = 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
Input = 248ac31085b6c2adaaa38259a0d7192c5c35d1bb4ef39ad94c38d1c82479e2dd2159a077024b0589bc8a20101b506f0a1ad0bbab76e83a83f1b94be6beae74e874cab692c5963a75436b776121ec9f62399a3e66b2d22707dae81933b6277f3c8516bcbe26dbbd86f373103d7cf4cad1888c952118fbfbd0d7b4bedc4ae4936aff91157e7aa47c54442ea78d6ac251d324a0fbe49d89cc3521b66d16e9c66a3709894e4eb0a4eedc4ae19468e66b81f271351b1d921ea551047abcc6b87a901fde7db79fa1818c11336dbc07244a40eb14cf77bde35e78ae9ad7d3f57ed7e7f23926c9172f82d77684ea5ed7d74ebc6f142b997036bcb7cce8df1bbc0d5b35a46509c954fc9469d214d6238f166cbf872156b4c41d7aac5942cffb175023078252a3f36e315c5d4ce0e39928a018252862becacef96a19f03bdcf46d75584299d1f8b03c0169e9e407d937145b5e5024139e7022a1978f114f24cdfa23780a119735c41da8fb759bbb3f025c6ec30e6c6e9bce8615be68e392fce59fd26a8e6a6cc5c606e3848116e4d01d29565a1facfb524b6d29643b826eee1e42869fc76df229dd79b39a2b1df28bb335c3a5f15a855d0121e4a6da34b5e4d5b7b5d5746a03ecff70811e1516fcec1bf7462e8876a2d21710aa168c78f45a6a15015950e221da85d3ec822ad6d0a6931b25a06b7bb5f3c10bb36cd4d647f9561982fde9818de5d4bf8db7f86c53b4ff14928ac15f79023b61861e73e44216540bb302153770da2533de9795252ab5fb77ad924c9338c8144c23d4c90dab9a18feac1a1574d4545e1435eb405e6c4c439fc724fce992ae85badf345bad16d85fbd338f04433703614754d0e7e54c4ccde2670587d52ecfb5a70a14a501bacc727722649931d8515b13d020a78e511fe136d45fbf97f9c7f689fcc677cfb3683723878350ffe9d08130cc6e567b6179e01b7eb2b3bbcf0873e1308eec018edeb8cce946338e15d5bf68c71916a83a99358039ef071e009546a2df936879dffbba397a93925d229a469fd17d71b7f524e03a30da6ee927542f8b369bed4734fe25dbd63d24ffd2a222f5f84f75d858ab989be925af570ad6d45bd28ce61b5139e1dd2f0b7795fe072e6e83acbb5e7b777a70c641e4cab2af40eed69abc334cd2703c3273204fac580c6a3d6680427e5f7d051e8380a53f93a180f4556ecea4530b9a2d5948dad63d415b6874f6b90e767d6d265be86351b53ba690780bb57c21b57418c5b97559e840c68257f839e7583a4bf7c7645c5987d40cc1ba79a218c35edfacdabe581d950e4bb7a481ebe64d61d00e75b1f25f1ce5f5462334a5b9038a697aa0937a3f8017e05d2c9c05dcb05c0b02508dea619b137f5444b6f088eb3cb2c66788f88afdfbba8faa1c490485624c88ae11e57347a676902e7553f056188493209bdbb30acc63c9e41e16a9d6c009416b520a76ba38f57628170c43626b5cb46179dc5bf65de865085f84bf741c223fbe474d2d19d8f43914fbd6586351089e73babf344f988b7963fe44528457d7aad3c564f6bcbd0d772a4c9fd328e6022d1c7c9f86726f8d5a23797d309c0f653ab1ac687833eb2700f156296062a8b377078f45f6b68c3d07cae1913ba8d5a6f9bf7525a3439eb932d4cefc4bf8e1b07b48ca13ece366cbc3e0388915915d1757475103a9e9454e7e6355de2d6acbf4710f9a63e4f6d3cd70c2d6fca88dd8a14448fdb63ce9350fdaafbe0b8bd1c5d307dae76dfed799aef2d8f23d5608d37d1330dd38b94860905dbeebf78d7b7318b7d42aed40d3f9899e9f420cbd92a6eeae3026f7725694e0e4bee016ba346fed2c21172bdb4a461cebe0cfe38e76645226ac127a259c193264d735ce8c8a57e17dd3f0579e2e86dc295ad1f45ba2d85db35044da61f7d401274b31eefbeb34e8d2ae596e9b4541aae117bdac5ed0b324c20539c27c07a411d5288b0b5f6fa16e9a7df85dc319fa6b71cd08a859c06a3f7b0289e1750adbf182f9750fea96fea5ab7aa3473340607cd7ed2c626f5382491c26d5d5bea61401dee7319c94d418f297e61ceac8f258ee8c23831bda081591f5a918e96855774ddedffc51e5b180f1971806d42fc333020b734aeb45adb0bc47325d0cea5f6713a786558022afc39d573892aa3635efbfd8bcb11c57f306c72146afe8b45388125cb7bf9ecf965a7ba4f768c77be366470dcdcf214b7f6a5a9460ed4fe44ae559d85e2fdc2094de83fff12ea8804db1215c4ca865871bdd7f8ef32ab799bf923ffb02c1ded7d129beadad46c5eda31ab1a6f43da05ea08bff7ffa88d8966353d01830558c39b930b01d175e437124d8edd0d2698fd8932f2b2c9b14746e52879c57a395538150f390264f00e60d470711202f4194499ff79037ca9885dc8d695f7d917a3086ca88e8f8d0243efee09302cf39e039eb7cc8dd19d28120d5fe533b5727cd39133181c729ca6f90a015ed30be7668d5cb5ecc33a53ee69bf7d1a5ecbdb153803743c6adaaabd36bf84e5be38d3f04a5d5dbfd67bdcd3b176e65bd1391ade775cc32ce43a847fb6c672a3fe97a5d4081c4986959ec5fb898f42a9397ba2b3ec2c1018f8d76d057f2366bd0e4465514ad6560c599664fb85621fe771e00f43d39b591b2a6a321100f4d1ef23a376d5ae3eeedbfe23da73dff0ee4d16b34ebddd8f5f053db9824105fc7300dbee7ea6af56b112319e3e215a0fc79ae946f6b5227453ec7fcaf17cf7651f71499a50d81221404d5f129ac50ea7528ff0e0069ec4ab8acb7919d81749ab37a870c5ef2cc5a15cf96709d3c65b4addc77e7416847160bcabb94ea36377e0ef71be80b5cc53effd5444888044a353574c72c924bba2a8b4e8354188ebfedc852f59073f4347a8c8a28c9
MAC = 33a4e0e0bed7c84c5cc5dd4784410f07
# Length 2061.
Key = 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
Input = 248ac31085b6c2adaaa38259a0d7192c5c35d1bb4ef39ad94c38d1c82479e2dd2159a077024b0589bc8a20101b506f0a1ad0bbab76e83a83f1b94be6beae74e874cab692c5963a75436b776121ec9f62399a3e66b2d22707dae81933b6277f3c8516bcbe26dbbd86f373103d7cf4cad1888c952118fbfbd0d7b4bedc4ae4936aff91157e7aa47c54442ea78d6ac251d324a0fbe49d89cc3521b66d16e9c66a3709894e4eb0a4eedc4ae19468e66b81f271351b1d921ea551047abcc6b87a901fde7db79fa1818c11336dbc07244a40eb14cf77bde35e78ae9ad7d3f57ed7e7f23926c9172f82d77684ea5ed7d74ebc6f142b997036bcb7cce8df1bbc0d5b35a46509c954fc9469d214d6238f166cbf872156b4c41d7aac5942cffb175023078252a3f36e315c5d4ce0e39928a018252862becacef96a19f03bdcf46d75584299d1f8b03c0169e9e407d937145b5e5024139e7022a1978f114f24cdfa23780a119735c41da8fb759bbb3f025c6ec30e6c6e9bce8615be68e392fce59fd26a8e6a6cc5c606e3848116e4d01d29565a1facfb524b6d29643b826eee1e42869fc76df229dd79b39a2b1df28bb335c3a5f15a855d0121e4a6da34b5e4d5b7b5d5746a03ecff70811e1516fcec1bf7462e8876a2d21710aa168c78f45a6a15015950e221da85d3ec822ad6d0a6931b25a06b7bb5f3c10bb36cd4d647f9561982fde9818de5d4bf8db7f86c53b4ff14928ac15f79023b61861e73e44216540bb302153770da2533de9795252ab5fb77ad924c9338c8144c23d4c90dab9a18feac1a1574d4545e1435eb405e6c4c439fc724fce992ae85badf345bad16d85fbd338f04433703614754d0e7e54c4ccde2670587d52ecfb5a70a14a501bacc727722649931d8515b13d020a78e511fe136d45fbf97f9c7f689fcc677cfb3683723878350ffe9d08130cc6e567b6179e01b7eb2b3bbcf0873e1308eec018edeb8cce946338e15d5bf68c71916a83a99358039ef071e009546a2df936879dffbba397a93925d229a469fd17d71b7f524e03a30da6ee927542f8b369bed4734fe25dbd63d24ffd2a222f5f84f75d858ab989be925af570ad6d45bd28ce61b5139e1dd2f0b7795fe072e6e83acbb5e7b777a70c641e4cab2af40eed69abc334cd2703c3273204fac580c6a3d6680427e5f7d051e8380a53f93a180f4556ecea4530b9a2d5948dad63d415b6874f6b90e767d6d265be86351b53ba690780bb57c21b57418c5b97559e840c68257f839e7583a4bf7c7645c5987d40cc1ba79a218c35edfacdabe581d950e4bb7a481ebe64d61d00e75b1f25f1ce5f5462334a5b9038a697aa0937a3f8017e05d2c9c05dcb05c0b02508dea619b137f5444b6f088eb3cb2c66788f88afdfbba8faa1c490485624c88ae11e57347a676902e7553f056188493209bdbb30acc63c9e41e16a9d6c009416b520a76ba38f57628170c43626b5cb46179dc5bf65de865085f84bf741c223fbe474d2d19d8f43914fbd6586351089e73babf344f988b7963fe44528457d7aad3c564f6bcbd0d772a4c9fd328e6022d1c7c9f86726f8d5a23797d309c0f653ab1ac687833eb2700f156296062a8b377078f45f6b68c3d07cae1913ba8d5a6f9bf7525a3439eb932d4cefc4bf8e1b07b48ca13ece366cbc3e0388915915d1757475103a9e9454e7e6355de2d6acbf4710f9a63e4f6d3cd70c2d6fca88dd8a14448fdb63ce9350fdaafbe0b8bd1c5d307dae76dfed799aef2d8f23d5608d37d1330dd38b94860905dbeebf78d7b7318b7d42aed40d3f9899e9f420cbd92a6eeae3026f7725694e0e4bee016ba346fed2c21172bdb4a461cebe0cfe38e76645226ac127a259c193264d735ce8c8a57e17dd3f0579e2e86dc295ad1f45ba2d85db35044da61f7d401274b31eefbeb34e8d2ae596e9b4541aae117bdac5ed0b324c20539c27c07a411d5288b0b5f6fa16e9a7df85dc319fa6b71cd08a859c06a3f7b0289e1750adbf182f9750fea96fea5ab7aa3473340607cd7ed2c626f5382491c26d5d5bea61401dee7319c94d418f297e61ceac8f258ee8c23831bda081591f5a918e96855774ddedffc51e5b180f1971806d42fc333020b734aeb45adb0bc47325d0cea5f6713a786558022afc39d573892aa3635efbfd8bcb11c57f306c72146afe8b45388125cb7bf9ecf965a7ba4f768c77be366470dcdcf214b7f6a5a9460ed4fe44ae559d85e2fdc2094de83fff12ea8804db1215c4ca865871bdd7f8ef32ab799bf923ffb02c1ded7d129beadad46c5eda31ab1a6f43da05ea08bff7ffa88d8966353d01830558c39b930b01d175e437124d8edd0d2698fd8932f2b2c9b14746e52879c57a395538150f390264f00e60d470711202f4194499ff79037ca9885dc8d695f7d917a3086ca88e8f8d0243efee09302cf39e039eb7cc8dd19d28120d5fe533b5727cd39133181c729ca6f90a015ed30be7668d5cb5ecc33a53ee69bf7d1a5ecbdb153803743c6adaaabd36bf84e5be38d3f04a5d5dbfd67bdcd3b176e65bd1391ade775cc32ce43a847fb6c672a3fe97a5d4081c4986959ec5fb898f42a9397ba2b3ec2c1018f8d76d057f2366bd0e4465514ad6560c599664fb85621fe771e00f43d39b591b2a6a321100f4d1ef23a376d5ae3eeedbfe23da73dff0ee4d16b34ebddd8f5f053db9824105fc7300dbee7ea6af56b112319e3e215a0fc79ae946f6b5227453ec7fcaf17cf7651f71499a50d81221404d5f129ac50ea7528ff0e0069ec4ab8acb7919d81749ab37a870c5ef2cc5a15cf96709d3c65b4addc77e7416847160bcabb94ea36377e0ef71be80b5cc53effd5444888044a353574c72c924bba2a8b4e8354188ebfedc852f59073f4347a8c8a28c99e
MAC = 8e41c40a2f8ec58fe594f3a3a2de4ae1
# Length 2062.
Key = 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
Input = 248ac31085b6c2adaaa38259a0d7192c5c35d1bb4ef39ad94c38d1c82479e2dd2159a077024b0589bc8a20101b506f0a1ad0bbab76e83a83f1b94be6beae74e874cab692c5963a75436b776121ec9f62399a3e66b2d22707dae81933b6277f3c8516bcbe26dbbd86f373103d7cf4cad1888c952118fbfbd0d7b4bedc4ae4936aff91157e7aa47c54442ea78d6ac251d324a0fbe49d89cc3521b66d16e9c66a3709894e4eb0a4eedc4ae19468e66b81f271351b1d921ea551047abcc6b87a901fde7db79fa1818c11336dbc07244a40eb14cf77bde35e78ae9ad7d3f57ed7e7f23926c9172f82d77684ea5ed7d74ebc6f142b997036bcb7cce8df1bbc0d5b35a46509c954fc9469d214d6238f166cbf872156b4c41d7aac5942cffb175023078252a3f36e315c5d4ce0e39928a018252862becacef96a19f03bdcf46d75584299d1f8b03c0169e9e407d937145b5e5024139e7022a1978f114f24cdfa23780a119735c41da8fb759bbb3f025c6ec30e6c6e9bce8615be68e392fce59fd26a8e6a6cc5c606e3848116e4d01d29565a1facfb524b6d29643b826eee1e42869fc76df229dd79b39a2b1df28bb335c3a5f15a855d0121e4a6da34b5e4d5b7b5d5746a03ecff70811e1516fcec1bf7462e8876a2d21710aa168c78f45a6a15015950e221da85d3ec822ad6d0a6931b25a06b7bb5f3c10bb36cd4d647f9561982fde9818de5d4bf8db7f86c53b4ff14928ac15f79023b61861e73e44216540bb302153770da2533de9795252ab5fb77ad924c9338c8144c23d4c90dab9a18feac1a1574d4545e1435eb405e6c4c439fc724fce992ae85badf345bad16d85fbd338f04433703614754d0e7e54c4ccde2670587d52ecfb5a70a14a501bacc727722649931d8515b13d020a78e511fe136d45fbf97f9c7f689fcc677cfb3683723878350ffe9d08130cc6e567b6179e01b7eb2b3bbcf0873e1308eec018edeb8cce946338e15d5bf68c71916a83a99358039ef071e009546a2df936879dffbba397a93925d229a469fd17d71b7f524e03a30da6ee927542f8b369bed4734fe25dbd63d24ffd2a222f5f84f75d858ab989be925af570ad6d45bd28ce61b5139e1dd2f0b7795fe072e6e83acbb5e7b777a70c641e4cab2af40eed69abc334cd2703c3273204fac580c6a3d6680427e5f7d051e8380a53f93a180f4556ecea4530b9a2d5948dad63d415b6874f6b90e767d6d265be86351b53ba690780bb57c21b57418c5b97559e840c68257f839e7583a4bf7c7645c5987d40cc1ba79a218c35edfacdabe581d950e4bb7a481ebe64d61d00e75b1f25f1ce5f5462334a5b9038a697aa0937a3f8017e05d2c9c05dcb05c0b02508dea619b137f5444b6f088eb3cb2c66788f88afdfbba8faa1c490485624c88ae11e57347a676902e7553f056188493209bdbb30acc63c9e41e16a9d6c009416b520a76ba38f57628170c43626b5cb46179dc5bf65de865085f84bf741c223fbe474d2d19d8f43914fbd6586351089e73babf344f988b7963fe44528457d7aad3c564f6bcbd0d772a4c9fd328e6022d1c7c9f86726f8d5a23797d309c0f653ab1ac687833eb2700f156296062a8b377078f45f6b68c3d07cae1913ba8d5a6f9bf7525a3439eb932d4cefc4bf8e1b07b48ca13ece366cbc3e0388915915d1757475103a9e9454e7e6355de2d6acbf4710f9a63e4f6d3cd70c2d6fca88dd8a14448fdb63ce9350fdaafbe0b8bd1c5d307dae76dfed799aef2d8f23d5608d37d1330dd38b94860905dbeebf78d7b7318b7d42aed40d3f9899e9f420cbd92a6eeae3026f7725694e0e4bee016ba346fed2c21172bdb4a461cebe0cfe38e76645226ac127a259c193264d735ce8c8a57e17dd3f0579e2e86dc295ad1f45ba2d85db35044da61f7d401274b31eefbeb34e8d2ae596e9b4541aae117bdac5ed0b324c20539c27c07a411d5288b0b5f6fa16e9a7df85dc319fa6b71cd08a859c06a3f7b0289e1750adbf182f9750fea96fea5ab7aa3473340607cd7ed2c626f5382491c26d5d5bea61401dee7319c94d418f297e61ceac8f258ee8c23831bda081591f5a918e96855774ddedffc51e5b180f1971806d42fc333020b734aeb45adb0bc47325d0cea5f6713a786558022afc39d573892aa3635efbfd8bcb11c57f306c72146afe8b45388125cb7bf9ecf965a7ba4f768c77be366470dcdcf214b7f6a5a9460ed4fe44ae559d85e2fdc2094de83fff12ea8804db1215c4ca865871bdd7f8ef32ab799bf923ffb02c1ded7d129beadad46c5eda31ab1a6f43da05ea08bff7ffa88d8966353d01830558c39b930b01d175e437124d8edd0d2698fd8932f2b2c9b14746e52879c57a395538150f390264f00e60d470711202f4194499ff79037ca9885dc8d695f7d917a3086ca88e8f8d0243efee09302cf39e039eb7cc8dd19d28120d5fe533b5727cd39133181c729ca6f90a015ed30be7668d5cb5ecc33a53ee69bf7d1a5ecbdb153803743c6adaaabd36bf84e5be38d3f04a5d5dbfd67bdcd3b176e65bd1391ade775cc32ce43a847fb6c672a3fe97a5d4081c4986959ec5fb898f42a9397ba2b3ec2c1018f8d76d057f2366bd0e4465514ad6560c599664fb85621fe771e00f43d39b591b2a6a321100f4d1ef23a376d5ae3eeedbfe23da73dff0ee4d16b34ebddd8f5f053db9824105fc7300dbee7ea6af56b112319e3e215a0fc79ae946f6b5227453ec7fcaf17cf7651f71499a50d81221404d5f129ac50ea7528ff0e0069ec4ab8acb7919d81749ab37a870c5ef2cc5a15cf96709d3c65b4addc77e7416847160bcabb94ea36377e0ef71be80b5cc53effd5444888044a353574c72c924bba2a8b4e8354188ebfedc852f59073f4347a8c8a28c99e21
MAC = c6e5d1810fd878ac6b844c66cef36a22
# Length 2063.
Key = 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
Input = 248ac31085b6c2adaaa38259a0d7192c5c35d1bb4ef39ad94c38d1c82479e2dd2159a077024b0589bc8a20101b506f0a1ad0bbab76e83a83f1b94be6beae74e874cab692c5963a75436b776121ec9f62399a3e66b2d22707dae81933b6277f3c8516bcbe26dbbd86f373103d7cf4cad1888c952118fbfbd0d7b4bedc4ae4936aff91157e7aa47c54442ea78d6ac251d324a0fbe49d89cc3521b66d16e9c66a3709894e4eb0a4eedc4ae19468e66b81f271351b1d921ea551047abcc6b87a901fde7db79fa1818c11336dbc07244a40eb14cf77bde35e78ae9ad7d3f57ed7e7f23926c9172f82d77684ea5ed7d74ebc6f142b997036bcb7cce8df1bbc0d5b35a46509c954fc9469d214d6238f166cbf872156b4c41d7aac5942cffb175023078252a3f36e315c5d4ce0e39928a018252862becacef96a19f03bdcf46d75584299d1f8b03c0169e9e407d937145b5e5024139e7022a1978f114f24cdfa23780a119735c41da8fb759bbb3f025c6ec30e6c6e9bce8615be68e392fce59fd26a8e6a6cc5c606e3848116e4d01d29565a1facfb524b6d29643b826eee1e42869fc76df229dd79b39a2b1df28bb335c3a5f15a855d0121e4a6da34b5e4d5b7b5d5746a03ecff70811e1516fcec1bf7462e8876a2d21710aa168c78f45a6a15015950e221da85d3ec822ad6d0a6931b25a06b7bb5f3c10bb36cd4d647f9561982fde9818de5d4bf8db7f86c53b4ff14928ac15f79023b61861e73e44216540bb302153770da2533de9795252ab5fb77ad924c9338c8144c23d4c90dab9a18feac1a1574d4545e1435eb405e6c4c439fc724fce992ae85badf345bad16d85fbd338f04433703614754d0e7e54c4ccde2670587d52ecfb5a70a14a501bacc727722649931d8515b13d020a78e511fe136d45fbf97f9c7f689fcc677cfb3683723878350ffe9d08130cc6e567b6179e01b7eb2b3bbcf0873e1308eec018edeb8cce946338e15d5bf68c71916a83a99358039ef071e009546a2df936879dffbba397a93925d229a469fd17d71b7f524e03a30da6ee927542f8b369bed4734fe25dbd63d24ffd2a222f5f84f75d858ab989be925af570ad6d45bd28ce61b5139e1dd2f0b7795fe072e6e83acbb5e7b777a70c641e4cab2af40eed69abc334cd2703c3273204fac580c6a3d6680427e5f7d051e8380a53f93a180f4556ecea4530b9a2d5948dad63d415b6874f6b90e767d6d265be86351b53ba690780bb57c21b57418c5b97559e840c68257f839e7583a4bf7c7645c5987d40cc1ba79a218c35edfacdabe581d950e4bb7a481ebe64d61d00e75b1f25f1ce5f5462334a5b9038a697aa0937a3f8017e05d2c9c05dcb05c0b02508dea619b137f5444b6f088eb3cb2c66788f88afdfbba8faa1c490485624c88ae11e57347a676902e7553f056188493209bdbb30acc63c9e41e16a9d6c009416b520a76ba38f57628170c43626b5cb46179dc5bf65de865085f84bf741c223fbe474d2d19d8f43914fbd6586351089e73babf344f988b7963fe44528457d7aad3c564f6bcbd0d772a4c9fd328e6022d1c7c9f86726f8d5a23797d309c0f653ab1ac687833eb2700f156296062a8b377078f45f6b68c3d07cae1913ba8d5a6f9bf7525a3439eb932d4cefc4bf8e1b07b48ca13ece366cbc3e0388915915d1757475103a9e9454e7e6355de2d6acbf4710f9a63e4f6d3cd70c2d6fca88dd8a14448fdb63ce9350fdaafbe0b8bd1c5d307dae76dfed799aef2d8f23d5608d37d1330dd38b94860905dbeebf78d7b7318b7d42aed40d3f9899e9f420cbd92a6eeae3026f7725694e0e4bee016ba346fed2c21172bdb4a461cebe0cfe38e76645226ac127a259c193264d735ce8c8a57e17dd3f0579e2e86dc295ad1f45ba2d85db35044da61f7d401274b31eefbeb34e8d2ae596e9b4541aae117bdac5ed0b324c20539c27c07a411d5288b0b5f6fa16e9a7df85dc319fa6b71cd08a859c06a3f7b0289e1750adbf182f9750fea96fea5ab7aa3473340607cd7ed2c626f5382491c26d5d5bea61401dee7319c94d418f297e61ceac8f258ee8c23831bda081591f5a918e96855774ddedffc51e5b180f1971806d42fc333020b734aeb45adb0bc47325d0cea5f6713a786558022afc39d573892aa3635efbfd8bcb11c57f306c72146afe8b45388125cb7bf9ecf965a7ba4f768c77be366470dcdcf214b7f6a5a9460ed4fe44ae559d85e2fdc2094de83fff12ea8804db1215c4ca865871bdd7f8ef32ab799bf923ffb02c1ded7d129beadad46c5eda31ab1a6f43da05ea08bff7ffa88d8966353d01830558c39b930b01d175e437124d8edd0d2698fd8932f2b2c9b14746e52879c57a395538150f390264f00e60d470711202f4194499ff79037ca9885dc8d695f7d917a3086ca88e8f8d0243efee09302cf39e039eb7cc8dd19d28120d5fe533b5727cd39133181c729ca6f90a015ed30be7668d5cb5ecc33a53ee69bf7d1a5ecbdb153803743c6adaaabd36bf84e5be38d3f04a5d5dbfd67bdcd3b176e65bd1391ade775cc32ce43a847fb6c672a3fe97a5d4081c4986959ec5fb898f42a9397ba2b3ec2c1018f8d76d057f2366bd0e4465514ad6560c599664fb85621fe771e00f43d39b591b2a6a321100f4d1ef23a376d5ae3eeedbfe23da73dff0ee4d16b34ebddd8f5f053db9824105fc7300dbee7ea6af56b112319e3e215a0fc79ae946f6b5227453ec7fcaf17cf7651f71499a50d81221404d5f129ac50ea7528ff0e0069ec4ab8acb7919d81749ab37a870c5ef2cc5a15cf96709d3c65b4addc77e7416847160bcabb94ea36377e0ef71be80b5cc53effd5444888044a353574c72c924bba2a8b4e8354188ebfedc852f59073f4347a8c8a28c99e21df
MAC = f6eaae369c3cb5c05748e8d919178e00
# Regression test for https://rt.openssl.org/Ticket/Display.html?id=4439
Key = 2d773be37adb1e4d683bf0075e79c4ee037918535a7f99ccb7040fb5f5f43aea
Input = 89dab80b7717c1db5db437860a3f70218e93e1b8f461fb677f16f35f6f87e2a91c99bc3a47ace47640cc95c345be5ecca5a3523c35cc01893af0b64a620334270372ec12482d1b1e363561698a578b359803495bb4e2ef1930b17a5190b580f141300df30adbeca28f6427a8bc1a999fd51c554a017d095d8c3e3127daf9f595
MAC = c85d15ed44c378d6b00e23064c7bcd51
# Regression tests for https://rt.openssl.org/Ticket/Display.html?id=4483
Key = 7f1b02640000000000000000000000000000000000000000cccccccccccccccc
Input = cccccccccccccccccccccccccccccccccccccccccccccccccc80ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccceccccccccccccccccccccccccccccccccccccc5cccccccccccccccccccccccccccccccccccccccccce3ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccaccccccccccccccccccccce6cccccccccc000000afccccccccccccccccccfffffff5000000000000000000000000000000000000000000000000000000ffffffe70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000719205a8521dfc
MAC = 8559b876eceed66eb37798c0457baff9
Key = e00016000000000000000000000000000000aaaaaaaaaaaaaaaaaaaaaaaaaaaa
Input = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa000000000000000000800264
MAC = 00bd1258978e205444c9aaaa82006fed
Key = 0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c
Input = 02fc
MAC = 06120c0c0c0c0c0c0c0c0c0c0c0c0c0c
Key = 00ff000000000000000000000000000000000000001e00000000000000007b7b
Input = 7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7a7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b5c7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b6e7b007b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7a7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b5c7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b6e7b001300000000b300000000000000000000000000000000000000000000f20000000000000000000000000000000000002000efff0009000000000000000000000000100000000009000000640000000000000000000000001300000000b300000000000000000000000000000000000000000000f20000000000000000000000000000000000002000efff00090000000000000000007a000010000000000900000064000000000000000000000000000000000000000000000000fc
MAC = 33205bbf9e9f8f7212ab9e2ab9b7e4a5

187
vendor/ring/src/aead/quic.rs vendored Normal file
View File

@@ -0,0 +1,187 @@
// Copyright 2018 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//! QUIC Header Protection.
//!
//! See draft-ietf-quic-tls.
use crate::{
aead::{aes, chacha},
cpu, error, hkdf,
};
/// A key for generating QUIC Header Protection masks.
pub struct HeaderProtectionKey {
inner: KeyInner,
algorithm: &'static Algorithm,
}
#[allow(clippy::large_enum_variant, variant_size_differences)]
enum KeyInner {
Aes(aes::Key),
ChaCha20(chacha::Key),
}
impl From<hkdf::Okm<'_, &'static Algorithm>> for HeaderProtectionKey {
fn from(okm: hkdf::Okm<&'static Algorithm>) -> Self {
let mut key_bytes = [0; super::MAX_KEY_LEN];
let algorithm = *okm.len();
let key_bytes = &mut key_bytes[..algorithm.key_len()];
okm.fill(key_bytes).unwrap();
Self::new(algorithm, key_bytes).unwrap()
}
}
impl HeaderProtectionKey {
/// Create a new header protection key.
///
/// `key_bytes` must be exactly `algorithm.key_len` bytes long.
pub fn new(
algorithm: &'static Algorithm,
key_bytes: &[u8],
) -> Result<Self, error::Unspecified> {
Ok(Self {
inner: (algorithm.init)(key_bytes, cpu::features())?,
algorithm,
})
}
/// Generate a new QUIC Header Protection mask.
///
/// `sample` must be exactly `self.algorithm().sample_len()` bytes long.
pub fn new_mask(&self, sample: &[u8]) -> Result<[u8; 5], error::Unspecified> {
let sample = <&[u8; SAMPLE_LEN]>::try_from(sample)?;
let out = (self.algorithm.new_mask)(&self.inner, *sample);
Ok(out)
}
/// The key's algorithm.
#[inline(always)]
pub fn algorithm(&self) -> &'static Algorithm {
self.algorithm
}
}
const SAMPLE_LEN: usize = super::TAG_LEN;
/// QUIC sample for new key masks
pub type Sample = [u8; SAMPLE_LEN];
/// A QUIC Header Protection Algorithm.
pub struct Algorithm {
init: fn(key: &[u8], cpu_features: cpu::Features) -> Result<KeyInner, error::Unspecified>,
new_mask: fn(key: &KeyInner, sample: Sample) -> [u8; 5],
key_len: usize,
id: AlgorithmID,
}
impl hkdf::KeyType for &'static Algorithm {
#[inline]
fn len(&self) -> usize {
self.key_len()
}
}
impl Algorithm {
/// The length of the key.
#[inline(always)]
pub fn key_len(&self) -> usize {
self.key_len
}
/// The required sample length.
#[inline(always)]
pub fn sample_len(&self) -> usize {
SAMPLE_LEN
}
}
derive_debug_via_id!(Algorithm);
#[derive(Debug, Eq, PartialEq)]
enum AlgorithmID {
AES_128,
AES_256,
CHACHA20,
}
impl PartialEq for Algorithm {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
impl Eq for Algorithm {}
/// AES-128.
pub static AES_128: Algorithm = Algorithm {
key_len: 16,
init: aes_init_128,
new_mask: aes_new_mask,
id: AlgorithmID::AES_128,
};
/// AES-256.
pub static AES_256: Algorithm = Algorithm {
key_len: 32,
init: aes_init_256,
new_mask: aes_new_mask,
id: AlgorithmID::AES_256,
};
fn aes_init_128(key: &[u8], cpu_features: cpu::Features) -> Result<KeyInner, error::Unspecified> {
let key = key.try_into().map_err(|_| error::Unspecified)?;
let aes_key = aes::Key::new(aes::KeyBytes::AES_128(key), cpu_features)?;
Ok(KeyInner::Aes(aes_key))
}
fn aes_init_256(key: &[u8], cpu_features: cpu::Features) -> Result<KeyInner, error::Unspecified> {
let key = key.try_into().map_err(|_| error::Unspecified)?;
let aes_key = aes::Key::new(aes::KeyBytes::AES_256(key), cpu_features)?;
Ok(KeyInner::Aes(aes_key))
}
fn aes_new_mask(key: &KeyInner, sample: Sample) -> [u8; 5] {
let aes_key = match key {
KeyInner::Aes(key) => key,
_ => unreachable!(),
};
aes_key.new_mask(sample)
}
/// ChaCha20.
pub static CHACHA20: Algorithm = Algorithm {
key_len: chacha::KEY_LEN,
init: chacha20_init,
new_mask: chacha20_new_mask,
id: AlgorithmID::CHACHA20,
};
fn chacha20_init(key: &[u8], _cpu_features: cpu::Features) -> Result<KeyInner, error::Unspecified> {
let chacha20_key: [u8; chacha::KEY_LEN] = key.try_into()?;
Ok(KeyInner::ChaCha20(chacha::Key::new(chacha20_key)))
}
fn chacha20_new_mask(key: &KeyInner, sample: Sample) -> [u8; 5] {
let chacha20_key = match key {
KeyInner::ChaCha20(key) => key,
_ => unreachable!(),
};
chacha20_key.new_mask(sample)
}

104
vendor/ring/src/aead/sealing_key.rs vendored Normal file
View File

@@ -0,0 +1,104 @@
// Copyright 2015-2021 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//! Authenticated Encryption with Associated Data (AEAD).
//!
//! See [Authenticated encryption: relations among notions and analysis of the
//! generic composition paradigm][AEAD] for an introduction to the concept of
//! AEADs.
//!
//! [AEAD]: https://eprint.iacr.org/2000/025.pdf
//! [`crypto.cipher.AEAD`]: https://golang.org/pkg/crypto/cipher/#AEAD
use super::{Aad, Algorithm, BoundKey, LessSafeKey, NonceSequence, Tag, UnboundKey};
use crate::error;
/// An AEAD key for encrypting and signing ("sealing"), bound to a nonce
/// sequence.
///
/// Intentionally not `Clone` or `Copy` since cloning would allow duplication
/// of the nonce sequence.
pub struct SealingKey<N: NonceSequence> {
key: LessSafeKey,
nonce_sequence: N,
}
impl<N: NonceSequence> BoundKey<N> for SealingKey<N> {
fn new(key: UnboundKey, nonce_sequence: N) -> Self {
Self {
key: key.into_inner(),
nonce_sequence,
}
}
#[inline]
fn algorithm(&self) -> &'static Algorithm {
self.key.algorithm()
}
}
impl<N: NonceSequence> core::fmt::Debug for SealingKey<N> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
self.key.fmt_debug("SealingKey", f)
}
}
impl<N: NonceSequence> SealingKey<N> {
/// Encrypts and signs (“seals”) data in place, appending the tag to the
/// resulting ciphertext.
///
/// `key.seal_in_place_append_tag(aad, in_out)` is equivalent to:
///
/// ```skip
/// key.seal_in_place_separate_tag(aad, in_out.as_mut())
/// .map(|tag| in_out.extend(tag.as_ref()))
/// ```
#[inline]
pub fn seal_in_place_append_tag<A, InOut>(
&mut self,
aad: Aad<A>,
in_out: &mut InOut,
) -> Result<(), error::Unspecified>
where
A: AsRef<[u8]>,
InOut: AsMut<[u8]> + for<'in_out> Extend<&'in_out u8>,
{
self.key
.seal_in_place_append_tag(self.nonce_sequence.advance()?, aad, in_out)
}
/// Encrypts and signs (“seals”) data in place.
///
/// `aad` is the additional authenticated data (AAD), if any. This is
/// authenticated but not encrypted. The type `A` could be a byte slice
/// `&[u8]`, a byte array `[u8; N]` for some constant `N`, `Vec<u8>`, etc.
/// If there is no AAD then use `Aad::empty()`.
///
/// The plaintext is given as the input value of `in_out`. `seal_in_place()`
/// will overwrite the plaintext with the ciphertext and return the tag.
/// For most protocols, the caller must append the tag to the ciphertext.
/// The tag will be `self.algorithm.tag_len()` bytes long.
#[inline]
pub fn seal_in_place_separate_tag<A>(
&mut self,
aad: Aad<A>,
in_out: &mut [u8],
) -> Result<Tag, error::Unspecified>
where
A: AsRef<[u8]>,
{
self.key
.seal_in_place_separate_tag(self.nonce_sequence.advance()?, aad, in_out)
}
}

32
vendor/ring/src/aead/shift.rs vendored Normal file
View File

@@ -0,0 +1,32 @@
// Copyright 2018 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#[cfg(target_arch = "x86")]
pub fn shift_full_blocks<const BLOCK_LEN: usize>(
in_out: super::overlapping::Overlapping<'_, u8>,
mut transform: impl FnMut(&[u8; BLOCK_LEN]) -> [u8; BLOCK_LEN],
) {
let (in_out, src) = in_out.into_slice_src_mut();
let in_out_len = in_out[src.clone()].len();
for i in (0..in_out_len).step_by(BLOCK_LEN) {
let block = {
let input =
<&[u8; BLOCK_LEN]>::try_from(&in_out[(src.start + i)..][..BLOCK_LEN]).unwrap();
transform(input)
};
let output = <&mut [u8; BLOCK_LEN]>::try_from(&mut in_out[i..][..BLOCK_LEN]).unwrap();
*output = block;
}
}

74
vendor/ring/src/aead/unbound_key.rs vendored Normal file
View File

@@ -0,0 +1,74 @@
// Copyright 2015-2021 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//! Authenticated Encryption with Associated Data (AEAD).
//!
//! See [Authenticated encryption: relations among notions and analysis of the
//! generic composition paradigm][AEAD] for an introduction to the concept of
//! AEADs.
//!
//! [AEAD]: https://eprint.iacr.org/2000/025.pdf
//! [`crypto.cipher.AEAD`]: https://golang.org/pkg/crypto/cipher/#AEAD
use super::{Algorithm, LessSafeKey, MAX_KEY_LEN};
use crate::{cpu, error, hkdf};
/// An AEAD key without a designated role or nonce sequence.
pub struct UnboundKey {
inner: LessSafeKey,
}
impl UnboundKey {
/// Constructs a `UnboundKey`.
///
/// Fails if `key_bytes.len() != algorithm.key_len()`.
#[inline]
pub fn new(
algorithm: &'static Algorithm,
key_bytes: &[u8],
) -> Result<Self, error::Unspecified> {
Ok(Self {
inner: LessSafeKey::new_(algorithm, key_bytes, cpu::features())?,
})
}
/// The key's AEAD algorithm.
#[inline]
pub fn algorithm(&self) -> &'static Algorithm {
self.inner.algorithm()
}
#[inline]
pub(super) fn into_inner(self) -> LessSafeKey {
self.inner
}
}
impl core::fmt::Debug for UnboundKey {
fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
self.inner.fmt_debug("UnboundKey", f)
}
}
impl From<hkdf::Okm<'_, &'static Algorithm>> for UnboundKey {
fn from(okm: hkdf::Okm<&'static Algorithm>) -> Self {
let mut key_bytes = [0; MAX_KEY_LEN];
let key_bytes = &mut key_bytes[..okm.len().key_len()];
let algorithm = *okm.len();
okm.fill(key_bytes).unwrap();
Self {
inner: LessSafeKey::new_(algorithm, key_bytes, cpu::features()).unwrap(),
}
}
}

311
vendor/ring/src/agreement.rs vendored Normal file
View File

@@ -0,0 +1,311 @@
// Copyright 2015-2017 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//! Key Agreement: ECDH, including X25519.
//!
//! # Example
//!
//! Note that this example uses X25519, but ECDH using NIST P-256/P-384 is done
//! exactly the same way, just substituting
//! `agreement::ECDH_P256`/`agreement::ECDH_P384` for `agreement::X25519`.
//!
//! ```
//! use ring::{agreement, rand};
//!
//! let rng = rand::SystemRandom::new();
//!
//! let my_private_key = agreement::EphemeralPrivateKey::generate(&agreement::X25519, &rng)?;
//!
//! // Make `my_public_key` a byte slice containing my public key. In a real
//! // application, this would be sent to the peer in an encoded protocol
//! // message.
//! let my_public_key = my_private_key.compute_public_key()?;
//!
//! let peer_public_key_bytes = {
//! // In a real application, the peer public key would be parsed out of a
//! // protocol message. Here we just generate one.
//! let peer_private_key =
//! agreement::EphemeralPrivateKey::generate(&agreement::X25519, &rng)?;
//! peer_private_key.compute_public_key()?
//! };
//!
//! let peer_public_key = agreement::UnparsedPublicKey::new(
//! &agreement::X25519,
//! peer_public_key_bytes);
//!
//! agreement::agree_ephemeral(
//! my_private_key,
//! &peer_public_key,
//! |_key_material| {
//! // In a real application, we'd apply a KDF to the key material and the
//! // public keys (as recommended in RFC 7748) and then derive session
//! // keys from the result. We omit all that here.
//! },
//! )?;
//!
//! # Ok::<(), ring::error::Unspecified>(())
//! ```
// The "NSA Guide" steps here are from from section 3.1, "Ephemeral Unified
// Model."
use crate::{cpu, debug, ec, error, rand};
pub use crate::ec::{
curve25519::x25519::X25519,
suite_b::ecdh::{ECDH_P256, ECDH_P384},
};
/// A key agreement algorithm.
pub struct Algorithm {
pub(crate) curve: &'static ec::Curve,
pub(crate) ecdh: fn(
out: &mut [u8],
private_key: &ec::Seed,
peer_public_key: untrusted::Input,
cpu: cpu::Features,
) -> Result<(), error::Unspecified>,
}
derive_debug_via_field!(Algorithm, curve);
impl Eq for Algorithm {}
impl PartialEq for Algorithm {
fn eq(&self, other: &Self) -> bool {
self.curve.id == other.curve.id
}
}
/// An ephemeral private key for use (only) with `agree_ephemeral`. The
/// signature of `agree_ephemeral` ensures that an `EphemeralPrivateKey` can be
/// used for at most one key agreement.
pub struct EphemeralPrivateKey {
private_key: ec::Seed,
algorithm: &'static Algorithm,
}
derive_debug_via_field!(
EphemeralPrivateKey,
stringify!(EphemeralPrivateKey),
algorithm
);
impl EphemeralPrivateKey {
/// Generate a new ephemeral private key for the given algorithm.
pub fn generate(
alg: &'static Algorithm,
rng: &dyn rand::SecureRandom,
) -> Result<Self, error::Unspecified> {
let cpu_features = cpu::features();
// NSA Guide Step 1.
//
// This only handles the key generation part of step 1. The rest of
// step one is done by `compute_public_key()`.
let private_key = ec::Seed::generate(alg.curve, rng, cpu_features)?;
Ok(Self {
private_key,
algorithm: alg,
})
}
/// Computes the public key from the private key.
#[inline(always)]
pub fn compute_public_key(&self) -> Result<PublicKey, error::Unspecified> {
// NSA Guide Step 1.
//
// Obviously, this only handles the part of Step 1 between the private
// key generation and the sending of the public key to the peer. `out`
// is what should be sent to the peer.
self.private_key
.compute_public_key(cpu::features())
.map(|public_key| PublicKey {
algorithm: self.algorithm,
bytes: public_key,
})
}
/// The algorithm for the private key.
#[inline]
pub fn algorithm(&self) -> &'static Algorithm {
self.algorithm
}
/// Do not use.
#[deprecated]
#[cfg(test)]
pub fn bytes(&self) -> &[u8] {
self.bytes_for_test()
}
#[cfg(test)]
pub(super) fn bytes_for_test(&self) -> &[u8] {
self.private_key.bytes_less_safe()
}
}
/// A public key for key agreement.
#[derive(Clone)]
pub struct PublicKey {
algorithm: &'static Algorithm,
bytes: ec::PublicKey,
}
impl AsRef<[u8]> for PublicKey {
fn as_ref(&self) -> &[u8] {
self.bytes.as_ref()
}
}
impl core::fmt::Debug for PublicKey {
fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
f.debug_struct("PublicKey")
.field("algorithm", &self.algorithm)
.field("bytes", &debug::HexStr(self.as_ref()))
.finish()
}
}
impl PublicKey {
/// The algorithm for the public key.
#[inline]
pub fn algorithm(&self) -> &'static Algorithm {
self.algorithm
}
}
/// An unparsed, possibly malformed, public key for key agreement.
#[derive(Clone, Copy)]
pub struct UnparsedPublicKey<B> {
algorithm: &'static Algorithm,
bytes: B,
}
impl<B> AsRef<[u8]> for UnparsedPublicKey<B>
where
B: AsRef<[u8]>,
{
fn as_ref(&self) -> &[u8] {
self.bytes.as_ref()
}
}
impl<B: core::fmt::Debug> core::fmt::Debug for UnparsedPublicKey<B>
where
B: AsRef<[u8]>,
{
fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
f.debug_struct("UnparsedPublicKey")
.field("algorithm", &self.algorithm)
.field("bytes", &debug::HexStr(self.bytes.as_ref()))
.finish()
}
}
impl<B> UnparsedPublicKey<B> {
/// Constructs a new `UnparsedPublicKey`.
pub fn new(algorithm: &'static Algorithm, bytes: B) -> Self {
Self { algorithm, bytes }
}
/// The algorithm for the public key.
#[inline]
pub fn algorithm(&self) -> &'static Algorithm {
self.algorithm
}
/// TODO: doc
#[inline]
pub fn bytes(&self) -> &B {
&self.bytes
}
}
/// Performs a key agreement with an ephemeral private key and the given public
/// key.
///
/// `my_private_key` is the ephemeral private key to use. Since it is moved, it
/// will not be usable after calling `agree_ephemeral`, thus guaranteeing that
/// the key is used for only one key agreement.
///
/// `peer_public_key` is the peer's public key. `agree_ephemeral` will return
/// `Err(error_value)` if it does not match `my_private_key's` algorithm/curve.
/// `agree_ephemeral` verifies that it is encoded in the standard form for the
/// algorithm and that the key is *valid*; see the algorithm's documentation for
/// details on how keys are to be encoded and what constitutes a valid key for
/// that algorithm.
///
/// After the key agreement is done, `agree_ephemeral` calls `kdf` with the raw
/// key material from the key agreement operation and then returns what `kdf`
/// returns.
#[inline]
pub fn agree_ephemeral<B: AsRef<[u8]>, R>(
my_private_key: EphemeralPrivateKey,
peer_public_key: &UnparsedPublicKey<B>,
kdf: impl FnOnce(&[u8]) -> R,
) -> Result<R, error::Unspecified> {
let peer_public_key = UnparsedPublicKey {
algorithm: peer_public_key.algorithm,
bytes: peer_public_key.bytes.as_ref(),
};
agree_ephemeral_(my_private_key, peer_public_key, kdf, cpu::features())
}
fn agree_ephemeral_<R>(
my_private_key: EphemeralPrivateKey,
peer_public_key: UnparsedPublicKey<&[u8]>,
kdf: impl FnOnce(&[u8]) -> R,
cpu: cpu::Features,
) -> Result<R, error::Unspecified> {
// NSA Guide Prerequisite 1.
//
// The domain parameters are hard-coded. This check verifies that the
// peer's public key's domain parameters match the domain parameters of
// this private key.
if peer_public_key.algorithm != my_private_key.algorithm {
return Err(error::Unspecified);
}
let alg = &my_private_key.algorithm;
// NSA Guide Prerequisite 2, regarding which KDFs are allowed, is delegated
// to the caller.
// NSA Guide Prerequisite 3, "Prior to or during the key-agreement process,
// each party shall obtain the identifier associated with the other party
// during the key-agreement scheme," is delegated to the caller.
// NSA Guide Step 1 is handled by `EphemeralPrivateKey::generate()` and
// `EphemeralPrivateKey::compute_public_key()`.
let mut shared_key = [0u8; ec::ELEM_MAX_BYTES];
let shared_key = &mut shared_key[..alg.curve.elem_scalar_seed_len];
// NSA Guide Steps 2, 3, and 4.
//
// We have a pretty liberal interpretation of the NIST's spec's "Destroy"
// that doesn't meet the NSA requirement to "zeroize."
(alg.ecdh)(
shared_key,
&my_private_key.private_key,
untrusted::Input::from(peer_public_key.bytes),
cpu,
)?;
// NSA Guide Steps 5 and 6.
//
// Again, we have a pretty liberal interpretation of the NIST's spec's
// "Destroy" that doesn't meet the NSA requirement to "zeroize."
Ok(kdf(shared_key))
}

47
vendor/ring/src/arithmetic.rs vendored Normal file
View File

@@ -0,0 +1,47 @@
// Copyright 2017-2023 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
pub(crate) use self::{constant::limbs_from_hex, limb_slice_error::LimbSliceError};
use crate::{error::LenMismatchError, limb::LIMB_BITS};
#[macro_use]
mod ffi;
mod constant;
#[cfg(feature = "alloc")]
pub mod bigint;
pub(crate) mod inout;
mod limbs;
mod limbs512;
pub mod montgomery;
mod n0;
// The minimum number of limbs allowed for any `&[Limb]` operation.
//
// TODO: Use `256 / LIMB_BITS` so that the limit is independent of limb size.
pub const MIN_LIMBS: usize = 4;
// The maximum number of limbs allowed for any `&[Limb]` operation.
pub const MAX_LIMBS: usize = 8192 / LIMB_BITS;
cold_exhaustive_error! {
enum limb_slice_error::LimbSliceError {
len_mismatch => LenMismatch(LenMismatchError),
too_short => TooShort(usize),
too_long => TooLong(usize),
}
}

1068
vendor/ring/src/arithmetic/bigint.rs vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,81 @@
// Copyright 2015-2023 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use super::Modulus;
use crate::{
error,
limb::{self, Limb},
};
use alloc::{boxed::Box, vec};
use core::{
marker::PhantomData,
ops::{Deref, DerefMut},
};
/// All `BoxedLimbs<M>` are stored in the same number of limbs.
pub(super) struct BoxedLimbs<M> {
limbs: Box<[Limb]>,
/// The modulus *m* that determines the size of `limbx`.
m: PhantomData<M>,
}
impl<M> Deref for BoxedLimbs<M> {
type Target = [Limb];
#[inline]
fn deref(&self) -> &Self::Target {
&self.limbs
}
}
impl<M> DerefMut for BoxedLimbs<M> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.limbs
}
}
// TODO: `derive(Clone)` after https://github.com/rust-lang/rust/issues/26925
// is resolved or restrict `M: Clone`.
impl<M> Clone for BoxedLimbs<M> {
fn clone(&self) -> Self {
Self {
limbs: self.limbs.clone(),
m: self.m,
}
}
}
impl<M> BoxedLimbs<M> {
pub(super) fn from_be_bytes_padded_less_than(
input: untrusted::Input,
m: &Modulus<M>,
) -> Result<Self, error::Unspecified> {
let mut r = Self::zero(m.limbs().len());
limb::parse_big_endian_and_pad_consttime(input, &mut r)?;
limb::verify_limbs_less_than_limbs_leak_bit(&r, m.limbs())?;
Ok(r)
}
pub(super) fn zero(len: usize) -> Self {
Self {
limbs: vec![0; len].into_boxed_slice(),
m: PhantomData,
}
}
pub(super) fn into_limbs(self) -> Box<[Limb]> {
self.limbs
}
}

View File

@@ -0,0 +1,202 @@
// Copyright 2015-2024 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use super::{
super::montgomery::Unencoded, unwrap_impossible_len_mismatch_error, BoxedLimbs, Elem,
OwnedModulusValue, PublicModulus, Storage, N0,
};
use crate::{
bits::BitLength,
cpu, error,
limb::{self, Limb, LIMB_BITS},
polyfill::LeadingZerosStripped,
};
use core::marker::PhantomData;
/// The modulus *m* for a ring /m, along with the precomputed values needed
/// for efficient Montgomery multiplication modulo *m*. The value must be odd
/// and larger than 2. The larger-than-1 requirement is imposed, at least, by
/// the modular inversion code.
pub struct OwnedModulus<M> {
inner: OwnedModulusValue<M>,
// n0 * N == -1 (mod r).
//
// r == 2**(N0::LIMBS_USED * LIMB_BITS) and LG_LITTLE_R == lg(r). This
// ensures that we can do integer division by |r| by simply ignoring
// `N0::LIMBS_USED` limbs. Similarly, we can calculate values modulo `r` by
// just looking at the lowest `N0::LIMBS_USED` limbs. This is what makes
// Montgomery multiplication efficient.
//
// As shown in Algorithm 1 of "Fast Prime Field Elliptic Curve Cryptography
// with 256 Bit Primes" by Shay Gueron and Vlad Krasnov, in the loop of a
// multi-limb Montgomery multiplication of a * b (mod n), given the
// unreduced product t == a * b, we repeatedly calculate:
//
// t1 := t % r |t1| is |t|'s lowest limb (see previous paragraph).
// t2 := t1*n0*n
// t3 := t + t2
// t := t3 / r copy all limbs of |t3| except the lowest to |t|.
//
// In the last step, it would only make sense to ignore the lowest limb of
// |t3| if it were zero. The middle steps ensure that this is the case:
//
// t3 == 0 (mod r)
// t + t2 == 0 (mod r)
// t + t1*n0*n == 0 (mod r)
// t1*n0*n == -t (mod r)
// t*n0*n == -t (mod r)
// n0*n == -1 (mod r)
// n0 == -1/n (mod r)
//
// Thus, in each iteration of the loop, we multiply by the constant factor
// n0, the negative inverse of n (mod r).
//
// TODO(perf): Not all 32-bit platforms actually make use of n0[1]. For the
// ones that don't, we could use a shorter `R` value and use faster `Limb`
// calculations instead of double-precision `u64` calculations.
n0: N0,
}
impl<M: PublicModulus> Clone for OwnedModulus<M> {
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
n0: self.n0,
}
}
}
impl<M> OwnedModulus<M> {
pub(crate) fn from(n: OwnedModulusValue<M>) -> Self {
// n_mod_r = n % r. As explained in the documentation for `n0`, this is
// done by taking the lowest `N0::LIMBS_USED` limbs of `n`.
#[allow(clippy::useless_conversion)]
let n0 = {
prefixed_extern! {
fn bn_neg_inv_mod_r_u64(n: u64) -> u64;
}
// XXX: u64::from isn't guaranteed to be constant time.
let mut n_mod_r: u64 = u64::from(n.limbs()[0]);
if N0::LIMBS_USED == 2 {
// XXX: If we use `<< LIMB_BITS` here then 64-bit builds
// fail to compile because of `deny(exceeding_bitshifts)`.
debug_assert_eq!(LIMB_BITS, 32);
n_mod_r |= u64::from(n.limbs()[1]) << 32;
}
N0::precalculated(unsafe { bn_neg_inv_mod_r_u64(n_mod_r) })
};
Self { inner: n, n0 }
}
pub fn to_elem<L>(&self, l: &Modulus<L>) -> Result<Elem<L, Unencoded>, error::Unspecified> {
self.inner.verify_less_than(l)?;
let mut limbs = BoxedLimbs::zero(l.limbs().len());
limbs[..self.inner.limbs().len()].copy_from_slice(self.inner.limbs());
Ok(Elem {
limbs,
encoding: PhantomData,
})
}
pub(crate) fn modulus(&self, cpu_features: cpu::Features) -> Modulus<M> {
Modulus {
limbs: self.inner.limbs(),
n0: self.n0,
len_bits: self.len_bits(),
m: PhantomData,
cpu_features,
}
}
pub fn len_bits(&self) -> BitLength {
self.inner.len_bits()
}
}
impl<M: PublicModulus> OwnedModulus<M> {
pub fn be_bytes(&self) -> LeadingZerosStripped<impl ExactSizeIterator<Item = u8> + Clone + '_> {
LeadingZerosStripped::new(limb::unstripped_be_bytes(self.inner.limbs()))
}
}
pub struct Modulus<'a, M> {
limbs: &'a [Limb],
n0: N0,
len_bits: BitLength,
m: PhantomData<M>,
cpu_features: cpu::Features,
}
impl<M> Modulus<'_, M> {
pub(super) fn oneR(&self, out: &mut [Limb]) {
assert_eq!(self.limbs.len(), out.len());
let r = self.limbs.len() * LIMB_BITS;
// out = 2**r - m where m = self.
limb::limbs_negative_odd(out, self.limbs);
let lg_m = self.len_bits().as_bits();
let leading_zero_bits_in_m = r - lg_m;
// When m's length is a multiple of LIMB_BITS, which is the case we
// most want to optimize for, then we already have
// out == 2**r - m == 2**r (mod m).
if leading_zero_bits_in_m != 0 {
debug_assert!(leading_zero_bits_in_m < LIMB_BITS);
// Correct out to 2**(lg m) (mod m). `limbs_negative_odd` flipped
// all the leading zero bits to ones. Flip them back.
*out.last_mut().unwrap() &= (!0) >> leading_zero_bits_in_m;
// Now we have out == 2**(lg m) (mod m). Keep doubling until we get
// to 2**r (mod m).
for _ in 0..leading_zero_bits_in_m {
limb::limbs_double_mod(out, self.limbs)
.unwrap_or_else(unwrap_impossible_len_mismatch_error);
}
}
// Now out == 2**r (mod m) == 1*R.
}
// TODO: XXX Avoid duplication with `Modulus`.
pub fn alloc_zero(&self) -> Storage<M> {
Storage {
limbs: BoxedLimbs::zero(self.limbs.len()),
}
}
#[inline]
pub(super) fn limbs(&self) -> &[Limb] {
self.limbs
}
#[inline]
pub(super) fn n0(&self) -> &N0 {
&self.n0
}
pub fn len_bits(&self) -> BitLength {
self.len_bits
}
#[inline]
pub(crate) fn cpu_features(&self) -> cpu::Features {
self.cpu_features
}
}

View File

@@ -0,0 +1,88 @@
// Copyright 2015-2024 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use super::{
super::{MAX_LIMBS, MIN_LIMBS},
BoxedLimbs, Modulus, PublicModulus,
};
use crate::{
bits::BitLength,
error,
limb::{self, Limb, LIMB_BYTES},
};
/// `OwnedModulus`, without the overhead of Montgomery multiplication support.
pub(crate) struct OwnedModulusValue<M> {
limbs: BoxedLimbs<M>, // Also `value >= 3`.
len_bits: BitLength,
}
impl<M: PublicModulus> Clone for OwnedModulusValue<M> {
fn clone(&self) -> Self {
Self {
limbs: self.limbs.clone(),
len_bits: self.len_bits,
}
}
}
impl<M> OwnedModulusValue<M> {
pub(crate) fn from_be_bytes(input: untrusted::Input) -> Result<Self, error::KeyRejected> {
let num_limbs = (input.len() + LIMB_BYTES - 1) / LIMB_BYTES;
const _MODULUS_MIN_LIMBS_AT_LEAST_2: () = assert!(MIN_LIMBS >= 2);
if num_limbs < MIN_LIMBS {
return Err(error::KeyRejected::unexpected_error());
}
if num_limbs > MAX_LIMBS {
return Err(error::KeyRejected::too_large());
}
// The above implies n >= 3, so we don't need to check that.
// Reject leading zeros. Also reject the value zero ([0]) because zero
// isn't positive.
if untrusted::Reader::new(input).peek(0) {
return Err(error::KeyRejected::invalid_encoding());
}
let mut limbs = BoxedLimbs::zero(num_limbs);
limb::parse_big_endian_and_pad_consttime(input, &mut limbs)
.map_err(|error::Unspecified| error::KeyRejected::unexpected_error())?;
limb::limbs_reject_even_leak_bit(&limbs)
.map_err(|_: error::Unspecified| error::KeyRejected::invalid_component())?;
let len_bits = limb::limbs_minimal_bits(&limbs);
Ok(Self { limbs, len_bits })
}
pub fn verify_less_than<L>(&self, l: &Modulus<L>) -> Result<(), error::Unspecified> {
if self.len_bits() > l.len_bits() {
return Err(error::Unspecified);
}
if self.limbs.len() == l.limbs().len() {
limb::verify_limbs_less_than_limbs_leak_bit(&self.limbs, l.limbs())?;
}
Ok(())
}
pub fn len_bits(&self) -> BitLength {
self.len_bits
}
#[inline]
pub(super) fn limbs(&self) -> &[Limb] {
&self.limbs
}
}

View File

@@ -0,0 +1,77 @@
// Copyright 2015-2023 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use super::{limb, BoxedLimbs, Limb, Modulus};
use crate::error;
use alloc::boxed::Box;
pub struct PrivateExponent {
// Unlike most `[Limb]` we deal with, these are stored most significant
// word first.
limbs: Box<[Limb]>,
}
impl PrivateExponent {
// `p` is the modulus for which the exponent is in the interval [1, `p` - 1).
pub fn from_be_bytes_padded<M>(
input: untrusted::Input,
p: &Modulus<M>,
) -> Result<Self, error::Unspecified> {
let mut dP = BoxedLimbs::from_be_bytes_padded_less_than(input, p)?;
// Proof that `dP < p - 1`:
//
// If `dP < p` then either `dP == p - 1` or `dP < p - 1`. Since `p` is
// odd, `p - 1` is even. `d` is odd, and an odd number modulo an even
// number is odd. Therefore `dP` must be odd. But then it cannot be
// `p - 1` and so we know `dP < p - 1`.
//
// Further we know `dP != 0` because `dP` is not even.
limb::limbs_reject_even_leak_bit(&dP)?;
dP.reverse();
Ok(Self {
limbs: dP.into_limbs(),
})
}
// Create a `PrivateExponent` with a value that we do not support in
// production use, to allow testing with additional test vectors.
#[cfg(test)]
pub fn from_be_bytes_for_test_only<M>(
input: untrusted::Input,
p: &Modulus<M>,
) -> Result<Self, error::Unspecified> {
use crate::limb::LIMB_BYTES;
// Do exactly what `from_be_bytes_padded` does for any inputs it accepts.
if let r @ Ok(_) = Self::from_be_bytes_padded(input, p) {
return r;
}
let num_limbs = (input.len() + LIMB_BYTES - 1) / LIMB_BYTES;
let mut limbs = BoxedLimbs::<M>::zero(num_limbs);
limb::parse_big_endian_and_pad_consttime(input, &mut limbs)
.map_err(|error::Unspecified| error::KeyRejected::unexpected_error())?;
limbs.reverse();
Ok(Self {
limbs: limbs.into_limbs(),
})
}
#[inline]
pub(super) fn limbs(&self) -> &[Limb] {
&self.limbs
}
}

27
vendor/ring/src/arithmetic/constant.rs vendored Normal file
View File

@@ -0,0 +1,27 @@
use crate::limb::LeakyLimb;
use core::mem::size_of;
const fn parse_digit(d: u8) -> u8 {
match d.to_ascii_lowercase() {
b'0'..=b'9' => d - b'0',
b'a'..=b'f' => d - b'a' + 10,
_ => panic!(),
}
}
// TODO: this would be nicer as a trait, but currently traits don't support const functions
pub const fn limbs_from_hex<const LIMBS: usize>(hex: &str) -> [LeakyLimb; LIMBS] {
let hex = hex.as_bytes();
let mut limbs = [0; LIMBS];
let limb_nibbles = size_of::<LeakyLimb>() * 2;
let mut i = 0;
while i < hex.len() {
let char = hex[hex.len() - 1 - i];
let val = parse_digit(char);
limbs[i / limb_nibbles] |= (val as LeakyLimb) << ((i % limb_nibbles) * 4);
i += 1;
}
limbs
}

97
vendor/ring/src/arithmetic/ffi.rs vendored Normal file
View File

@@ -0,0 +1,97 @@
// Copyright 2024-2025 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use super::{inout::AliasingSlices3, n0::N0, LimbSliceError, MAX_LIMBS, MIN_LIMBS};
use crate::{c, limb::Limb, polyfill::usize_from_u32};
use core::{mem::size_of, num::NonZeroUsize};
const _MAX_LIMBS_ADDRESSES_MEMORY_SAFETY_ISSUES: () = {
// BoringSSL's limit: 8 kiloBYTES.
const BN_MONTGOMERY_MAX_WORDS: usize = (8 * 1092) / size_of::<Limb>();
assert!(MAX_LIMBS <= BN_MONTGOMERY_MAX_WORDS);
// Some 64-bit assembly implementations were written to take `len` as a
// `c_int`, so they zero out the undefined top half of `len` to convert it
// to a `usize`. But, others don't.
assert!(MAX_LIMBS <= usize_from_u32(u32::MAX));
};
macro_rules! bn_mul_mont_ffi {
( $in_out:expr, $n:expr, $n0:expr, $cpu:expr,
unsafe { ($MIN_LEN:expr, $MOD_LEN:expr, $Cpu:ty) => $f:ident }) => {{
use crate::{c, limb::Limb};
prefixed_extern! {
// `r` and/or 'a' and/or 'b' may alias.
// XXX: BoringSSL declares these functions to return `int`.
fn $f(
r: *mut Limb,
a: *const Limb,
b: *const Limb,
n: *const Limb,
n0: &N0,
len: c::NonZero_size_t,
);
}
unsafe {
crate::arithmetic::ffi::bn_mul_mont_ffi::<$Cpu, { $MIN_LEN }, { $MOD_LEN }>(
$in_out, $n, $n0, $cpu, $f,
)
}
}};
}
#[inline]
pub(super) unsafe fn bn_mul_mont_ffi<Cpu, const LEN_MIN: usize, const LEN_MOD: usize>(
in_out: impl AliasingSlices3<Limb>,
n: &[Limb],
n0: &N0,
cpu: Cpu,
f: unsafe extern "C" fn(
r: *mut Limb,
a: *const Limb,
b: *const Limb,
n: *const Limb,
n0: &N0,
len: c::NonZero_size_t,
),
) -> Result<(), LimbSliceError> {
assert_eq!(n.len() % LEN_MOD, 0); // The caller should guard against this.
/// The x86 implementation of `bn_mul_mont`, at least, requires at least 4
/// limbs. For a long time we have required 4 limbs for all targets, though
/// this may be unnecessary.
const _MIN_LIMBS_AT_LEAST_4: () = assert!(MIN_LIMBS >= 4);
// We haven't tested shorter lengths.
assert!(LEN_MIN >= MIN_LIMBS);
if n.len() < LEN_MIN {
return Err(LimbSliceError::too_short(n.len()));
}
let len = NonZeroUsize::new(n.len()).unwrap_or_else(|| {
// Unreachable because we checked against `LEN_MIN`, and we checked
// `LEN_MIN` is nonzero.
unreachable!()
});
// Avoid stack overflow from the alloca inside.
if len.get() > MAX_LIMBS {
return Err(LimbSliceError::too_long(n.len()));
}
in_out
.with_non_dangling_non_null_pointers_rab(len, |r, a, b| {
let n = n.as_ptr();
let _: Cpu = cpu;
unsafe { f(r, a, b, n, n0, len) };
})
.map_err(LimbSliceError::len_mismatch)
}

177
vendor/ring/src/arithmetic/inout.rs vendored Normal file
View File

@@ -0,0 +1,177 @@
// Copyright 2025 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
pub(crate) use crate::error::LenMismatchError;
use core::num::NonZeroUsize;
pub(crate) trait AliasingSlices2<T> {
/// The pointers passed to `f` will be valid and non-null, and will not
/// be dangling, so they can be passed to C functions.
///
/// The first pointer, `r`, may be pointing to uninitialized memory for
/// `expected_len` elements of type `T`, properly aligned and writable.
/// `f` must not read from `r` before writing to it.
///
/// The second & third pointers, `a` and `b`, point to `expected_len`
/// values of type `T`, properly aligned.
///
/// `r`, `a`, and/or `b` may alias each other only in the following ways:
/// `ptr::eq(r, a)`, `ptr::eq(r, b)`, and/or `ptr::eq(a, b)`; i.e. they
/// will not be "overlapping."
///
/// Implementations of this trait shouldn't override this default
/// implementation.
#[inline(always)]
fn with_non_dangling_non_null_pointers_ra<R>(
self,
expected_len: NonZeroUsize,
f: impl FnOnce(*mut T, *const T) -> R,
) -> Result<R, LenMismatchError>
where
Self: Sized,
{
self.with_potentially_dangling_non_null_pointers_ra(expected_len.get(), f)
}
/// If `expected_len == 0` then the pointers passed to `f` may be
/// dangling pointers, which should not be passed to C functions. In all
/// other respects, this works like
/// `Self::with_non_dangling_non_null_pointers_rab`.
///
/// Implementations of this trait should implement this method and not
/// `with_non_dangling_non_null_pointers_rab`. Users of this trait should
/// use `with_non_dangling_non_null_pointers_rab` and not this.
fn with_potentially_dangling_non_null_pointers_ra<R>(
self,
expected_len: usize,
f: impl FnOnce(*mut T, *const T) -> R,
) -> Result<R, LenMismatchError>;
}
impl<T> AliasingSlices2<T> for &mut [T] {
fn with_potentially_dangling_non_null_pointers_ra<R>(
self,
expected_len: usize,
f: impl FnOnce(*mut T, *const T) -> R,
) -> Result<R, LenMismatchError> {
let r = self;
if r.len() != expected_len {
return Err(LenMismatchError::new(r.len()));
}
Ok(f(r.as_mut_ptr(), r.as_ptr()))
}
}
impl<T> AliasingSlices2<T> for (&mut [T], &[T]) {
fn with_potentially_dangling_non_null_pointers_ra<R>(
self,
expected_len: usize,
f: impl FnOnce(*mut T, *const T) -> R,
) -> Result<R, LenMismatchError> {
let (r, a) = self;
if r.len() != expected_len {
return Err(LenMismatchError::new(r.len()));
}
if a.len() != expected_len {
return Err(LenMismatchError::new(a.len()));
}
Ok(f(r.as_mut_ptr(), a.as_ptr()))
}
}
pub(crate) trait AliasingSlices3<T> {
/// The pointers passed to `f` will all be non-null and properly aligned,
/// and will not be dangling.
///
/// The first pointer, `r` points to potentially-uninitialized writable
/// space for `expected_len` elements of type `T`. Accordingly, `f` must
/// not read from `r` before writing to it.
///
/// The second & third pointers, `a` and `b`, point to `expected_len`
/// initialized values of type `T`.
///
/// `r`, `a`, and/or `b` may alias each other, but only in the following
/// ways: `ptr::eq(r, a)`, `ptr::eq(r, b)`, and/or `ptr::eq(a, b)`; they
/// will not be "overlapping."
///
/// Implementations of this trait shouldn't override this default
/// implementation.
#[inline(always)]
fn with_non_dangling_non_null_pointers_rab<R>(
self,
expected_len: NonZeroUsize,
f: impl FnOnce(*mut T, *const T, *const T) -> R,
) -> Result<R, LenMismatchError>
where
Self: Sized,
{
self.with_potentially_dangling_non_null_pointers_rab(expected_len.get(), f)
}
/// If `expected_len == 0` then the pointers passed to `f` may be
/// dangling pointers, which should not be passed to C functions. In all
/// other respects, this works like
/// `Self::with_non_dangling_non_null_pointers_rab`.
///
/// Implementations of this trait should implement this method and not
/// `with_non_dangling_non_null_pointers_rab`. Users of this trait should
/// use `with_non_dangling_non_null_pointers_rab` and not this.
fn with_potentially_dangling_non_null_pointers_rab<R>(
self,
expected_len: usize,
f: impl FnOnce(*mut T, *const T, *const T) -> R,
) -> Result<R, LenMismatchError>;
}
impl<T> AliasingSlices3<T> for &mut [T] {
fn with_potentially_dangling_non_null_pointers_rab<R>(
self,
expected_len: usize,
f: impl FnOnce(*mut T, *const T, *const T) -> R,
) -> Result<R, LenMismatchError> {
<Self as AliasingSlices2<T>>::with_potentially_dangling_non_null_pointers_ra(
self,
expected_len,
|r, a| f(r, r, a),
)
}
}
impl<T> AliasingSlices3<T> for (&mut [T], &[T], &[T]) {
fn with_potentially_dangling_non_null_pointers_rab<R>(
self,
expected_len: usize,
f: impl FnOnce(*mut T, *const T, *const T) -> R,
) -> Result<R, LenMismatchError> {
let (r, a, b) = self;
((r, a), b).with_potentially_dangling_non_null_pointers_rab(expected_len, f)
}
}
impl<RA, T> AliasingSlices3<T> for (RA, &[T])
where
RA: AliasingSlices2<T>,
{
fn with_potentially_dangling_non_null_pointers_rab<R>(
self,
expected_len: usize,
f: impl FnOnce(*mut T, *const T, *const T) -> R,
) -> Result<R, LenMismatchError> {
let (ra, b) = self;
if b.len() != expected_len {
return Err(LenMismatchError::new(b.len()));
}
ra.with_potentially_dangling_non_null_pointers_ra(expected_len, |r, a| f(r, a, b.as_ptr()))
}
}

View File

@@ -0,0 +1,17 @@
// Copyright 2025 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#![cfg(all(target_arch = "aarch64", target_endian = "little"))]
pub(in super::super) mod mont;

View File

@@ -0,0 +1,59 @@
// Copyright 2025 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#![cfg(all(target_arch = "aarch64", target_endian = "little"))]
use super::super::super::{inout::AliasingSlices3 as _, n0::N0, LimbSliceError, MAX_LIMBS};
use crate::{
c,
limb::Limb,
polyfill::slice::{AsChunks, AsChunksMut},
};
use core::num::NonZeroUsize;
#[inline]
pub(in super::super::super) fn sqr_mont5(
mut in_out: AsChunksMut<Limb, 8>,
n: AsChunks<Limb, 8>,
n0: &N0,
) -> Result<(), LimbSliceError> {
prefixed_extern! {
// `r` and/or 'a' may alias.
// XXX: BoringSSL (kinda, implicitly) declares this to return `int`.
// `num` must be a non-zero multiple of 8.
fn bn_sqr8x_mont(
rp: *mut Limb,
ap: *const Limb,
ap_again: *const Limb,
np: *const Limb,
n0: &N0,
num: c::NonZero_size_t);
}
let in_out = in_out.as_flattened_mut();
let n = n.as_flattened();
let num_limbs = NonZeroUsize::new(n.len()).ok_or_else(|| LimbSliceError::too_short(n.len()))?;
// Avoid stack overflow from the alloca inside.
if num_limbs.get() > MAX_LIMBS {
return Err(LimbSliceError::too_long(num_limbs.get()));
}
in_out
.with_non_dangling_non_null_pointers_rab(num_limbs, |r, a, a_again| {
let n = n.as_ptr(); // Non-dangling because num_limbs > 0.
unsafe { bn_sqr8x_mont(r, a, a_again, n, n0, num_limbs) };
})
.map_err(LimbSliceError::len_mismatch)
}

16
vendor/ring/src/arithmetic/limbs/mod.rs vendored Normal file
View File

@@ -0,0 +1,16 @@
// Copyright 2025 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
pub(super) mod aarch64;
pub(super) mod x86_64;

View File

@@ -0,0 +1,17 @@
// Copyright 2025 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#![cfg(target_arch = "x86_64")]
pub(in super::super::super) mod mont;

View File

@@ -0,0 +1,312 @@
// Copyright 2015-2025 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#![cfg(target_arch = "x86_64")]
use super::super::super::{
inout::{AliasingSlices2, AliasingSlices3},
n0::N0,
LimbSliceError, MAX_LIMBS,
};
use crate::{
c,
cpu::intel::{Adx, Bmi1, Bmi2},
error::LenMismatchError,
limb::{LeakyWindow, Limb, Window},
polyfill::slice::{AsChunks, AsChunksMut},
};
use core::num::NonZeroUsize;
const _512_IS_LIMB_BITS_TIMES_8: () = assert!(8 * Limb::BITS == 512);
#[inline]
pub(in super::super::super) fn mul_mont5(
mut r: AsChunksMut<Limb, 8>,
a: AsChunks<Limb, 8>,
b: AsChunks<Limb, 8>,
m: AsChunks<Limb, 8>,
n0: &N0,
maybe_adx_bmi2: Option<(Adx, Bmi2)>,
) -> Result<(), LimbSliceError> {
mul_mont5_4x(
(r.as_flattened_mut(), a.as_flattened(), b.as_flattened()),
m.into(),
n0,
maybe_adx_bmi2,
)
}
pub const MIN_4X: usize = 8;
#[inline]
pub(in super::super::super) fn mul_mont5_4x(
in_out: impl AliasingSlices3<Limb>,
n: AsChunks<Limb, 4>,
n0: &N0,
maybe_adx_bmi2: Option<(Adx, Bmi2)>,
) -> Result<(), LimbSliceError> {
const MOD_4X: usize = 4;
let n = n.as_flattened();
if let Some(cpu) = maybe_adx_bmi2 {
bn_mul_mont_ffi!(in_out, n, n0, cpu, unsafe {
(MIN_4X, MOD_4X, (Adx, Bmi2)) => bn_mulx4x_mont
})
} else {
bn_mul_mont_ffi!(in_out, n, n0, (), unsafe {
(MIN_4X, MOD_4X, ()) => bn_mul4x_mont
})
}
}
#[inline]
pub(in super::super::super) fn sqr_mont5(
mut in_out: AsChunksMut<Limb, 8>,
n: AsChunks<Limb, 8>,
n0: &N0,
maybe_adx_bmi2: Option<(Adx, Bmi2)>,
) -> Result<(), LimbSliceError> {
prefixed_extern! {
// `r` and/or 'a' may alias.
// XXX: BoringSSL declares this to return `int`.
// `num` must be a non-zero multiple of 8.
fn bn_sqr8x_mont(
rp: *mut Limb,
ap: *const Limb,
mulx_adx_capable: Limb,
np: *const Limb,
n0: &N0,
num: c::NonZero_size_t);
}
let in_out = in_out.as_flattened_mut();
let n = n.as_flattened();
let num_limbs = NonZeroUsize::new(n.len()).ok_or_else(|| LimbSliceError::too_short(n.len()))?;
// Avoid stack overflow from the alloca inside.
if num_limbs.get() > MAX_LIMBS {
return Err(LimbSliceError::too_long(num_limbs.get()));
}
// `Limb::from(mulx_adx.is_some())`, but intentionally branchy.
let mulx_adx_capable = match maybe_adx_bmi2 {
Some(_) => Limb::from(true),
None => Limb::from(false),
};
in_out
.with_non_dangling_non_null_pointers_ra(num_limbs, |r, a| {
let n = n.as_ptr(); // Non-dangling because num_limbs > 0.
unsafe { bn_sqr8x_mont(r, a, mulx_adx_capable, n, n0, num_limbs) };
})
.map_err(LimbSliceError::len_mismatch)
}
#[inline(always)]
pub(in super::super::super) fn scatter5(
a: AsChunks<Limb, 8>,
mut table: AsChunksMut<Limb, 8>,
power: LeakyWindow,
) -> Result<(), LimbSliceError> {
prefixed_extern! {
// Upstream uses `num: c::size_t` too, and `power: c::size_t`; see
// `_MAX_LIMBS_ADDRESSES_MEMORY_SAFETY_ISSUES`.
fn bn_scatter5(
inp: *const Limb,
num: c::NonZero_size_t,
table: *mut Limb,
power: LeakyWindow,
);
}
let num_limbs = check_common(a, table.as_ref())?;
let a = a.as_flattened();
let table = table.as_flattened_mut();
assert!(power < 32);
unsafe { bn_scatter5(a.as_ptr(), num_limbs, table.as_mut_ptr(), power) };
Ok(())
}
// SAFETY: `power` must be less than 32.
#[inline(always)]
pub(in super::super::super) unsafe fn gather5(
mut r: AsChunksMut<Limb, 8>,
table: AsChunks<Limb, 8>,
power: Window,
) -> Result<(), LimbSliceError> {
prefixed_extern! {
// Upstream uses `num: c::size_t` too, and `power: c::size_t`; see
// `_MAX_LIMBS_ADDRESSES_MEMORY_SAFETY_ISSUES`.
fn bn_gather5(
out: *mut Limb,
num: c::NonZero_size_t,
table: *const Limb,
power: Window);
}
let num_limbs = check_common(r.as_ref(), table)?;
let r = r.as_flattened_mut();
let table = table.as_flattened();
// SAFETY: We cannot assert that `power` is in range because it is secret.
// TODO: Create a `Window5` type that is guaranteed to be in range.
unsafe { bn_gather5(r.as_mut_ptr(), num_limbs, table.as_ptr(), power) };
Ok(())
}
// SAFETY: `power` must be less than 32.
#[inline(always)]
pub(in super::super::super) unsafe fn mul_mont_gather5_amm(
mut r: AsChunksMut<Limb, 8>,
a: AsChunks<Limb, 8>,
table: AsChunks<Limb, 8>,
n: AsChunks<Limb, 8>,
n0: &N0,
power: Window,
maybe_adx_bmi1_bmi2: Option<(Adx, Bmi1, Bmi2)>,
) -> Result<(), LimbSliceError> {
prefixed_extern! {
// Upstream has `num: c_int` and `power: c_int`; see
// `_MAX_LIMBS_ADDRESSES_MEMORY_SAFETY_ISSUES`.
fn bn_mul4x_mont_gather5(
rp: *mut Limb,
ap: *const Limb,
table: *const Limb,
np: *const Limb,
n0: &N0,
num: c::NonZero_size_t,
power: Window,
);
// Upstream has `num: c_int` and `power: c_int`; see
// `_MAX_LIMBS_ADDRESSES_MEMORY_SAFETY_ISSUES`.
fn bn_mulx4x_mont_gather5(
rp: *mut Limb,
ap: *const Limb,
table: *const Limb,
np: *const Limb,
n0: &N0,
num: c::NonZero_size_t,
power: Window,
);
}
let num_limbs = check_common_with_n(r.as_ref(), table, n)?;
let a = a.as_flattened();
if a.len() != num_limbs.get() {
return Err(LimbSliceError::len_mismatch(LenMismatchError::new(a.len())));
}
let r = r.as_flattened_mut();
let r = r.as_mut_ptr();
let a = a.as_ptr();
let table = table.as_flattened();
let table = table.as_ptr();
let n = n.as_flattened();
let n = n.as_ptr();
// SAFETY: We cannot assert that `power` is in range because it is secret.
// TODO: Create a `Window5` type that is guaranteed to be in range.
if maybe_adx_bmi1_bmi2.is_some() {
unsafe { bn_mulx4x_mont_gather5(r, a, table, n, n0, num_limbs, power) }
} else {
unsafe { bn_mul4x_mont_gather5(r, a, table, n, n0, num_limbs, power) }
};
Ok(())
}
// SAFETY: `power` must be less than 32.
#[inline(always)]
pub(in super::super::super) unsafe fn power5_amm(
mut in_out: AsChunksMut<Limb, 8>,
table: AsChunks<Limb, 8>,
n: AsChunks<Limb, 8>,
n0: &N0,
power: Window,
maybe_adx_bmi1_bmi2: Option<(Adx, Bmi1, Bmi2)>,
) -> Result<(), LimbSliceError> {
prefixed_extern! {
// Upstream has `num: c_int` and `power: c_int`; see
// `_MAX_LIMBS_ADDRESSES_MEMORY_SAFETY_ISSUES`.
fn bn_power5_nohw(
rp: *mut Limb,
ap: *const Limb,
table: *const Limb,
np: *const Limb,
n0: &N0,
num: c::NonZero_size_t,
power: Window,
);
// Upstream has `num: c_int` and `power: c_int`; see
// `_MAX_LIMBS_ADDRESSES_MEMORY_SAFETY_ISSUES`.
fn bn_powerx5(
rp: *mut Limb,
ap: *const Limb,
table: *const Limb,
np: *const Limb,
n0: &N0,
num: c::NonZero_size_t,
power: Window,
);
}
let num_limbs = check_common_with_n(in_out.as_ref(), table, n)?;
let in_out = in_out.as_flattened_mut();
let r = in_out.as_mut_ptr();
let a = in_out.as_ptr();
let table = table.as_flattened();
let table = table.as_ptr();
let n = n.as_flattened();
let n = n.as_ptr();
// SAFETY: We cannot assert that `power` is in range because it is secret.
// TODO: Create a `Window5` type that is guaranteed to be in range.
if maybe_adx_bmi1_bmi2.is_some() {
unsafe { bn_powerx5(r, a, table, n, n0, num_limbs, power) }
} else {
unsafe { bn_power5_nohw(r, a, table, n, n0, num_limbs, power) }
};
Ok(())
}
// Helps the compiler will be able to hoist all of these checks out of the
// loops in the caller. Try to help the compiler by doing the checks
// consistently in each function and also by inlining this function and all the
// callers.
#[inline(always)]
fn check_common(
a: AsChunks<Limb, 8>,
table: AsChunks<Limb, 8>,
) -> Result<NonZeroUsize, LimbSliceError> {
assert_eq!((table.as_ptr() as usize) % 16, 0); // According to BoringSSL.
let a = a.as_flattened();
let table = table.as_flattened();
let num_limbs = NonZeroUsize::new(a.len()).ok_or_else(|| LimbSliceError::too_short(a.len()))?;
if num_limbs.get() > MAX_LIMBS {
return Err(LimbSliceError::too_long(a.len()));
}
if num_limbs.get() * 32 != table.len() {
return Err(LimbSliceError::len_mismatch(LenMismatchError::new(
table.len(),
)));
};
Ok(num_limbs)
}
#[inline(always)]
fn check_common_with_n(
a: AsChunks<Limb, 8>,
table: AsChunks<Limb, 8>,
n: AsChunks<Limb, 8>,
) -> Result<NonZeroUsize, LimbSliceError> {
// Choose `a` instead of `n` so that every function starts with
// `check_common` passing the exact same arguments, so that the compiler
// can easily de-dupe the checks.
let num_limbs = check_common(a, table)?;
let n = n.as_flattened();
if n.len() != num_limbs.get() {
return Err(LimbSliceError::len_mismatch(LenMismatchError::new(n.len())));
}
Ok(num_limbs)
}

View File

@@ -0,0 +1,17 @@
// Copyright 2025 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
mod storage;
pub(super) use self::storage::{AlignedStorage, LIMBS_PER_CHUNK};

View File

@@ -0,0 +1,60 @@
// Copyright 2025 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use crate::{
error::LenMismatchError,
limb::{Limb, LIMB_BITS},
polyfill::slice::{self, AsChunksMut},
};
use core::mem::{align_of, size_of};
// Some x86_64 assembly is written under the assumption that some of its
// input data and/or temporary storage is aligned to `MOD_EXP_CTIME_ALIGN`
// bytes, which was/is 64 in OpenSSL.
//
// We use this in the non-X86-64 implementation of exponentiation as well,
// with the hope of converging th two implementations into one.
#[repr(C, align(64))]
pub struct AlignedStorage<const N: usize>([Limb; N]);
const _LIMB_SIZE_DIVIDES_ALIGNMENT: () =
assert!(align_of::<AlignedStorage<1>>() % size_of::<Limb>() == 0);
pub const LIMBS_PER_CHUNK: usize = 512 / LIMB_BITS;
impl<const N: usize> AlignedStorage<N> {
pub fn zeroed() -> Self {
assert_eq!(N % LIMBS_PER_CHUNK, 0); // TODO: const.
Self([0; N])
}
// The result will have every chunk aligned on a 64 byte boundary.
pub fn aligned_chunks_mut(
&mut self,
num_entries: usize,
chunks_per_entry: usize,
) -> Result<AsChunksMut<Limb, LIMBS_PER_CHUNK>, LenMismatchError> {
let total_limbs = num_entries * chunks_per_entry * LIMBS_PER_CHUNK;
let len = self.0.len();
let flattened = self
.0
.get_mut(..total_limbs)
.ok_or_else(|| LenMismatchError::new(len))?;
match slice::as_chunks_mut(flattened) {
(chunks, []) => Ok(chunks),
(_, r) => Err(LenMismatchError::new(r.len())),
}
}
}

384
vendor/ring/src/arithmetic/montgomery.rs vendored Normal file
View File

@@ -0,0 +1,384 @@
// Copyright 2017-2025 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
pub use super::n0::N0;
use super::{inout::AliasingSlices3, LimbSliceError, MIN_LIMBS};
use crate::cpu;
use cfg_if::cfg_if;
// Indicates that the element is not encoded; there is no *R* factor
// that needs to be canceled out.
#[derive(Copy, Clone)]
pub enum Unencoded {}
// Indicates that the element is encoded; the value has one *R*
// factor that needs to be canceled out.
#[derive(Copy, Clone)]
pub enum R {}
// Indicates the element is encoded three times; the value has three
// *R* factors that need to be canceled out.
#[allow(clippy::upper_case_acronyms)]
#[derive(Copy, Clone)]
pub enum RRR {}
// Indicates the element is encoded twice; the value has two *R*
// factors that need to be canceled out.
#[derive(Copy, Clone)]
pub enum RR {}
// Indicates the element is inversely encoded; the value has one
// 1/*R* factor that needs to be canceled out.
#[derive(Copy, Clone)]
pub enum RInverse {}
pub trait Encoding {}
impl Encoding for RRR {}
impl Encoding for RR {}
impl Encoding for R {}
impl Encoding for Unencoded {}
impl Encoding for RInverse {}
/// The encoding of the result of a reduction.
pub trait ReductionEncoding {
type Output: Encoding;
}
impl ReductionEncoding for RRR {
type Output = RR;
}
impl ReductionEncoding for RR {
type Output = R;
}
impl ReductionEncoding for R {
type Output = Unencoded;
}
impl ReductionEncoding for Unencoded {
type Output = RInverse;
}
/// The encoding of the result of a multiplication.
pub trait ProductEncoding {
type Output: Encoding;
}
impl<E: ReductionEncoding> ProductEncoding for (Unencoded, E) {
type Output = E::Output;
}
impl<E: Encoding> ProductEncoding for (R, E) {
type Output = E;
}
impl ProductEncoding for (RR, RR) {
type Output = RRR;
}
impl<E: ReductionEncoding> ProductEncoding for (RInverse, E)
where
E::Output: ReductionEncoding,
{
type Output = <<E as ReductionEncoding>::Output as ReductionEncoding>::Output;
}
// XXX: Rust doesn't allow overlapping impls,
// TODO (if/when Rust allows it):
// impl<E1, E2: ReductionEncoding> ProductEncoding for
// (E1, E2) {
// type Output = <(E2, E1) as ProductEncoding>::Output;
// }
impl ProductEncoding for (RR, Unencoded) {
type Output = <(Unencoded, RR) as ProductEncoding>::Output;
}
impl ProductEncoding for (RR, RInverse) {
type Output = <(RInverse, RR) as ProductEncoding>::Output;
}
impl ProductEncoding for (RRR, RInverse) {
type Output = <(RInverse, RRR) as ProductEncoding>::Output;
}
#[allow(unused_imports)]
use crate::{bssl, c, limb::Limb};
#[inline(always)]
pub(super) fn limbs_mul_mont(
in_out: impl AliasingSlices3<Limb>,
n: &[Limb],
n0: &N0,
cpu: cpu::Features,
) -> Result<(), LimbSliceError> {
const MOD_FALLBACK: usize = 1; // No restriction.
cfg_if! {
if #[cfg(all(target_arch = "aarch64", target_endian = "little"))] {
let _: cpu::Features = cpu;
const MIN_4X: usize = 4;
const MOD_4X: usize = 4;
if n.len() >= MIN_4X && n.len() % MOD_4X == 0 {
bn_mul_mont_ffi!(in_out, n, n0, (), unsafe {
(MIN_4X, MOD_4X, ()) => bn_mul4x_mont
})
} else {
bn_mul_mont_ffi!(in_out, n, n0, (), unsafe {
(MIN_LIMBS, MOD_FALLBACK, ()) => bn_mul_mont_nohw
})
}
} else if #[cfg(all(target_arch = "arm", target_endian = "little"))] {
const MIN_8X: usize = 8;
const MOD_8X: usize = 8;
if n.len() >= MIN_8X && n.len() % MOD_8X == 0 {
use crate::cpu::{GetFeature as _, arm::Neon};
if let Some(cpu) = cpu.get_feature() {
return bn_mul_mont_ffi!(in_out, n, n0, cpu, unsafe {
(MIN_8X, MOD_8X, Neon) => bn_mul8x_mont_neon
});
}
}
// The ARM version of `bn_mul_mont_nohw` has a minimum of 2.
const _MIN_LIMBS_AT_LEAST_2: () = assert!(MIN_LIMBS >= 2);
bn_mul_mont_ffi!(in_out, n, n0, (), unsafe {
(MIN_LIMBS, MOD_FALLBACK, ()) => bn_mul_mont_nohw
})
} else if #[cfg(target_arch = "x86")] {
use crate::{cpu::GetFeature as _, cpu::intel::Sse2};
// The X86 implementation of `bn_mul_mont` has a minimum of 4.
const _MIN_LIMBS_AT_LEAST_4: () = assert!(MIN_LIMBS >= 4);
if let Some(cpu) = cpu.get_feature() {
bn_mul_mont_ffi!(in_out, n, n0, cpu, unsafe {
(MIN_LIMBS, MOD_FALLBACK, Sse2) => bn_mul_mont
})
} else {
// This isn't really an FFI call; it's defined below.
unsafe {
super::ffi::bn_mul_mont_ffi::<(), {MIN_LIMBS}, 1>(in_out, n, n0, (),
bn_mul_mont_fallback)
}
}
} else if #[cfg(target_arch = "x86_64")] {
use crate::{cpu::GetFeature as _, polyfill::slice};
use super::limbs::x86_64;
if n.len() >= x86_64::mont::MIN_4X {
if let (n, []) = slice::as_chunks(n) {
return x86_64::mont::mul_mont5_4x(in_out, n, n0, cpu.get_feature());
}
}
bn_mul_mont_ffi!(in_out, n, n0, (), unsafe {
(MIN_LIMBS, MOD_FALLBACK, ()) => bn_mul_mont_nohw
})
} else {
// Use the fallback implementation implemented below through the
// FFI wrapper defined below, so that Rust and C code both go
// through `bn_mul_mont`.
bn_mul_mont_ffi!(in_out, n, n0, cpu, unsafe {
(MIN_LIMBS, MOD_FALLBACK, cpu::Features) => bn_mul_mont
})
}
}
}
cfg_if! {
if #[cfg(not(any(
all(target_arch = "aarch64", target_endian = "little"),
all(target_arch = "arm", target_endian = "little"),
target_arch = "x86_64")))] {
// TODO: Stop calling this from C and un-export it.
#[cfg(not(target_arch = "x86"))]
prefixed_export! {
unsafe extern "C" fn bn_mul_mont(
r: *mut Limb,
a: *const Limb,
b: *const Limb,
n: *const Limb,
n0: &N0,
num_limbs: c::NonZero_size_t,
) {
unsafe { bn_mul_mont_fallback(r, a, b, n, n0, num_limbs) }
}
}
#[cfg_attr(target_arch = "x86", cold)]
#[cfg_attr(target_arch = "x86", inline(never))]
unsafe extern "C" fn bn_mul_mont_fallback(
r: *mut Limb,
a: *const Limb,
b: *const Limb,
n: *const Limb,
n0: &N0,
num_limbs: c::NonZero_size_t,
) {
use super::MAX_LIMBS;
let num_limbs = num_limbs.get();
// The mutable pointer `r` may alias `a` and/or `b`, so the lifetimes of
// any slices for `a` or `b` must not overlap with the lifetime of any
// mutable for `r`.
// Nothing aliases `n`
let n = unsafe { core::slice::from_raw_parts(n, num_limbs) };
let mut tmp = [0; 2 * MAX_LIMBS];
let tmp = &mut tmp[..(2 * num_limbs)];
{
let a: &[Limb] = unsafe { core::slice::from_raw_parts(a, num_limbs) };
let b: &[Limb] = unsafe { core::slice::from_raw_parts(b, num_limbs) };
limbs_mul(tmp, a, b);
}
let r: &mut [Limb] = unsafe { core::slice::from_raw_parts_mut(r, num_limbs) };
limbs_from_mont_in_place(r, tmp, n, n0);
}
}
}
// `bigint` needs then when the `alloc` feature is enabled. `bn_mul_mont` above needs this when
// we are using the platforms for which we don't have `bn_mul_mont` in assembly.
#[cfg(any(
feature = "alloc",
not(any(
all(target_arch = "aarch64", target_endian = "little"),
all(target_arch = "arm", target_endian = "little"),
target_arch = "x86_64"
))
))]
pub(super) fn limbs_from_mont_in_place(r: &mut [Limb], tmp: &mut [Limb], m: &[Limb], n0: &N0) {
prefixed_extern! {
fn bn_from_montgomery_in_place(
r: *mut Limb,
num_r: c::size_t,
a: *mut Limb,
num_a: c::size_t,
n: *const Limb,
num_n: c::size_t,
n0: &N0,
) -> bssl::Result;
}
Result::from(unsafe {
bn_from_montgomery_in_place(
r.as_mut_ptr(),
r.len(),
tmp.as_mut_ptr(),
tmp.len(),
m.as_ptr(),
m.len(),
n0,
)
})
.unwrap()
}
#[cfg(not(any(
all(target_arch = "aarch64", target_endian = "little"),
all(target_arch = "arm", target_endian = "little"),
target_arch = "x86_64"
)))]
fn limbs_mul(r: &mut [Limb], a: &[Limb], b: &[Limb]) {
debug_assert_eq!(r.len(), 2 * a.len());
debug_assert_eq!(a.len(), b.len());
let ab_len = a.len();
r[..ab_len].fill(0);
for (i, &b_limb) in b.iter().enumerate() {
r[ab_len + i] = unsafe {
limbs_mul_add_limb(r[i..][..ab_len].as_mut_ptr(), a.as_ptr(), b_limb, ab_len)
};
}
}
#[cfg(any(
test,
not(any(
all(target_arch = "aarch64", target_endian = "little"),
all(target_arch = "arm", target_endian = "little"),
target_arch = "x86_64",
))
))]
prefixed_extern! {
// `r` must not alias `a`
#[must_use]
fn limbs_mul_add_limb(r: *mut Limb, a: *const Limb, b: Limb, num_limbs: c::size_t) -> Limb;
}
/// r = r**2
pub(super) fn limbs_square_mont(
r: &mut [Limb],
n: &[Limb],
n0: &N0,
cpu: cpu::Features,
) -> Result<(), LimbSliceError> {
#[cfg(all(target_arch = "aarch64", target_endian = "little"))]
{
use super::limbs::aarch64;
use crate::polyfill::slice;
if let ((r, []), (n, [])) = (slice::as_chunks_mut(r), slice::as_chunks(n)) {
return aarch64::mont::sqr_mont5(r, n, n0);
}
}
#[cfg(target_arch = "x86_64")]
{
use super::limbs::x86_64;
use crate::{cpu::GetFeature as _, polyfill::slice};
if let ((r, []), (n, [])) = (slice::as_chunks_mut(r), slice::as_chunks(n)) {
return x86_64::mont::sqr_mont5(r, n, n0, cpu.get_feature());
}
}
limbs_mul_mont(r, n, n0, cpu)
}
#[cfg(test)]
mod tests {
use super::super::MAX_LIMBS;
use super::*;
use crate::limb::Limb;
#[test]
// TODO: wasm
fn test_mul_add_words() {
const ZERO: Limb = 0;
const MAX: Limb = ZERO.wrapping_sub(1);
static TEST_CASES: &[(&[Limb], &[Limb], Limb, Limb, &[Limb])] = &[
(&[0], &[0], 0, 0, &[0]),
(&[MAX], &[0], MAX, 0, &[MAX]),
(&[0], &[MAX], MAX, MAX - 1, &[1]),
(&[MAX], &[MAX], MAX, MAX, &[0]),
(&[0, 0], &[MAX, MAX], MAX, MAX - 1, &[1, MAX]),
(&[1, 0], &[MAX, MAX], MAX, MAX - 1, &[2, MAX]),
(&[MAX, 0], &[MAX, MAX], MAX, MAX, &[0, 0]),
(&[0, 1], &[MAX, MAX], MAX, MAX, &[1, 0]),
(&[MAX, MAX], &[MAX, MAX], MAX, MAX, &[0, MAX]),
];
for (i, (r_input, a, w, expected_retval, expected_r)) in TEST_CASES.iter().enumerate() {
let mut r = [0; MAX_LIMBS];
let r = {
let r = &mut r[..r_input.len()];
r.copy_from_slice(r_input);
r
};
assert_eq!(r.len(), a.len()); // Sanity check
let actual_retval =
unsafe { limbs_mul_add_limb(r.as_mut_ptr(), a.as_ptr(), *w, a.len()) };
assert_eq!(&r, expected_r, "{}: {:x?} != {:x?}", i, r, expected_r);
assert_eq!(
actual_retval, *expected_retval,
"{}: {:x?} != {:x?}",
i, actual_retval, *expected_retval
);
}
}
}

37
vendor/ring/src/arithmetic/n0.rs vendored Normal file
View File

@@ -0,0 +1,37 @@
// Copyright 2015-2022 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use crate::limb::Limb;
#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct N0([Limb; 2]);
impl N0 {
#[cfg(feature = "alloc")]
pub(super) const LIMBS_USED: usize = 64 / crate::limb::LIMB_BITS;
#[inline]
pub const fn precalculated(n0: u64) -> Self {
#[cfg(target_pointer_width = "64")]
{
Self([n0, 0])
}
#[cfg(target_pointer_width = "32")]
{
Self([n0 as Limb, (n0 >> crate::limb::LIMB_BITS) as Limb])
}
}
}

41
vendor/ring/src/bb/boolmask.rs vendored Normal file
View File

@@ -0,0 +1,41 @@
// Copyright 2024 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use super::Word;
use core::ops;
// BoolMask is either `BoolMask::TRUE` or `BoolMask::FALSE`.
#[repr(transparent)]
pub struct BoolMask(Word);
impl BoolMask {
#[cfg(test)]
pub(super) const TRUE: Self = Self(Word::MAX);
#[cfg(test)]
pub(super) const FALSE: Self = Self(0);
/// Returns true if `self` is `BoolMask::TRUE`; otherwise, returns false
/// (`self` is `BoolMask::FALSE`).
pub(crate) fn leak(self) -> bool {
self.0 != 0
}
}
impl ops::BitAnd for BoolMask {
type Output = Self;
fn bitand(self, rhs: Self) -> Self {
Self(self.0 & rhs.0)
}
}

27
vendor/ring/src/bb/leaky.rs vendored Normal file
View File

@@ -0,0 +1,27 @@
// Copyright 2015-2024 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#[cfg(target_pointer_width = "64")]
type CompilerWord = u64;
#[cfg(target_pointer_width = "32")]
type CompilerWord = u32;
/// A native word that isn't secret.
///
/// `LeakyWord` supports `as` conversions to/from native types.
///
/// XXX: This isn't the native word size on targets where a pointer isn't the
/// same size as a native word. TODO: Fix this.
pub(crate) type LeakyWord = CompilerWord;

162
vendor/ring/src/bb/mod.rs vendored Normal file
View File

@@ -0,0 +1,162 @@
// Copyright 2015-2025 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//! Building blocks.
use crate::{c, error};
use core::{ffi::c_int, num::NonZeroUsize};
mod boolmask;
mod leaky;
mod word;
pub(crate) use self::{boolmask::BoolMask, leaky::LeakyWord, word::Word};
/// Returns `Ok(())` if `a == b` and `Err(error::Unspecified)` otherwise.
pub fn verify_slices_are_equal(a: &[u8], b: &[u8]) -> Result<(), error::Unspecified> {
let len = a.len(); // Arbitrary choice.
if b.len() != len {
return Err(error::Unspecified);
}
match NonZeroUsize::new(len) {
Some(len) => {
let a = a.as_ptr();
let b = b.as_ptr();
// SAFETY: `a` and `b` are valid non-null non-dangling pointers to `len`
// bytes.
let result = unsafe { CRYPTO_memcmp(a, b, len) };
match result {
0 => Ok(()),
_ => Err(error::Unspecified),
}
}
None => Ok(()), // Empty slices are equal.
}
}
prefixed_extern! {
fn CRYPTO_memcmp(a: *const u8, b: *const u8, len: c::NonZero_size_t) -> c_int;
}
pub(crate) fn xor_16(a: [u8; 16], b: [u8; 16]) -> [u8; 16] {
let a = u128::from_ne_bytes(a);
let b = u128::from_ne_bytes(b);
let r = a ^ b;
r.to_ne_bytes()
}
#[inline(always)]
pub(crate) fn xor_assign<'a>(a: impl IntoIterator<Item = &'a mut u8>, b: u8) {
a.into_iter().for_each(|a| *a ^= b);
}
/// XORs the first N bytes of `b` into `a`, where N is
/// `core::cmp::min(a.len(), b.len())`.
#[inline(always)]
pub(crate) fn xor_assign_at_start<'a>(
a: impl IntoIterator<Item = &'a mut u8>,
b: impl IntoIterator<Item = &'a u8>,
) {
a.into_iter().zip(b).for_each(|(a, b)| *a ^= *b);
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{bssl, rand};
fn leak_in_test(a: BoolMask) -> bool {
a.leak()
}
#[test]
fn test_constant_time() -> Result<(), error::Unspecified> {
prefixed_extern! {
fn bssl_constant_time_test_main() -> bssl::Result;
}
Result::from(unsafe { bssl_constant_time_test_main() })
}
#[test]
fn constant_time_conditional_memcpy() -> Result<(), error::Unspecified> {
let rng = rand::SystemRandom::new();
for _ in 0..100 {
let mut out = rand::generate::<[u8; 256]>(&rng)?.expose();
let input = rand::generate::<[u8; 256]>(&rng)?.expose();
// Mask to 16 bits to make zero more likely than it would otherwise be.
let b = (rand::generate::<[u8; 1]>(&rng)?.expose()[0] & 0x0f) == 0;
let ref_in = input;
let ref_out = if b { input } else { out };
prefixed_extern! {
fn bssl_constant_time_test_conditional_memcpy(dst: &mut [u8; 256], src: &[u8; 256], b: BoolMask);
}
unsafe {
bssl_constant_time_test_conditional_memcpy(
&mut out,
&input,
if b { BoolMask::TRUE } else { BoolMask::FALSE },
)
}
assert_eq!(ref_in, input);
assert_eq!(ref_out, out);
}
Ok(())
}
#[test]
fn constant_time_conditional_memxor() -> Result<(), error::Unspecified> {
let rng = rand::SystemRandom::new();
for _ in 0..256 {
let mut out = rand::generate::<[u8; 256]>(&rng)?.expose();
let input = rand::generate::<[u8; 256]>(&rng)?.expose();
// Mask to 16 bits to make zero more likely than it would otherwise be.
let b = (rand::generate::<[u8; 1]>(&rng)?.expose()[0] & 0x0f) != 0;
let ref_in = input;
let mut ref_out = out;
if b {
xor_assign_at_start(&mut ref_out, &ref_in)
};
prefixed_extern! {
fn bssl_constant_time_test_conditional_memxor(dst: &mut [u8; 256], src: &[u8; 256], b: BoolMask);
}
unsafe {
bssl_constant_time_test_conditional_memxor(
&mut out,
&input,
if b { BoolMask::TRUE } else { BoolMask::FALSE },
);
}
assert_eq!(ref_in, input);
assert_eq!(ref_out, out);
}
Ok(())
}
#[test]
fn test_bool_mask_bitwise_and_is_logical_and() {
assert!(leak_in_test(BoolMask::TRUE & BoolMask::TRUE));
assert!(!leak_in_test(BoolMask::TRUE & BoolMask::FALSE));
assert!(!leak_in_test(BoolMask::FALSE & BoolMask::TRUE));
assert!(!leak_in_test(BoolMask::FALSE & BoolMask::FALSE));
}
}

44
vendor/ring/src/bb/word.rs vendored Normal file
View File

@@ -0,0 +1,44 @@
// Copyright 2015-2024 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use super::LeakyWord;
/// A native word that may hold a secret.
///
/// XXX: Currently this is a type alias of `LeakyWord` so it doesn't enforce,
/// except by convention, the prevention of leaks. This is a temporary state to
/// support the refactorings that will
///
/// XXX: This isn't the native word size on targets where a pointer isn't the
/// same size as a native word. TODO: Fix this.
///
/// XXX: Over time, we'll evolve Word into a newtype with an API that minimizes
/// leaks and makes all leaks explicit, like so:
pub(crate) type Word = LeakyWord;
/* TODO:
#[repr(transparent)]
pub(crate) struct Word(LeakyWord);
impl Word {
pub fn leak_word(self) -> LeakyWord { self.0 }
}
impl From<LeakyWord> for Word {
fn from(w: LeakyWord) -> Self {
// TODO: Use a stronger `black_box`.
Self(core::hint::black_box(w))
}
}
*/

135
vendor/ring/src/bits.rs vendored Normal file
View File

@@ -0,0 +1,135 @@
// Copyright 2016 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//! Bit lengths.
use crate::{error::InputTooLongError, polyfill};
/// The length of something, in bits.
///
/// This can represent a bit length that isn't a whole number of bytes.
#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd)]
#[repr(transparent)]
pub struct BitLength<T = usize>(T);
pub(crate) trait FromByteLen<T>: Sized {
/// Constructs a `BitLength` from the given length in bytes.
///
/// Fails if `bytes * 8` is too large for a `T`.
fn from_byte_len(bytes: T) -> Result<Self, InputTooLongError<T>>;
}
impl FromByteLen<usize> for BitLength<usize> {
#[inline]
fn from_byte_len(bytes: usize) -> Result<Self, InputTooLongError> {
match bytes.checked_mul(8) {
Some(bits) => Ok(Self(bits)),
None => Err(InputTooLongError::new(bytes)),
}
}
}
impl FromByteLen<u64> for BitLength<u64> {
#[inline]
fn from_byte_len(bytes: u64) -> Result<Self, InputTooLongError<u64>> {
match bytes.checked_mul(8) {
Some(bits) => Ok(Self(bits)),
None => Err(InputTooLongError::new(bytes)),
}
}
}
impl FromByteLen<usize> for BitLength<u64> {
#[inline]
fn from_byte_len(bytes: usize) -> Result<Self, InputTooLongError<usize>> {
match polyfill::u64_from_usize(bytes).checked_mul(8) {
Some(bits) => Ok(Self(bits)),
None => Err(InputTooLongError::new(bytes)),
}
}
}
impl<T> BitLength<T> {
/// Constructs a `BitLength` from the given length in bits.
#[inline]
pub const fn from_bits(bits: T) -> Self {
Self(bits)
}
}
impl<T: Copy> BitLength<T> {
/// The number of bits this bit length represents, as the underlying type.
#[inline]
pub fn as_bits(self) -> T {
self.0
}
}
// Lengths measured in bits, where all arithmetic is guaranteed not to
// overflow.
impl BitLength<usize> {
#[cfg(feature = "alloc")]
#[inline]
pub(crate) fn half_rounded_up(&self) -> Self {
let round_up = self.0 & 1;
Self((self.0 / 2) + round_up)
}
/// The bit length, rounded up to a whole number of bytes.
#[inline]
pub const fn as_usize_bytes_rounded_up(&self) -> usize {
// Equivalent to (self.0 + 7) / 8, except with no potential for
// overflow and without branches.
// Branchless round_up = if self.0 & 0b111 != 0 { 1 } else { 0 };
let round_up = ((self.0 >> 2) | (self.0 >> 1) | self.0) & 1;
(self.0 / 8) + round_up
}
#[cfg(feature = "alloc")]
#[inline]
pub(crate) fn try_sub_1(self) -> Result<Self, crate::error::Unspecified> {
let sum = self.0.checked_sub(1).ok_or(crate::error::Unspecified)?;
Ok(Self(sum))
}
}
impl BitLength<u64> {
pub fn to_be_bytes(self) -> [u8; 8] {
self.0.to_be_bytes()
}
}
#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
impl From<BitLength<usize>> for BitLength<u64> {
fn from(BitLength(value): BitLength<usize>) -> Self {
BitLength(polyfill::u64_from_usize(value))
}
}
impl TryFrom<BitLength<u64>> for BitLength<core::num::NonZeroU64> {
type Error = <core::num::NonZeroU64 as TryFrom<u64>>::Error;
fn try_from(BitLength(value): BitLength<u64>) -> Result<Self, Self::Error> {
value.try_into().map(BitLength)
}
}
const _TEST_AS_USIZE_BYTES_ROUNDED_UP_EVEN: () =
assert!(BitLength::from_bits(8192).as_usize_bytes_rounded_up() == 8192 / 8);
const _TEST_AS_USIZE_BYTES_ROUNDED_UP_ONE_BIT_HIGH: () =
assert!(BitLength::from_bits(8192 + 1).as_usize_bytes_rounded_up() == (8192 / 8) + 1);
const _TEST_AS_USIZE_BYTES_ROUNDED_UP_SEVEN_BITS_HIGH: () =
assert!(BitLength::from_bits(8192 + 7).as_usize_bytes_rounded_up() == (8192 / 8) + 1);

59
vendor/ring/src/bssl.rs vendored Normal file
View File

@@ -0,0 +1,59 @@
// Copyright 2015 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use crate::error;
use core::ffi::c_int;
/// An `int` returned from a foreign function containing **1** if the function
/// was successful or **0** if an error occurred. This is the convention used by
/// C code in `ring`.
#[must_use]
#[repr(transparent)]
pub struct Result(c_int);
impl From<Result> for core::result::Result<(), error::Unspecified> {
fn from(ret: Result) -> Self {
match ret.0 {
1 => Ok(()),
c => {
debug_assert_eq!(c, 0, "`bssl::Result` value must be 0 or 1");
Err(error::Unspecified)
}
}
}
}
#[cfg(test)]
mod tests {
mod result {
use crate::bssl;
use core::{
ffi::c_int,
mem::{align_of, size_of},
};
#[test]
fn size_and_alignment() {
type Underlying = c_int;
assert_eq!(size_of::<bssl::Result>(), size_of::<Underlying>());
assert_eq!(align_of::<bssl::Result>(), align_of::<Underlying>());
}
#[test]
fn semantics() {
assert!(Result::from(bssl::Result(0)).is_err());
assert!(Result::from(bssl::Result(1)).is_ok());
}
}
}

33
vendor/ring/src/c.rs vendored Normal file
View File

@@ -0,0 +1,33 @@
// Copyright 2016-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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//! C types.
//!
//! Avoid using the `libc` crate to get C types since `libc` doesn't support
//! all the targets we need to support. It turns out that the few types we need
//! are all uniformly defined on the platforms we care about. This will
//! probably change if/when we support 16-bit platforms or platforms where
//! `usize` and `uintptr_t` are different sizes.
//!
//! TODO(MSRV, feature(c_size_t)): Use `core::{ffi::c_size_t}`.
//! TODO(MSRV-1.79): Use `NonZero<c_size_t>`.
// Keep in sync with the checks in base.h that verify these assumptions.
#![allow(dead_code)]
use core::num::NonZeroUsize;
pub(crate) type size_t = usize;
pub(crate) type NonZero_size_t = NonZeroUsize;

231
vendor/ring/src/cpu.rs vendored Normal file
View File

@@ -0,0 +1,231 @@
// Copyright 2016 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
pub(crate) use self::features::Features;
use core::mem::size_of;
macro_rules! impl_get_feature {
{
features: [
$( { ( $( $arch:expr ),+ ) => $Name:ident }, )+
],
} => {
$(
#[cfg(any( $( target_arch = $arch ),+ ))]
#[derive(Clone, Copy)]
pub(crate) struct $Name(crate::cpu::Features);
#[cfg(any( $( target_arch = $arch ),+ ))]
impl $Name {
const fn mask() -> u32 {
1 << (Shift::$Name as u32)
}
}
#[cfg(any( $( target_arch = $arch ),+ ))]
impl crate::cpu::GetFeature<$Name> for super::features::Values {
#[inline(always)]
fn get_feature(&self) -> Option<$Name> {
const MASK: u32 = $Name::mask();
const STATICALLY_DETECTED: bool = (crate::cpu::CAPS_STATIC & MASK) == MASK;
if STATICALLY_DETECTED { // TODO: `const`
return Some($Name(self.cpu()));
}
if (self.values() & MASK) == MASK {
Some($Name(self.cpu()))
} else {
None
}
}
}
)+
#[repr(u32)]
enum Shift {
$(
#[cfg(any( $( target_arch = $arch ),+ ))]
$Name,
)+
#[cfg(target_arch = "x86_64")]
IntelCpu,
#[cfg(any(all(target_arch = "aarch64", target_endian = "little"),
all(target_arch = "arm", target_endian = "little"),
target_arch = "x86", target_arch = "x86_64"))]
// Synthesized to ensure the dynamic flag set is always non-zero.
//
// Keep this at the end as it is never checked except during init.
Initialized,
}
}
}
pub(crate) trait GetFeature<T> {
fn get_feature(&self) -> Option<T>;
}
impl GetFeature<()> for features::Values {
#[inline(always)]
fn get_feature(&self) -> Option<()> {
Some(())
}
}
impl<A, B> GetFeature<(A, B)> for features::Values
where
features::Values: GetFeature<A>,
features::Values: GetFeature<B>,
{
#[inline(always)]
fn get_feature(&self) -> Option<(A, B)> {
match (self.get_feature(), self.get_feature()) {
(Some(a), Some(b)) => Some((a, b)),
_ => None,
}
}
}
impl<A, B, C> GetFeature<(A, B, C)> for features::Values
where
features::Values: GetFeature<A>,
features::Values: GetFeature<B>,
features::Values: GetFeature<C>,
{
#[inline(always)]
fn get_feature(&self) -> Option<(A, B, C)> {
match (self.get_feature(), self.get_feature(), self.get_feature()) {
(Some(a), Some(b), Some(c)) => Some((a, b, c)),
_ => None,
}
}
}
impl<F> GetFeature<F> for Features
where
features::Values: GetFeature<F>,
{
#[inline(always)]
fn get_feature(&self) -> Option<F> {
self.values().get_feature()
}
}
#[inline(always)]
pub(crate) fn features() -> Features {
featureflags::get_or_init()
}
mod features {
use crate::polyfill::NotSend;
/// A witness indicating that CPU features have been detected and cached.
///
/// This is a zero-sized type so that it can be "stored" wherever convenient.
#[derive(Copy, Clone)]
pub(crate) struct Features(NotSend);
impl Features {
pub fn values(self) -> Values {
Values {
values: super::featureflags::get(self),
cpu: self,
}
}
}
cfg_if::cfg_if! {
if #[cfg(any(all(target_arch = "aarch64", target_endian = "little"), all(target_arch = "arm", target_endian = "little"),
target_arch = "x86", target_arch = "x86_64"))] {
impl Features {
// SAFETY: This must only be called after CPU features have been written
// and synchronized.
pub(super) unsafe fn new_after_feature_flags_written_and_synced_unchecked() -> Self {
Self(NotSend::VALUE)
}
}
} else {
impl Features {
pub(super) fn new_no_features_to_detect() -> Self {
Self(NotSend::VALUE)
}
}
}
}
pub struct Values {
values: u32,
cpu: Features,
}
impl Values {
#[inline(always)]
pub(super) fn values(&self) -> u32 {
self.values
}
#[inline(always)]
pub(super) fn cpu(&self) -> Features {
self.cpu
}
}
}
const _: () = assert!(size_of::<Features>() == 0);
cfg_if::cfg_if! {
if #[cfg(any(all(target_arch = "aarch64", target_endian = "little"), all(target_arch = "arm", target_endian = "little")))] {
pub mod arm;
use arm::featureflags;
} else if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
pub mod intel;
use intel::featureflags;
} else {
mod featureflags {
use super::Features;
#[inline(always)]
pub(super) fn get_or_init() -> Features {
Features::new_no_features_to_detect()
}
#[inline(always)]
pub(super) fn get(_cpu_features: Features) -> u32 {
STATIC_DETECTED
}
pub(super) const STATIC_DETECTED: u32 = 0;
pub(super) const FORCE_DYNAMIC_DETECTION: u32 = 0;
}
}
}
const CAPS_STATIC: u32 = featureflags::STATIC_DETECTED & !featureflags::FORCE_DYNAMIC_DETECTION;
#[allow(clippy::assertions_on_constants, clippy::bad_bit_mask)]
const _FORCE_DYNAMIC_DETECTION_HONORED: () =
assert!((CAPS_STATIC & featureflags::FORCE_DYNAMIC_DETECTION) == 0);
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_static_is_subset_of_dynamic() {
let cpu = features();
let dynamic = featureflags::get(cpu);
assert_eq!(dynamic & CAPS_STATIC, CAPS_STATIC);
}
}

192
vendor/ring/src/cpu/arm.rs vendored Normal file
View File

@@ -0,0 +1,192 @@
// Copyright 2016-2024 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use super::CAPS_STATIC;
mod abi_assumptions {
use core::mem::size_of;
// TODO: Support ARM64_32; see
// https://github.com/briansmith/ring/issues/1832#issuecomment-1892928147. This also requires
// replacing all `cfg(target_pointer_width)` logic for non-pointer/reference things
// (`N0`, `Limb`, `LimbMask`, `crypto_word_t` etc.).
#[cfg(target_arch = "aarch64")]
const _ASSUMED_POINTER_SIZE: usize = 8;
#[cfg(target_arch = "arm")]
const _ASSUMED_POINTER_SIZE: usize = 4;
const _ASSUMED_USIZE_SIZE: () = assert!(size_of::<usize>() == _ASSUMED_POINTER_SIZE);
const _ASSUMED_REF_SIZE: () = assert!(size_of::<&'static u8>() == _ASSUMED_POINTER_SIZE);
// To support big-endian, we'd need to make several changes as described in
// https://github.com/briansmith/ring/issues/1832.
const _ASSUMED_ENDIANNESS: () = assert!(cfg!(target_endian = "little"));
}
// uclibc: When linked statically, uclibc doesn't provide getauxval.
// When linked dynamically, recent versions do provide it, but we
// want to support older versions too. Assume that if uclibc is being
// used, this is an embedded target where the user cares a lot about
// minimizing code size and also that they know in advance exactly
// what target features are supported, so rely only on static feature
// detection.
cfg_if::cfg_if! {
if #[cfg(all(all(target_arch = "aarch64", target_endian = "little"),
any(target_os = "ios", target_os = "macos", target_os = "tvos", target_os = "visionos", target_os = "watchos")))] {
mod darwin;
use darwin as detect;
} else if #[cfg(all(all(target_arch = "aarch64", target_endian = "little"), target_os = "fuchsia"))] {
mod fuchsia;
use fuchsia as detect;
} else if #[cfg(any(target_os = "android", target_os = "linux"))] {
mod linux;
use linux as detect;
} else if #[cfg(all(all(target_arch = "aarch64", target_endian = "little"), target_os = "windows"))] {
mod windows;
use windows as detect;
} else {
mod detect {
pub const FORCE_DYNAMIC_DETECTION: u32 = 0;
pub fn detect_features() -> u32 { 0 }
}
}
}
impl_get_feature! {
features: [
// TODO(MSRV): 32-bit ARM doesn't have `target_feature = "neon"` yet.
{ ("aarch64", "arm") => Neon },
// TODO(MSRV): There is no "pmull" feature listed from
// `rustc --print cfg --target=aarch64-apple-darwin`. Originally ARMv8 tied
// PMULL detection into AES detection, but later versions split it; see
// https://developer.arm.com/downloads/-/exploration-tools/feature-names-for-a-profile
// "Features introduced prior to 2020." Change this to use "pmull" when
// that is supported.
{ ("aarch64") => PMull },
{ ("aarch64") => Aes },
{ ("aarch64") => Sha256 },
// Keep in sync with `ARMV8_SHA512`.
// "sha3" is overloaded for both SHA-3 and SHA-512.
{ ("aarch64") => Sha512 },
],
}
pub(super) mod featureflags {
pub(in super::super) use super::detect::FORCE_DYNAMIC_DETECTION;
use super::*;
use crate::{
cpu,
polyfill::{once_cell::race, usize_from_u32},
};
use core::num::NonZeroUsize;
#[cfg(all(target_arch = "arm", target_endian = "little"))]
use core::sync::atomic::{AtomicU32, Ordering};
pub(in super::super) fn get_or_init() -> cpu::Features {
fn init() -> NonZeroUsize {
let detected = detect::detect_features();
let filtered = (if cfg!(feature = "unstable-testing-arm-no-hw") {
!Neon::mask()
} else {
0
}) | (if cfg!(feature = "unstable-testing-arm-no-neon") {
Neon::mask()
} else {
0
});
let detected = detected & !filtered;
let merged = CAPS_STATIC | detected;
#[cfg(all(
target_arch = "arm",
target_endian = "little",
target_has_atomic = "32"
))]
if (merged & Neon::mask()) == Neon::mask() {
// `neon_available` is declared as `alignas(4) uint32_t` in the C code.
// AtomicU32 is `#[repr(C, align(4))]`.
prefixed_extern! {
static neon_available: AtomicU32;
}
// SAFETY: The C code only reads `neon_available`, and its
// reads are synchronized through the `OnceNonZeroUsize`
// Acquire/Release semantics as we ensure we have a
// `cpu::Features` instance before calling into the C code.
let p = unsafe { &neon_available };
p.store(1, Ordering::Relaxed);
}
let merged = usize_from_u32(merged) | (1 << (Shift::Initialized as u32));
NonZeroUsize::new(merged).unwrap() // Can't fail because we just set a bit.
}
// SAFETY: This is the only caller. Any concurrent reading doesn't
// affect the safety of the writing.
let _: NonZeroUsize = FEATURES.get_or_init(init);
// SAFETY: We initialized the CPU features as required.
unsafe { cpu::Features::new_after_feature_flags_written_and_synced_unchecked() }
}
pub(in super::super) fn get(_cpu_features: cpu::Features) -> u32 {
// SAFETY: Since only `get_or_init()` could have created
// `_cpu_features`, and it only does so after `FEATURES.get_or_init()`,
// we know we are reading from `FEATURES` after initializing it.
//
// Also, 0 means "no features detected" to users, which is designed to
// be a safe configuration.
let features = FEATURES.get().map(NonZeroUsize::get).unwrap_or(0);
// The truncation is lossless, as we set the value with a u32.
#[allow(clippy::cast_possible_truncation)]
let features = features as u32;
features
}
static FEATURES: race::OnceNonZeroUsize = race::OnceNonZeroUsize::new();
// TODO(MSRV): There is no "pmull" feature listed from
// `rustc --print cfg --target=aarch64-apple-darwin`. Originally ARMv8 tied
// PMULL detection into AES detection, but later versions split it; see
// https://developer.arm.com/downloads/-/exploration-tools/feature-names-for-a-profile
// "Features introduced prior to 2020." Change this to use "pmull" when
// that is supported.
//
// "sha3" is overloaded for both SHA-3 and SHA-512.
#[cfg(all(target_arch = "aarch64", target_endian = "little"))]
#[rustfmt::skip]
pub(in super::super) const STATIC_DETECTED: u32 = 0
| (if cfg!(target_feature = "neon") { Neon::mask() } else { 0 })
| (if cfg!(target_feature = "aes") { Aes::mask() } else { 0 })
| (if cfg!(target_feature = "aes") { PMull::mask() } else { 0 })
| (if cfg!(target_feature = "sha2") { Sha256::mask() } else { 0 })
| (if cfg!(target_feature = "sha3") { Sha512::mask() } else { 0 })
;
// TODO(MSRV): 32-bit ARM doesn't support any static feature detection yet.
#[cfg(all(target_arch = "arm", target_endian = "little"))]
pub(in super::super) const STATIC_DETECTED: u32 = 0;
}
#[allow(clippy::assertions_on_constants)]
const _AARCH64_HAS_NEON: () = assert!(
((CAPS_STATIC & Neon::mask()) == Neon::mask())
|| !cfg!(all(target_arch = "aarch64", target_endian = "little"))
);

113
vendor/ring/src/cpu/arm/darwin.rs vendored Normal file
View File

@@ -0,0 +1,113 @@
// Copyright 2016-2024 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use super::{Aes, Neon, PMull, Sha256, Sha512, CAPS_STATIC};
use crate::polyfill::cstr;
// ```
// $ rustc +1.61.0 --print cfg --target=aarch64-apple-ios | grep -E "neon|aes|sha|pmull"
// target_feature="aes"
// target_feature="neon"
// target_feature="sha2"
// $ rustc +1.61.0 --print cfg --target=aarch64-apple-darwin | grep -E "neon|aes|sha|pmull"
// target_feature="aes"
// target_feature="neon"
// target_feature="sha2"
// target_feature="sha3"
// ```
//
// XXX/TODO(coverage)/TODO(size): aarch64-apple-darwin is statically guaranteed to have "sha3" but
// other aarch64-apple-* targets require dynamic detection. Since we don't have test coverage for
// the other targets yet, we wouldn't have a way of testing the dynamic detection if we statically
// enabled `Sha512` for -darwin. So instead, temporarily, we statically ignore the static
// availability of the feature on -darwin so that it runs the dynamic detection.
pub const MIN_STATIC_FEATURES: u32 = Neon::mask() | Aes::mask() | Sha256::mask() | PMull::mask();
pub const FORCE_DYNAMIC_DETECTION: u32 = !MIN_STATIC_FEATURES;
// MSRV: Enforce 1.61.0 onaarch64-apple-*, in particular) prior to. Earlier
// versions of Rust before did not report the AAarch64 CPU features correctly
// for these targets. Cargo.toml specifies `rust-version` but versions before
// Rust 1.56 don't know about it.
#[allow(clippy::assertions_on_constants)]
const _AARCH64_APPLE_TARGETS_EXPECTED_FEATURES: () =
assert!((CAPS_STATIC & MIN_STATIC_FEATURES) == MIN_STATIC_FEATURES);
// Ensure we don't accidentally allow features statically beyond
// `MIN_STATIC_FEATURES` so that dynamic detection is done uniformly for
// all of these targets.
#[allow(clippy::assertions_on_constants)]
const _AARCH64_APPLE_DARWIN_TARGETS_EXPECTED_FEATURES: () =
assert!(CAPS_STATIC == MIN_STATIC_FEATURES);
pub fn detect_features() -> u32 {
fn detect_feature(name: cstr::Ref) -> bool {
use crate::polyfill;
use core::mem;
use libc::{c_int, c_void};
let mut value: c_int = 0;
let mut len = mem::size_of_val(&value);
let value_ptr = polyfill::ptr::from_mut(&mut value).cast::<c_void>();
// SAFETY: `value_ptr` is a valid pointer to `value` and `len` is the size of `value`.
let rc = unsafe {
libc::sysctlbyname(name.as_ptr(), value_ptr, &mut len, core::ptr::null_mut(), 0)
};
// All the conditions are separated so we can observe them in code coverage.
if rc != 0 {
return false;
}
debug_assert_eq!(len, mem::size_of_val(&value));
if len != mem::size_of_val(&value) {
return false;
}
value != 0
}
// We do not need to check for the presence of NEON, as Armv8-A always has it
const _ASSERT_NEON_DETECTED: () = assert!((CAPS_STATIC & Neon::mask()) == Neon::mask());
let mut features = 0;
// TODO(MSRV 1.77): Use c"..." literal.
const SHA512_NAME: cstr::Ref =
cstr::unwrap_const_from_bytes_with_nul(b"hw.optional.armv8_2_sha512\0");
if detect_feature(SHA512_NAME) {
features |= Sha512::mask();
}
features
}
#[cfg(test)]
mod tests {
use super::*;
use crate::cpu;
#[test]
fn sha512_detection() {
// We intentionally disable static feature detection for SHA-512.
const _SHA512_NOT_STATICALLY_DETECTED: () = assert!((CAPS_STATIC & Sha512::mask()) == 0);
if cfg!(target_os = "macos") {
use crate::cpu::{arm::Sha512, GetFeature as _};
// All aarch64-apple-darwin targets have SHA3 enabled statically...
assert!(cfg!(target_feature = "sha3"));
// ...so we should detect it.
let cpu = cpu::features();
assert!(matches!(cpu.get_feature(), Some(Sha512 { .. })));
}
}
}

58
vendor/ring/src/cpu/arm/fuchsia.rs vendored Normal file
View File

@@ -0,0 +1,58 @@
// Copyright 2016-2024 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use super::{Aes, Neon, PMull, Sha256, Sha512, CAPS_STATIC};
pub const FORCE_DYNAMIC_DETECTION: u32 = 0;
pub fn detect_features() -> u32 {
type zx_status_t = i32;
#[link(name = "zircon")]
extern "C" {
fn zx_system_get_features(kind: u32, features: *mut u32) -> zx_status_t;
}
const ZX_OK: i32 = 0;
const ZX_FEATURE_KIND_CPU: u32 = 0;
const ZX_ARM64_FEATURE_ISA_AES: u32 = 1 << 3;
const ZX_ARM64_FEATURE_ISA_PMULL: u32 = 1 << 4;
const ZX_ARM64_FEATURE_ISA_SHA256: u32 = 1 << 6;
const ZX_ARM64_FEATURE_ISA_SHA512: u32 = 1 << 18;
let mut caps = 0;
let rc = unsafe { zx_system_get_features(ZX_FEATURE_KIND_CPU, &mut caps) };
let mut features = 0;
// We do not need to check for the presence of NEON, as Armv8-A always has it
const _ASSERT_NEON_DETECTED: () = assert!((CAPS_STATIC & Neon::mask()) == Neon::mask());
if rc == ZX_OK {
if caps & ZX_ARM64_FEATURE_ISA_AES == ZX_ARM64_FEATURE_ISA_AES {
features |= Aes::mask();
}
if caps & ZX_ARM64_FEATURE_ISA_PMULL == ZX_ARM64_FEATURE_ISA_PMULL {
features |= PMull::mask();
}
if caps & ZX_ARM64_FEATURE_ISA_SHA256 == ZX_ARM64_FEATURE_ISA_SHA256 {
features |= Sha256::mask();
}
if caps & ZX_ARM64_FEATURE_ISA_SHA512 == ZX_ARM64_FEATURE_ISA_SHA512 {
features |= Sha512::mask();
}
}
features
}

107
vendor/ring/src/cpu/arm/linux.rs vendored Normal file
View File

@@ -0,0 +1,107 @@
// Copyright 2016-2024 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use super::Neon;
// Work around a bug in LLVM/rustc where `-C target_cpu=cortex-a72`--
// and `-C target_cpu=native` on Cortex-A72 Raspberry PI devices in
// particular--enables crypto features even though not all Cortex-A72
// CPUs have crypto features:
//
// ```
// $ rustc --print cfg --target=aarch64-unknown-linux-gnu | grep feature
// target_feature="neon"
// $ rustc --print cfg --target=aarch64-unknown-linux-gnu -C target_cpu=cortex-a72 | grep feature
// target_feature="aes"
// target_feature="crc"
// target_feature="neon"
// target_feature="pmuv3"
// target_feature="sha2"
// ```
//
// XXX/TODO(MSRV https://github.com/llvm/llvm-project/issues/90365): This
// workaround is heavy-handed since it forces extra branches for devices that
// have correctly-modeled feature sets, so it should be removed.
pub const FORCE_DYNAMIC_DETECTION: u32 = !Neon::mask();
// `uclibc` does not provide `getauxval` so just use static feature detection
// for it.
#[cfg(target_env = "uclibc")]
pub fn detect_features() -> u32 {
0
}
#[cfg(all(
not(target_env = "uclibc"),
all(target_arch = "aarch64", target_endian = "little")
))]
pub fn detect_features() -> u32 {
use super::{Aes, PMull, Sha256, Sha512, CAPS_STATIC};
use libc::{getauxval, AT_HWCAP, HWCAP_AES, HWCAP_PMULL, HWCAP_SHA2, HWCAP_SHA512};
let mut features = 0;
// We do not need to check for the presence of NEON, as Armv8-A always has it
const _ASSERT_NEON_DETECTED: () = assert!((CAPS_STATIC & Neon::mask()) == Neon::mask());
let caps = unsafe { getauxval(AT_HWCAP) };
if caps & HWCAP_AES == HWCAP_AES {
features |= Aes::mask();
}
if caps & HWCAP_PMULL == HWCAP_PMULL {
features |= PMull::mask();
}
if caps & HWCAP_SHA2 == HWCAP_SHA2 {
features |= Sha256::mask();
}
if caps & HWCAP_SHA512 == HWCAP_SHA512 {
features |= Sha512::mask();
}
features
}
#[cfg(all(
not(target_env = "uclibc"),
all(target_arch = "arm", target_endian = "little")
))]
pub fn detect_features() -> u32 {
use super::CAPS_STATIC;
// The `libc` crate doesn't provide this functionality on all
// 32-bit Linux targets, like Android or -musl. Use this polyfill
// for all 32-bit ARM targets so that testing on one of them will
// be more meaningful to the others.
use libc::c_ulong;
extern "C" {
pub fn getauxval(type_: c_ulong) -> c_ulong;
}
const AT_HWCAP: c_ulong = 16;
const HWCAP_NEON: c_ulong = 1 << 12;
let mut features = 0;
if CAPS_STATIC & Neon::mask() != Neon::mask() {
let caps = unsafe { getauxval(AT_HWCAP) };
// OpenSSL and BoringSSL don't enable any other features if NEON isn't
// available. We don't enable any hardware implementations for 32-bit ARM.
if caps & HWCAP_NEON == HWCAP_NEON {
features |= Neon::mask();
}
}
features
}

38
vendor/ring/src/cpu/arm/windows.rs vendored Normal file
View File

@@ -0,0 +1,38 @@
// Copyright 2016-2024 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use super::{Aes, Neon, PMull, Sha256, CAPS_STATIC};
use windows_sys::Win32::System::Threading::{
IsProcessorFeaturePresent, PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE,
};
pub const FORCE_DYNAMIC_DETECTION: u32 = 0;
pub fn detect_features() -> u32 {
// We do not need to check for the presence of NEON, as Armv8-A always has it
const _ASSERT_NEON_DETECTED: () = assert!((CAPS_STATIC & Neon::mask()) == Neon::mask());
let mut features = 0;
let result = unsafe { IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE) };
if result != 0 {
// These are all covered by one call in Windows
features |= Aes::mask();
features |= PMull::mask();
features |= Sha256::mask();
}
features
}

382
vendor/ring/src/cpu/intel.rs vendored Normal file
View File

@@ -0,0 +1,382 @@
// Copyright 2016-2021 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use cfg_if::cfg_if;
mod abi_assumptions {
use core::mem::size_of;
// TOOD: Support targets that do not have SSE and SSE2 enabled, such as
// x86_64-unknown-linux-none. See
// https://github.com/briansmith/ring/issues/1793#issuecomment-1793243725,
// https://github.com/briansmith/ring/issues/1832,
// https://github.com/briansmith/ring/issues/1833.
const _ASSUMES_SSE2: () =
assert!(cfg!(target_feature = "sse") && cfg!(target_feature = "sse2"));
#[cfg(target_arch = "x86_64")]
const _ASSUMED_POINTER_SIZE: usize = 8;
#[cfg(target_arch = "x86")]
const _ASSUMED_POINTER_SIZE: usize = 4;
const _ASSUMED_USIZE_SIZE: () = assert!(size_of::<usize>() == _ASSUMED_POINTER_SIZE);
const _ASSUMED_REF_SIZE: () = assert!(size_of::<&'static u8>() == _ASSUMED_POINTER_SIZE);
const _ASSUMED_ENDIANNESS: () = assert!(cfg!(target_endian = "little"));
}
pub(super) mod featureflags {
use super::super::CAPS_STATIC;
use crate::{
cpu,
polyfill::{once_cell::race, usize_from_u32},
};
use core::num::NonZeroUsize;
pub(in super::super) fn get_or_init() -> cpu::Features {
// SAFETY: `OPENSSL_cpuid_setup` must be called only in
// `INIT.call_once()` below.
prefixed_extern! {
fn OPENSSL_cpuid_setup(out: &mut [u32; 4]);
}
let _: NonZeroUsize = FEATURES.get_or_init(|| {
let mut cpuid = [0; 4];
// SAFETY: We assume that it is safe to execute CPUID and XGETBV.
unsafe {
OPENSSL_cpuid_setup(&mut cpuid);
}
let detected = super::cpuid_to_caps_and_set_c_flags(&cpuid);
let merged = CAPS_STATIC | detected;
let merged = usize_from_u32(merged) | (1 << (super::Shift::Initialized as u32));
NonZeroUsize::new(merged).unwrap() // Can't fail because we just set a bit.
});
// SAFETY: We initialized the CPU features as required.
// `INIT.call_once` has `happens-before` semantics.
unsafe { cpu::Features::new_after_feature_flags_written_and_synced_unchecked() }
}
pub(in super::super) fn get(_cpu_features: cpu::Features) -> u32 {
// SAFETY: Since only `get_or_init()` could have created
// `_cpu_features`, and it only does so after `FEATURES.get_or_init()`,
// we know we are reading from `FEATURES` after initializing it.
//
// Also, 0 means "no features detected" to users, which is designed to
// be a safe configuration.
let features = FEATURES.get().map(NonZeroUsize::get).unwrap_or(0);
// The truncation is lossless, as we set the value with a u32.
#[allow(clippy::cast_possible_truncation)]
let features = features as u32;
features
}
static FEATURES: race::OnceNonZeroUsize = race::OnceNonZeroUsize::new();
#[cfg(target_arch = "x86")]
#[rustfmt::skip]
pub const STATIC_DETECTED: u32 = 0
| (if cfg!(target_feature = "sse2") { super::Sse2::mask() } else { 0 })
;
// Limited to x86_64-v2 features.
// TODO: Add missing x86-64-v3 features if we find real-world use of x86-64-v3.
// TODO: Add all features we use.
#[cfg(target_arch = "x86_64")]
#[rustfmt::skip]
pub const STATIC_DETECTED: u32 = 0
| if cfg!(target_feature = "sse4.1") { super::Sse41::mask() } else { 0 }
| if cfg!(target_feature = "ssse3") { super::Ssse3::mask() } else { 0 }
;
pub const FORCE_DYNAMIC_DETECTION: u32 = 0;
}
fn cpuid_to_caps_and_set_c_flags(cpuid: &[u32; 4]) -> u32 {
// "Intel" citations are for "Intel 64 and IA-32 Architectures Software
// Developers Manual", Combined Volumes, December 2024.
// "AMD" citations are for "AMD64 Technology AMD64 Architecture
// Programmers Manual, Volumes 1-5" Revision 4.08 April 2024.
// The `prefixed_extern!` uses below assume this
#[cfg(target_arch = "x86_64")]
use core::{mem::align_of, sync::atomic::AtomicU32};
#[cfg(target_arch = "x86_64")]
const _ATOMIC32_ALIGNMENT_EQUALS_U32_ALIGNMENT: () =
assert!(align_of::<AtomicU32>() == align_of::<u32>());
fn check(leaf: u32, bit: u32) -> bool {
let shifted = 1 << bit;
(leaf & shifted) == shifted
}
fn set(out: &mut u32, shift: Shift) {
let shifted = 1 << (shift as u32);
debug_assert_eq!(*out & shifted, 0);
*out |= shifted;
debug_assert_eq!(*out & shifted, shifted);
}
#[cfg(target_arch = "x86_64")]
let is_intel = check(cpuid[0], 30); // Synthesized by `OPENSSL_cpuid_setup`
// CPUID leaf 1.
let leaf1_ecx = cpuid[1];
// Intel: "Structured Extended Feature Flags Enumeration Leaf"
#[cfg(target_arch = "x86_64")]
let (extended_features_ebx, extended_features_ecx) = (cpuid[2], cpuid[3]);
let mut caps = 0;
// AMD: "Collectively the SSE1, [...] are referred to as the legacy SSE
// instructions. All legacy SSE instructions support 128-bit vector
// operands."
// Intel: "11.6.2 Checking for Intel SSE and SSE2 Support"
// We have to assume the prerequisites for SSE/SSE2 are met since we're
// already almost definitely using SSE registers if these target features
// are enabled.
//
// These also seem to help ensure CMOV support; There doesn't seem to be
// a `cfg!(target_feature = "cmov")`. It is likely that removing these
// assertions will remove the requirement for CMOV. With our without
// CMOV, it is likely that some of our timing side channel prevention does
// not work. Presumably the people who delete these are verifying that it
// all works fine.
const _SSE_REQUIRED: () = assert!(cfg!(target_feature = "sse"));
const _SSE2_REQUIRED: () = assert!(cfg!(target_feature = "sse2"));
#[cfg(all(target_arch = "x86", not(target_feature = "sse2")))]
{
// If somebody is trying to compile for an x86 target without SSE2
// and they deleted the `_SSE2_REQUIRED` const assertion above then
// they're probably trying to support a Linux/BSD/etc. distro that
// tries to support ancient x86 systems without SSE/SSE2. Try to
// reduce the harm caused, by implementing dynamic feature detection
// for them so that most systems will work like normal.
//
// Note that usually an x86-64 target with SSE2 disabled by default,
// usually `-none-` targets, will not support dynamically-detected use
// of SIMD registers via CPUID. A whole different mechanism is needed
// to support them. Same for i*86-*-none targets.
let leaf1_edx = cpuid[0];
let sse1_available = check(leaf1_edx, 25);
let sse2_available = check(leaf1_edx, 26);
if sse1_available && sse2_available {
set(&mut caps, Shift::Sse2);
}
}
// Sometimes people delete the `_SSE_REQUIRED`/`_SSE2_REQUIRED` const
// assertions in an attempt to support pre-SSE2 32-bit x86 systems. If they
// do, hopefully they won't delete these redundant assertions, so that
// x86_64 isn't affected.
#[cfg(target_arch = "x86_64")]
const _SSE2_REQUIRED_X86_64: () = assert!(cfg!(target_feature = "sse2"));
#[cfg(target_arch = "x86_64")]
const _SSE_REQUIRED_X86_64: () = assert!(cfg!(target_feature = "sse2"));
// Intel: "12.7.2 Checking for SSSE3 Support"
// If/when we support dynamic detection of SSE/SSE2, make this conditional
// on SSE/SSE2.
if check(leaf1_ecx, 9) {
set(&mut caps, Shift::Ssse3);
}
// Intel: "12.12.2 Checking for Intel SSE4.1 Support"
// If/when we support dynamic detection of SSE/SSE2, make this conditional
// on SSE/SSE2.
// XXX: We don't check for SSE3 and we're not sure if it is compatible for
// us to do so; does AMD advertise SSE3? TODO: address this.
// XXX: We don't condition this on SSSE3 being available. TODO: address
// this.
#[cfg(target_arch = "x86_64")]
if check(leaf1_ecx, 19) {
set(&mut caps, Shift::Sse41);
}
// AMD: "The extended SSE instructions include [...]."
// Intel: "14.3 DETECTION OF INTEL AVX INSTRUCTIONS"
// `OPENSSL_cpuid_setup` clears this bit when it detects the OS doesn't
// support AVX state.
let avx_available = check(leaf1_ecx, 28);
if avx_available {
set(&mut caps, Shift::Avx);
}
#[cfg(target_arch = "x86_64")]
if avx_available {
// The Intel docs don't seem to document the detection. The instruction
// definitions of the VEX.256 instructions reference the
// VAES/VPCLMULQDQ features and the documentation for the extended
// features gives the values. We combine these into one feature because
// we never use them independently.
let vaes_available = check(extended_features_ecx, 9);
let vclmul_available = check(extended_features_ecx, 10);
if vaes_available && vclmul_available {
set(&mut caps, Shift::VAesClmul);
}
}
// "14.7.1 Detection of Intel AVX2 Hardware support"
// XXX: We don't condition AVX2 on AVX. TODO: Address this.
// `OPENSSL_cpuid_setup` clears this bit when it detects the OS doesn't
// support AVX state.
#[cfg(target_arch = "x86_64")]
if check(extended_features_ebx, 5) {
set(&mut caps, Shift::Avx2);
// Declared as `uint32_t` in the C code.
prefixed_extern! {
static avx2_available: AtomicU32;
}
// SAFETY: The C code only reads `avx2_available`, and its reads are
// synchronized through the `OnceNonZeroUsize` Acquire/Release
// semantics as we ensure we have a `cpu::Features` instance before
// calling into the C code.
let flag = unsafe { &avx2_available };
flag.store(1, core::sync::atomic::Ordering::Relaxed);
}
// Intel: "12.13.4 Checking for Intel AES-NI Support"
// If/when we support dynamic detection of SSE/SSE2, revisit this.
// TODO: Clarify "interesting" states like (!SSE && AVX && AES-NI)
// and AES-NI & !AVX.
// Each check of `ClMul`, `Aes`, and `Sha` must be paired with a check for
// an AVX feature (e.g. `Avx`) or an SSE feature (e.g. `Ssse3`), as every
// use will either be supported by SSE* or AVX* instructions. We then
// assume that those supporting instructions' prerequisites (e.g. OS
// support for AVX or SSE state, respectively) are the only prerequisites
// for these features.
if check(leaf1_ecx, 1) {
set(&mut caps, Shift::ClMul);
}
if check(leaf1_ecx, 25) {
set(&mut caps, Shift::Aes);
}
// See BoringSSL 69c26de93c82ad98daecaec6e0c8644cdf74b03f before enabling
// static feature detection for this.
#[cfg(target_arch = "x86_64")]
if check(extended_features_ebx, 29) {
set(&mut caps, Shift::Sha);
}
#[cfg(target_arch = "x86_64")]
{
if is_intel {
set(&mut caps, Shift::IntelCpu);
}
if check(leaf1_ecx, 22) {
set(&mut caps, Shift::Movbe);
}
let adx_available = check(extended_features_ebx, 19);
if adx_available {
set(&mut caps, Shift::Adx);
}
// Some 6th Generation (Skylake) CPUs claim to support BMI1 and BMI2
// when they don't; see erratum "SKD052". The Intel document at
// https://www.intel.com/content/dam/www/public/us/en/documents/specification-updates/6th-gen-core-u-y-spec-update.pdf
// contains the footnote "Affects 6th Generation Intel Pentium processor
// family and Intel Celeron processor family". Further research indicates
// that Skylake Pentium/Celeron do not implement AVX or ADX. It turns
// out that we only use BMI1 and BMI2 in combination with ADX and/or
// AVX.
//
// rust `std::arch::is_x86_feature_detected` does a very similar thing
// but only looks at AVX, not ADX. Note that they reference an older
// version of the erratum labeled SKL052.
let believe_bmi_bits = !is_intel || (adx_available || avx_available);
if check(extended_features_ebx, 3) && believe_bmi_bits {
set(&mut caps, Shift::Bmi1);
}
let bmi2_available = check(extended_features_ebx, 8) && believe_bmi_bits;
if bmi2_available {
set(&mut caps, Shift::Bmi2);
}
if adx_available && bmi2_available {
// Declared as `uint32_t` in the C code.
prefixed_extern! {
static adx_bmi2_available: AtomicU32;
}
// SAFETY: The C code only reads `adx_bmi2_available`, and its
// reads are synchronized through the `OnceNonZeroUsize`
// Acquire/Release semantics as we ensure we have a
// `cpu::Features` instance before calling into the C code.
let flag = unsafe { &adx_bmi2_available };
flag.store(1, core::sync::atomic::Ordering::Relaxed);
}
}
caps
}
impl_get_feature! {
features: [
{ ("x86_64") => VAesClmul },
{ ("x86", "x86_64") => ClMul },
{ ("x86", "x86_64") => Ssse3 },
{ ("x86_64") => Sse41 },
{ ("x86_64") => Movbe },
{ ("x86", "x86_64") => Aes },
{ ("x86", "x86_64") => Avx },
{ ("x86_64") => Bmi1 },
{ ("x86_64") => Avx2 },
{ ("x86_64") => Bmi2 },
{ ("x86_64") => Adx },
// See BoringSSL 69c26de93c82ad98daecaec6e0c8644cdf74b03f before enabling
// static feature detection for this.
{ ("x86_64") => Sha },
// x86_64 can just assume SSE2 is available.
{ ("x86") => Sse2 },
],
}
cfg_if! {
if #[cfg(target_arch = "x86_64")] {
#[derive(Clone, Copy)]
pub(crate) struct IntelCpu(super::Features);
impl super::GetFeature<IntelCpu> for super::features::Values {
fn get_feature(&self) -> Option<IntelCpu> {
const MASK: u32 = 1 << (Shift::IntelCpu as u32);
if (self.values() & MASK) == MASK {
Some(IntelCpu(self.cpu()))
} else {
None
}
}
}
}
}
#[cfg(test)]
mod tests {
// This should always pass on any x86 system except very, very, old ones.
#[cfg(target_arch = "x86")]
#[test]
fn x86_has_sse2() {
use super::*;
use crate::cpu::{self, GetFeature as _};
assert!(matches!(cpu::features().get_feature(), Some(Sse2 { .. })))
}
}

Binary file not shown.

84
vendor/ring/src/debug.rs vendored Normal file
View File

@@ -0,0 +1,84 @@
// Copyright 2018 Trent Clarke.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
// Generates an implementation of the Debug trait for a type that defers to the
// Debug implementation for a given field.
macro_rules! derive_debug_via_id {
($typename:ident) => {
impl ::core::fmt::Debug for $typename {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> Result<(), ::core::fmt::Error> {
::core::fmt::Debug::fmt(&self.id, f)
}
}
};
}
macro_rules! derive_debug_via_field {
($type:ty, $field:ident) => {
derive_debug_via_field!($type, stringify!($type), $field);
};
($type:ty, $typename:expr, $field:ident) => {
impl ::core::fmt::Debug for $type {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> Result<(), ::core::fmt::Error> {
f.debug_struct($typename)
.field(stringify!($field), &self.$field)
.finish()
}
}
};
}
// Generates an implementation of the Debug trait for a type that outputs the
// hex encoding of the byte slice representation of the value.
macro_rules! derive_debug_self_as_ref_hex_bytes {
($typename:ident) => {
impl ::core::fmt::Debug for $typename {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> Result<(), ::core::fmt::Error> {
crate::debug::write_hex_tuple(f, stringify!($typename), self)
}
}
};
}
pub(crate) fn write_hex_tuple(
fmt: &mut core::fmt::Formatter,
type_name: &str,
value: &dyn AsRef<[u8]>,
) -> Result<(), ::core::fmt::Error> {
fmt.debug_tuple(type_name)
.field(&HexStr(value.as_ref()))
.finish()
}
pub struct HexStr<'a>(pub &'a [u8]);
impl core::fmt::Debug for HexStr<'_> {
fn fmt(&self, fmt: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
fmt.write_str("\"")?;
write_hex_bytes(fmt, self.0)?;
fmt.write_str("\"")?;
Ok(())
}
}
pub(crate) fn write_hex_bytes(
fmt: &mut core::fmt::Formatter,
bytes: &[u8],
) -> Result<(), ::core::fmt::Error> {
for byte in bytes {
write!(fmt, "{:02x}", byte)?;
}
Ok(())
}

View File

@@ -0,0 +1,22 @@
// Copyright 2015-2025 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use crate::{bb, error};
#[deprecated(
note = "To be removed. Internal function not intended for external use with no promises regarding side channels."
)]
pub fn verify_slices_are_equal(a: &[u8], b: &[u8]) -> Result<(), error::Unspecified> {
bb::verify_slices_are_equal(a, b)
}

45
vendor/ring/src/deprecated_test.rs vendored Normal file
View File

@@ -0,0 +1,45 @@
// Copyright 2025 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#![doc(hidden)]
/// References a test input file.
#[macro_export]
macro_rules! test_file {
($file_name:expr) => {
$crate::test::File {
file_name: $file_name,
contents: include_str!($file_name),
}
};
}
pub use crate::testutil::{
compile_time_assert_clone, compile_time_assert_copy, compile_time_assert_eq,
compile_time_assert_send, compile_time_assert_sync, from_hex, run, File, TestCase,
};
#[cfg(feature = "std")]
pub use crate::testutil::compile_time_assert_std_error_error;
#[deprecated(note = "internal API that will be removed")]
#[doc(hidden)]
pub mod rand {
#[deprecated(note = "internal API that will be removed")]
pub type FixedByteRandom = crate::testutil::rand::FixedByteRandom;
#[deprecated(note = "internal API that will be removed")]
pub type FixedSliceRandom<'a> = crate::testutil::rand::FixedSliceRandom<'a>;
#[deprecated(note = "internal API that will be removed")]
pub type FixedSliceSequenceRandom<'a> = crate::testutil::rand::FixedSliceSequenceRandom<'a>;
}

680
vendor/ring/src/digest.rs vendored Normal file
View File

@@ -0,0 +1,680 @@
// 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//! SHA-2 and the legacy SHA-1 digest algorithm.
//!
//! If all the data is available in a single contiguous slice then the `digest`
//! function should be used. Otherwise, the digest can be calculated in
//! multiple steps using `Context`.
use self::{
dynstate::DynState,
sha2::{SHA256_BLOCK_LEN, SHA512_BLOCK_LEN},
};
use crate::{
bits::{BitLength, FromByteLen as _},
cpu, debug, error,
polyfill::{self, slice, sliceutil},
};
use core::num::Wrapping;
pub(crate) use self::finish_error::FinishError;
mod dynstate;
mod sha1;
mod sha2;
#[derive(Clone)]
pub(crate) struct BlockContext {
state: DynState,
// Note that SHA-512 has a 128-bit input bit counter, but this
// implementation only supports up to 2^64-1 input bits for all algorithms,
// so a 64-bit counter is more than sufficient.
completed_bytes: u64,
/// The context's algorithm.
pub algorithm: &'static Algorithm,
}
impl BlockContext {
pub(crate) fn new(algorithm: &'static Algorithm) -> Self {
Self {
state: algorithm.initial_state.clone(),
completed_bytes: 0,
algorithm,
}
}
/// Processes all the full blocks in `input`, returning the partial block
/// at the end, which may be empty.
pub(crate) fn update<'i>(&mut self, input: &'i [u8], cpu_features: cpu::Features) -> &'i [u8] {
let (completed_bytes, leftover) = self.block_data_order(input, cpu_features);
// Using saturated addition here allows `update` to be infallible and
// panic-free. If we were to reach the maximum value here then `finish`
// will detect that we processed too much data when it converts this to
// a bit length.
self.completed_bytes = self
.completed_bytes
.saturating_add(polyfill::u64_from_usize(completed_bytes));
leftover
}
// On input, `block[..num_pending]` is the (possibly-empty) last *partial*
// chunk of input. It *must* be partial; that is, it is required that
// `num_pending < self.algorithm.block_len`.
//
// `block` may be arbitrarily overwritten.
pub(crate) fn try_finish(
mut self,
block: &mut [u8; MAX_BLOCK_LEN],
num_pending: usize,
cpu_features: cpu::Features,
) -> Result<Digest, FinishError> {
let completed_bits = self
.completed_bytes
.checked_add(polyfill::u64_from_usize(num_pending))
.ok_or_else(|| {
// Choosing self.completed_bytes here is lossy & somewhat arbitrary.
InputTooLongError::new(self.completed_bytes)
})
.and_then(BitLength::from_byte_len)
.map_err(FinishError::input_too_long)?;
let block_len = self.algorithm.block_len();
let block = &mut block[..block_len];
let padding = match block.get_mut(num_pending..) {
Some([separator, padding @ ..]) => {
*separator = 0x80;
padding
}
// Precondition violated.
unreachable => {
return Err(FinishError::pending_not_a_partial_block(
unreachable.as_deref(),
));
}
};
let padding = match padding
.len()
.checked_sub(self.algorithm.block_len.len_len())
{
Some(_) => padding,
None => {
padding.fill(0);
let (completed_bytes, leftover) = self.block_data_order(block, cpu_features);
debug_assert_eq!((completed_bytes, leftover.len()), (block_len, 0));
// We don't increase |self.completed_bytes| because the padding
// isn't data, and so it isn't included in the data length.
&mut block[..]
}
};
let (to_zero, len) = padding.split_at_mut(padding.len() - 8);
to_zero.fill(0);
len.copy_from_slice(&completed_bits.to_be_bytes());
let (completed_bytes, leftover) = self.block_data_order(block, cpu_features);
debug_assert_eq!((completed_bytes, leftover.len()), (block_len, 0));
Ok(Digest {
algorithm: self.algorithm,
value: self.state.format_output(),
})
}
#[must_use]
fn block_data_order<'d>(
&mut self,
data: &'d [u8],
cpu_features: cpu::Features,
) -> (usize, &'d [u8]) {
(self.algorithm.block_data_order)(&mut self.state, data, cpu_features)
}
}
pub(crate) type InputTooLongError = error::InputTooLongError<u64>;
cold_exhaustive_error! {
enum finish_error::FinishError {
input_too_long => InputTooLong(InputTooLongError),
pending_not_a_partial_block_inner => PendingNotAPartialBlock(usize),
}
}
impl FinishError {
#[cold]
#[inline(never)]
fn pending_not_a_partial_block(padding: Option<&[u8]>) -> Self {
match padding {
None => Self::pending_not_a_partial_block_inner(0),
Some(padding) => Self::pending_not_a_partial_block_inner(padding.len()),
}
}
}
/// A context for multi-step (Init-Update-Finish) digest calculations.
///
/// # Examples
///
/// ```
/// use ring::digest;
///
/// let one_shot = digest::digest(&digest::SHA384, b"hello, world");
///
/// let mut ctx = digest::Context::new(&digest::SHA384);
/// ctx.update(b"hello");
/// ctx.update(b", ");
/// ctx.update(b"world");
/// let multi_part = ctx.finish();
///
/// assert_eq!(&one_shot.as_ref(), &multi_part.as_ref());
/// ```
#[derive(Clone)]
pub struct Context {
block: BlockContext,
// TODO: More explicitly force 64-bit alignment for |pending|.
pending: [u8; MAX_BLOCK_LEN],
// Invariant: `self.num_pending < self.block.algorithm.block_len`.
num_pending: usize,
}
impl Context {
/// Constructs a new context.
pub fn new(algorithm: &'static Algorithm) -> Self {
Self {
block: BlockContext::new(algorithm),
pending: [0u8; MAX_BLOCK_LEN],
num_pending: 0,
}
}
pub(crate) fn clone_from(block: &BlockContext) -> Self {
Self {
block: block.clone(),
pending: [0u8; MAX_BLOCK_LEN],
num_pending: 0,
}
}
/// Updates the digest with all the data in `data`.
pub fn update(&mut self, data: &[u8]) {
let cpu_features = cpu::features();
let block_len = self.block.algorithm.block_len();
let buffer = &mut self.pending[..block_len];
let to_digest = if self.num_pending == 0 {
data
} else {
let buffer_to_fill = match buffer.get_mut(self.num_pending..) {
Some(buffer_to_fill) => buffer_to_fill,
None => {
// Impossible because of the invariant.
unreachable!();
}
};
sliceutil::overwrite_at_start(buffer_to_fill, data);
match slice::split_at_checked(data, buffer_to_fill.len()) {
Some((just_copied, to_digest)) => {
debug_assert_eq!(buffer_to_fill.len(), just_copied.len());
debug_assert_eq!(self.num_pending + just_copied.len(), block_len);
let leftover = self.block.update(buffer, cpu_features);
debug_assert_eq!(leftover.len(), 0);
self.num_pending = 0;
to_digest
}
None => {
self.num_pending += data.len();
// If `data` isn't enough to complete a block, buffer it and stop.
debug_assert!(self.num_pending < block_len);
return;
}
}
};
let leftover = self.block.update(to_digest, cpu_features);
sliceutil::overwrite_at_start(buffer, leftover);
self.num_pending = leftover.len();
debug_assert!(self.num_pending < block_len);
}
/// Finalizes the digest calculation and returns the digest value.
///
/// `finish` consumes the context so it cannot be (mis-)used after `finish`
/// has been called.
pub fn finish(self) -> Digest {
let cpu = cpu::features();
self.try_finish(cpu)
.map_err(error::erase::<InputTooLongError>)
.unwrap()
}
pub(crate) fn try_finish(
mut self,
cpu_features: cpu::Features,
) -> Result<Digest, InputTooLongError> {
self.block
.try_finish(&mut self.pending, self.num_pending, cpu_features)
.map_err(|err| match err {
FinishError::InputTooLong(i) => i,
FinishError::PendingNotAPartialBlock(_) => {
// Due to invariant.
unreachable!()
}
})
}
/// The algorithm that this context is using.
#[inline(always)]
pub fn algorithm(&self) -> &'static Algorithm {
self.block.algorithm
}
}
/// Returns the digest of `data` using the given digest algorithm.
pub fn digest(algorithm: &'static Algorithm, data: &[u8]) -> Digest {
let cpu = cpu::features();
Digest::compute_from(algorithm, data, cpu)
.map_err(error::erase::<InputTooLongError>)
.unwrap()
}
/// A calculated digest value.
///
/// Use [`Self::as_ref`] to get the value as a `&[u8]`.
#[derive(Clone, Copy)]
pub struct Digest {
value: Output,
algorithm: &'static Algorithm,
}
impl Digest {
pub(crate) fn compute_from(
algorithm: &'static Algorithm,
data: &[u8],
cpu: cpu::Features,
) -> Result<Self, InputTooLongError> {
let mut ctx = Context::new(algorithm);
ctx.update(data);
ctx.try_finish(cpu)
}
/// The algorithm that was used to calculate the digest value.
#[inline(always)]
pub fn algorithm(&self) -> &'static Algorithm {
self.algorithm
}
}
impl AsRef<[u8]> for Digest {
#[inline(always)]
fn as_ref(&self) -> &[u8] {
&self.value.0[..self.algorithm.output_len()]
}
}
impl core::fmt::Debug for Digest {
fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(fmt, "{:?}:", self.algorithm)?;
debug::write_hex_bytes(fmt, self.as_ref())
}
}
/// A digest algorithm.
pub struct Algorithm {
output_len: OutputLen,
chaining_len: usize,
block_len: BlockLen,
/// `block_data_order` processes all the full blocks of data in `data`. It
/// returns the number of bytes processed and the unprocessed data, which
/// is guaranteed to be less than `block_len` bytes long.
block_data_order: for<'d> fn(
state: &mut DynState,
data: &'d [u8],
cpu_features: cpu::Features,
) -> (usize, &'d [u8]),
initial_state: DynState,
id: AlgorithmID,
}
#[derive(Debug, Eq, PartialEq)]
enum AlgorithmID {
SHA1,
SHA256,
SHA384,
SHA512,
SHA512_256,
}
impl PartialEq for Algorithm {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
impl Eq for Algorithm {}
derive_debug_via_id!(Algorithm);
impl Algorithm {
/// The internal block length.
pub fn block_len(&self) -> usize {
self.block_len.into()
}
/// The size of the chaining value of the digest function, in bytes.
///
/// For non-truncated algorithms (SHA-1, SHA-256, SHA-512), this is equal
/// to [`Self::output_len()`]. For truncated algorithms (e.g. SHA-384,
/// SHA-512/256), this is equal to the length before truncation. This is
/// mostly helpful for determining the size of an HMAC key that is
/// appropriate for the digest algorithm.
pub fn chaining_len(&self) -> usize {
self.chaining_len
}
/// The length of a finalized digest.
pub fn output_len(&self) -> usize {
self.output_len.into()
}
}
/// SHA-1 as specified in [FIPS 180-4]. Deprecated.
///
/// [FIPS 180-4]: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf
pub static SHA1_FOR_LEGACY_USE_ONLY: Algorithm = Algorithm {
output_len: sha1::OUTPUT_LEN,
chaining_len: sha1::CHAINING_LEN,
block_len: sha1::BLOCK_LEN,
block_data_order: dynstate::sha1_block_data_order,
initial_state: DynState::new32([
Wrapping(0x67452301u32),
Wrapping(0xefcdab89u32),
Wrapping(0x98badcfeu32),
Wrapping(0x10325476u32),
Wrapping(0xc3d2e1f0u32),
Wrapping(0),
Wrapping(0),
Wrapping(0),
]),
id: AlgorithmID::SHA1,
};
/// SHA-256 as specified in [FIPS 180-4].
///
/// [FIPS 180-4]: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf
pub static SHA256: Algorithm = Algorithm {
output_len: OutputLen::_256,
chaining_len: SHA256_OUTPUT_LEN,
block_len: SHA256_BLOCK_LEN,
block_data_order: dynstate::sha256_block_data_order,
initial_state: DynState::new32([
Wrapping(0x6a09e667u32),
Wrapping(0xbb67ae85u32),
Wrapping(0x3c6ef372u32),
Wrapping(0xa54ff53au32),
Wrapping(0x510e527fu32),
Wrapping(0x9b05688cu32),
Wrapping(0x1f83d9abu32),
Wrapping(0x5be0cd19u32),
]),
id: AlgorithmID::SHA256,
};
/// SHA-384 as specified in [FIPS 180-4].
///
/// [FIPS 180-4]: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf
pub static SHA384: Algorithm = Algorithm {
output_len: OutputLen::_384,
chaining_len: SHA512_OUTPUT_LEN,
block_len: SHA512_BLOCK_LEN,
block_data_order: dynstate::sha512_block_data_order,
initial_state: DynState::new64([
Wrapping(0xcbbb9d5dc1059ed8),
Wrapping(0x629a292a367cd507),
Wrapping(0x9159015a3070dd17),
Wrapping(0x152fecd8f70e5939),
Wrapping(0x67332667ffc00b31),
Wrapping(0x8eb44a8768581511),
Wrapping(0xdb0c2e0d64f98fa7),
Wrapping(0x47b5481dbefa4fa4),
]),
id: AlgorithmID::SHA384,
};
/// SHA-512 as specified in [FIPS 180-4].
///
/// [FIPS 180-4]: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf
pub static SHA512: Algorithm = Algorithm {
output_len: OutputLen::_512,
chaining_len: SHA512_OUTPUT_LEN,
block_len: SHA512_BLOCK_LEN,
block_data_order: dynstate::sha512_block_data_order,
initial_state: DynState::new64([
Wrapping(0x6a09e667f3bcc908),
Wrapping(0xbb67ae8584caa73b),
Wrapping(0x3c6ef372fe94f82b),
Wrapping(0xa54ff53a5f1d36f1),
Wrapping(0x510e527fade682d1),
Wrapping(0x9b05688c2b3e6c1f),
Wrapping(0x1f83d9abfb41bd6b),
Wrapping(0x5be0cd19137e2179),
]),
id: AlgorithmID::SHA512,
};
/// SHA-512/256 as specified in [FIPS 180-4].
///
/// This is *not* the same as just truncating the output of SHA-512, as
/// SHA-512/256 has its own initial state distinct from SHA-512's initial
/// state.
///
/// [FIPS 180-4]: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf
pub static SHA512_256: Algorithm = Algorithm {
output_len: OutputLen::_256,
chaining_len: SHA512_OUTPUT_LEN,
block_len: SHA512_BLOCK_LEN,
block_data_order: dynstate::sha512_block_data_order,
initial_state: DynState::new64([
Wrapping(0x22312194fc2bf72c),
Wrapping(0x9f555fa3c84c64c2),
Wrapping(0x2393b86b6f53b151),
Wrapping(0x963877195940eabd),
Wrapping(0x96283ee2a88effe3),
Wrapping(0xbe5e1e2553863992),
Wrapping(0x2b0199fc2c85b8aa),
Wrapping(0x0eb72ddc81c52ca2),
]),
id: AlgorithmID::SHA512_256,
};
#[derive(Clone, Copy)]
struct Output([u8; MAX_OUTPUT_LEN]);
/// The maximum block length ([`Algorithm::block_len()`]) of all the algorithms
/// in this module.
pub const MAX_BLOCK_LEN: usize = BlockLen::MAX.into();
/// The maximum output length ([`Algorithm::output_len()`]) of all the
/// algorithms in this module.
pub const MAX_OUTPUT_LEN: usize = OutputLen::MAX.into();
/// The maximum chaining length ([`Algorithm::chaining_len()`]) of all the
/// algorithms in this module.
pub const MAX_CHAINING_LEN: usize = MAX_OUTPUT_LEN;
#[inline]
fn format_output<T, F, const N: usize>(input: [Wrapping<T>; sha2::CHAINING_WORDS], f: F) -> Output
where
F: Fn(T) -> [u8; N],
T: Copy,
{
let mut output = Output([0; MAX_OUTPUT_LEN]);
output
.0
.chunks_mut(N)
.zip(input.iter().copied().map(|Wrapping(w)| f(w)))
.for_each(|(o, i)| {
o.copy_from_slice(&i);
});
output
}
/// The length of the output of SHA-1, in bytes.
pub const SHA1_OUTPUT_LEN: usize = sha1::OUTPUT_LEN.into();
/// The length of the output of SHA-256, in bytes.
pub const SHA256_OUTPUT_LEN: usize = OutputLen::_256.into();
/// The length of the output of SHA-384, in bytes.
pub const SHA384_OUTPUT_LEN: usize = OutputLen::_384.into();
/// The length of the output of SHA-512, in bytes.
pub const SHA512_OUTPUT_LEN: usize = OutputLen::_512.into();
/// The length of the output of SHA-512/256, in bytes.
pub const SHA512_256_OUTPUT_LEN: usize = OutputLen::_256.into();
#[derive(Clone, Copy)]
enum BlockLen {
_512 = 512 / 8,
_1024 = 1024 / 8, // MAX
}
impl BlockLen {
const MAX: Self = Self::_1024;
#[inline(always)]
const fn into(self) -> usize {
self as usize
}
#[inline(always)]
const fn len_len(self) -> usize {
let len_len = match self {
BlockLen::_512 => LenLen::_64,
BlockLen::_1024 => LenLen::_128,
};
len_len as usize
}
}
#[derive(Clone, Copy)]
enum LenLen {
_64 = 64 / 8,
_128 = 128 / 8,
}
#[derive(Clone, Copy)]
enum OutputLen {
_160 = 160 / 8,
_256 = 256 / 8,
_384 = 384 / 8,
_512 = 512 / 8, // MAX
}
impl OutputLen {
const MAX: Self = Self::_512;
#[inline(always)]
const fn into(self) -> usize {
self as usize
}
}
#[cfg(test)]
mod tests {
mod max_input {
extern crate alloc;
use super::super::super::digest;
use crate::polyfill::u64_from_usize;
use alloc::vec;
macro_rules! max_input_tests {
( $algorithm_name:ident ) => {
mod $algorithm_name {
use super::super::super::super::digest;
#[test]
fn max_input_test() {
super::max_input_test(&digest::$algorithm_name);
}
#[test]
#[should_panic]
fn too_long_input_test_block() {
super::too_long_input_test_block(&digest::$algorithm_name);
}
#[test]
#[should_panic]
fn too_long_input_test_byte() {
super::too_long_input_test_byte(&digest::$algorithm_name);
}
}
};
}
fn max_input_test(alg: &'static digest::Algorithm) {
let mut context = nearly_full_context(alg);
let next_input = vec![0u8; alg.block_len() - 1];
context.update(&next_input);
let _ = context.finish(); // no panic
}
fn too_long_input_test_block(alg: &'static digest::Algorithm) {
let mut context = nearly_full_context(alg);
let next_input = vec![0u8; alg.block_len()];
context.update(&next_input);
let _ = context.finish(); // should panic
}
fn too_long_input_test_byte(alg: &'static digest::Algorithm) {
let mut context = nearly_full_context(alg);
let next_input = vec![0u8; alg.block_len() - 1];
context.update(&next_input);
context.update(&[0]);
let _ = context.finish(); // should panic
}
fn nearly_full_context(alg: &'static digest::Algorithm) -> digest::Context {
// All implementations currently support up to 2^64-1 bits
// of input; according to the spec, SHA-384 and SHA-512
// support up to 2^128-1, but that's not implemented yet.
let max_bytes = 1u64 << (64 - 3);
let max_blocks = max_bytes / u64_from_usize(alg.block_len());
let completed_bytes = (max_blocks - 1) * u64_from_usize(alg.block_len());
digest::Context {
block: digest::BlockContext {
state: alg.initial_state.clone(),
completed_bytes,
algorithm: alg,
},
pending: [0u8; digest::MAX_BLOCK_LEN],
num_pending: 0,
}
}
max_input_tests!(SHA1_FOR_LEGACY_USE_ONLY);
max_input_tests!(SHA256);
max_input_tests!(SHA384);
max_input_tests!(SHA512);
}
}

98
vendor/ring/src/digest/dynstate.rs vendored Normal file
View File

@@ -0,0 +1,98 @@
// 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use super::{format_output, sha1, sha2, Output};
use crate::{cpu, polyfill::slice};
use core::mem::size_of;
// Invariant: When constructed with `new32` (resp. `new64`), `As32` (resp.
// `As64`) is the active variant.
// Invariant: The active variant never changes after initialization.
#[derive(Clone)]
pub(super) enum DynState {
As64(sha2::State64),
As32(sha2::State32),
}
impl DynState {
pub const fn new32(initial_state: sha2::State32) -> Self {
Self::As32(initial_state)
}
pub const fn new64(initial_state: sha2::State64) -> Self {
Self::As64(initial_state)
}
pub fn format_output(self) -> Output {
match self {
Self::As64(state) => {
format_output::<_, _, { size_of::<u64>() }>(state, u64::to_be_bytes)
}
Self::As32(state) => {
format_output::<_, _, { size_of::<u32>() }>(state, u32::to_be_bytes)
}
}
}
}
pub(super) fn sha1_block_data_order<'d>(
state: &mut DynState,
data: &'d [u8],
_cpu_features: cpu::Features,
) -> (usize, &'d [u8]) {
let state = match state {
DynState::As32(state) => state,
_ => {
unreachable!();
}
};
let (full_blocks, leftover) = slice::as_chunks(data);
sha1::sha1_block_data_order(state, full_blocks);
(full_blocks.as_flattened().len(), leftover)
}
pub(super) fn sha256_block_data_order<'d>(
state: &mut DynState,
data: &'d [u8],
cpu_features: cpu::Features,
) -> (usize, &'d [u8]) {
let state = match state {
DynState::As32(state) => state,
_ => {
unreachable!();
}
};
let (full_blocks, leftover) = slice::as_chunks(data);
sha2::block_data_order_32(state, full_blocks, cpu_features);
(full_blocks.len() * sha2::SHA256_BLOCK_LEN.into(), leftover)
}
pub(super) fn sha512_block_data_order<'d>(
state: &mut DynState,
data: &'d [u8],
cpu_features: cpu::Features,
) -> (usize, &'d [u8]) {
let state = match state {
DynState::As64(state) => state,
_ => {
unreachable!();
}
};
let (full_blocks, leftover) = slice::as_chunks(data);
sha2::block_data_order_64(state, full_blocks, cpu_features);
(full_blocks.len() * sha2::SHA512_BLOCK_LEN.into(), leftover)
}

119
vendor/ring/src/digest/sha1.rs vendored Normal file
View File

@@ -0,0 +1,119 @@
// Copyright 2015-2025 Brian Smith.
// Copyright 2016 Simon Sapin.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use super::{
sha2::{
fallback::{ch, maj, Word},
State32,
},
BlockLen, OutputLen,
};
use crate::polyfill::slice::{self, AsChunks};
use core::{mem::size_of, num::Wrapping};
pub(super) const BLOCK_LEN: BlockLen = BlockLen::_512;
pub const CHAINING_LEN: usize = 160 / 8;
pub(super) const OUTPUT_LEN: OutputLen = OutputLen::_160;
const CHAINING_WORDS: usize = CHAINING_LEN / 4;
type W32 = Wrapping<u32>;
// FIPS 180-4 4.1.1
#[inline]
fn parity(x: W32, y: W32, z: W32) -> W32 {
x ^ y ^ z
}
type State = [W32; CHAINING_WORDS];
const ROUNDS: usize = 80;
pub fn sha1_block_data_order(state: &mut State32, data: AsChunks<u8, { BLOCK_LEN.into() }>) {
// The unwrap won't fail because `CHAINING_WORDS` is smaller than the
// length.
let state: &mut State = (&mut state[..CHAINING_WORDS]).try_into().unwrap();
// SAFETY: The caller guarantees that this is called with data pointing to `num`
// `BLOCK_LEN`-long blocks.
*state = block_data_order(*state, data)
}
#[inline]
#[rustfmt::skip]
fn block_data_order(
mut H: [W32; CHAINING_WORDS],
M: AsChunks<u8, { BLOCK_LEN.into() }>,
) -> [W32; CHAINING_WORDS]
{
for M in M {
let (M, remainder): (AsChunks<u8, {size_of::<W32>()}>, &[u8]) = slice::as_chunks(M);
debug_assert!(remainder.is_empty());
// FIPS 180-4 6.1.2 Step 1
let mut W: [W32; ROUNDS] = [W32::ZERO; ROUNDS];
W.iter_mut().zip(M).for_each(|(Wt, Mt)| {
*Wt = W32::from_be_bytes(*Mt);
});
for t in 16..ROUNDS {
let wt = W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16];
W[t] = rotl(wt, 1);
}
// FIPS 180-4 6.1.2 Step 2
let [a, b, c, d, e] = H;
// FIPS 180-4 6.1.2 Step 3 with constants and functions from FIPS 180-4 {4.1.1, 4.2.1}
let (a, b, c, d, e) = step3(a, b, c, d, e, &W, 0, Wrapping(0x5a827999), ch);
let (a, b, c, d, e) = step3(a, b, c, d, e, &W, 20, Wrapping(0x6ed9eba1), parity);
let (a, b, c, d, e) = step3(a, b, c, d, e, &W, 40, Wrapping(0x8f1bbcdc), maj);
let (a, b, c, d, e) = step3(a, b, c, d, e, &W, 60, Wrapping(0xca62c1d6), parity);
// FIPS 180-4 6.1.2 Step 4
H[0] += a;
H[1] += b;
H[2] += c;
H[3] += d;
H[4] += e;
}
H
}
#[inline(always)]
fn step3(
mut a: W32,
mut b: W32,
mut c: W32,
mut d: W32,
mut e: W32,
W: &[W32; 80],
t: usize,
k: W32,
f: impl Fn(W32, W32, W32) -> W32,
) -> (W32, W32, W32, W32, W32) {
let W = &W[t..(t + 20)];
for W_t in W.iter() {
let T = rotl(a, 5) + f(b, c, d) + e + k + W_t;
e = d;
d = c;
c = rotl(b, 30);
b = a;
a = T;
}
(a, b, c, d, e)
}
#[inline(always)]
fn rotl(x: W32, n: u32) -> W32 {
Wrapping(x.0.rotate_left(n))
}

372
vendor/ring/src/digest/sha2/fallback.rs vendored Normal file
View File

@@ -0,0 +1,372 @@
// Copyright 2019-2025 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use super::CHAINING_WORDS;
use crate::polyfill::slice::{self, AsChunks};
use core::{
num::Wrapping,
ops::{Add, AddAssign, BitAnd, BitOr, BitXor, Not, Shr},
};
#[cfg_attr(
any(
all(target_arch = "aarch64", target_endian = "little"),
all(target_arch = "arm", target_endian = "little"),
target_arch = "x86_64"
),
allow(dead_code)
)]
#[inline]
pub(super) fn block_data_order<S: Sha2, const BLOCK_LEN: usize, const BYTES_LEN: usize>(
mut H: [S; CHAINING_WORDS],
M: AsChunks<u8, BLOCK_LEN>,
) -> [S; CHAINING_WORDS]
where
for<'a> &'a S::InputBytes: From<&'a [u8; BYTES_LEN]>,
{
for M in M {
let (M, remainder): (AsChunks<u8, BYTES_LEN>, &[u8]) = slice::as_chunks(M);
debug_assert!(remainder.is_empty());
// FIPS 180-4 {6.2.2, 6.4.2} Step 1
//
// TODO(MSRV): Use `let W: [S::from(0); S::ROUNDS]` instead; depends on
// https://github.com/rust-lang/rust/issues/43408.
let mut W = S::zero_w();
let W = W.as_mut();
W.iter_mut().zip(M).for_each(|(Wt, Mt)| {
let Mt: &S::InputBytes = Mt.into();
*Wt = S::from_be_bytes(*Mt);
});
for t in 16..S::ROUNDS {
W[t] = sigma_1(W[t - 2]) + W[t - 7] + sigma_0(W[t - 15]) + W[t - 16]
}
// FIPS 180-4 {6.2.2, 6.4.2} Step 2
let [mut a, mut b, mut c, mut d, mut e, mut f, mut g, mut h] = H;
// FIPS 180-4 {6.2.2, 6.4.2} Step 3
for (Kt, Wt) in S::K.as_ref().iter().zip(W.iter()) {
let T1 = h + SIGMA_1(e) + ch(e, f, g) + *Kt + *Wt;
let T2 = SIGMA_0(a) + maj(a, b, c);
h = g;
g = f;
f = e;
e = d + T1;
d = c;
c = b;
b = a;
a = T1 + T2;
}
// FIPS 180-4 {6.2.2, 6.4.2} Step 4
H[0] += a;
H[1] += b;
H[2] += c;
H[3] += d;
H[4] += e;
H[5] += f;
H[6] += g;
H[7] += h;
}
H
}
// FIPS 180-4 {4.1.1, 4.1.2, 4.1.3}
#[inline(always)]
pub(in super::super) fn ch<W: Word>(x: W, y: W, z: W) -> W {
(x & y) | (!x & z)
}
// FIPS 180-4 {4.1.1, 4.1.2, 4.1.3}
#[inline(always)]
pub(in super::super) fn maj<W: Word>(x: W, y: W, z: W) -> W {
(x & y) | (x & z) | (y & z)
}
// FIPS 180-4 {4.1.2, 4.1.3}
#[inline(always)]
fn SIGMA_0<S: Sha2>(x: S) -> S {
x.rotr(S::BIG_SIGMA_0.0) ^ x.rotr(S::BIG_SIGMA_0.1) ^ x.rotr(S::BIG_SIGMA_0.2)
}
// FIPS 180-4 {4.1.2, 4.1.3}
#[inline(always)]
fn SIGMA_1<S: Sha2>(x: S) -> S {
x.rotr(S::BIG_SIGMA_1.0) ^ x.rotr(S::BIG_SIGMA_1.1) ^ x.rotr(S::BIG_SIGMA_1.2)
}
// FIPS 180-4 {4.1.2, 4.1.3}
#[inline(always)]
fn sigma_0<S: Sha2>(x: S) -> S {
x.rotr(S::SMALL_SIGMA_0.0) ^ x.rotr(S::SMALL_SIGMA_0.1) ^ (x >> S::SMALL_SIGMA_0.2)
}
// FIPS 180-4 {4.1.2, 4.1.3}
#[inline(always)]
fn sigma_1<S: Sha2>(x: S) -> S {
x.rotr(S::SMALL_SIGMA_1.0) ^ x.rotr(S::SMALL_SIGMA_1.1) ^ (x >> S::SMALL_SIGMA_1.2)
}
// Commonality between SHA-1 and SHA-2 words.
pub(in super::super) trait Word:
'static
+ Sized
+ Copy
+ Add<Output = Self>
+ AddAssign
+ BitAnd<Output = Self>
+ BitOr<Output = Self>
+ Not<Output = Self>
{
const ZERO: Self;
type InputBytes: Copy;
fn from_be_bytes(input: Self::InputBytes) -> Self;
fn rotr(self, count: u32) -> Self;
}
/// A SHA-2 input word.
pub(super) trait Sha2: Word + BitXor<Output = Self> + Shr<usize, Output = Self> {
const BIG_SIGMA_0: (u32, u32, u32);
const BIG_SIGMA_1: (u32, u32, u32);
const SMALL_SIGMA_0: (u32, u32, usize);
const SMALL_SIGMA_1: (u32, u32, usize);
const ROUNDS: usize;
type W: AsRef<[Self]> + AsMut<[Self]>;
fn zero_w() -> Self::W;
const K: &'static Self::W;
}
impl Word for Wrapping<u32> {
const ZERO: Self = Self(0);
type InputBytes = [u8; 4];
#[inline(always)]
fn from_be_bytes(input: Self::InputBytes) -> Self {
Self(u32::from_be_bytes(input))
}
#[inline(always)]
fn rotr(self, count: u32) -> Self {
Self(self.0.rotate_right(count))
}
}
// SHA-256
impl Sha2 for Wrapping<u32> {
// FIPS 180-4 4.1.2
const BIG_SIGMA_0: (u32, u32, u32) = (2, 13, 22);
const BIG_SIGMA_1: (u32, u32, u32) = (6, 11, 25);
const SMALL_SIGMA_0: (u32, u32, usize) = (7, 18, 3);
const SMALL_SIGMA_1: (u32, u32, usize) = (17, 19, 10);
// FIPS 180-4 {6.2.2} Step 1
const ROUNDS: usize = 64;
type W = [Self; Self::ROUNDS];
fn zero_w() -> Self::W {
[Self::ZERO; Self::ROUNDS]
}
// FIPS 180-4 4.2.2
const K: &'static Self::W = &[
Self(0x428a2f98),
Self(0x71374491),
Self(0xb5c0fbcf),
Self(0xe9b5dba5),
Self(0x3956c25b),
Self(0x59f111f1),
Self(0x923f82a4),
Self(0xab1c5ed5),
Self(0xd807aa98),
Self(0x12835b01),
Self(0x243185be),
Self(0x550c7dc3),
Self(0x72be5d74),
Self(0x80deb1fe),
Self(0x9bdc06a7),
Self(0xc19bf174),
Self(0xe49b69c1),
Self(0xefbe4786),
Self(0x0fc19dc6),
Self(0x240ca1cc),
Self(0x2de92c6f),
Self(0x4a7484aa),
Self(0x5cb0a9dc),
Self(0x76f988da),
Self(0x983e5152),
Self(0xa831c66d),
Self(0xb00327c8),
Self(0xbf597fc7),
Self(0xc6e00bf3),
Self(0xd5a79147),
Self(0x06ca6351),
Self(0x14292967),
Self(0x27b70a85),
Self(0x2e1b2138),
Self(0x4d2c6dfc),
Self(0x53380d13),
Self(0x650a7354),
Self(0x766a0abb),
Self(0x81c2c92e),
Self(0x92722c85),
Self(0xa2bfe8a1),
Self(0xa81a664b),
Self(0xc24b8b70),
Self(0xc76c51a3),
Self(0xd192e819),
Self(0xd6990624),
Self(0xf40e3585),
Self(0x106aa070),
Self(0x19a4c116),
Self(0x1e376c08),
Self(0x2748774c),
Self(0x34b0bcb5),
Self(0x391c0cb3),
Self(0x4ed8aa4a),
Self(0x5b9cca4f),
Self(0x682e6ff3),
Self(0x748f82ee),
Self(0x78a5636f),
Self(0x84c87814),
Self(0x8cc70208),
Self(0x90befffa),
Self(0xa4506ceb),
Self(0xbef9a3f7),
Self(0xc67178f2),
];
}
impl Word for Wrapping<u64> {
const ZERO: Self = Self(0);
type InputBytes = [u8; 8];
#[inline(always)]
fn from_be_bytes(input: Self::InputBytes) -> Self {
Self(u64::from_be_bytes(input))
}
#[inline(always)]
fn rotr(self, count: u32) -> Self {
Self(self.0.rotate_right(count))
}
}
// SHA-384 and SHA-512
impl Sha2 for Wrapping<u64> {
// FIPS 180-4 4.1.3
const BIG_SIGMA_0: (u32, u32, u32) = (28, 34, 39);
const BIG_SIGMA_1: (u32, u32, u32) = (14, 18, 41);
const SMALL_SIGMA_0: (u32, u32, usize) = (1, 8, 7);
const SMALL_SIGMA_1: (u32, u32, usize) = (19, 61, 6);
// FIPS 180-4 {6.4.2} Step 1
const ROUNDS: usize = 80;
type W = [Self; Self::ROUNDS];
fn zero_w() -> Self::W {
[Self::ZERO; Self::ROUNDS]
}
// FIPS 180-4 4.2.3
const K: &'static Self::W = &[
Self(0x428a2f98d728ae22),
Self(0x7137449123ef65cd),
Self(0xb5c0fbcfec4d3b2f),
Self(0xe9b5dba58189dbbc),
Self(0x3956c25bf348b538),
Self(0x59f111f1b605d019),
Self(0x923f82a4af194f9b),
Self(0xab1c5ed5da6d8118),
Self(0xd807aa98a3030242),
Self(0x12835b0145706fbe),
Self(0x243185be4ee4b28c),
Self(0x550c7dc3d5ffb4e2),
Self(0x72be5d74f27b896f),
Self(0x80deb1fe3b1696b1),
Self(0x9bdc06a725c71235),
Self(0xc19bf174cf692694),
Self(0xe49b69c19ef14ad2),
Self(0xefbe4786384f25e3),
Self(0x0fc19dc68b8cd5b5),
Self(0x240ca1cc77ac9c65),
Self(0x2de92c6f592b0275),
Self(0x4a7484aa6ea6e483),
Self(0x5cb0a9dcbd41fbd4),
Self(0x76f988da831153b5),
Self(0x983e5152ee66dfab),
Self(0xa831c66d2db43210),
Self(0xb00327c898fb213f),
Self(0xbf597fc7beef0ee4),
Self(0xc6e00bf33da88fc2),
Self(0xd5a79147930aa725),
Self(0x06ca6351e003826f),
Self(0x142929670a0e6e70),
Self(0x27b70a8546d22ffc),
Self(0x2e1b21385c26c926),
Self(0x4d2c6dfc5ac42aed),
Self(0x53380d139d95b3df),
Self(0x650a73548baf63de),
Self(0x766a0abb3c77b2a8),
Self(0x81c2c92e47edaee6),
Self(0x92722c851482353b),
Self(0xa2bfe8a14cf10364),
Self(0xa81a664bbc423001),
Self(0xc24b8b70d0f89791),
Self(0xc76c51a30654be30),
Self(0xd192e819d6ef5218),
Self(0xd69906245565a910),
Self(0xf40e35855771202a),
Self(0x106aa07032bbd1b8),
Self(0x19a4c116b8d2d0c8),
Self(0x1e376c085141ab53),
Self(0x2748774cdf8eeb99),
Self(0x34b0bcb5e19b48a8),
Self(0x391c0cb3c5c95a63),
Self(0x4ed8aa4ae3418acb),
Self(0x5b9cca4f7763e373),
Self(0x682e6ff3d6b2b8a3),
Self(0x748f82ee5defb2fc),
Self(0x78a5636f43172f60),
Self(0x84c87814a1f0ab72),
Self(0x8cc702081a6439ec),
Self(0x90befffa23631e28),
Self(0xa4506cebde82bde9),
Self(0xbef9a3f7b2c67915),
Self(0xc67178f2e372532b),
Self(0xca273eceea26619c),
Self(0xd186b8c721c0c207),
Self(0xeada7dd6cde0eb1e),
Self(0xf57d4f7fee6ed178),
Self(0x06f067aa72176fba),
Self(0x0a637dc5a2c898a6),
Self(0x113f9804bef90dae),
Self(0x1b710b35131c471b),
Self(0x28db77f523047d84),
Self(0x32caab7b40c72493),
Self(0x3c9ebe0a15c9bebc),
Self(0x431d67c49c100d4c),
Self(0x4cc5d4becb3e42b6),
Self(0x597f299cfc657e2a),
Self(0x5fcb6fab3ad6faec),
Self(0x6c44198c4a475817),
];
}

71
vendor/ring/src/digest/sha2/ffi.rs vendored Normal file
View File

@@ -0,0 +1,71 @@
// Copyright 2024 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use super::CHAINING_WORDS;
use crate::polyfill::slice::AsChunks;
use core::num::{NonZeroUsize, Wrapping};
/// `unsafe { T => f }` means it is safe to call `f` iff we can construct
/// a value of type `T`.
macro_rules! sha2_ffi {
( $U:ty, $BLOCK_LEN:expr, unsafe { $Cpu:ty => $f:ident },
$state:expr, $data:expr, $cpu:expr $(,)? ) => {{
prefixed_extern! {
fn $f(
state: *mut [core::num::Wrapping<$U>; crate::digest::sha2::CHAINING_WORDS],
data: *const [u8; $BLOCK_LEN],
num: crate::c::NonZero_size_t);
}
// SAFETY: The user asserts that $f has the signature above and is safe
// to call if additionally we have a value of type `$Cpu`, which we do.
unsafe {
crate::digest::sha2::ffi::sha2_ffi::<$U, $Cpu, { $BLOCK_LEN }>($state, $data, $cpu, $f)
}
}};
}
macro_rules! sha2_32_ffi {
( unsafe { $Cpu:ty => $f:ident }, $state:expr, $data:expr, $cpu:expr $(,)? ) => {
sha2_ffi!(u32, crate::digest::sha2::SHA256_BLOCK_LEN.into(),
unsafe { $Cpu => $f }, $state, $data, $cpu)
}
}
macro_rules! sha2_64_ffi {
( unsafe { $Cpu:ty => $f:ident }, $state:expr, $data:expr, $cpu:expr $(,)? ) => {
sha2_ffi!(u64, SHA512_BLOCK_LEN.into(), unsafe { $Cpu => $f }, $state, $data, $cpu)
}
}
pub(super) unsafe fn sha2_ffi<U, Cpu, const BLOCK_LEN: usize>(
state: &mut [Wrapping<U>; CHAINING_WORDS],
data: AsChunks<u8, BLOCK_LEN>,
cpu: Cpu,
f: unsafe extern "C" fn(
*mut [Wrapping<U>; CHAINING_WORDS],
*const [u8; BLOCK_LEN],
crate::c::NonZero_size_t,
),
) {
if let Some(blocks) = NonZeroUsize::new(data.len()) {
let data = data.as_ptr();
let _: Cpu = cpu;
// SAFETY:
// * `blocks` is non-zero.
// * `data` is non-NULL and points to `blocks` blocks.
// * The caller asserted that `f` meets this contract if we have
// an instance of `Cpu`.
unsafe { f(state, data, blocks) }
}
}

34
vendor/ring/src/digest/sha2/mod.rs vendored Normal file
View File

@@ -0,0 +1,34 @@
// Copyright 2019-2024 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use super::BlockLen;
pub(super) use self::{
sha2_32::{block_data_order_32, State32, SHA256_BLOCK_LEN},
sha2_64::{block_data_order_64, State64, SHA512_BLOCK_LEN},
};
pub(super) const CHAINING_WORDS: usize = 8;
#[cfg(any(
all(target_arch = "aarch64", target_endian = "little"),
all(target_arch = "arm", target_endian = "little"),
target_arch = "x86_64"
))]
#[macro_use]
mod ffi;
pub(super) mod fallback;
mod sha2_32;
mod sha2_64;

63
vendor/ring/src/digest/sha2/sha2_32.rs vendored Normal file
View File

@@ -0,0 +1,63 @@
// Copyright 2024 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use super::{BlockLen, CHAINING_WORDS};
use crate::{cpu, polyfill::slice::AsChunks};
use cfg_if::cfg_if;
use core::num::Wrapping;
pub(in super::super) const SHA256_BLOCK_LEN: BlockLen = BlockLen::_512;
pub type State32 = [Wrapping<u32>; CHAINING_WORDS];
pub(crate) fn block_data_order_32(
state: &mut State32,
data: AsChunks<u8, { SHA256_BLOCK_LEN.into() }>,
cpu: cpu::Features,
) {
cfg_if! {
if #[cfg(all(target_arch = "aarch64", target_endian = "little"))] {
use cpu::{GetFeature as _, arm::Sha256};
if let Some(cpu) = cpu.get_feature() {
sha2_32_ffi!(unsafe { Sha256 => sha256_block_data_order_hw }, state, data, cpu)
} else {
sha2_32_ffi!(unsafe { () => sha256_block_data_order_nohw }, state, data, ())
}
} else if #[cfg(all(target_arch = "arm", target_endian = "little"))] {
use cpu::{GetFeature as _, arm::Neon};
if let Some(cpu) = cpu.get_feature() {
sha2_32_ffi!(unsafe { Neon => sha256_block_data_order_neon }, state, data, cpu)
} else {
sha2_32_ffi!(unsafe { () => sha256_block_data_order_nohw }, state, data, ())
}
} else if #[cfg(target_arch = "x86_64")] {
use cpu::{GetFeature as _, intel::{Avx, IntelCpu, Sha, Ssse3 }};
let cpu = cpu.values();
if let Some(cpu) = cpu.get_feature() {
sha2_32_ffi!(unsafe { (Sha, Ssse3) => sha256_block_data_order_hw }, state, data, cpu)
} else if let Some(cpu) = cpu.get_feature() {
// Pre-Zen AMD CPUs had slow SHLD/SHRD; Zen added the SHA
// extension; see the discussion in upstream's sha1-586.pl.
sha2_32_ffi!(unsafe { (Avx, IntelCpu) => sha256_block_data_order_avx }, state, data, cpu)
} else if let Some(cpu) = cpu.get_feature() {
sha2_32_ffi!(unsafe { Ssse3 => sha256_block_data_order_ssse3 }, state, data, cpu)
} else {
sha2_32_ffi!(unsafe { () => sha256_block_data_order_nohw }, state, data, ())
}
} else {
let _ = cpu; // Unneeded.
*state = super::fallback::block_data_order(*state, data)
}
}
}

60
vendor/ring/src/digest/sha2/sha2_64.rs vendored Normal file
View File

@@ -0,0 +1,60 @@
// Copyright 2024 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use super::{BlockLen, CHAINING_WORDS};
use crate::{cpu, polyfill::slice::AsChunks};
use cfg_if::cfg_if;
use core::num::Wrapping;
pub(in super::super) const SHA512_BLOCK_LEN: BlockLen = BlockLen::_1024;
pub type State64 = [Wrapping<u64>; CHAINING_WORDS];
pub(crate) fn block_data_order_64(
state: &mut State64,
data: AsChunks<u8, { SHA512_BLOCK_LEN.into() }>,
cpu: cpu::Features,
) {
cfg_if! {
if #[cfg(all(target_arch = "aarch64", target_endian = "little"))] {
use cpu::{GetFeature as _, arm::Sha512};
if let Some(cpu) = cpu.get_feature() {
sha2_64_ffi!(unsafe { Sha512 => sha512_block_data_order_hw }, state, data, cpu)
} else {
sha2_64_ffi!(unsafe { () => sha512_block_data_order_nohw }, state, data, ())
}
} else if #[cfg(all(target_arch = "arm", target_endian = "little"))] {
use cpu::{GetFeature as _, arm::Neon};
if let Some(cpu) = cpu.get_feature() {
sha2_64_ffi!(unsafe { Neon => sha512_block_data_order_neon }, state, data, cpu)
} else {
sha2_64_ffi!(unsafe { () => sha512_block_data_order_nohw }, state, data, ())
}
} else if #[cfg(target_arch = "x86_64")] {
use cpu::{GetFeature as _, intel::{Avx, IntelCpu}};
if let Some(cpu) = cpu.get_feature() {
// Pre-Zen AMD CPUs had microcoded SHLD/SHRD which makes the
// AVX version slow. We're also unsure of the side channel
// ramifications of those microcoded instructions.
sha2_64_ffi!(unsafe { (Avx, IntelCpu) => sha512_block_data_order_avx },
state, data, cpu);
} else {
sha2_64_ffi!(unsafe { () => sha512_block_data_order_nohw }, state, data, ())
}
} else {
let _ = cpu; // Unneeded.
*state = super::fallback::block_data_order(*state, data)
}
}
}

68
vendor/ring/src/ec.rs vendored Normal file
View File

@@ -0,0 +1,68 @@
// Copyright 2015-2017 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use crate::{cpu, error, rand};
pub use self::keys::{KeyPair, PublicKey, Seed};
pub struct Curve {
pub public_key_len: usize,
pub elem_scalar_seed_len: usize,
pub id: CurveID,
// Precondition: `bytes` is the correct length.
check_private_key_bytes: fn(bytes: &[u8], cpu: cpu::Features) -> Result<(), error::Unspecified>,
generate_private_key: fn(
rng: &dyn rand::SecureRandom,
&mut [u8],
cpu: cpu::Features,
) -> Result<(), error::Unspecified>,
public_from_private: fn(
public_out: &mut [u8],
private_key: &Seed,
cpu: cpu::Features,
) -> Result<(), error::Unspecified>,
}
derive_debug_via_id!(Curve);
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum CurveID {
Curve25519,
P256,
P384,
}
const ELEM_MAX_BITS: usize = 384;
pub const ELEM_MAX_BYTES: usize = (ELEM_MAX_BITS + 7) / 8;
pub const SCALAR_MAX_BYTES: usize = ELEM_MAX_BYTES;
const SEED_MAX_BYTES: usize = ELEM_MAX_BYTES;
/// The maximum length of a PKCS#8 documents generated by *ring* for ECC keys.
///
/// This is NOT the maximum length of a PKCS#8 document that can be consumed by
/// `pkcs8::unwrap_key()`.
///
/// `40` is the length of the P-384 template. It is actually one byte shorter
/// than the P-256 template, but the private key and the public key are much
/// longer.
pub const PKCS8_DOCUMENT_MAX_LEN: usize = 40 + SCALAR_MAX_BYTES + keys::PUBLIC_KEY_MAX_LEN;
pub mod curve25519;
mod keys;
pub mod suite_b;

22
vendor/ring/src/ec/curve25519.rs vendored Normal file
View File

@@ -0,0 +1,22 @@
// Copyright 2016 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//! Elliptic curve operations and schemes using Curve25519.
pub mod ed25519;
pub mod x25519;
mod ops;
mod scalar;

View File

@@ -0,0 +1,32 @@
// Copyright 2015-2016 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//! EdDSA Signatures.
use super::ops::ELEM_LEN;
use crate::digest;
pub mod signing;
pub mod verification;
/// The length of an Ed25519 public key.
pub const ED25519_PUBLIC_KEY_LEN: usize = ELEM_LEN;
pub fn eddsa_digest(signature_r: &[u8], public_key: &[u8], msg: &[u8]) -> digest::Digest {
let mut ctx = digest::Context::new(&digest::SHA512);
ctx.update(signature_r);
ctx.update(public_key);
ctx.update(msg);
ctx.finish()
}

Binary file not shown.

View File

@@ -0,0 +1,275 @@
// Copyright 2015-2016 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//! EdDSA Signatures.
use super::{super::ops::*, eddsa_digest, ED25519_PUBLIC_KEY_LEN};
use crate::{
cpu, digest, error,
io::der,
pkcs8, rand,
signature::{self, KeyPair as SigningKeyPair},
};
/// An Ed25519 key pair, for signing.
pub struct Ed25519KeyPair {
// RFC 8032 Section 5.1.6 calls this *s*.
private_scalar: Scalar,
// RFC 8032 Section 5.1.6 calls this *prefix*.
private_prefix: Prefix,
// RFC 8032 Section 5.1.5 calls this *A*.
public_key: PublicKey,
}
derive_debug_via_field!(Ed25519KeyPair, stringify!(Ed25519KeyPair), public_key);
impl Ed25519KeyPair {
/// Generates a new key pair and returns the key pair serialized as a
/// PKCS#8 document.
///
/// The PKCS#8 document will be a v2 `OneAsymmetricKey` with the public key,
/// as described in [RFC 5958 Section 2]; see [RFC 8410 Section 10.3] for an
/// example.
///
/// [RFC 5958 Section 2]: https://tools.ietf.org/html/rfc5958#section-2
/// [RFC 8410 Section 10.3]: https://tools.ietf.org/html/rfc8410#section-10.3
pub fn generate_pkcs8(
rng: &dyn rand::SecureRandom,
) -> Result<pkcs8::Document, error::Unspecified> {
let cpu_features = cpu::features();
let seed: [u8; SEED_LEN] = rand::generate(rng)?.expose();
let key_pair = Self::from_seed_(&seed, cpu_features);
Ok(pkcs8::wrap_key(
&PKCS8_TEMPLATE,
&seed[..],
key_pair.public_key().as_ref(),
))
}
/// Constructs an Ed25519 key pair by parsing an unencrypted PKCS#8 v2
/// Ed25519 private key.
///
/// `openssl genpkey -algorithm ED25519` generates PKCS# v1 keys, which
/// require the use of `Ed25519KeyPair::from_pkcs8_maybe_unchecked()`
/// instead of `Ed25519KeyPair::from_pkcs8()`.
///
/// The input must be in PKCS#8 v2 format, and in particular it must contain
/// the public key in addition to the private key. `from_pkcs8()` will
/// verify that the public key and the private key are consistent with each
/// other.
///
/// Some early implementations of PKCS#8 v2, including earlier versions of
/// *ring* and other implementations, wrapped the public key in the wrong
/// ASN.1 tags. Both that incorrect form and the standardized form are
/// accepted.
///
/// If you need to parse PKCS#8 v1 files (without the public key) then use
/// `Ed25519KeyPair::from_pkcs8_maybe_unchecked()` instead.
pub fn from_pkcs8(pkcs8: &[u8]) -> Result<Self, error::KeyRejected> {
let version = pkcs8::Version::V2Only(pkcs8::PublicKeyOptions {
accept_legacy_ed25519_public_key_tag: true,
});
let (seed, public_key) = unwrap_pkcs8(version, untrusted::Input::from(pkcs8))?;
Self::from_seed_and_public_key(
seed.as_slice_less_safe(),
public_key.unwrap().as_slice_less_safe(),
)
}
/// Constructs an Ed25519 key pair by parsing an unencrypted PKCS#8 v1 or v2
/// Ed25519 private key.
///
/// `openssl genpkey -algorithm ED25519` generates PKCS# v1 keys.
///
/// It is recommended to use `Ed25519KeyPair::from_pkcs8()`, which accepts
/// only PKCS#8 v2 files that contain the public key.
/// `from_pkcs8_maybe_unchecked()` parses PKCS#2 files exactly like
/// `from_pkcs8()`. It also accepts v1 files. PKCS#8 v1 files do not contain
/// the public key, so when a v1 file is parsed the public key will be
/// computed from the private key, and there will be no consistency check
/// between the public key and the private key.
///
/// Some early implementations of PKCS#8 v2, including earlier versions of
/// *ring* and other implementations, wrapped the public key in the wrong
/// ASN.1 tags. Both that incorrect form and the standardized form are
/// accepted.
///
/// PKCS#8 v2 files are parsed exactly like `Ed25519KeyPair::from_pkcs8()`.
pub fn from_pkcs8_maybe_unchecked(pkcs8: &[u8]) -> Result<Self, error::KeyRejected> {
let version = pkcs8::Version::V1OrV2(pkcs8::PublicKeyOptions {
accept_legacy_ed25519_public_key_tag: true,
});
let (seed, public_key) = unwrap_pkcs8(version, untrusted::Input::from(pkcs8))?;
if let Some(public_key) = public_key {
Self::from_seed_and_public_key(
seed.as_slice_less_safe(),
public_key.as_slice_less_safe(),
)
} else {
Self::from_seed_unchecked(seed.as_slice_less_safe())
}
}
/// Constructs an Ed25519 key pair from the private key seed `seed` and its
/// public key `public_key`.
///
/// It is recommended to use `Ed25519KeyPair::from_pkcs8()` instead.
///
/// The private and public keys will be verified to be consistent with each
/// other. This helps avoid misuse of the key (e.g. accidentally swapping
/// the private key and public key, or using the wrong private key for the
/// public key). This also detects any corruption of the public or private
/// key.
pub fn from_seed_and_public_key(
seed: &[u8],
public_key: &[u8],
) -> Result<Self, error::KeyRejected> {
let pair = Self::from_seed_unchecked(seed)?;
// This implicitly verifies that `public_key` is the right length.
// XXX: This rejects ~18 keys when they are partially reduced, though
// those keys are virtually impossible to find.
if public_key != pair.public_key.as_ref() {
let err = if public_key.len() != pair.public_key.as_ref().len() {
error::KeyRejected::invalid_encoding()
} else {
error::KeyRejected::inconsistent_components()
};
return Err(err);
}
Ok(pair)
}
/// Constructs a Ed25519 key pair from the private key seed `seed`.
///
/// It is recommended to use `Ed25519KeyPair::from_pkcs8()` instead. When
/// that is not practical, it is recommended to use
/// `Ed25519KeyPair::from_seed_and_public_key()` instead.
///
/// Since the public key is not given, the public key will be computed from
/// the private key. It is not possible to detect misuse or corruption of
/// the private key since the public key isn't given as input.
pub fn from_seed_unchecked(seed: &[u8]) -> Result<Self, error::KeyRejected> {
let seed = seed
.try_into()
.map_err(|_| error::KeyRejected::invalid_encoding())?;
Ok(Self::from_seed_(seed, cpu::features()))
}
fn from_seed_(seed: &Seed, cpu_features: cpu::Features) -> Self {
let h = digest::digest(&digest::SHA512, seed);
let (private_scalar, private_prefix) = h.as_ref().split_at(SCALAR_LEN);
let private_scalar =
MaskedScalar::from_bytes_masked(private_scalar.try_into().unwrap()).into();
let a = ExtPoint::from_scalarmult_base(&private_scalar, cpu_features);
Self {
private_scalar,
private_prefix: private_prefix.try_into().unwrap(),
public_key: PublicKey(a.into_encoded_point(cpu_features)),
}
}
/// Returns the signature of the message `msg`.
pub fn sign(&self, msg: &[u8]) -> signature::Signature {
let cpu_features = cpu::features();
signature::Signature::new(|signature_bytes| {
prefixed_extern! {
fn x25519_sc_muladd(
s: &mut [u8; SCALAR_LEN],
a: &Scalar,
b: &Scalar,
c: &Scalar,
);
}
let (signature_bytes, _unused) = signature_bytes.split_at_mut(ELEM_LEN + SCALAR_LEN);
let (signature_r, signature_s) = signature_bytes.split_at_mut(ELEM_LEN);
let nonce = {
let mut ctx = digest::Context::new(&digest::SHA512);
ctx.update(&self.private_prefix);
ctx.update(msg);
ctx.finish()
};
let nonce = Scalar::from_sha512_digest_reduced(nonce);
let r = ExtPoint::from_scalarmult_base(&nonce, cpu_features);
signature_r.copy_from_slice(&r.into_encoded_point(cpu_features));
let hram_digest = eddsa_digest(signature_r, self.public_key.as_ref(), msg);
let hram = Scalar::from_sha512_digest_reduced(hram_digest);
unsafe {
x25519_sc_muladd(
signature_s.try_into().unwrap(),
&hram,
&self.private_scalar,
&nonce,
);
}
SIGNATURE_LEN
})
}
}
impl signature::KeyPair for Ed25519KeyPair {
type PublicKey = PublicKey;
fn public_key(&self) -> &Self::PublicKey {
&self.public_key
}
}
#[derive(Clone, Copy)]
pub struct PublicKey([u8; ED25519_PUBLIC_KEY_LEN]);
impl AsRef<[u8]> for PublicKey {
fn as_ref(&self) -> &[u8] {
self.0.as_ref()
}
}
derive_debug_self_as_ref_hex_bytes!(PublicKey);
fn unwrap_pkcs8(
version: pkcs8::Version,
input: untrusted::Input,
) -> Result<(untrusted::Input, Option<untrusted::Input>), error::KeyRejected> {
let (private_key, public_key) = pkcs8::unwrap_key(&PKCS8_TEMPLATE, version, input)?;
let private_key = private_key
.read_all(error::Unspecified, |input| {
der::expect_tag_and_get_value(input, der::Tag::OctetString)
})
.map_err(|error::Unspecified| error::KeyRejected::invalid_encoding())?;
Ok((private_key, public_key))
}
type Prefix = [u8; PREFIX_LEN];
const PREFIX_LEN: usize = digest::SHA512_OUTPUT_LEN - SCALAR_LEN;
const SIGNATURE_LEN: usize = ELEM_LEN + SCALAR_LEN;
type Seed = [u8; SEED_LEN];
const SEED_LEN: usize = 32;
static PKCS8_TEMPLATE: pkcs8::Template = pkcs8::Template {
bytes: include_bytes!("ed25519_pkcs8_v2_template.der"),
alg_id_range: core::ops::Range { start: 7, end: 12 },
curve_id_index: 0,
private_key_index: 0x10,
};

View File

@@ -0,0 +1,85 @@
// Copyright 2015-2016 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//! EdDSA Signatures.
use super::{super::ops::*, eddsa_digest};
use crate::{cpu, error, sealed, signature};
/// Parameters for EdDSA signing and verification.
pub struct EdDSAParameters;
impl core::fmt::Debug for EdDSAParameters {
fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
write!(f, "ring::signature::ED25519")
}
}
/// Verification of [Ed25519] signatures.
///
/// Ed25519 uses SHA-512 as the digest algorithm.
///
/// [Ed25519]: https://ed25519.cr.yp.to/
pub static ED25519: EdDSAParameters = EdDSAParameters {};
impl signature::VerificationAlgorithm for EdDSAParameters {
fn verify(
&self,
public_key: untrusted::Input,
msg: untrusted::Input,
signature: untrusted::Input,
) -> Result<(), error::Unspecified> {
let cpu_features = cpu::features();
let public_key: &[u8; ELEM_LEN] = public_key.as_slice_less_safe().try_into()?;
let (signature_r, signature_s) = signature.read_all(error::Unspecified, |input| {
let signature_r: &[u8; ELEM_LEN] = input
.read_bytes(ELEM_LEN)?
.as_slice_less_safe()
.try_into()?;
let signature_s: &[u8; SCALAR_LEN] = input
.read_bytes(SCALAR_LEN)?
.as_slice_less_safe()
.try_into()?;
Ok((signature_r, signature_s))
})?;
let signature_s = Scalar::from_bytes_checked(*signature_s)?;
let mut a = ExtPoint::from_encoded_point_vartime(public_key)?;
a.invert_vartime();
let h_digest = eddsa_digest(signature_r, public_key, msg.as_slice_less_safe());
let h = Scalar::from_sha512_digest_reduced(h_digest);
let mut r = Point::new_at_infinity();
unsafe { x25519_ge_double_scalarmult_vartime(&mut r, &h, &a, &signature_s) };
let r_check = r.into_encoded_point(cpu_features);
if *signature_r != r_check {
return Err(error::Unspecified);
}
Ok(())
}
}
impl sealed::Sealed for EdDSAParameters {}
prefixed_extern! {
fn x25519_ge_double_scalarmult_vartime(
r: &mut Point,
a_coeff: &Scalar,
a: &ExtPoint,
b_coeff: &Scalar,
);
}

180
vendor/ring/src/ec/curve25519/ops.rs vendored Normal file
View File

@@ -0,0 +1,180 @@
// Copyright 2015-2017 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//! Elliptic curve operations on the birationally equivalent curves Curve25519
//! and Edwards25519.
pub use super::scalar::{MaskedScalar, Scalar, SCALAR_LEN};
use crate::{
bssl, cpu, error,
limb::{Limb, LIMB_BITS},
};
use core::{ffi::c_int, marker::PhantomData};
// Elem<T>` is `fe` in curve25519/internal.h.
// Elem<L> is `fe_loose` in curve25519/internal.h.
// Keep this in sync with curve25519/internal.h.
#[repr(C)]
pub struct Elem<E: Encoding> {
limbs: [Limb; ELEM_LIMBS], // This is called `v` in the C code.
encoding: PhantomData<E>,
}
pub trait Encoding {}
pub struct T;
impl Encoding for T {}
const ELEM_LIMBS: usize = 5 * 64 / LIMB_BITS;
impl<E: Encoding> Elem<E> {
fn zero() -> Self {
Self {
limbs: Default::default(),
encoding: PhantomData,
}
}
}
impl Elem<T> {
fn negate(&mut self) {
unsafe {
x25519_fe_neg(self);
}
}
}
// An encoding of a curve point. If on Curve25519, it should be encoded as
// described in Section 5 of [RFC 7748]. If on Edwards25519, it should be
// encoded as described in section 5.1.2 of [RFC 8032].
//
// [RFC 7748] https://tools.ietf.org/html/rfc7748#section-5
// [RFC 8032] https://tools.ietf.org/html/rfc8032#section-5.1.2
pub type EncodedPoint = [u8; ELEM_LEN];
pub const ELEM_LEN: usize = 32;
// Keep this in sync with `ge_p3` in curve25519/internal.h.
#[repr(C)]
pub struct ExtPoint {
x: Elem<T>,
y: Elem<T>,
z: Elem<T>,
t: Elem<T>,
}
impl ExtPoint {
// Returns the result of multiplying the base point by the scalar in constant time.
pub(super) fn from_scalarmult_base(scalar: &Scalar, cpu: cpu::Features) -> Self {
let mut r = Self {
x: Elem::zero(),
y: Elem::zero(),
z: Elem::zero(),
t: Elem::zero(),
};
prefixed_extern! {
fn x25519_ge_scalarmult_base(h: &mut ExtPoint, a: &Scalar, has_fe25519_adx: c_int);
}
unsafe {
x25519_ge_scalarmult_base(&mut r, scalar, has_fe25519_adx(cpu).into());
}
r
}
pub fn from_encoded_point_vartime(encoded: &EncodedPoint) -> Result<Self, error::Unspecified> {
let mut point = Self {
x: Elem::zero(),
y: Elem::zero(),
z: Elem::zero(),
t: Elem::zero(),
};
Result::from(unsafe { x25519_ge_frombytes_vartime(&mut point, encoded) }).map(|()| point)
}
pub(super) fn into_encoded_point(self, cpu_features: cpu::Features) -> EncodedPoint {
encode_point(self.x, self.y, self.z, cpu_features)
}
pub(super) fn invert_vartime(&mut self) {
self.x.negate();
self.t.negate();
}
}
// Keep this in sync with `ge_p2` in curve25519/internal.h.
#[repr(C)]
pub struct Point {
x: Elem<T>,
y: Elem<T>,
z: Elem<T>,
}
impl Point {
pub fn new_at_infinity() -> Self {
Self {
x: Elem::zero(),
y: Elem::zero(),
z: Elem::zero(),
}
}
pub(super) fn into_encoded_point(self, cpu_features: cpu::Features) -> EncodedPoint {
encode_point(self.x, self.y, self.z, cpu_features)
}
}
fn encode_point(x: Elem<T>, y: Elem<T>, z: Elem<T>, _cpu_features: cpu::Features) -> EncodedPoint {
let mut bytes = [0; ELEM_LEN];
let sign_bit: u8 = unsafe {
let mut recip = Elem::zero();
x25519_fe_invert(&mut recip, &z);
let mut x_over_z = Elem::zero();
x25519_fe_mul_ttt(&mut x_over_z, &x, &recip);
let mut y_over_z = Elem::zero();
x25519_fe_mul_ttt(&mut y_over_z, &y, &recip);
x25519_fe_tobytes(&mut bytes, &y_over_z);
x25519_fe_isnegative(&x_over_z)
};
// The preceding computations must execute in constant time, but this
// doesn't need to.
bytes[ELEM_LEN - 1] ^= sign_bit << 7;
bytes
}
#[inline(always)]
pub(super) fn has_fe25519_adx(cpu: cpu::Features) -> bool {
cfg_if::cfg_if! {
if #[cfg(all(target_arch = "x86_64", not(target_os = "windows")))] {
use cpu::{intel::{Adx, Bmi1, Bmi2}, GetFeature as _};
matches!(cpu.get_feature(), Some((Adx { .. }, Bmi1 { .. }, Bmi2 { .. })))
} else {
let _ = cpu;
false
}
}
}
prefixed_extern! {
fn x25519_fe_invert(out: &mut Elem<T>, z: &Elem<T>);
fn x25519_fe_isnegative(elem: &Elem<T>) -> u8;
fn x25519_fe_mul_ttt(h: &mut Elem<T>, f: &Elem<T>, g: &Elem<T>);
fn x25519_fe_neg(f: &mut Elem<T>);
fn x25519_fe_tobytes(bytes: &mut EncodedPoint, elem: &Elem<T>);
fn x25519_ge_frombytes_vartime(h: &mut ExtPoint, s: &EncodedPoint) -> bssl::Result;
}

78
vendor/ring/src/ec/curve25519/scalar.rs vendored Normal file
View File

@@ -0,0 +1,78 @@
// 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use crate::{
arithmetic::limbs_from_hex,
digest, error, limb,
polyfill::slice::{self, AsChunks},
};
use core::array;
#[repr(transparent)]
pub struct Scalar([u8; SCALAR_LEN]);
pub const SCALAR_LEN: usize = 32;
impl Scalar {
// Constructs a `Scalar` from `bytes`, failing if `bytes` encodes a scalar
// that is not in the range [0, n).
pub fn from_bytes_checked(bytes: [u8; SCALAR_LEN]) -> Result<Self, error::Unspecified> {
const ORDER: [limb::Limb; SCALAR_LEN / limb::LIMB_BYTES] =
limbs_from_hex("1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed");
let order = ORDER.map(limb::Limb::from);
let (limbs_as_bytes, _empty): (AsChunks<u8, { limb::LIMB_BYTES }>, _) =
slice::as_chunks(&bytes);
debug_assert!(_empty.is_empty());
let limbs: [limb::Limb; SCALAR_LEN / limb::LIMB_BYTES] =
array::from_fn(|i| limb::Limb::from_le_bytes(limbs_as_bytes[i]));
limb::verify_limbs_less_than_limbs_leak_bit(&limbs, &order)?;
Ok(Self(bytes))
}
// Constructs a `Scalar` from `digest` reduced modulo n.
pub fn from_sha512_digest_reduced(digest: digest::Digest) -> Self {
prefixed_extern! {
fn x25519_sc_reduce(s: &mut UnreducedScalar);
}
let mut unreduced = [0u8; digest::SHA512_OUTPUT_LEN];
unreduced.copy_from_slice(digest.as_ref());
unsafe { x25519_sc_reduce(&mut unreduced) };
Self((&unreduced[..SCALAR_LEN]).try_into().unwrap())
}
}
#[repr(transparent)]
pub struct MaskedScalar([u8; SCALAR_LEN]);
impl MaskedScalar {
pub fn from_bytes_masked(bytes: [u8; SCALAR_LEN]) -> Self {
prefixed_extern! {
fn x25519_sc_mask(a: &mut [u8; SCALAR_LEN]);
}
let mut r = Self(bytes);
unsafe { x25519_sc_mask(&mut r.0) };
r
}
}
impl From<MaskedScalar> for Scalar {
fn from(MaskedScalar(scalar): MaskedScalar) -> Self {
Self(scalar)
}
}
type UnreducedScalar = [u8; UNREDUCED_SCALAR_LEN];
const UNREDUCED_SCALAR_LEN: usize = SCALAR_LEN * 2;

249
vendor/ring/src/ec/curve25519/x25519.rs vendored Normal file
View File

@@ -0,0 +1,249 @@
// Copyright 2015-2016 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//! X25519 Key agreement.
use super::{ops, scalar::SCALAR_LEN};
use crate::{agreement, bb, cpu, ec, error, rand};
use core::ffi::c_int;
static CURVE25519: ec::Curve = ec::Curve {
public_key_len: PUBLIC_KEY_LEN,
elem_scalar_seed_len: ELEM_AND_SCALAR_LEN,
id: ec::CurveID::Curve25519,
check_private_key_bytes: x25519_check_private_key_bytes,
generate_private_key: x25519_generate_private_key,
public_from_private: x25519_public_from_private,
};
/// X25519 (ECDH using Curve25519) as described in [RFC 7748].
///
/// Everything is as described in RFC 7748. Key agreement will fail if the
/// result of the X25519 operation is zero; see the notes on the
/// "all-zero value" in [RFC 7748 section 6.1].
///
/// [RFC 7748]: https://tools.ietf.org/html/rfc7748
/// [RFC 7748 section 6.1]: https://tools.ietf.org/html/rfc7748#section-6.1
pub static X25519: agreement::Algorithm = agreement::Algorithm {
curve: &CURVE25519,
ecdh: x25519_ecdh,
};
#[allow(clippy::unnecessary_wraps)]
fn x25519_check_private_key_bytes(
bytes: &[u8],
_: cpu::Features,
) -> Result<(), error::Unspecified> {
debug_assert_eq!(bytes.len(), PRIVATE_KEY_LEN);
Ok(())
}
fn x25519_generate_private_key(
rng: &dyn rand::SecureRandom,
out: &mut [u8],
_: cpu::Features,
) -> Result<(), error::Unspecified> {
rng.fill(out)
}
fn x25519_public_from_private(
public_out: &mut [u8],
private_key: &ec::Seed,
cpu_features: cpu::Features,
) -> Result<(), error::Unspecified> {
let public_out = public_out.try_into()?;
let private_key: &[u8; SCALAR_LEN] = private_key.bytes_less_safe().try_into()?;
let private_key = ops::MaskedScalar::from_bytes_masked(*private_key);
#[cfg(all(
all(target_arch = "arm", target_endian = "little"),
any(target_os = "android", target_os = "linux")
))]
if let Some(cpu) = <cpu::Features as cpu::GetFeature<_>>::get_feature(&cpu_features) {
static MONTGOMERY_BASE_POINT: [u8; 32] = [
9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0,
];
x25519_neon(public_out, &private_key, &MONTGOMERY_BASE_POINT, cpu);
return Ok(());
}
prefixed_extern! {
fn x25519_public_from_private_generic_masked(
public_key_out: &mut PublicKey,
private_key: &PrivateKey,
use_adx: c_int,
);
}
unsafe {
x25519_public_from_private_generic_masked(
public_out,
&private_key,
ops::has_fe25519_adx(cpu_features).into(),
);
}
Ok(())
}
fn x25519_ecdh(
out: &mut [u8],
my_private_key: &ec::Seed,
peer_public_key: untrusted::Input,
cpu_features: cpu::Features,
) -> Result<(), error::Unspecified> {
let my_private_key: &[u8; SCALAR_LEN] = my_private_key.bytes_less_safe().try_into()?;
let my_private_key = ops::MaskedScalar::from_bytes_masked(*my_private_key);
let peer_public_key: &[u8; PUBLIC_KEY_LEN] = peer_public_key.as_slice_less_safe().try_into()?;
fn scalar_mult(
out: &mut ops::EncodedPoint,
scalar: &ops::MaskedScalar,
point: &ops::EncodedPoint,
#[allow(unused_variables)] cpu_features: cpu::Features,
) {
#[cfg(all(
all(target_arch = "arm", target_endian = "little"),
any(target_os = "android", target_os = "linux")
))]
if let Some(cpu) = <cpu::Features as cpu::GetFeature<_>>::get_feature(&cpu_features) {
return x25519_neon(out, scalar, point, cpu);
}
#[cfg(all(target_arch = "x86_64", not(target_os = "windows")))]
{
if ops::has_fe25519_adx(cpu_features) {
prefixed_extern! {
fn x25519_scalar_mult_adx(
out: &mut ops::EncodedPoint,
scalar: &ops::MaskedScalar,
point: &ops::EncodedPoint,
);
}
return unsafe { x25519_scalar_mult_adx(out, scalar, point) };
}
}
prefixed_extern! {
fn x25519_scalar_mult_generic_masked(
out: &mut ops::EncodedPoint,
scalar: &ops::MaskedScalar,
point: &ops::EncodedPoint,
);
}
unsafe {
x25519_scalar_mult_generic_masked(out, scalar, point);
}
}
scalar_mult(
out.try_into()?,
&my_private_key,
peer_public_key,
cpu_features,
);
let zeros: SharedSecret = [0; SHARED_SECRET_LEN];
if bb::verify_slices_are_equal(out, &zeros).is_ok() {
// All-zero output results when the input is a point of small order.
return Err(error::Unspecified);
}
Ok(())
}
// BoringSSL uses `!defined(OPENSSL_APPLE)`.
#[cfg(all(
all(target_arch = "arm", target_endian = "little"),
any(target_os = "android", target_os = "linux")
))]
fn x25519_neon(
out: &mut ops::EncodedPoint,
scalar: &ops::MaskedScalar,
point: &ops::EncodedPoint,
_cpu: cpu::arm::Neon,
) {
prefixed_extern! {
fn x25519_NEON(
out: &mut ops::EncodedPoint,
scalar: &ops::MaskedScalar,
point: &ops::EncodedPoint,
);
}
unsafe { x25519_NEON(out, scalar, point) }
}
const ELEM_AND_SCALAR_LEN: usize = ops::ELEM_LEN;
type PrivateKey = ops::MaskedScalar;
const PRIVATE_KEY_LEN: usize = ELEM_AND_SCALAR_LEN;
// An X25519 public key as an encoded Curve25519 point.
type PublicKey = [u8; PUBLIC_KEY_LEN];
const PUBLIC_KEY_LEN: usize = ELEM_AND_SCALAR_LEN;
// An X25519 shared secret as an encoded Curve25519 point.
type SharedSecret = [u8; SHARED_SECRET_LEN];
const SHARED_SECRET_LEN: usize = ELEM_AND_SCALAR_LEN;
#[cfg(test)]
mod tests {
use super::*;
use crate::ec;
use untrusted::Input;
#[test]
fn test_x25519_public_from_private() {
struct TestVector {
private: [u8; 32],
public: [u8; 32],
}
static TEST_CASES: &[TestVector] = &[
TestVector {
private: [
0x77, 0x07, 0x6d, 0x0a, 0x73, 0x18, 0xa5, 0x7d, 0x3c, 0x16, 0xc1, 0x72, 0x51,
0xb2, 0x66, 0x45, 0xdf, 0x4c, 0x2f, 0x87, 0xeb, 0xc0, 0x99, 0x2a, 0xb1, 0x77,
0xfb, 0xa5, 0x1d, 0xb9, 0x2c, 0x2a,
],
public: [
0x85, 0x20, 0xf0, 0x09, 0x89, 0x30, 0xa7, 0x54, 0x74, 0x8b, 0x7d, 0xdc, 0xb4,
0x3e, 0xf7, 0x5a, 0x0d, 0xbf, 0x3a, 0x0d, 0x26, 0x38, 0x1a, 0xf4, 0xeb, 0xa4,
0xa9, 0x8e, 0xaa, 0x9b, 0x4e, 0x6a,
],
},
TestVector {
private: [
0x5d, 0xab, 0x08, 0x7e, 0x62, 0x4a, 0x8a, 0x4b, 0x79, 0xe1, 0x7f, 0x8b, 0x83,
0x80, 0x0e, 0xe6, 0x6f, 0x3b, 0xb1, 0x29, 0x26, 0x18, 0xb6, 0xfd, 0x1c, 0x2f,
0x8b, 0x27, 0xff, 0x88, 0xe0, 0xeb,
],
public: [
0xde, 0x9e, 0xdb, 0x7d, 0x7b, 0x7d, 0xc1, 0xb4, 0xd3, 0x5b, 0x61, 0xc2, 0xec,
0xe4, 0x35, 0x37, 0x3f, 0x83, 0x43, 0xc8, 0x5b, 0x78, 0x67, 0x4d, 0xad, 0xfc,
0x7e, 0x14, 0x6f, 0x88, 0x2b, 0x4f,
],
},
];
let cpu_features = cpu::features();
for test_case in TEST_CASES {
let seed =
ec::Seed::from_bytes(&CURVE25519, Input::from(&test_case.private), cpu_features)
.unwrap();
let mut output = [0u8; 32];
x25519_public_from_private(&mut output, &seed, cpu_features).unwrap();
assert_eq!(output, test_case.public);
}
}
}

97
vendor/ring/src/ec/keys.rs vendored Normal file
View File

@@ -0,0 +1,97 @@
use super::{Curve, ELEM_MAX_BYTES, SEED_MAX_BYTES};
use crate::{cpu, error, rand};
pub struct KeyPair {
seed: Seed,
public_key: PublicKey,
}
impl KeyPair {
pub(super) fn derive(
seed: Seed,
cpu_features: cpu::Features,
) -> Result<Self, error::Unspecified> {
let public_key = seed.compute_public_key(cpu_features)?;
Ok(Self { seed, public_key })
}
pub fn public_key(&self) -> &PublicKey {
&self.public_key
}
pub fn split(self) -> (Seed, PublicKey) {
(self.seed, self.public_key)
}
}
pub struct Seed {
bytes: [u8; SEED_MAX_BYTES],
curve: &'static Curve,
}
impl Seed {
pub(crate) fn generate(
curve: &'static Curve,
rng: &dyn rand::SecureRandom,
cpu: cpu::Features,
) -> Result<Self, error::Unspecified> {
let mut r = Self {
bytes: [0u8; SEED_MAX_BYTES],
curve,
};
(curve.generate_private_key)(rng, &mut r.bytes[..curve.elem_scalar_seed_len], cpu)?;
Ok(r)
}
pub(crate) fn from_bytes(
curve: &'static Curve,
bytes: untrusted::Input,
cpu: cpu::Features,
) -> Result<Self, error::Unspecified> {
let bytes = bytes.as_slice_less_safe();
if curve.elem_scalar_seed_len != bytes.len() {
return Err(error::Unspecified);
}
(curve.check_private_key_bytes)(bytes, cpu)?;
let mut r = Self {
bytes: [0; SEED_MAX_BYTES],
curve,
};
r.bytes[..curve.elem_scalar_seed_len].copy_from_slice(bytes);
Ok(r)
}
pub fn bytes_less_safe(&self) -> &[u8] {
&self.bytes[..self.curve.elem_scalar_seed_len]
}
pub(crate) fn compute_public_key(
&self,
cpu_features: cpu::Features,
) -> Result<PublicKey, error::Unspecified> {
let mut public_key = PublicKey {
bytes: [0u8; PUBLIC_KEY_MAX_LEN],
len: self.curve.public_key_len,
};
(self.curve.public_from_private)(
&mut public_key.bytes[..public_key.len],
self,
cpu_features,
)?;
Ok(public_key)
}
}
#[derive(Copy, Clone)]
pub struct PublicKey {
bytes: [u8; PUBLIC_KEY_MAX_LEN],
len: usize,
}
impl AsRef<[u8]> for PublicKey {
fn as_ref(&self) -> &[u8] {
&self.bytes[..self.len]
}
}
/// The maximum length, in bytes, of an encoded public key.
pub const PUBLIC_KEY_MAX_LEN: usize = 1 + (2 * ELEM_MAX_BYTES);

239
vendor/ring/src/ec/suite_b.rs vendored Normal file
View File

@@ -0,0 +1,239 @@
// Copyright 2016 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//! Elliptic curve operations on P-256 & P-384.
use self::ops::*;
use crate::{arithmetic::montgomery::*, cpu, ec, error, io::der, pkcs8};
// NIST SP 800-56A Step 3: "If q is an odd prime p, verify that
// yQ**2 = xQ**3 + axQ + b in GF(p), where the arithmetic is performed modulo
// p."
//
// That is, verify that (x, y) is on the curve, which is true iif:
//
// y**2 == x**3 + a*x + b (mod q)
//
// Or, equivalently, but more efficiently:
//
// y**2 == (x**2 + a)*x + b (mod q)
//
fn verify_affine_point_is_on_the_curve(
q: &Modulus<Q>,
(x, y): (&Elem<R>, &Elem<R>),
) -> Result<(), error::Unspecified> {
verify_affine_point_is_on_the_curve_scaled(q, (x, y), &Elem::from(q.a()), &Elem::from(q.b()))
}
// Use `verify_affine_point_is_on_the_curve` instead of this function whenever
// the affine coordinates are available or will become available. This function
// should only be used then the affine coordinates are never calculated. See
// the notes for `verify_affine_point_is_on_the_curve_scaled`.
//
// The value `z**2` is returned on success because it is useful for ECDSA
// verification.
//
// This function also verifies that the point is not at infinity.
fn verify_jacobian_point_is_on_the_curve(
q: &Modulus<Q>,
p: &Point,
) -> Result<Elem<R>, error::Unspecified> {
let z = q.point_z(p);
// Verify that the point is not at infinity.
q.elem_verify_is_not_zero(&z)?;
let x = q.point_x(p);
let y = q.point_y(p);
// We are given Jacobian coordinates (x, y, z). So, we have:
//
// (x/z**2, y/z**3) == (x', y'),
//
// where (x', y') are the affine coordinates. The curve equation is:
//
// y'**2 == x'**3 + a*x' + b == (x'**2 + a)*x' + b
//
// Substituting our Jacobian coordinates, we get:
//
// / y \**2 / / x \**2 \ / x \
// | ---- | == | | ---- | + a | * | ---- | + b
// \ z**3 / \ \ z**2 / / \ z**2 /
//
// Simplify:
//
// y**2 / x**2 \ x
// ---- == | ---- + a | * ---- + b
// z**6 \ z**4 / z**2
//
// Multiply both sides by z**6:
//
// z**6 / x**2 \ z**6
// ---- * y**2 == | ---- + a | * ---- * x + (z**6) * b
// z**6 \ z**4 / z**2
//
// Simplify:
//
// / x**2 \
// y**2 == | ---- + a | * z**4 * x + (z**6) * b
// \ z**4 /
//
// Distribute z**4:
//
// / z**4 \
// y**2 == | ---- * x**2 + z**4 * a | * x + (z**6) * b
// \ z**4 /
//
// Simplify:
//
// y**2 == (x**2 + z**4 * a) * x + (z**6) * b
//
let z2 = q.elem_squared(&z);
let z4 = q.elem_squared(&z2);
let z4_a = q.elem_product(&z4, &Elem::from(q.a()));
let z6 = q.elem_product(&z4, &z2);
let z6_b = q.elem_product(&z6, &Elem::from(q.b()));
verify_affine_point_is_on_the_curve_scaled(q, (&x, &y), &z4_a, &z6_b)?;
Ok(z2)
}
// Handles the common logic of point-is-on-the-curve checks for both affine and
// Jacobian cases.
//
// When doing the check that the point is on the curve after a computation,
// to avoid fault attacks or mitigate potential bugs, it is better for security
// to use `verify_affine_point_is_on_the_curve` on the affine coordinates,
// because it provides some protection against faults that occur in the
// computation of the inverse of `z`. See the paper and presentation "Fault
// Attacks on Projective-to-Affine Coordinates Conversion" by Diana Maimuţ,
// Cédric Murdica, David Naccache, Mehdi Tibouchi. That presentation concluded
// simply "Check the validity of the result after conversion to affine
// coordinates." (It seems like a good idea to verify that
// z_inv * z == 1 mod q too).
//
// In the case of affine coordinates (x, y), `a_scaled` and `b_scaled` are
// `a` and `b`, respectively. In the case of Jacobian coordinates (x, y, z),
// the computation and comparison is the same, except `a_scaled` and `b_scaled`
// are (z**4 * a) and (z**6 * b), respectively. Thus, performance is another
// reason to prefer doing the check on the affine coordinates, as Jacobian
// computation requires 3 extra multiplications and 2 extra squarings.
//
// An example of a fault attack that isn't mitigated by a point-on-the-curve
// check after multiplication is given in "Sign Change Fault Attacks On
// Elliptic Curve Cryptosystems" by Johannes Blömer, Martin Otto, and
// Jean-Pierre Seifert.
fn verify_affine_point_is_on_the_curve_scaled(
q: &Modulus<Q>,
(x, y): (&Elem<R>, &Elem<R>),
a_scaled: &Elem<R>,
b_scaled: &Elem<R>,
) -> Result<(), error::Unspecified> {
let lhs = q.elem_squared(y);
let mut rhs = q.elem_squared(x);
q.add_assign(&mut rhs, a_scaled);
q.elem_mul(&mut rhs, x);
q.add_assign(&mut rhs, b_scaled);
if !q.elems_are_equal(&lhs, &rhs).leak() {
return Err(error::Unspecified);
}
Ok(())
}
pub(crate) fn key_pair_from_pkcs8(
curve: &'static ec::Curve,
template: &pkcs8::Template,
input: untrusted::Input,
cpu_features: cpu::Features,
) -> Result<ec::KeyPair, error::KeyRejected> {
let (ec_private_key, _) = pkcs8::unwrap_key(template, pkcs8::Version::V1Only, input)?;
let (private_key, public_key) =
ec_private_key.read_all(error::KeyRejected::invalid_encoding(), |input| {
// https://tools.ietf.org/html/rfc5915#section-3
der::nested(
input,
der::Tag::Sequence,
error::KeyRejected::invalid_encoding(),
|input| key_pair_from_pkcs8_(template, input),
)
})?;
key_pair_from_bytes(curve, private_key, public_key, cpu_features)
}
fn key_pair_from_pkcs8_<'a>(
template: &pkcs8::Template,
input: &mut untrusted::Reader<'a>,
) -> Result<(untrusted::Input<'a>, untrusted::Input<'a>), error::KeyRejected> {
let version = der::small_nonnegative_integer(input)
.map_err(|error::Unspecified| error::KeyRejected::invalid_encoding())?;
if version != 1 {
return Err(error::KeyRejected::version_not_supported());
}
let private_key = der::expect_tag_and_get_value(input, der::Tag::OctetString)
.map_err(|error::Unspecified| error::KeyRejected::invalid_encoding())?;
// [0] parameters (optional).
if input.peek(u8::from(der::Tag::ContextSpecificConstructed0)) {
let actual_alg_id =
der::expect_tag_and_get_value(input, der::Tag::ContextSpecificConstructed0)
.map_err(|error::Unspecified| error::KeyRejected::invalid_encoding())?;
if actual_alg_id.as_slice_less_safe() != template.curve_oid().as_slice_less_safe() {
return Err(error::KeyRejected::wrong_algorithm());
}
}
// [1] publicKey. The RFC says it is optional, but we require it
// to be present.
let public_key = der::nested(
input,
der::Tag::ContextSpecificConstructed1,
error::Unspecified,
der::bit_string_with_no_unused_bits,
)
.map_err(|error::Unspecified| error::KeyRejected::invalid_encoding())?;
Ok((private_key, public_key))
}
pub(crate) fn key_pair_from_bytes(
curve: &'static ec::Curve,
private_key_bytes: untrusted::Input,
public_key_bytes: untrusted::Input,
cpu_features: cpu::Features,
) -> Result<ec::KeyPair, error::KeyRejected> {
let seed = ec::Seed::from_bytes(curve, private_key_bytes, cpu_features)
.map_err(|error::Unspecified| error::KeyRejected::invalid_component())?;
let r = ec::KeyPair::derive(seed, cpu_features)
.map_err(|error::Unspecified| error::KeyRejected::unexpected_error())?;
if public_key_bytes.as_slice_less_safe() != r.public_key().as_ref() {
return Err(error::KeyRejected::inconsistent_components());
}
Ok(r)
}
pub mod curve;
pub mod ecdh;
pub mod ecdsa;
mod ops;
mod private_key;
mod public_key;

93
vendor/ring/src/ec/suite_b/curve.rs vendored Normal file
View File

@@ -0,0 +1,93 @@
// Copyright 2015-2017 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use crate::{cpu, ec, error, rand};
/// A key agreement algorithm.
macro_rules! suite_b_curve {
( $NAME:ident, $bits:expr, $private_key_ops:expr, $id:expr,
$check_private_key_bytes:ident, $generate_private_key:ident,
$public_from_private:ident) => {
/// Public keys are encoding in uncompressed form using the
/// Octet-String-to-Elliptic-Curve-Point algorithm in
/// [SEC 1: Elliptic Curve Cryptography, Version 2.0]. Public keys are
/// validated during key agreement according to
/// [NIST Special Publication 800-56A, revision 2] and Appendix B.3 of
/// the NSA's [Suite B Implementer's Guide to NIST SP 800-56A].
///
/// [SEC 1: Elliptic Curve Cryptography, Version 2.0]:
/// http://www.secg.org/sec1-v2.pdf
/// [NIST Special Publication 800-56A, revision 2]:
/// http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-56Ar2.pdf
/// [Suite B Implementer's Guide to NIST SP 800-56A]:
/// https://github.com/briansmith/ring/blob/main/doc/ecdh.pdf
pub static $NAME: ec::Curve = ec::Curve {
public_key_len: 1 + (2 * (($bits + 7) / 8)),
elem_scalar_seed_len: ($bits + 7) / 8,
id: $id,
check_private_key_bytes: $check_private_key_bytes,
generate_private_key: $generate_private_key,
public_from_private: $public_from_private,
};
fn $check_private_key_bytes(
bytes: &[u8],
cpu: cpu::Features,
) -> Result<(), error::Unspecified> {
debug_assert_eq!(bytes.len(), $bits / 8);
ec::suite_b::private_key::check_scalar_big_endian_bytes($private_key_ops, bytes, cpu)
}
fn $generate_private_key(
rng: &dyn rand::SecureRandom,
out: &mut [u8],
cpu: cpu::Features,
) -> Result<(), error::Unspecified> {
ec::suite_b::private_key::generate_private_scalar_bytes($private_key_ops, rng, out, cpu)
}
fn $public_from_private(
public_out: &mut [u8],
private_key: &ec::Seed,
cpu: cpu::Features,
) -> Result<(), error::Unspecified> {
ec::suite_b::private_key::public_from_private(
$private_key_ops,
public_out,
private_key,
cpu,
)
}
};
}
suite_b_curve!(
P256,
256,
&ec::suite_b::ops::p256::PRIVATE_KEY_OPS,
ec::CurveID::P256,
p256_check_private_key_bytes,
p256_generate_private_key,
p256_public_from_private
);
suite_b_curve!(
P384,
384,
&ec::suite_b::ops::p384::PRIVATE_KEY_OPS,
ec::CurveID::P384,
p384_check_private_key_bytes,
p384_generate_private_key,
p384_public_from_private
);

243
vendor/ring/src/ec/suite_b/ecdh.rs vendored Normal file
View File

@@ -0,0 +1,243 @@
// Copyright 2015-2017 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//! ECDH key agreement using the P-256 and P-384 curves.
use super::{ops::*, private_key::*, public_key::*};
use crate::{agreement, cpu, ec, error};
/// A key agreement algorithm.
macro_rules! ecdh {
( $NAME:ident, $curve:expr, $name_str:expr, $private_key_ops:expr,
$public_key_ops:expr, $ecdh:ident ) => {
#[doc = "ECDH using the NSA Suite B"]
#[doc=$name_str]
#[doc = "curve."]
///
/// Public keys are encoding in uncompressed form using the
/// Octet-String-to-Elliptic-Curve-Point algorithm in
/// [SEC 1: Elliptic Curve Cryptography, Version 2.0]. Public keys are
/// validated during key agreement according to
/// [NIST Special Publication 800-56A, revision 2] and Appendix B.3 of
/// the NSA's [Suite B Implementer's Guide to NIST SP 800-56A].
///
/// [SEC 1: Elliptic Curve Cryptography, Version 2.0]:
/// http://www.secg.org/sec1-v2.pdf
/// [NIST Special Publication 800-56A, revision 2]:
/// http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-56Ar2.pdf
/// [Suite B Implementer's Guide to NIST SP 800-56A]:
/// https://github.com/briansmith/ring/blob/main/doc/ecdh.pdf
pub static $NAME: agreement::Algorithm = agreement::Algorithm {
curve: $curve,
ecdh: $ecdh,
};
fn $ecdh(
out: &mut [u8],
my_private_key: &ec::Seed,
peer_public_key: untrusted::Input,
cpu: cpu::Features,
) -> Result<(), error::Unspecified> {
ecdh(
$private_key_ops,
$public_key_ops,
out,
my_private_key,
peer_public_key,
cpu,
)
}
};
}
ecdh!(
ECDH_P256,
&ec::suite_b::curve::P256,
"P-256 (secp256r1)",
&p256::PRIVATE_KEY_OPS,
&p256::PUBLIC_KEY_OPS,
p256_ecdh
);
ecdh!(
ECDH_P384,
&ec::suite_b::curve::P384,
"P-384 (secp384r1)",
&p384::PRIVATE_KEY_OPS,
&p384::PUBLIC_KEY_OPS,
p384_ecdh
);
fn ecdh(
private_key_ops: &PrivateKeyOps,
public_key_ops: &PublicKeyOps,
out: &mut [u8],
my_private_key: &ec::Seed,
peer_public_key: untrusted::Input,
cpu: cpu::Features,
) -> Result<(), error::Unspecified> {
// The NIST SP 800-56Ar2 steps are from section 5.7.1.2 Elliptic Curve
// Cryptography Cofactor Diffie-Hellman (ECC CDH) Primitive.
//
// The "NSA Guide" steps are from section 3.1 of the NSA guide, "Ephemeral
// Unified Model."
let q = &public_key_ops.common.elem_modulus(cpu);
// NSA Guide Step 1 is handled separately.
// NIST SP 800-56Ar2 5.6.2.2.2.
// NSA Guide Step 2.
//
// `parse_uncompressed_point` verifies that the point is not at infinity
// and that it is on the curve, using the Partial Public-Key Validation
// Routine.
let peer_public_key = parse_uncompressed_point(public_key_ops, q, peer_public_key)?;
// NIST SP 800-56Ar2 Step 1.
// NSA Guide Step 3 (except point at infinity check).
//
// Note that the cofactor (h) is one since we only support prime-order
// curves, so we can safely ignore the cofactor.
//
// It is impossible for the result to be the point at infinity because our
// private key is in the range [1, n) and the curve has prime order and
// `parse_uncompressed_point` verified that the peer public key is on the
// curve and not at infinity. However, since the standards require the
// check, we do it using `assert!`.
//
// NIST SP 800-56Ar2 defines "Destroy" thusly: "In this Recommendation, to
// destroy is an action applied to a key or a piece of secret data. After
// a key or a piece of secret data is destroyed, no information about its
// value can be recovered." We interpret "destroy" somewhat liberally: we
// assume that since we throw away the values to be destroyed, no
// information about their values can be recovered. This doesn't meet the
// NSA guide's explicit requirement to "zeroize" them though.
// TODO: this only needs common scalar ops
let n = &private_key_ops.common.scalar_modulus(cpu);
let my_private_key = private_key_as_scalar(n, my_private_key);
let product = private_key_ops.point_mul(&my_private_key, &peer_public_key, cpu);
// NIST SP 800-56Ar2 Steps 2, 3, 4, and 5.
// NSA Guide Steps 3 (point at infinity check) and 4.
//
// Again, we have a pretty liberal interpretation of the NIST's spec's
// "Destroy" that doesn't meet the NSA requirement to "zeroize."
// `big_endian_affine_from_jacobian` verifies that the result is not at
// infinity and also does an extra check to verify that the point is on
// the curve.
big_endian_affine_from_jacobian(private_key_ops, q, out, None, &product)
// NSA Guide Step 5 & 6 are deferred to the caller. Again, we have a
// pretty liberal interpretation of the NIST's spec's "Destroy" that
// doesn't meet the NSA requirement to "zeroize."
}
#[cfg(test)]
mod tests {
use super::super::ops;
use crate::testutil as test;
use crate::{agreement, ec, limb};
static SUPPORTED_SUITE_B_ALGS: [(&str, &agreement::Algorithm, &ec::Curve, &ops::CommonOps); 2] = [
(
"P-256",
&agreement::ECDH_P256,
&super::super::curve::P256,
&ops::p256::COMMON_OPS,
),
(
"P-384",
&agreement::ECDH_P384,
&super::super::curve::P384,
&ops::p384::COMMON_OPS,
),
];
#[test]
fn test_agreement_suite_b_ecdh_generate() {
// Generates a string of bytes 0x00...00, which will always result in
// a scalar value of zero.
let random_00 = test::rand::FixedByteRandom { byte: 0x00 };
// Generates a string of bytes 0xFF...FF, which will be larger than the
// group order of any curve that is supported.
let random_ff = test::rand::FixedByteRandom { byte: 0xff };
for &(_, alg, curve, ops) in SUPPORTED_SUITE_B_ALGS.iter() {
// Test that the private key value zero is rejected and that
// `generate` gives up after a while of only getting zeros.
assert!(agreement::EphemeralPrivateKey::generate(alg, &random_00).is_err());
// Test that the private key value larger than the group order is
// rejected and that `generate` gives up after a while of only
// getting values larger than the group order.
assert!(agreement::EphemeralPrivateKey::generate(alg, &random_ff).is_err());
// Test that a private key value exactly equal to the group order
// is rejected and that `generate` gives up after a while of only
// getting that value from the PRNG.
let mut n_bytes = [0u8; ec::SCALAR_MAX_BYTES];
let num_bytes = curve.elem_scalar_seed_len;
limb::big_endian_from_limbs(ops.n_limbs(), &mut n_bytes[..num_bytes]);
{
let n_bytes = &mut n_bytes[..num_bytes];
let rng = test::rand::FixedSliceRandom { bytes: n_bytes };
assert!(agreement::EphemeralPrivateKey::generate(alg, &rng).is_err());
}
// Test that a private key value exactly equal to the group order
// minus 1 is accepted.
let mut n_minus_1_bytes = n_bytes;
{
let n_minus_1_bytes = &mut n_minus_1_bytes[..num_bytes];
n_minus_1_bytes[num_bytes - 1] -= 1;
let rng = test::rand::FixedSliceRandom {
bytes: n_minus_1_bytes,
};
let key = agreement::EphemeralPrivateKey::generate(alg, &rng).unwrap();
assert_eq!(n_minus_1_bytes, key.bytes_for_test());
}
// Test that n + 1 also fails.
let mut n_plus_1_bytes = n_bytes;
{
let n_plus_1_bytes = &mut n_plus_1_bytes[..num_bytes];
n_plus_1_bytes[num_bytes - 1] += 1;
let rng = test::rand::FixedSliceRandom {
bytes: n_plus_1_bytes,
};
assert!(agreement::EphemeralPrivateKey::generate(alg, &rng).is_err());
}
// Test recovery from initial RNG failure. The first value will be
// n, then n + 1, then zero, the next value will be n - 1, which
// will be accepted.
{
let bytes = [
&n_bytes[..num_bytes],
&n_plus_1_bytes[..num_bytes],
&[0u8; ec::SCALAR_MAX_BYTES][..num_bytes],
&n_minus_1_bytes[..num_bytes],
];
let rng = test::rand::FixedSliceSequenceRandom {
bytes: &bytes,
current: core::cell::UnsafeCell::new(0),
};
let key = agreement::EphemeralPrivateKey::generate(alg, &rng).unwrap();
assert_eq!(&n_minus_1_bytes[..num_bytes], key.bytes_for_test());
}
}
}
}

3
vendor/ring/src/ec/suite_b/ecdsa.rs vendored Normal file
View File

@@ -0,0 +1,3 @@
mod digest_scalar;
pub mod signing;
pub mod verification;

View File

@@ -0,0 +1,119 @@
// Copyright 2015-2016 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//! ECDSA Signatures using the P-256 and P-384 curves.
use crate::{digest, ec::suite_b::ops::*};
/// Calculate the digest of `msg` using the digest algorithm `digest_alg`. Then
/// convert the digest to a scalar in the range [0, n) as described in
/// NIST's FIPS 186-4 Section 4.2. Note that this is one of the few cases where
/// a `Scalar` is allowed to have the value zero.
///
/// NIST's FIPS 186-4 4.2 says "When the length of the output of the hash
/// function is greater than N (i.e., the bit length of q), then the leftmost N
/// bits of the hash function output block shall be used in any calculation
/// using the hash function output during the generation or verification of a
/// digital signature."
///
/// "Leftmost N bits" means "N most significant bits" because we interpret the
/// digest as a bit-endian encoded integer.
///
/// The NSA guide instead vaguely suggests that we should convert the digest
/// value to an integer and then reduce it mod `n`. However, real-world
/// implementations (e.g. `digest_to_bn` in OpenSSL and `hashToInt` in Go) do
/// what FIPS 186-4 says to do, not what the NSA guide suggests.
///
/// Why shifting the value right by at most one bit is sufficient: P-256's `n`
/// has its 256th bit set; i.e. 2**255 < n < 2**256. Once we've truncated the
/// digest to 256 bits and converted it to an integer, it will have a value
/// less than 2**256. If the value is larger than `n` then shifting it one bit
/// right will give a value less than 2**255, which is less than `n`. The
/// analogous argument applies for P-384. However, it does *not* apply in
/// general; for example, it doesn't apply to P-521.
pub(super) fn digest_scalar(n: &Modulus<N>, msg: digest::Digest) -> Scalar {
digest_scalar_(n, msg.as_ref())
}
#[cfg(test)]
pub(super) fn digest_bytes_scalar(n: &Modulus<N>, digest: &[u8]) -> Scalar {
digest_scalar_(n, digest)
}
// This is a separate function solely so that we can test specific digest
// values like all-zero values and values larger than `n`.
fn digest_scalar_(n: &Modulus<N>, digest: &[u8]) -> Scalar {
let len = n.bytes_len();
let digest = if digest.len() > len {
&digest[..len]
} else {
digest
};
scalar_parse_big_endian_partially_reduced_variable_consttime(n, untrusted::Input::from(digest))
.unwrap()
}
#[cfg(test)]
mod tests {
use super::digest_bytes_scalar;
use crate::testutil as test;
use crate::{cpu, digest, ec::suite_b::ops::*, limb};
#[test]
fn test() {
let cpu = cpu::features();
test::run(
test_vector_file!("ecdsa_digest_scalar_tests.txt"),
|section, test_case| {
assert_eq!(section, "");
let curve_name = test_case.consume_string("Curve");
let digest_name = test_case.consume_string("Digest");
let input = test_case.consume_bytes("Input");
let output = test_case.consume_bytes("Output");
let (ops, digest_alg) = match (curve_name.as_str(), digest_name.as_str()) {
("P-256", "SHA256") => (&p256::PUBLIC_SCALAR_OPS, &digest::SHA256),
("P-256", "SHA384") => (&p256::PUBLIC_SCALAR_OPS, &digest::SHA384),
("P-384", "SHA256") => (&p384::PUBLIC_SCALAR_OPS, &digest::SHA256),
("P-384", "SHA384") => (&p384::PUBLIC_SCALAR_OPS, &digest::SHA384),
_ => {
panic!("Unsupported curve+digest: {}+{}", curve_name, digest_name);
}
};
let n = &ops.scalar_ops.scalar_modulus(cpu);
assert_eq!(input.len(), digest_alg.output_len());
assert_eq!(output.len(), ops.scalar_ops.scalar_bytes_len());
assert_eq!(output.len(), n.bytes_len());
let expected = scalar_parse_big_endian_variable(
n,
limb::AllowZero::Yes,
untrusted::Input::from(&output),
)
.unwrap();
let actual = digest_bytes_scalar(n, &input);
assert_eq!(
ops.scalar_ops.leak_limbs(&actual),
ops.scalar_ops.leak_limbs(&expected)
);
Ok(())
},
);
}
}

Some files were not shown because too many files have changed in this diff Show More