Cryptographic Secret type (#615)
* Adds a type for cryptographic secrets * default implementations and zeroize documentation * removes whitespace
This commit is contained in:
@@ -20,6 +20,7 @@ serde = { version = "1.0", optional = true, features = ["derive"] }
|
||||
serde_json = { version = "=1.0.69", optional = true }
|
||||
regex = { version = "1", optional = true }
|
||||
rand_core = "0.6.4"
|
||||
zeroize = { version = "1.5.7", features = ["derive"] }
|
||||
|
||||
[features]
|
||||
std = ["hex", "ring", "untrusted", "serde", "serde_json", "regex", "rand_core/getrandom"]
|
||||
|
||||
@@ -12,18 +12,29 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! A portable and naive textbook implementation of AES-256
|
||||
|
||||
use super::util::{xor_block_16, Block16};
|
||||
use arrayref::{array_mut_ref, array_ref};
|
||||
use zeroize::Zeroize;
|
||||
|
||||
/** A portable and naive textbook implementation of AES-256 **/
|
||||
type Word = [u8; 4];
|
||||
|
||||
/** This structure caches the round keys, to avoid re-computing the key schedule for each block. **/
|
||||
/// Encryption key for AES256.
|
||||
///
|
||||
/// Never call zeroize explicitly, to not invalidate any invariants.
|
||||
#[derive(Zeroize)]
|
||||
pub struct EncryptionKey {
|
||||
// This structure caches the round keys, to avoid re-computing the key schedule for each block.
|
||||
enc_round_keys: [Block16; 15],
|
||||
}
|
||||
|
||||
/// Decryption key for AES256.
|
||||
///
|
||||
/// Never call zeroize explicitly, to not invalidate any invariants.
|
||||
#[derive(Zeroize)]
|
||||
pub struct DecryptionKey {
|
||||
// This structure caches the round keys, to avoid re-computing the key schedule for each block.
|
||||
dec_round_keys: [Block16; 15],
|
||||
}
|
||||
|
||||
|
||||
@@ -16,9 +16,12 @@ use super::int256::{Digit, Int256};
|
||||
use core::ops::Mul;
|
||||
use rand_core::RngCore;
|
||||
use subtle::{self, Choice, ConditionallySelectable, CtOption};
|
||||
use zeroize::Zeroize;
|
||||
|
||||
// An exponent on the elliptic curve, that is an element modulo the curve order N.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
/// An exponent on the elliptic curve, that is an element modulo the curve order N.
|
||||
///
|
||||
/// Never call zeroize explicitly, to not invalidate any invariants.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Zeroize)]
|
||||
// TODO: remove this Default once https://github.com/dalek-cryptography/subtle/issues/63 is
|
||||
// resolved.
|
||||
#[derive(Default)]
|
||||
@@ -90,8 +93,10 @@ impl Mul for &ExponentP256 {
|
||||
}
|
||||
}
|
||||
|
||||
// A non-zero exponent on the elliptic curve.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
/// A non-zero exponent on the elliptic curve.
|
||||
///
|
||||
/// Never call zeroize explicitly, to not invalidate any invariants.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Zeroize)]
|
||||
// TODO: remove this Default once https://github.com/dalek-cryptography/subtle/issues/63 is
|
||||
// resolved.
|
||||
#[derive(Default)]
|
||||
|
||||
@@ -15,12 +15,16 @@
|
||||
use super::int256::{Digit, Int256};
|
||||
use core::ops::Mul;
|
||||
use subtle::Choice;
|
||||
use zeroize::Zeroize;
|
||||
|
||||
// A field element on the elliptic curve, that is an element modulo the prime P.
|
||||
// This is the format used to serialize coordinates of points on the curve.
|
||||
// This implements enough methods to validate points and to convert them to/from the Montgomery
|
||||
// form, which is more convenient to operate on.
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
/// A field element on the elliptic curve, that is an element modulo the prime P.
|
||||
///
|
||||
/// This is the format used to serialize coordinates of points on the curve.
|
||||
/// This implements enough methods to validate points and to convert them to/from the Montgomery
|
||||
/// form, which is more convenient to operate on.
|
||||
///
|
||||
/// Never call zeroize explicitly, to not invalidate any invariants.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Zeroize)]
|
||||
pub struct GFP256 {
|
||||
int: Int256,
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ use byteorder::{BigEndian, ByteOrder};
|
||||
use core::ops::{Add, AddAssign, Sub, SubAssign};
|
||||
use rand_core::RngCore;
|
||||
use subtle::{self, Choice, ConditionallySelectable, ConstantTimeEq};
|
||||
use zeroize::Zeroize;
|
||||
|
||||
const BITS_PER_DIGIT: usize = 32;
|
||||
const BYTES_PER_DIGIT: usize = BITS_PER_DIGIT >> 3;
|
||||
@@ -29,7 +30,10 @@ pub type Digit = u32;
|
||||
type DoubleDigit = u64;
|
||||
type SignedDoubleDigit = i64;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
/// Big integer implementation with 256 bits.
|
||||
///
|
||||
/// Never call zeroize explicitly, to not invalidate any invariants.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Zeroize)]
|
||||
// TODO: remove this Default once https://github.com/dalek-cryptography/subtle/issues/63 is
|
||||
// resolved.
|
||||
#[derive(Default)]
|
||||
|
||||
@@ -17,13 +17,16 @@ use super::int256::Int256;
|
||||
use super::precomputed;
|
||||
use core::ops::{Add, Mul, Sub};
|
||||
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
|
||||
use zeroize::Zeroize;
|
||||
|
||||
pub const NLIMBS: usize = 9;
|
||||
pub const BOTTOM_28_BITS: u32 = 0x0fff_ffff;
|
||||
pub const BOTTOM_29_BITS: u32 = 0x1fff_ffff;
|
||||
|
||||
/** Field element on the secp256r1 curve, represented in Montgomery form **/
|
||||
#[derive(Clone, Copy)]
|
||||
/// Field element on the secp256r1 curve, represented in Montgomery form.
|
||||
///
|
||||
/// Never call zeroize explicitly, to not invalidate any invariants.
|
||||
#[derive(Clone, Copy, Zeroize)]
|
||||
pub struct Montgomery {
|
||||
// The 9 limbs use 28 or 29 bits, alternatively: even limbs use 29 bits, odd limbs use 28 bits.
|
||||
// The Montgomery form stores a field element x as (x * 2^257) mod P.
|
||||
|
||||
@@ -21,11 +21,15 @@ use arrayref::array_mut_ref;
|
||||
use arrayref::array_ref;
|
||||
use core::ops::Add;
|
||||
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
|
||||
use zeroize::Zeroize;
|
||||
|
||||
// A point on the elliptic curve is represented by two field elements.
|
||||
// The "direct" representation with GFP256 (integer modulo p) is used for serialization of public
|
||||
// keys.
|
||||
#[derive(Clone, Copy)]
|
||||
/// A point on the elliptic curve, represented by two field elements.
|
||||
///
|
||||
/// The "direct" representation with GFP256 (integer modulo p) is used for serialization of public
|
||||
/// keys.
|
||||
///
|
||||
/// Never call zeroize explicitly, to not invalidate any invariants.
|
||||
#[derive(Clone, Copy, Zeroize)]
|
||||
pub struct PointP256 {
|
||||
x: GFP256,
|
||||
y: GFP256,
|
||||
@@ -128,12 +132,15 @@ impl PointP256 {
|
||||
}
|
||||
}
|
||||
|
||||
// A point on the elliptic curve in projective form.
|
||||
// This uses Montgomery representation for field elements.
|
||||
// This is in projective coordinates, i.e. it represents the point { x: x / z, y: y / z }.
|
||||
// This representation is more convenient to implement complete formulas for elliptic curve
|
||||
// arithmetic.
|
||||
#[derive(Clone, Copy)]
|
||||
/// A point on the elliptic curve in projective form.
|
||||
///
|
||||
/// This uses Montgomery representation for field elements.
|
||||
/// This is in projective coordinates, i.e. it represents the point { x: x / z, y: y / z }.
|
||||
/// This representation is more convenient to implement complete formulas for elliptic curve
|
||||
/// arithmetic.
|
||||
///
|
||||
/// Never call zeroize explicitly, to not invalidate any invariants.
|
||||
#[derive(Clone, Copy, Zeroize)]
|
||||
pub struct PointProjective {
|
||||
x: Montgomery,
|
||||
y: Montgomery,
|
||||
@@ -150,8 +157,10 @@ impl ConditionallySelectable for PointProjective {
|
||||
}
|
||||
}
|
||||
|
||||
// Equivalent to PointProjective { x, y, z: 1 }
|
||||
#[derive(Clone, Copy)]
|
||||
/// Equivalent to PointProjective { x, y, z: 1 }
|
||||
///
|
||||
/// Never call zeroize explicitly, to not invalidate any invariants.
|
||||
#[derive(Clone, Copy, Zeroize)]
|
||||
pub struct PointAffine {
|
||||
x: Montgomery,
|
||||
y: Montgomery,
|
||||
|
||||
@@ -17,14 +17,22 @@ use super::ec::int256;
|
||||
use super::ec::int256::Int256;
|
||||
use super::ec::point::PointP256;
|
||||
use rand_core::RngCore;
|
||||
use zeroize::Zeroize;
|
||||
|
||||
pub const NBYTES: usize = int256::NBYTES;
|
||||
|
||||
/// A private key for ECDH.
|
||||
///
|
||||
/// Never call zeroize explicitly, to not invalidate any invariants.
|
||||
#[derive(Zeroize)]
|
||||
pub struct SecKey {
|
||||
a: NonZeroExponentP256,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
/// A public key for ECDH.
|
||||
///
|
||||
/// Never call zeroize explicitly, to not invalidate any invariants.
|
||||
#[derive(Clone, Debug, PartialEq, Zeroize)]
|
||||
pub struct PubKey {
|
||||
p: PointP256,
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ use super::ec::exponent256::{ExponentP256, NonZeroExponentP256};
|
||||
use super::ec::int256;
|
||||
use super::ec::int256::Int256;
|
||||
use super::ec::point::PointP256;
|
||||
use super::hmac::hmac_256;
|
||||
use super::Hash256;
|
||||
use alloc::vec;
|
||||
use alloc::vec::Vec;
|
||||
@@ -25,20 +24,31 @@ use arrayref::array_mut_ref;
|
||||
use arrayref::{array_ref, mut_array_refs};
|
||||
use core::marker::PhantomData;
|
||||
use rand_core::RngCore;
|
||||
use zeroize::Zeroize;
|
||||
|
||||
pub const NBYTES: usize = int256::NBYTES;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
/// A private key for ECDSA.
|
||||
///
|
||||
/// Never call zeroize explicitly, to not invalidate any invariants.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Zeroize)]
|
||||
pub struct SecKey {
|
||||
k: NonZeroExponentP256,
|
||||
}
|
||||
|
||||
/// An ECDSA signature.
|
||||
///
|
||||
/// Never call zeroize explicitly, to not invalidate any invariants.
|
||||
#[derive(Zeroize)]
|
||||
pub struct Signature {
|
||||
r: NonZeroExponentP256,
|
||||
s: NonZeroExponentP256,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
/// A public key for ECDSA.
|
||||
///
|
||||
/// Never call zeroize explicitly, to not invalidate any invariants.
|
||||
#[derive(Clone, Zeroize)]
|
||||
pub struct PubKey {
|
||||
p: PointP256,
|
||||
}
|
||||
@@ -310,15 +320,15 @@ where
|
||||
Int256::to_bin(&sk.k.to_int(), contents_k);
|
||||
Int256::to_bin(&Int256::from_bin(&h1).modd(&Int256::N), contents_h1);
|
||||
|
||||
let k = hmac_256::<H>(&k, &contents);
|
||||
let v = hmac_256::<H>(&k, &v);
|
||||
let k = H::hmac(&k, &contents);
|
||||
let v = H::hmac(&k, &v);
|
||||
|
||||
let (contents_v, marker, _) = mut_array_refs![&mut contents, 32, 1, 64];
|
||||
contents_v.copy_from_slice(&v);
|
||||
marker[0] = 0x01;
|
||||
|
||||
let k = hmac_256::<H>(&k, &contents);
|
||||
let v = hmac_256::<H>(&k, &v);
|
||||
let k = H::hmac(&k, &contents);
|
||||
let v = H::hmac(&k, &v);
|
||||
|
||||
Rfc6979 {
|
||||
k,
|
||||
@@ -330,14 +340,14 @@ where
|
||||
fn next(&mut self) -> Int256 {
|
||||
// Note: at this step, the logic from RFC 6979 is simplified, because the HMAC produces 256
|
||||
// bits and we need 256 bits.
|
||||
let t = hmac_256::<H>(&self.k, &self.v);
|
||||
let t = H::hmac(&self.k, &self.v);
|
||||
let result = Int256::from_bin(&t);
|
||||
|
||||
let mut v1 = [0; 33];
|
||||
v1[..32].copy_from_slice(&self.v);
|
||||
v1[32] = 0x00;
|
||||
self.k = hmac_256::<H>(&self.k, &v1);
|
||||
self.v = hmac_256::<H>(&self.k, &self.v);
|
||||
self.k = H::hmac(&self.k, &v1);
|
||||
self.v = H::hmac(&self.k, &self.v);
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
@@ -27,15 +27,15 @@ const HASH_SIZE: usize = 32;
|
||||
///
|
||||
/// This implementation is equivalent to a standard HKD, with `salt` fixed at a length of
|
||||
/// 32 byte and the output length l as 32.
|
||||
pub fn hkdf_256<H>(ikm: &[u8], salt: &[u8; HASH_SIZE], info: &[u8]) -> [u8; HASH_SIZE]
|
||||
pub fn hkdf_256<H>(ikm: &[u8], salt: &[u8; HASH_SIZE], info: &[u8], okm: &mut [u8; HASH_SIZE])
|
||||
where
|
||||
H: Hash256,
|
||||
{
|
||||
let prk = hmac_256::<H>(salt, ikm);
|
||||
let prk = H::hmac(salt, ikm);
|
||||
// l is implicitly the block size, so we iterate exactly once.
|
||||
let mut t = info.to_vec();
|
||||
t.push(1);
|
||||
hmac_256::<H>(&prk, t.as_slice())
|
||||
hmac_256::<H>(&prk, t.as_slice(), okm);
|
||||
}
|
||||
|
||||
/// Computes the HKDF with empty salt and 256 bit (one block) output.
|
||||
@@ -47,12 +47,12 @@ where
|
||||
///
|
||||
/// This implementation is equivalent to the below hkdf, with `salt` set to the
|
||||
/// default block of zeros and the output length l as 32.
|
||||
pub fn hkdf_empty_salt_256<H>(ikm: &[u8], info: &[u8]) -> [u8; HASH_SIZE]
|
||||
pub fn hkdf_empty_salt_256<H>(ikm: &[u8], info: &[u8], okm: &mut [u8; HASH_SIZE])
|
||||
where
|
||||
H: Hash256,
|
||||
{
|
||||
// Salt is a zero block here.
|
||||
hkdf_256::<H>(ikm, &[0; HASH_SIZE], info)
|
||||
hkdf_256::<H>(ikm, &[0; HASH_SIZE], info, okm);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -81,10 +81,9 @@ mod test {
|
||||
// Byte i.
|
||||
let info = [i as u8];
|
||||
let okm = hex::decode(okm).unwrap();
|
||||
assert_eq!(
|
||||
&hkdf_empty_salt_256::<Sha256>(&ikm.as_bytes(), &info[..]),
|
||||
array_ref!(okm, 0, 32)
|
||||
);
|
||||
let mut output = [0; HASH_SIZE];
|
||||
hkdf_empty_salt_256::<Sha256>(&ikm.as_bytes(), &info[..], &mut output);
|
||||
assert_eq!(&output, array_ref!(okm, 0, HASH_SIZE));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,10 +108,9 @@ mod test {
|
||||
// Byte i.
|
||||
let info = [i as u8];
|
||||
let okm = hex::decode(okm).unwrap();
|
||||
assert_eq!(
|
||||
&hkdf_256::<Sha256>(&ikm.as_bytes(), &salt, &info[..]),
|
||||
array_ref!(okm, 0, 32)
|
||||
);
|
||||
let mut output = [0; HASH_SIZE];
|
||||
hkdf_256::<Sha256>(&ikm.as_bytes(), &salt, &info[..], &mut output);
|
||||
assert_eq!(&output, array_ref!(okm, 0, HASH_SIZE));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,8 @@ pub fn verify_hmac_256<H>(key: &[u8; KEY_SIZE], contents: &[u8], mac: &[u8; HASH
|
||||
where
|
||||
H: Hash256,
|
||||
{
|
||||
let expected_mac = hmac_256::<H>(key, contents);
|
||||
let mut expected_mac = [0; HASH_SIZE];
|
||||
hmac_256::<H>(key, contents, &mut expected_mac);
|
||||
bool::from(expected_mac.ct_eq(mac))
|
||||
}
|
||||
|
||||
@@ -38,19 +39,23 @@ pub fn verify_hmac_256_first_128bits<H>(
|
||||
where
|
||||
H: Hash256,
|
||||
{
|
||||
let expected_mac = hmac_256::<H>(key, contents);
|
||||
let mut expected_mac = [0; HASH_SIZE];
|
||||
hmac_256::<H>(key, contents, &mut expected_mac);
|
||||
bool::from(array_ref![expected_mac, 0, 16].ct_eq(pin))
|
||||
}
|
||||
|
||||
pub fn hmac_256<H>(key: &[u8; KEY_SIZE], contents: &[u8]) -> [u8; HASH_SIZE]
|
||||
pub fn hmac_256<H>(key: &[u8; KEY_SIZE], contents: &[u8], output: &mut [u8; HASH_SIZE])
|
||||
where
|
||||
H: Hash256,
|
||||
{
|
||||
H::hmac(key, contents)
|
||||
H::hmac_mut(key, contents, output)
|
||||
}
|
||||
|
||||
pub(crate) fn software_hmac_256<H>(key: &[u8; KEY_SIZE], contents: &[u8]) -> [u8; HASH_SIZE]
|
||||
where
|
||||
pub(crate) fn software_hmac_256<H>(
|
||||
key: &[u8; KEY_SIZE],
|
||||
contents: &[u8],
|
||||
output: &mut [u8; HASH_SIZE],
|
||||
) where
|
||||
H: Hash256,
|
||||
{
|
||||
let mut ipad: [u8; BLOCK_SIZE] = [0x36; BLOCK_SIZE];
|
||||
@@ -64,13 +69,13 @@ where
|
||||
let mut ihasher = H::new();
|
||||
ihasher.update(&ipad);
|
||||
ihasher.update(contents);
|
||||
let ihash = ihasher.finalize();
|
||||
let mut ihash = [0; HASH_SIZE];
|
||||
ihasher.finalize(&mut ihash);
|
||||
|
||||
let mut ohasher = H::new();
|
||||
ohasher.update(&opad);
|
||||
ohasher.update(&ihash);
|
||||
|
||||
ohasher.finalize()
|
||||
ohasher.finalize(output);
|
||||
}
|
||||
|
||||
fn xor_pads(ipad: &mut [u8; BLOCK_SIZE], opad: &mut [u8; BLOCK_SIZE], key: &[u8; KEY_SIZE]) {
|
||||
@@ -91,7 +96,8 @@ mod test {
|
||||
for len in 0..128 {
|
||||
let key = [0; KEY_SIZE];
|
||||
let contents = vec![0; len];
|
||||
let mac = hmac_256::<Sha256>(&key, &contents);
|
||||
let mut mac = [0; HASH_SIZE];
|
||||
hmac_256::<Sha256>(&key, &contents, &mut mac);
|
||||
assert!(verify_hmac_256::<Sha256>(&key, &contents, &mac));
|
||||
}
|
||||
}
|
||||
@@ -102,7 +108,8 @@ mod test {
|
||||
for len in 0..128 {
|
||||
let key = [0; KEY_SIZE];
|
||||
let contents = vec![0; len];
|
||||
let mac = hmac_256::<Sha256>(&key, &contents);
|
||||
let mut mac = [0; HASH_SIZE];
|
||||
hmac_256::<Sha256>(&key, &contents, &mut mac);
|
||||
|
||||
// Check that invalid MACs don't verify, by changing any byte of the valid MAC.
|
||||
for i in 0..HASH_SIZE {
|
||||
@@ -116,14 +123,21 @@ mod test {
|
||||
#[test]
|
||||
fn test_hmac_sha256_examples() {
|
||||
let key = [0; KEY_SIZE];
|
||||
let mut mac = [0; HASH_SIZE];
|
||||
hmac_256::<Sha256>(&key, &[], &mut mac);
|
||||
assert_eq!(
|
||||
hmac_256::<Sha256>(&key, &[]),
|
||||
mac,
|
||||
hex::decode("b613679a0814d9ec772f95d778c35fc5ff1697c493715653c6c712144292c5ad")
|
||||
.unwrap()
|
||||
.as_slice()
|
||||
);
|
||||
hmac_256::<Sha256>(
|
||||
&key,
|
||||
b"The quick brown fox jumps over the lazy dog",
|
||||
&mut mac,
|
||||
);
|
||||
assert_eq!(
|
||||
hmac_256::<Sha256>(&key, b"The quick brown fox jumps over the lazy dog"),
|
||||
mac,
|
||||
hex::decode("fb011e6154a19b9a4c767373c305275a5a69e8b68b0b4c9200c383dced19a416")
|
||||
.unwrap()
|
||||
.as_slice()
|
||||
@@ -274,11 +288,10 @@ mod test {
|
||||
|
||||
let mut input = Vec::new();
|
||||
let key = [b'A'; KEY_SIZE];
|
||||
let mut mac = [0; HASH_SIZE];
|
||||
for i in 0..128 {
|
||||
assert_eq!(
|
||||
hmac_256::<Sha256>(&key, &input),
|
||||
hex::decode(hashes[i] as &[u8]).unwrap().as_slice()
|
||||
);
|
||||
hmac_256::<Sha256>(&key, &input, &mut mac);
|
||||
assert_eq!(mac, hex::decode(hashes[i] as &[u8]).unwrap().as_slice());
|
||||
input.push(b'A');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,26 +27,39 @@ pub mod hmac;
|
||||
pub mod sha256;
|
||||
pub mod util;
|
||||
|
||||
// Trait for hash functions that returns a 256-bit hash.
|
||||
// The type must be Sized (size known at compile time) so that we can instanciate one on the stack
|
||||
// in the hash() method.
|
||||
/// Trait for hash functions that returns a 256-bit hash.
|
||||
///
|
||||
/// When you implement this trait, make sure to implement `hash_mut` and `hmac_mut` first, because
|
||||
/// the default implementations of `hash` and `hmac` rely on it.
|
||||
pub trait Hash256: Sized {
|
||||
fn new() -> Self;
|
||||
fn update(&mut self, contents: &[u8]);
|
||||
fn finalize(self) -> [u8; 32];
|
||||
fn finalize(self, output: &mut [u8; 32]);
|
||||
|
||||
fn hash(contents: &[u8]) -> [u8; 32] {
|
||||
let mut output = [0; 32];
|
||||
Self::hash_mut(contents, &mut output);
|
||||
output
|
||||
}
|
||||
|
||||
fn hash_mut(contents: &[u8], output: &mut [u8; 32]) {
|
||||
let mut h = Self::new();
|
||||
h.update(contents);
|
||||
h.finalize()
|
||||
h.finalize(output)
|
||||
}
|
||||
|
||||
fn hmac(key: &[u8; 32], contents: &[u8]) -> [u8; 32] {
|
||||
hmac::software_hmac_256::<Self>(key, contents)
|
||||
let mut output = [0; 32];
|
||||
Self::hmac_mut(key, contents, &mut output);
|
||||
output
|
||||
}
|
||||
|
||||
fn hmac_mut(key: &[u8; 32], contents: &[u8], output: &mut [u8; 32]) {
|
||||
hmac::software_hmac_256::<Self>(key, contents, output);
|
||||
}
|
||||
}
|
||||
|
||||
// Trait for hash functions that operate on 64-byte input blocks.
|
||||
/// Trait for hash functions that operate on 64-byte input blocks.
|
||||
pub trait HashBlockSize64Bytes {
|
||||
type State;
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ use arrayref::{array_mut_ref, array_ref};
|
||||
use byteorder::{BigEndian, ByteOrder};
|
||||
use core::cell::Cell;
|
||||
use core::num::Wrapping;
|
||||
use zeroize::Zeroize;
|
||||
|
||||
const BLOCK_SIZE: usize = 64;
|
||||
|
||||
@@ -32,6 +33,17 @@ pub struct Sha256 {
|
||||
total_len: usize,
|
||||
}
|
||||
|
||||
impl Drop for Sha256 {
|
||||
// TODO derive Zeroize instead when we upgrade the toolchain
|
||||
fn drop(&mut self) {
|
||||
for s in self.state.iter_mut() {
|
||||
s.0.zeroize();
|
||||
}
|
||||
self.block.zeroize();
|
||||
self.total_len.zeroize();
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash256 for Sha256 {
|
||||
fn new() -> Self {
|
||||
assert!(!BUSY.replace(true));
|
||||
@@ -72,7 +84,7 @@ impl Hash256 for Sha256 {
|
||||
}
|
||||
}
|
||||
|
||||
fn finalize(mut self) -> [u8; 32] {
|
||||
fn finalize(mut self, output: &mut [u8; 32]) {
|
||||
// Last block and padding.
|
||||
let cursor_in_block = self.total_len % BLOCK_SIZE;
|
||||
self.block[cursor_in_block] = 0x80;
|
||||
@@ -97,12 +109,10 @@ impl Hash256 for Sha256 {
|
||||
Sha256::hash_block(&mut self.state, &self.block);
|
||||
|
||||
// Encode the state's 32-bit words into bytes, using big-endian.
|
||||
let mut result: [u8; 32] = [0; 32];
|
||||
for i in 0..8 {
|
||||
BigEndian::write_u32(array_mut_ref![result, 4 * i, 4], self.state[i].0);
|
||||
BigEndian::write_u32(array_mut_ref![output, 4 * i, 4], self.state[i].0);
|
||||
}
|
||||
BUSY.set(false);
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
@@ -272,7 +282,9 @@ mod test {
|
||||
h.update(&input[..i]);
|
||||
h.update(&input[i..j]);
|
||||
h.update(&input[j..]);
|
||||
assert_eq!(h.finalize(), hash.as_slice());
|
||||
let mut digest = [0; 32];
|
||||
h.finalize(&mut digest);
|
||||
assert_eq!(digest, hash.as_slice());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user