ds_rom/rom/raw/
hmac_sha1_signature.rs1use std::{backtrace::Backtrace, fmt::Display, num::ParseIntError, str::FromStr};
2
3use bytemuck::{Pod, PodCastError, Zeroable};
4use serde::{Deserialize, Deserializer, Serialize};
5use snafu::Snafu;
6
7use crate::crypto::hmac_sha1::HmacSha1;
8
9#[repr(C)]
11#[derive(Clone, Copy, Zeroable, Pod, PartialEq, Eq)]
12pub struct HmacSha1Signature {
13 pub hash: [u8; 20],
15}
16
17#[derive(Debug, Snafu)]
19pub enum HmacSha1SignatureError {
20 #[snafu(display("the HMAC-SHA1 signature table must be a multiple of {} bytes:\n{backtrace}", size_of::<HmacSha1Signature>()))]
22 InvalidSize {
23 backtrace: Backtrace,
25 },
26 #[snafu(display("expected {expected}-alignment for HMAC-SHA1 signature table but got {actual}-alignment:\n{backtrace}"))]
28 Misaligned {
29 expected: usize,
31 actual: usize,
33 backtrace: Backtrace,
35 },
36}
37
38impl HmacSha1Signature {
39 pub fn from_hmac_sha1(hmac_sha1: &HmacSha1, data: &[u8]) -> Self {
41 let hash = hmac_sha1.compute(data);
42 Self { hash }
43 }
44
45 pub fn set(&mut self, hash: [u8; 20]) {
47 self.hash = hash;
48 }
49
50 fn check_size(data: &[u8]) -> Result<(), HmacSha1SignatureError> {
51 let size = size_of::<Self>();
52 if !data.len().is_multiple_of(size) {
53 InvalidSizeSnafu {}.fail()
54 } else {
55 Ok(())
56 }
57 }
58
59 fn handle_pod_cast<T>(result: Result<T, PodCastError>, addr: usize) -> Result<T, HmacSha1SignatureError> {
60 match result {
61 Ok(signatures) => Ok(signatures),
62 Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned) => {
63 MisalignedSnafu { expected: size_of::<Self>(), actual: addr }.fail()
64 }
65 Err(PodCastError::AlignmentMismatch) => panic!(),
66 Err(PodCastError::OutputSliceWouldHaveSlop) => panic!(),
67 Err(PodCastError::SizeMismatch) => unreachable!(),
68 }
69 }
70
71 pub fn borrow_from_slice(data: &'_ [u8]) -> Result<&'_ [Self], HmacSha1SignatureError> {
77 Self::check_size(data)?;
78 let addr = data as *const [u8] as *const () as usize;
79 Self::handle_pod_cast(bytemuck::try_cast_slice(data), addr)
80 }
81
82 pub fn borrow_from_slice_mut(data: &'_ mut [u8]) -> Result<&'_ mut [Self], HmacSha1SignatureError> {
88 Self::check_size(data)?;
89 let addr = data as *const [u8] as *const () as usize;
90 Self::handle_pod_cast(bytemuck::try_cast_slice_mut(data), addr)
91 }
92}
93
94impl Display for HmacSha1Signature {
95 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
96 for byte in &self.hash {
97 write!(f, "{:02x}", byte)?;
98 }
99 Ok(())
100 }
101}
102
103#[derive(Debug, Snafu)]
105pub enum HmacSha1SignatureParseError {
106 #[snafu(display("invalid length: {length}:\n{backtrace}"))]
108 InvalidLength {
109 length: usize,
111 backtrace: Backtrace,
113 },
114 #[snafu(display("invalid hex string '{string}':{error}\n{backtrace}"))]
116 ParseInt {
117 error: ParseIntError,
119 string: String,
121 backtrace: Backtrace,
123 },
124}
125
126impl FromStr for HmacSha1Signature {
127 type Err = HmacSha1SignatureParseError;
128
129 fn from_str(s: &str) -> Result<Self, Self::Err> {
130 if s.len() != 40 {
131 return InvalidLengthSnafu { length: s.len() }.fail();
132 }
133
134 let mut hash = [0u8; 20];
135 for i in 0..20 {
136 let byte_str = &s[i * 2..i * 2 + 2];
137 hash[i] = u8::from_str_radix(byte_str, 16)
138 .map_err(|error| ParseIntSnafu { error, string: byte_str.to_string() }.build())?;
139 }
140
141 Ok(Self { hash })
142 }
143}
144
145impl Serialize for HmacSha1Signature {
146 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
147 where
148 S: serde::Serializer,
149 {
150 serializer.serialize_str(self.to_string().as_str())
151 }
152}
153
154impl<'de> Deserialize<'de> for HmacSha1Signature {
155 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
156 where
157 D: Deserializer<'de>,
158 {
159 let s = String::deserialize(deserializer)?;
160 Self::from_str(&s).map_err(serde::de::Error::custom)
161 }
162}