Skip to content

Commit 89f44fc

Browse files
committed
sha2 impls SerializableState
1 parent 5e439a8 commit 89f44fc

7 files changed

Lines changed: 224 additions & 40 deletions

File tree

crypto/core/src/errors.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#[derive(Debug)]
22
pub enum CoreError {
33
IncompatibleVersion,
4+
InvalidData,
45
}
56

67
#[derive(Debug)]

crypto/core/src/serializable_state.rs

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -45,17 +45,12 @@ fn test_cmp_lib_ver() {
4545
assert_eq!(cmp_lib_ver(&[1, 1, 1], &[1, 1, 1]), 0);
4646
}
4747

48-
/// A helper for serializing an object's state
48+
/// Puts the library version into the first three bytes of the state array.
4949
///
50-
/// The state array must have length SERIALIZED_LEN - 3 to account for adding the 3-byte symver tag.
51-
pub fn add_lib_ver<const SERIALIZED_LEN: usize>(state: &[u8]) -> [u8; SERIALIZED_LEN] {
52-
assert_eq!(state.len(), SERIALIZED_LEN - 3);
53-
54-
let mut out = [0u8; SERIALIZED_LEN];
55-
out[..3].copy_from_slice(&LIB_VERSION);
56-
out[3..].copy_from_slice(state);
57-
58-
out
50+
/// Hands back a slice to the same array, starting after the version tag.
51+
pub fn add_lib_ver<const SERIALIZED_LEN: usize>(state: &mut [u8; SERIALIZED_LEN]) -> &mut [u8] {
52+
state[..3].copy_from_slice(&LIB_VERSION);
53+
&mut state[3..]
5954
}
6055

6156
/// A helper for deserializing an object's state
@@ -67,14 +62,13 @@ pub fn add_lib_ver<const SERIALIZED_LEN: usize>(state: &[u8]) -> [u8; SERIALIZED
6762
///
6863
/// Note that for testability, this will always reject if the serialized state contains a version tag
6964
/// of `[0,0,0]`.
70-
pub fn remove_lib_ver<const SERIALIZED_LEN: usize>(
71-
state_in: &[u8; SERIALIZED_LEN],
72-
state_out: &mut [u8],
65+
///
66+
/// Hands back a slice to the same array, starting after the version tag.
67+
pub fn check_lib_ver<const SERIALIZED_LEN: usize>(
68+
state: &[u8; SERIALIZED_LEN],
7369
not_before: Option<[u8; 3]>,
74-
) -> Result<usize, CoreError> {
75-
assert!(state_out.len() >= SERIALIZED_LEN - 3);
76-
77-
let ver: [u8; 3] = state_in[..3].try_into().unwrap();
70+
) -> Result<&[u8], CoreError> {
71+
let ver: [u8; 3] = state[..3].try_into().unwrap();
7872

7973
let not_before = not_before.unwrap_or([0, 0, 0]);
8074

@@ -85,6 +79,5 @@ pub fn remove_lib_ver<const SERIALIZED_LEN: usize>(
8579
return Err(CoreError::IncompatibleVersion);
8680
};
8781

88-
state_out.copy_from_slice(&state_in[3..]);
89-
Ok(SERIALIZED_LEN - 3)
82+
Ok(&state[3..])
9083
}

crypto/sha2/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ edition.workspace = true
66
[dependencies]
77
bouncycastle-core.workspace = true
88
bouncycastle-utils.workspace = true
9+
serde = { version = "1.0.228", features = ["derive"] }
910

1011
[dev-dependencies]
1112
criterion.workspace = true

crypto/sha2/src/lib.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ mod sha256;
4141
mod sha512;
4242

4343
pub use self::sha256::SHA256Internal;
44-
pub use self::sha512::Sha512Internal;
44+
pub use self::sha512::SHA512Internal;
4545
use bouncycastle_core::traits::{Algorithm, HashAlgParams, SecurityStrength};
4646

4747
/*** String constants ***/
@@ -53,8 +53,8 @@ pub const SHA512_NAME: &str = "SHA512";
5353
/*** pub types ***/
5454
pub type SHA224 = SHA256Internal<SHA224Params>;
5555
pub type SHA256 = SHA256Internal<SHA256Params>;
56-
pub type SHA384 = Sha512Internal<SHA384Params>;
57-
pub type SHA512 = Sha512Internal<SHA512Params>;
56+
pub type SHA384 = SHA512Internal<SHA384Params>;
57+
pub type SHA512 = SHA512Internal<SHA512Params>;
5858

5959
/*** Param traits ***/
6060

crypto/sha2/src/sha256.rs

Lines changed: 71 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::SHA2Params;
2-
use bouncycastle_core::errors::HashError;
3-
use bouncycastle_core::traits::{Hash, SecurityStrength};
2+
use bouncycastle_core::errors::{CoreError, HashError};
3+
use bouncycastle_core::serializable_state::{add_lib_ver, check_lib_ver};
4+
use bouncycastle_core::traits::{Hash, SecurityStrength, SerializableState};
45
use bouncycastle_utils::min;
56
use core::slice;
67

@@ -45,11 +46,9 @@ fn theta1(x: u32) -> u32 {
4546
x.rotate_right(17) ^ x.rotate_right(19) ^ (x >> 10)
4647
}
4748

48-
// todo -- cleanup
49-
// #[derive(Clone, Copy)]
5049
#[derive(Clone)]
5150
pub(crate) struct Sha256State<PARAMS: SHA2Params> {
52-
_params: std::marker::PhantomData<PARAMS>,
51+
_params: core::marker::PhantomData<PARAMS>,
5352
h: [u32; 8],
5453
}
5554

@@ -63,7 +62,7 @@ impl<PARAMS: SHA2Params> Sha256State<PARAMS> {
6362
pub(crate) fn new() -> Self {
6463
match PARAMS::OUTPUT_LEN * 8 {
6564
224 => Self {
66-
_params: std::marker::PhantomData,
65+
_params: core::marker::PhantomData,
6766
h: [
6867
0xC1059ED8, 0x367CD507, 0x3070DD17, 0xF70E5939, 0xFFC00B31, 0x68581511,
6968
0x64F98FA7, 0xBEFA4FA4,
@@ -145,11 +144,9 @@ impl<PARAMS: SHA2Params> Sha256State<PARAMS> {
145144
}
146145
}
147146

148-
// todo -- cleanup
149-
// #[derive(Clone, Copy)]
150147
#[derive(Clone)]
151148
pub struct SHA256Internal<PARAMS: SHA2Params> {
152-
_params: std::marker::PhantomData<PARAMS>,
149+
_params: core::marker::PhantomData<PARAMS>,
153150
state: Sha256State<PARAMS>,
154151
byte_count: u64,
155152
x_buf: [u8; 64],
@@ -166,7 +163,7 @@ impl<PARAMS: SHA2Params> Drop for SHA256Internal<PARAMS> {
166163
impl<PARAMS: SHA2Params> SHA256Internal<PARAMS> {
167164
pub fn new() -> Self {
168165
Self {
169-
_params: std::marker::PhantomData,
166+
_params: core::marker::PhantomData,
170167
state: Sha256State::<PARAMS>::new(),
171168
byte_count: 0,
172169
x_buf: [0; 64],
@@ -306,3 +303,67 @@ impl<PARAMS: SHA2Params> Hash for SHA256Internal<PARAMS> {
306303
SecurityStrength::from_bytes(PARAMS::OUTPUT_LEN / 2)
307304
}
308305
}
306+
307+
impl<PARAMS: SHA2Params> SerializableState<108> for SHA256Internal<PARAMS> {
308+
fn serialize_state(&self) -> [u8; 108] {
309+
let mut out_to_return = [0u8; 108];
310+
311+
// insert the version tag
312+
let out: &mut [u8; 105] = add_lib_ver(&mut out_to_return).try_into().unwrap();
313+
314+
// state.h: [u32; 8]
315+
// 4 * 8 = 32
316+
for i in 0..8 {
317+
out[i * 4..(i * 4) + 4].copy_from_slice(&self.state.h[i].to_le_bytes());
318+
}
319+
320+
// byte_count: u64
321+
out[32..40].copy_from_slice(&self.byte_count.to_le_bytes());
322+
323+
// x_buf: [u8; 64]
324+
out[40..104].copy_from_slice(&self.x_buf);
325+
326+
// x_buf_off: usize
327+
// in general, a usize should be serialized into a u64, but in this case, it can't ever be larger than 64
328+
debug_assert!(self.x_buf_off < 64);
329+
out[104] = self.x_buf_off as u8;
330+
331+
out_to_return
332+
}
333+
334+
fn from_serialized_state(serialized_state: [u8; 108]) -> Result<Self, CoreError> {
335+
// check the version tag
336+
// At the moment, we have no not_before version to specify.
337+
let input: &[u8; 105] = check_lib_ver(&serialized_state, None)?.try_into().unwrap();
338+
339+
// state.h: [u32; 8]
340+
// 4 * 8 = 32
341+
let mut h = [0u32; 8];
342+
for i in 0..8 {
343+
h[i] = u32::from_le_bytes(input[i * 4..(i * 4) + 4].try_into().unwrap());
344+
}
345+
346+
// byte_count: u64
347+
let byte_count: u64 = u64::from_le_bytes(input[32..40].try_into().unwrap());
348+
349+
// x_buf: [u8; 64]
350+
let x_buf: [u8; 64] = input[40..104].try_into().unwrap();
351+
352+
// x_buf_off: usize
353+
// in general, a usize should be serialized into a u64, but in this case, it can't ever be larger than 64
354+
let x_buf_off: usize = input[104] as usize;
355+
if x_buf_off >= 64 {
356+
return Err(CoreError::InvalidData);
357+
}
358+
359+
// Construct the object
360+
let state = Sha256State { _params: core::marker::PhantomData, h };
361+
Ok(SHA256Internal {
362+
_params: core::marker::PhantomData,
363+
state,
364+
byte_count,
365+
x_buf,
366+
x_buf_off,
367+
})
368+
}
369+
}

crypto/sha2/src/sha512.rs

Lines changed: 73 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
use crate::SHA2Params;
2-
use bouncycastle_core::errors::HashError;
3-
use bouncycastle_core::traits::{Hash, SecurityStrength};
1+
use crate::{SHA2Params};
2+
use bouncycastle_core::errors::{CoreError, HashError};
3+
use bouncycastle_core::serializable_state::{add_lib_ver, check_lib_ver};
4+
use bouncycastle_core::traits::{Hash, SecurityStrength, SerializableState};
45
use bouncycastle_utils::min;
56
use core::slice;
67

@@ -160,21 +161,21 @@ impl<PARAMS: SHA2Params> Sha512State<PARAMS> {
160161
// todo -- cleanup
161162
// #[derive(Clone, Copy)]
162163
#[derive(Clone)]
163-
pub struct Sha512Internal<PARAMS: SHA2Params> {
164+
pub struct SHA512Internal<PARAMS: SHA2Params> {
164165
_params: std::marker::PhantomData<PARAMS>,
165166
state: Sha512State<PARAMS>,
166167
byte_count: u64, // NOTE We only support 2^67 bits, not the full 2^128
167168
x_buf: [u8; 128],
168169
x_buf_off: usize,
169170
}
170171

171-
impl<PARAMS: SHA2Params> Drop for Sha512Internal<PARAMS> {
172+
impl<PARAMS: SHA2Params> Drop for SHA512Internal<PARAMS> {
172173
fn drop(&mut self) {
173174
self.x_buf.fill(0);
174175
}
175176
}
176177

177-
impl<PARAMS: SHA2Params> Sha512Internal<PARAMS> {
178+
impl<PARAMS: SHA2Params> SHA512Internal<PARAMS> {
178179
pub fn new() -> Self {
179180
Self {
180181
_params: std::marker::PhantomData,
@@ -186,13 +187,13 @@ impl<PARAMS: SHA2Params> Sha512Internal<PARAMS> {
186187
}
187188
}
188189

189-
impl<PARAMS: SHA2Params> Default for Sha512Internal<PARAMS> {
190+
impl<PARAMS: SHA2Params> Default for SHA512Internal<PARAMS> {
190191
fn default() -> Self {
191192
Self::new()
192193
}
193194
}
194195

195-
impl<PARAMS: SHA2Params> Hash for Sha512Internal<PARAMS> {
196+
impl<PARAMS: SHA2Params> Hash for SHA512Internal<PARAMS> {
196197
/// As per FIPS 180-4 Figure 1
197198
fn block_bitlen(&self) -> usize {
198199
1024
@@ -317,3 +318,67 @@ impl<PARAMS: SHA2Params> Hash for Sha512Internal<PARAMS> {
317318
SecurityStrength::from_bytes(PARAMS::OUTPUT_LEN / 2)
318319
}
319320
}
321+
322+
impl<PARAMS: SHA2Params> SerializableState<204> for SHA512Internal<PARAMS> {
323+
fn serialize_state(&self) -> [u8; 204] {
324+
let mut out_to_return = [0u8; 204];
325+
326+
// insert the version tag
327+
let out: &mut [u8; 201] = add_lib_ver(&mut out_to_return).try_into().unwrap();
328+
329+
// state.h: [u64; 8]
330+
// 8 * 8 = 64
331+
for i in 0..8 {
332+
out[i * 8..(i * 8) + 8].copy_from_slice(&self.state.h[i].to_le_bytes());
333+
}
334+
335+
// byte_count: u64
336+
out[64..72].copy_from_slice(&self.byte_count.to_le_bytes());
337+
338+
// x_buf: [u8; 128]
339+
out[72..200].copy_from_slice(&self.x_buf);
340+
341+
// x_buf_off: usize
342+
// in general, a usize should be serialized into a u64, but in this case, it can't ever be larger than 128
343+
debug_assert!(self.x_buf_off < 128);
344+
out[200] = self.x_buf_off as u8;
345+
346+
out_to_return
347+
}
348+
349+
fn from_serialized_state(serialized_state: [u8; 204]) -> Result<Self, CoreError> {
350+
// check the version tag
351+
// At the moment, we have no not_before version to specify.
352+
let input: &[u8; 201] = check_lib_ver(&serialized_state, None)?.try_into().unwrap();
353+
354+
// state.h: [u64; 8]
355+
// 8 * 8 = 64
356+
let mut h = [0u64; 8];
357+
for i in 0..8 {
358+
h[i] = u64::from_le_bytes(input[i * 8..(i * 8) + 8].try_into().unwrap());
359+
}
360+
361+
// byte_count: u64
362+
let byte_count: u64 = u64::from_le_bytes(input[64..72].try_into().unwrap());
363+
364+
// x_buf: [u8; 128]
365+
let x_buf: [u8; 128] = input[72..200].try_into().unwrap();
366+
367+
// x_buf_off: usize
368+
// in general, a usize should be serialized into a u64, but in this case, it can't ever be larger than 128
369+
let x_buf_off: usize = input[200] as usize;
370+
if x_buf_off >= 128 {
371+
return Err(CoreError::InvalidData);
372+
}
373+
374+
// Construct the object
375+
let state = Sha512State { _params: core::marker::PhantomData, h };
376+
Ok(SHA512Internal {
377+
_params: core::marker::PhantomData,
378+
state,
379+
byte_count,
380+
x_buf,
381+
x_buf_off,
382+
})
383+
}
384+
}

0 commit comments

Comments
 (0)