Skip to content

Commit 7cc52d3

Browse files
committed
sha256: hide ring Digest. add const sha256.
1 parent 357ded4 commit 7cc52d3

File tree

7 files changed

+193
-21
lines changed

7 files changed

+193
-21
lines changed

Cargo.lock

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

common/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ serde_json = "1"
7979
# Core SGX types
8080
# NOTE: version must exactly match patched version
8181
sgx-isa = "=0.4.0"
82+
# Const SHA256 hash
83+
sha2-const = "0"
8284
# Easy error definition
8385
thiserror = "1"
8486
# Logging

common/src/api/mod.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use proptest_derive::Arbitrary;
66
use serde::{Deserialize, Serialize};
77

88
use crate::hex::{self, FromHex};
9-
use crate::hexstr_or_bytes;
9+
use crate::{ed25519, hexstr_or_bytes};
1010

1111
/// Traits defining the various REST API interfaces.
1212
pub mod def;
@@ -39,6 +39,10 @@ impl UserPk {
3939
self.0
4040
}
4141

42+
pub const fn as_ed25519(&self) -> &ed25519::PublicKey {
43+
ed25519::PublicKey::from_ref(&self.0)
44+
}
45+
4246
/// Used to quickly construct `UserPk`s for tests.
4347
pub fn from_i64(i: i64) -> Self {
4448
// Convert i64 to [u8; 8]

common/src/attest/verify.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -291,11 +291,11 @@ impl SgxQuoteVerifier {
291291
.context("Invalid QE identity")?;
292292

293293
ensure!(
294-
&qe3_reportdata[..32] == expected_reportdata.as_ref(),
294+
&qe3_reportdata[..32] == expected_reportdata.as_slice(),
295295
"Quoting Enclave's Report data doesn't match the Quote attestation pk: \
296296
actual: '{}', expected: '{}'",
297297
hex::display(&qe3_reportdata[..32]),
298-
hex::display(expected_reportdata.as_ref()),
298+
expected_reportdata,
299299
);
300300

301301
// 4. Verify the attestation key endorses the Quote Header and our

common/src/ed25519.rs

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,9 @@ use ring::signature::KeyPair as _;
4141
use thiserror::Error;
4242
use x509_parser::x509::SubjectPublicKeyInfo;
4343

44+
use crate::hex::{self, FromHex};
4445
use crate::rng::Crng;
45-
use crate::{const_assert_usize_eq, const_ref_cast, hex};
46+
use crate::{const_assert_usize_eq, const_ref_cast};
4647

4748
/// The standard PKCS OID for Ed25519
4849
#[rustfmt::skip]
@@ -260,15 +261,15 @@ impl PublicKey {
260261
.map_err(|_| Error::InvalidSignature)
261262
}
262263

263-
pub fn as_slice(&self) -> &[u8] {
264+
pub const fn as_slice(&self) -> &[u8] {
264265
self.0.as_slice()
265266
}
266267

267-
pub fn into_inner(self) -> [u8; 32] {
268+
pub const fn into_inner(self) -> [u8; 32] {
268269
self.0
269270
}
270271

271-
pub fn as_inner(&self) -> &[u8; 32] {
272+
pub const fn as_inner(&self) -> &[u8; 32] {
272273
&self.0
273274
}
274275
}
@@ -320,6 +321,12 @@ impl AsRef<[u8; 32]> for PublicKey {
320321
}
321322
}
322323

324+
impl FromHex for PublicKey {
325+
fn from_hex(s: &str) -> Result<Self, hex::DecodeError> {
326+
<[u8; 32]>::from_hex(s).map(Self::new)
327+
}
328+
}
329+
323330
impl fmt::Display for PublicKey {
324331
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
325332
write!(f, "{}", hex::display(self.as_slice()))
@@ -345,15 +352,15 @@ impl Signature {
345352
const_ref_cast(sig)
346353
}
347354

348-
pub fn as_slice(&self) -> &[u8] {
355+
pub const fn as_slice(&self) -> &[u8] {
349356
self.0.as_slice()
350357
}
351358

352-
pub fn into_inner(self) -> [u8; 64] {
359+
pub const fn into_inner(self) -> [u8; 64] {
353360
self.0
354361
}
355362

356-
pub fn as_inner(&self) -> &[u8; 64] {
363+
pub const fn as_inner(&self) -> &[u8; 64] {
357364
&self.0
358365
}
359366
}
@@ -379,6 +386,12 @@ impl TryFrom<&[u8]> for Signature {
379386
}
380387
}
381388

389+
impl FromHex for Signature {
390+
fn from_hex(s: &str) -> Result<Self, hex::DecodeError> {
391+
<[u8; 64]>::from_hex(s).map(Self::new)
392+
}
393+
}
394+
382395
impl fmt::Display for Signature {
383396
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
384397
write!(f, "{}", hex::display(self.as_slice()))

common/src/root_seed.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -236,15 +236,14 @@ mod test {
236236
use proptest::arbitrary::any;
237237
use proptest::collection::vec;
238238
use proptest::proptest;
239-
use ring::digest::Digest;
240239

241240
use super::*;
242241
use crate::sha256;
243242

244243
// simple implementations of some crypto functions for equivalence testing
245244

246245
// an inefficient impl of HMAC-SHA256 for equivalence testing
247-
fn hmac_sha256(key: &[u8], msg: &[u8]) -> Digest {
246+
fn hmac_sha256(key: &[u8], msg: &[u8]) -> sha256::Hash {
248247
let h_key = sha256::digest(key);
249248
let mut zero_pad_key = [0u8; 64];
250249

common/src/sha256.rs

Lines changed: 156 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,183 @@
11
//! A convenience module for hasing things with SHA-256.
22
3+
use std::{fmt, io};
4+
5+
use ref_cast::RefCast;
6+
7+
use crate::hex::FromHex;
8+
use crate::{const_ref_cast, hex};
9+
10+
pub const HASH_LEN: usize = 32;
11+
12+
/// A SHA-256 Hash value.
13+
#[derive(Copy, Clone, Default, PartialEq, Eq, RefCast)]
14+
#[repr(transparent)]
15+
pub struct Hash([u8; 32]);
16+
17+
/// A SHA-256 digest accumulator.
18+
#[derive(Clone)]
19+
pub struct Context(ring::digest::Context);
20+
321
/// SHA-256 digest a single input.
4-
pub fn digest(input: &[u8]) -> ring::digest::Digest {
22+
pub fn digest(input: &[u8]) -> Hash {
523
digest_many(&[input])
624
}
725

826
/// SHA-256 digest several input slices concatenated together, without
927
/// allocating.
10-
pub fn digest_many(inputs: &[&[u8]]) -> ring::digest::Digest {
11-
let mut ctx = context();
28+
pub fn digest_many(inputs: &[&[u8]]) -> Hash {
29+
let mut ctx = Context::new();
1230
for input in inputs {
1331
ctx.update(input);
1432
}
1533
ctx.finish()
1634
}
1735

18-
/// Create a SHA-256 digest context for manually hashing e.g. large input files.
19-
pub fn context() -> ring::digest::Context {
20-
ring::digest::Context::new(&ring::digest::SHA256)
36+
/// SHA-256 digest a single input at compile time.
37+
pub const fn digest_const(input: &[u8]) -> Hash {
38+
digest_many_const(&[input])
39+
}
40+
41+
/// SHA-256 digest a multiple concatenated inputs at compile time.
42+
pub const fn digest_many_const(mut inputs: &[&[u8]]) -> Hash {
43+
let mut acc = sha2_const::Sha256::new();
44+
while let Some((input, rest)) = inputs.split_first() {
45+
acc = acc.update(input);
46+
inputs = rest;
47+
}
48+
Hash::new(acc.finalize())
49+
}
50+
51+
// -- impl Hash -- //
52+
53+
impl Hash {
54+
pub const fn new(value: [u8; 32]) -> Self {
55+
Self(value)
56+
}
57+
58+
pub const fn from_ref(value: &[u8; 32]) -> &Self {
59+
const_ref_cast(value)
60+
}
61+
62+
pub const fn as_slice(&self) -> &[u8] {
63+
self.0.as_slice()
64+
}
65+
66+
pub const fn as_inner(&self) -> &[u8; 32] {
67+
&self.0
68+
}
69+
70+
pub const fn into_inner(self) -> [u8; 32] {
71+
self.0
72+
}
73+
74+
// Note: not pub, since `ring::digest::Digest` is not always SHA-256, but
75+
// we can guarantee this invariant inside the module.
76+
fn from_ring(output: ring::digest::Digest) -> Self {
77+
Self::new(<[u8; 32]>::try_from(output.as_ref()).unwrap())
78+
}
79+
}
80+
81+
impl AsRef<[u8]> for Hash {
82+
fn as_ref(&self) -> &[u8] {
83+
self.0.as_slice()
84+
}
85+
}
86+
87+
impl AsRef<[u8; 32]> for Hash {
88+
fn as_ref(&self) -> &[u8; 32] {
89+
&self.0
90+
}
91+
}
92+
93+
impl FromHex for Hash {
94+
fn from_hex(s: &str) -> Result<Self, hex::DecodeError> {
95+
<[u8; 32]>::from_hex(s).map(Self::new)
96+
}
97+
}
98+
99+
impl fmt::Display for Hash {
100+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101+
write!(f, "{}", hex::display(self.as_slice()))
102+
}
103+
}
104+
105+
impl fmt::Debug for Hash {
106+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
107+
write!(f, "{}", self)
108+
}
109+
}
110+
111+
// -- impl Context -- //
112+
113+
impl Context {
114+
pub fn new() -> Self {
115+
Self(ring::digest::Context::new(&ring::digest::SHA256))
116+
}
117+
118+
pub fn update(&mut self, input: &[u8]) {
119+
self.0.update(input);
120+
}
121+
122+
pub fn finish(self) -> Hash {
123+
Hash::from_ring(self.0.finish())
124+
}
125+
}
126+
127+
impl Default for Context {
128+
fn default() -> Self {
129+
Self::new()
130+
}
131+
}
132+
133+
impl io::Write for Context {
134+
fn write(&mut self, input: &[u8]) -> io::Result<usize> {
135+
self.update(input);
136+
Ok(input.len())
137+
}
138+
139+
fn flush(&mut self) -> io::Result<()> {
140+
Ok(())
141+
}
21142
}
22143

23144
#[cfg(test)]
24145
mod test {
25-
use super::*;
26-
use crate::hex;
146+
use std::io::Write;
147+
148+
use proptest::arbitrary::any;
149+
use proptest::proptest;
150+
151+
use crate::{hex, sha256};
27152

28153
// sanity check
29154
#[test]
30155
fn test_sha256() {
31-
let actual = hex::encode(digest(b"").as_ref());
156+
let actual = hex::encode(sha256::digest(b"").as_ref());
32157
let expected =
33158
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
34159
assert_eq!(&actual, expected);
35160
}
161+
162+
#[test]
163+
fn test_digest_equiv() {
164+
proptest!(|(inputs in any::<Vec<Vec<u8>>>())| {
165+
let inputs_ref = inputs
166+
.iter()
167+
.map(|v| v.as_slice())
168+
.collect::<Vec<_>>();
169+
170+
let h1 = sha256::digest_many(&inputs_ref);
171+
let h2 = sha256::digest_many_const(&inputs_ref);
172+
173+
let mut ctxt = sha256::Context::new();
174+
for input in inputs_ref {
175+
ctxt.write_all(input).unwrap();
176+
}
177+
let h3 = ctxt.finish();
178+
179+
assert_eq!(h1, h2);
180+
assert_eq!(h1, h3);
181+
});
182+
}
36183
}

0 commit comments

Comments
 (0)