File
Blob: firmware/crates/esp32-radio/src/platform/crypto/hashes.rs
| 1 | use super::native; |
| 2 | use dimpl::{ |
| 3 | HashAlgorithm, |
| 4 | crypto::{Buf, HashContext, HashProvider, HmacProvider}, |
| 5 | }; |
| 6 | use radio_webrtc::crypto::{Sha1HmacProvider, Sha256Provider}; |
| 7 | |
| 8 | #[derive(Debug)] |
| 9 | pub(super) struct Hashes; |
| 10 | |
| 11 | pub(super) fn bits(algorithm: HashAlgorithm) -> Option<i32> { |
| 12 | match algorithm { |
| 13 | HashAlgorithm::SHA256 => Some(256), |
| 14 | HashAlgorithm::SHA384 => Some(384), |
| 15 | _ => None, |
| 16 | } |
| 17 | } |
| 18 | |
| 19 | impl Sha256Provider for Hashes { |
| 20 | fn sha256(&self, data: &[u8]) -> [u8; 32] { |
| 21 | native::sha256(data).unwrap_or_else(|_| { |
| 22 | str0m_rust_crypto::default_provider() |
| 23 | .sha256_provider |
| 24 | .sha256(data) |
| 25 | }) |
| 26 | } |
| 27 | } |
| 28 | impl Sha1HmacProvider for Hashes { |
| 29 | fn sha1_hmac(&self, key: &[u8], payloads: &[&[u8]]) -> [u8; 20] { |
| 30 | let mut out = [0; 20]; |
| 31 | if native::hmac(160, key, payloads, &mut out).is_ok() { |
| 32 | out |
| 33 | } else { |
| 34 | str0m_rust_crypto::default_provider() |
| 35 | .sha1_hmac_provider |
| 36 | .sha1_hmac(key, payloads) |
| 37 | } |
| 38 | } |
| 39 | } |
| 40 | impl HmacProvider for Hashes { |
| 41 | fn hmac( |
| 42 | &self, |
| 43 | algorithm: HashAlgorithm, |
| 44 | key: &[u8], |
| 45 | data: &[u8], |
| 46 | out: &mut [u8], |
| 47 | ) -> Result<usize, dimpl::CryptoError> { |
| 48 | if let Some(bits) = bits(algorithm) |
| 49 | && native::hmac(bits, key, &[data], out).is_ok() |
| 50 | { |
| 51 | return Ok(bits as usize / 8); |
| 52 | } |
| 53 | dimpl::crypto::rust_crypto::default_provider() |
| 54 | .hmac_provider |
| 55 | .hmac(algorithm, key, data, out) |
| 56 | } |
| 57 | } |
| 58 | |
| 59 | struct Hash { |
| 60 | state: native::HashState, |
| 61 | length: usize, |
| 62 | } |
| 63 | impl std::fmt::Debug for Hash { |
| 64 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| 65 | f.debug_struct("EspHash").finish_non_exhaustive() |
| 66 | } |
| 67 | } |
| 68 | impl HashProvider for Hashes { |
| 69 | fn create_hash(&self, algorithm: HashAlgorithm) -> Box<dyn HashContext> { |
| 70 | if let Some(bits) = bits(algorithm) { |
| 71 | Box::new(Hash { |
| 72 | state: native::HashState::new(bits).expect("SHA state initialization failed"), |
| 73 | length: bits as usize / 8, |
| 74 | }) |
| 75 | } else { |
| 76 | dimpl::crypto::rust_crypto::default_provider() |
| 77 | .hash_provider |
| 78 | .create_hash(algorithm) |
| 79 | } |
| 80 | } |
| 81 | } |
| 82 | impl HashContext for Hash { |
| 83 | fn update(&mut self, data: &[u8]) { |
| 84 | // This upstream trait cannot return errors. A failed incremental hash |
| 85 | // aborts the firmware rather than producing an invalid transcript. |
| 86 | self.state.update(data).expect("SHA hardware update failed"); |
| 87 | } |
| 88 | fn clone_and_finalize(&self, out: &mut Buf) { |
| 89 | let mut digest = [0; 64]; |
| 90 | self.state |
| 91 | .finish(&mut digest) |
| 92 | .expect("SHA hardware finalization failed"); |
| 93 | out.clear(); |
| 94 | out.extend_from_slice(&digest[..self.length]); |
| 95 | } |
| 96 | } |