Skip to content

Commit a7f25bc

Browse files
committed
Add basic SHA1 support
1 parent 977f10a commit a7f25bc

6 files changed

Lines changed: 372 additions & 3 deletions

File tree

graviola/src/high/hash.rs

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,16 @@
44
use core::ops::{Deref, DerefMut};
55

66
use crate::low::ct_equal;
7+
use crate::mid::sha1;
78
use crate::mid::sha2;
89

910
/// Output from a hash function.
1011
///
1112
/// This has one variant per supported hash function.
1213
#[derive(Clone, Debug)]
1314
pub enum HashOutput {
15+
/// Output from SHA1
16+
Sha1([u8; sha1::Sha1Context::OUTPUT_SZ]),
1417
/// Output from SHA256
1518
Sha256([u8; sha2::Sha256Context::OUTPUT_SZ]),
1619
/// Output from SHA384
@@ -43,6 +46,7 @@ impl HashOutput {
4346
impl PartialEq for HashOutput {
4447
fn eq(&self, other: &Self) -> bool {
4548
match (self, other) {
49+
(Self::Sha1(s), Self::Sha1(o)) => ct_equal(s, o),
4650
(Self::Sha256(s), Self::Sha256(o)) => ct_equal(s, o),
4751
(Self::Sha384(s), Self::Sha384(o)) => ct_equal(s, o),
4852
(Self::Sha512(s), Self::Sha512(o)) => ct_equal(s, o),
@@ -54,6 +58,7 @@ impl PartialEq for HashOutput {
5458
impl AsRef<[u8]> for HashOutput {
5559
fn as_ref(&self) -> &[u8] {
5660
match self {
61+
Self::Sha1(v) => v,
5762
Self::Sha256(v) => v,
5863
Self::Sha384(v) => v,
5964
Self::Sha512(v) => v,
@@ -64,6 +69,7 @@ impl AsRef<[u8]> for HashOutput {
6469
impl AsMut<[u8]> for HashOutput {
6570
fn as_mut(&mut self) -> &mut [u8] {
6671
match self {
72+
Self::Sha1(v) => v,
6773
Self::Sha256(v) => v,
6874
Self::Sha384(v) => v,
6975
Self::Sha512(v) => v,
@@ -259,12 +265,87 @@ impl HashContext for Sha512Context {
259265
}
260266
}
261267

268+
/// This is SHA1.
269+
///
270+
/// Do not use SHA1 for new applications or for applications involving signatures.
271+
///
272+
/// This is described in [FIPS180-1](https://nvlpubs.nist.gov/nistpubs/Legacy/FIPS/fipspub180-1.pdf).
273+
#[derive(Clone)]
274+
pub struct Sha1;
275+
276+
impl Hash for Sha1 {
277+
type Context = Sha1Context;
278+
279+
fn new() -> Self::Context {
280+
Sha1Context(sha1::Sha1Context::new())
281+
}
282+
283+
fn hash(bytes: &[u8]) -> HashOutput {
284+
let mut ctx = Self::new();
285+
ctx.update(bytes);
286+
ctx.finish()
287+
}
288+
289+
fn zeroed_block() -> HashBlock {
290+
HashBlock::new(sha1::Sha1Context::BLOCK_SZ)
291+
}
292+
293+
fn zeroed_output() -> HashOutput {
294+
HashOutput::Sha1([0u8; sha1::Sha1Context::OUTPUT_SZ])
295+
}
296+
}
297+
298+
#[derive(Clone)]
299+
pub struct Sha1Context(sha1::Sha1Context);
300+
301+
impl HashContext for Sha1Context {
302+
fn update(&mut self, bytes: &[u8]) {
303+
self.0.update(bytes)
304+
}
305+
306+
fn finish(self) -> HashOutput {
307+
HashOutput::Sha1(self.0.finish())
308+
}
309+
}
310+
262311
#[cfg(test)]
263312
#[cfg_attr(coverage_nightly, coverage(off))]
264313
mod tests {
265314
use super::*;
266315
use crate::test::*;
267316

317+
#[test]
318+
fn equality() {
319+
let s1a = Sha1::hash(b"a");
320+
let s1b = Sha1::hash(b"b");
321+
let s256a = Sha256::hash(b"a");
322+
let s256b = Sha256::hash(b"b");
323+
let s384a = Sha384::hash(b"a");
324+
let s384b = Sha384::hash(b"b");
325+
let s512a = Sha512::hash(b"a");
326+
let s512b = Sha512::hash(b"b");
327+
328+
assert_eq!(s1a, Sha1::hash(b"a"));
329+
for other in [&s1b, &s256a, &s384a, &s512a] {
330+
assert_ne!(&s1a, other);
331+
}
332+
333+
assert_eq!(s256a, Sha256::hash(b"a"));
334+
for other in [&s1a, &s256b, &s384a, &s512a] {
335+
assert_ne!(&s256a, other);
336+
}
337+
338+
assert_eq!(s384a, Sha384::hash(b"a"));
339+
for other in [&s1a, &s256a, &s384b, &s512a] {
340+
assert_ne!(&s384a, other);
341+
}
342+
343+
assert_eq!(s512a, Sha512::hash(b"a"));
344+
for other in [&s1a, &s256a, &s384a, &s512b] {
345+
assert_ne!(&s512a, other);
346+
}
347+
}
348+
268349
#[test]
269350
fn cavp() {
270351
#[derive(Debug)]

graviola/src/high/hmac_drbg.rs

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ impl<H: Hash> RandomSource for HmacDrbg<H> {
121121
#[cfg_attr(coverage_nightly, coverage(off))]
122122
mod tests {
123123
use super::*;
124-
use crate::high::hash::Sha256;
124+
use crate::high::hash::{Sha1, Sha256, Sha384, Sha512};
125125

126126
#[test]
127127
fn rfc6979_example() {
@@ -139,4 +139,49 @@ mod tests {
139139
ctx.fill(&mut t2).unwrap();
140140
assert_eq!(&t2, b"\xC7\x0C\x78\x60\x8A\x3B\x5B\xE9\x28\x9B\xE9\x0E\xF6\xE8\x1A\x9E\x2C\x15\x16\xD5\x75\x1D\x2F\x75\xF5\x00\x33\xE4\x5F\x73\xBD\xEB");
141141
}
142+
143+
#[test]
144+
fn vectors() {
145+
// Generated independently with python.
146+
fn check<H: Hash>(first: &[u8; 70], second: &[u8; 30]) {
147+
let entropy: [u8; 32] = core::array::from_fn(|i| i as u8);
148+
let nonce: [u8; 16] = core::array::from_fn(|i| 0x40 + i as u8);
149+
let perso = b"graviola hmac-drbg";
150+
151+
let mut ctx = HmacDrbg::<H>::new(&entropy, &nonce, perso);
152+
153+
let mut o1 = [0u8; 70];
154+
ctx.fill(&mut o1).unwrap();
155+
assert_eq!(&o1, first);
156+
157+
let mut o2 = [0u8; 30];
158+
ctx.fill(&mut o2).unwrap();
159+
assert_eq!(&o2, second);
160+
}
161+
162+
check::<Sha1>(
163+
b"\x8d\x1b\xb7\x15\xf8\xdb\x72\x42\x65\x10\xd5\x2e\xac\x76\x59\x53\x5c\xf6\xb9\x1c\x3a\x6b\xf3\x4d\x73\x38\xc9\xf9\x7f\xe2\
164+
\xdb\x77\xcc\x4b\xa9\xb6\x8a\xec\x28\x85\xf0\xa9\x5c\x65\x96\x63\x73\x0a\xd0\x2e\x88\x7c\x55\xc0\x25\xb5\xd3\xe8\xbb\x93\
165+
\x9f\x8a\xb7\x62\x75\x18\x2b\xbb\x6f\x9b",
166+
b"\x05\x6d\x9e\xdb\x14\x7b\x7f\x07\x13\xa7\x0f\xc9\xb1\xdd\x3d\xb2\x4a\x57\x55\x0f\xe5\xb2\x05\xb7\x0d\x90\x34\x13\x1d\xa9",
167+
);
168+
check::<Sha256>(
169+
b"\xc5\xc1\x25\x25\xc2\x09\xb9\x25\x91\x57\xc8\x31\x76\xd2\xd0\xd5\x88\x5e\x5e\xaf\x29\xd9\x22\x86\xec\xe7\x6a\x94\x27\x0c\
170+
\x79\x9a\x57\x1d\xb2\x31\xb5\x87\xe1\x7c\x3b\x64\x2e\x26\x62\xac\x5d\x62\x16\x8d\xc5\xbe\x78\x0f\xde\xa8\x76\x6e\x03\x8a\
171+
\xc3\xd7\xb5\x15\x3b\x33\xbc\x21\x21\xab",
172+
b"\x7d\xbb\x59\xe0\x36\x7a\x1c\x0a\xc3\x1a\xbd\x60\xfc\x42\xba\x3c\x4c\x2b\x0a\xf2\x5c\xf8\xe1\x65\x00\x62\x7c\x82\x14\x21",
173+
);
174+
check::<Sha384>(
175+
b"\x93\xb3\x8c\xe3\x14\x37\x84\x75\x2a\x48\x20\xd6\x87\xda\x6c\xc8\xc6\x1a\x2c\x54\xc1\x64\x7b\xff\x4c\x81\x16\x43\x57\xdf\
176+
\x65\x02\x1c\xee\x99\x71\x77\xa3\x31\x04\x63\x67\x60\xa1\xb3\x5e\x35\x9d\x55\xa6\x5f\x48\xce\x79\x45\x3b\x54\x44\x19\x21\
177+
\xd8\xae\x2e\xaa\x84\xc8\x73\x69\xa4\xef",
178+
b"\xca\xd6\x29\x26\x73\x0e\x38\xad\x07\xaf\x3a\x06\xe4\xfa\x48\xc5\x9e\x50\xbe\x2e\x71\x20\x6d\x1e\x0f\xee\x4a\x3e\x95\x4f",
179+
);
180+
check::<Sha512>(
181+
b"\x41\x86\x6a\x14\x61\x21\x70\x57\xab\x66\xde\x78\xb7\x05\x9c\xbc\x87\x4e\x05\xe7\x49\xde\x57\xbd\x17\xff\x5e\x44\xaf\x88\
182+
\x16\xd2\x72\x4e\x5a\xa3\xf5\x41\x61\x47\xc2\x18\x1f\xdd\x39\x8d\xed\xc6\xa2\xb6\x79\x9e\x2d\xa3\xf2\x22\x72\x7e\xaa\xaa\
183+
\xd8\x7e\x68\xc3\x7a\x2e\xee\x9e\x1b\xa3",
184+
b"\xb2\x6d\x4e\xf0\x66\x27\x45\xc1\xa3\x80\x51\xf6\x18\x3d\x22\x0c\x94\xd7\x3a\xaf\xa4\x00\xc7\x2a\xee\x47\xf3\x74\x1c\x55",
185+
);
186+
}
142187
}

graviola/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,8 +166,9 @@ pub mod signing {
166166

167167
/// Cryptographic hash functions.
168168
pub mod hashing {
169-
pub use super::high::hash::{Hash, HashContext, HashOutput, Sha256, Sha384, Sha512};
169+
pub use super::high::hash::{Hash, HashContext, HashOutput, Sha1, Sha256, Sha384, Sha512};
170170
pub use super::high::hmac;
171+
pub use super::mid::sha1;
171172
pub use super::mid::sha2;
172173
pub use super::mid::sha3;
173174
}

graviola/src/mid/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ pub(super) mod p384;
1212
pub(super) mod rng;
1313
pub(super) mod rsa_priv;
1414
pub(super) mod rsa_pub;
15+
pub mod sha1;
1516
pub mod sha2;
1617
pub mod sha3;
1718
pub(super) mod util;

0 commit comments

Comments
 (0)