Commit
+85 -63 +/-10 browse
1 | diff --git a/examples/arc_seal.rs b/examples/arc_seal.rs |
2 | index 1c31c3c..f6f84c0 100644 |
3 | --- a/examples/arc_seal.rs |
4 | +++ b/examples/arc_seal.rs |
5 | @@ -10,10 +10,12 @@ |
6 | |
7 | use mail_auth::{ |
8 | arc::ArcSealer, |
9 | - common::{crypto::RsaKey, headers::HeaderWriter}, |
10 | + common::{ |
11 | + crypto::{RsaKey, Sha256}, |
12 | + headers::HeaderWriter, |
13 | + }, |
14 | AuthenticatedMessage, AuthenticationResults, Resolver, |
15 | }; |
16 | - use sha2::Sha256; |
17 | |
18 | const TEST_MESSAGE: &str = include_str!("../resources/arc/001.txt"); |
19 | |
20 | diff --git a/examples/dkim_sign.rs b/examples/dkim_sign.rs |
21 | index a05e196..edf9fa0 100644 |
22 | --- a/examples/dkim_sign.rs |
23 | +++ b/examples/dkim_sign.rs |
24 | @@ -9,11 +9,14 @@ |
25 | */ |
26 | |
27 | use mail_auth::{ |
28 | - common::{crypto::Ed25519Key, crypto::RsaKey, headers::HeaderWriter}, |
29 | + common::{ |
30 | + crypto::RsaKey, |
31 | + crypto::{Ed25519Key, Sha256}, |
32 | + headers::HeaderWriter, |
33 | + }, |
34 | dkim::DkimSigner, |
35 | }; |
36 | use mail_parser::decoders::base64::base64_decode; |
37 | - use sha2::Sha256; |
38 | |
39 | const RSA_PRIVATE_KEY: &str = r#"-----BEGIN RSA PRIVATE KEY----- |
40 | MIICXwIBAAKBgQDwIRP/UC3SBsEmGqZ9ZJW3/DkMoGeLnQg1fWn7/zYtIxN2SnFC |
41 | diff --git a/src/arc/builder.rs b/src/arc/builder.rs |
42 | index f5780d4..57c5ed8 100644 |
43 | --- a/src/arc/builder.rs |
44 | +++ b/src/arc/builder.rs |
45 | @@ -8,10 +8,8 @@ |
46 | * except according to those terms. |
47 | */ |
48 | |
49 | - use sha2::Sha256; |
50 | - |
51 | use crate::{ |
52 | - common::crypto::SigningKey, |
53 | + common::crypto::{Sha256, SigningKey}, |
54 | dkim::{Canonicalization, Done, NeedDomain, NeedHeaders, NeedSelector}, |
55 | }; |
56 | |
57 | diff --git a/src/arc/mod.rs b/src/arc/mod.rs |
58 | index ed4ea20..a285379 100644 |
59 | --- a/src/arc/mod.rs |
60 | +++ b/src/arc/mod.rs |
61 | @@ -14,11 +14,9 @@ pub mod parse; |
62 | pub mod seal; |
63 | pub mod verify; |
64 | |
65 | - use sha2::Sha256; |
66 | - |
67 | use crate::{ |
68 | common::{ |
69 | - crypto::{Algorithm, SigningKey}, |
70 | + crypto::{Algorithm, Sha256, SigningKey}, |
71 | headers::Header, |
72 | verify::VerifySignature, |
73 | }, |
74 | diff --git a/src/arc/seal.rs b/src/arc/seal.rs |
75 | index 6835c16..c61c245 100644 |
76 | --- a/src/arc/seal.rs |
77 | +++ b/src/arc/seal.rs |
78 | @@ -11,11 +11,10 @@ |
79 | use std::time::SystemTime; |
80 | |
81 | use mail_builder::encoders::base64::base64_encode; |
82 | - use sha2::Sha256; |
83 | |
84 | use crate::{ |
85 | common::{ |
86 | - crypto::{HashContext, SigningKey}, |
87 | + crypto::{HashContext, Sha256, SigningKey}, |
88 | headers::Writer, |
89 | }, |
90 | dkim::{Canonicalization, Done}, |
91 | @@ -169,12 +168,11 @@ mod test { |
92 | use std::time::{Duration, Instant}; |
93 | |
94 | use mail_parser::decoders::base64::base64_decode; |
95 | - use sha2::Sha256; |
96 | |
97 | use crate::{ |
98 | arc::ArcSealer, |
99 | common::{ |
100 | - crypto::{Ed25519Key, RsaKey, SigningKey}, |
101 | + crypto::{Ed25519Key, RsaKey, Sha256, SigningKey}, |
102 | headers::HeaderWriter, |
103 | parse::TxtRecordParser, |
104 | verify::DomainKey, |
105 | diff --git a/src/common/base32.rs b/src/common/base32.rs |
106 | index c9e9d88..3b270a7 100644 |
107 | --- a/src/common/base32.rs |
108 | +++ b/src/common/base32.rs |
109 | @@ -78,9 +78,11 @@ impl Writer for Base32Writer { |
110 | |
111 | #[cfg(test)] |
112 | mod tests { |
113 | - use sha1::{Digest, Sha1}; |
114 | - |
115 | - use crate::common::{base32::Base32Writer, headers::Writer}; |
116 | + use crate::common::{ |
117 | + base32::Base32Writer, |
118 | + crypto::{HashContext, HashImpl, Sha1}, |
119 | + headers::Writer, |
120 | + }; |
121 | |
122 | #[test] |
123 | fn base32_hash() { |
124 | @@ -89,9 +91,9 @@ mod tests { |
125 | ("two.example.net", "ZTZGRRV3F45A4U6HLDKBF3ZCOW4V2AJX"), |
126 | ] { |
127 | let mut writer = Base32Writer::with_capacity(10); |
128 | - let mut hash = Sha1::new(); |
129 | - hash.update(test.as_bytes()); |
130 | - writer.write(&hash.finalize()[..]); |
131 | + let mut hash = Sha1::hasher(); |
132 | + hash.write(test.as_bytes()); |
133 | + writer.write(hash.finish().as_ref()); |
134 | assert_eq!(writer.finalize(), expected_result); |
135 | } |
136 | } |
137 | diff --git a/src/common/crypto.rs b/src/common/crypto.rs |
138 | index a897c9b..0852061 100644 |
139 | --- a/src/common/crypto.rs |
140 | +++ b/src/common/crypto.rs |
141 | @@ -1,4 +1,4 @@ |
142 | - use std::{io, marker::PhantomData}; |
143 | + use std::marker::PhantomData; |
144 | |
145 | use ed25519_dalek::Signer; |
146 | use rsa::{ |
147 | @@ -6,20 +6,20 @@ use rsa::{ |
148 | pkcs8::{AssociatedOid, ObjectIdentifier}, |
149 | PaddingScheme, PublicKey as _, RsaPrivateKey, |
150 | }; |
151 | - use sha1::{digest::Output, Sha1}; |
152 | - use sha2::{digest::Digest, Sha256}; |
153 | + use sha1::digest::Output; |
154 | + use sha2::digest::Digest; |
155 | |
156 | use crate::{dkim::Canonicalization, Error, Result}; |
157 | |
158 | use super::headers::Writer; |
159 | |
160 | pub trait SigningKey { |
161 | - type Hasher: HashContext; |
162 | + type Hasher: HashImpl; |
163 | |
164 | fn sign(&self, data: HashOutput) -> Result<Vec<u8>>; |
165 | |
166 | - fn hasher(&self) -> Self::Hasher { |
167 | - Self::Hasher::new() |
168 | + fn hasher(&self) -> <Self::Hasher as HashImpl>::Context { |
169 | + <Self::Hasher as HashImpl>::hasher() |
170 | } |
171 | |
172 | fn algorithm(&self) -> Algorithm; |
173 | @@ -31,7 +31,7 @@ pub struct RsaKey<T> { |
174 | padding: PhantomData<T>, |
175 | } |
176 | |
177 | - impl<T: Digest + AssociatedOid + io::Write> RsaKey<T> { |
178 | + impl<T: HashImpl> RsaKey<T> { |
179 | /// Creates a new RSA private key from a PKCS1 PEM string. |
180 | pub fn from_pkcs1_pem(private_key_pem: &str) -> Result<Self> { |
181 | let inner = RsaPrivateKey::from_pkcs1_pem(private_key_pem) |
182 | @@ -61,7 +61,7 @@ impl SigningKey for RsaKey<Sha1> { |
183 | fn sign(&self, data: HashOutput) -> Result<Vec<u8>> { |
184 | self.inner |
185 | .sign( |
186 | - PaddingScheme::new_pkcs1v15_sign::<Self::Hasher>(), |
187 | + PaddingScheme::new_pkcs1v15_sign::<<Self::Hasher as HashImpl>::Context>(), |
188 | data.as_ref(), |
189 | ) |
190 | .map_err(|err| Error::CryptoError(err.to_string())) |
191 | @@ -78,7 +78,7 @@ impl SigningKey for RsaKey<Sha256> { |
192 | fn sign(&self, data: HashOutput) -> Result<Vec<u8>> { |
193 | self.inner |
194 | .sign( |
195 | - PaddingScheme::new_pkcs1v15_sign::<Self::Hasher>(), |
196 | + PaddingScheme::new_pkcs1v15_sign::<<Self::Hasher as HashImpl>::Context>(), |
197 | data.as_ref(), |
198 | ) |
199 | .map_err(|err| Error::CryptoError(err.to_string())) |
200 | @@ -173,7 +173,7 @@ impl VerifyingKey for RsaPublicKey { |
201 | let hash = canonicalization.hash_headers::<Sha256>(headers); |
202 | self.inner |
203 | .verify( |
204 | - PaddingScheme::new_pkcs1v15_sign::<Sha256>(), |
205 | + PaddingScheme::new_pkcs1v15_sign::<sha2::Sha256>(), |
206 | hash.as_ref(), |
207 | signature, |
208 | ) |
209 | @@ -183,7 +183,7 @@ impl VerifyingKey for RsaPublicKey { |
210 | let hash = canonicalization.hash_headers::<Sha1>(headers); |
211 | self.inner |
212 | .verify( |
213 | - PaddingScheme::new_pkcs1v15_sign::<Sha1>(), |
214 | + PaddingScheme::new_pkcs1v15_sign::<sha1::Sha1>(), |
215 | hash.as_ref(), |
216 | signature, |
217 | ) |
218 | @@ -221,40 +221,59 @@ impl VerifyingKey for Ed25519PublicKey { |
219 | } |
220 | } |
221 | |
222 | - impl Writer for Sha1 { |
223 | + impl Writer for sha1::Sha1 { |
224 | fn write(&mut self, buf: &[u8]) { |
225 | self.update(buf); |
226 | } |
227 | } |
228 | |
229 | - impl Writer for Sha256 { |
230 | + impl Writer for sha2::Sha256 { |
231 | fn write(&mut self, buf: &[u8]) { |
232 | self.update(buf); |
233 | } |
234 | } |
235 | |
236 | pub trait HashContext: Writer + Sized { |
237 | - fn new() -> Self; |
238 | fn finish(self) -> HashOutput; |
239 | } |
240 | |
241 | - impl HashContext for Sha1 { |
242 | - fn new() -> Self { |
243 | - <Self as Digest>::new() |
244 | + impl HashContext for sha1::Sha1 { |
245 | + fn finish(self) -> HashOutput { |
246 | + HashOutput::Sha1(self.finalize()) |
247 | } |
248 | + } |
249 | |
250 | + impl HashContext for sha2::Sha256 { |
251 | fn finish(self) -> HashOutput { |
252 | - HashOutput::Sha1(self.finalize()) |
253 | + HashOutput::Sha256(self.finalize()) |
254 | } |
255 | } |
256 | |
257 | - impl HashContext for Sha256 { |
258 | - fn new() -> Self { |
259 | - <Self as Digest>::new() |
260 | + pub trait HashImpl { |
261 | + type Context: HashContext; |
262 | + |
263 | + fn hasher() -> Self::Context; |
264 | + } |
265 | + |
266 | + #[derive(Clone, Copy)] |
267 | + pub struct Sha1; |
268 | + |
269 | + impl HashImpl for Sha1 { |
270 | + type Context = sha1::Sha1; |
271 | + |
272 | + fn hasher() -> Self::Context { |
273 | + <Self::Context as Digest>::new() |
274 | } |
275 | + } |
276 | |
277 | - fn finish(self) -> HashOutput { |
278 | - HashOutput::Sha256(self.finalize()) |
279 | + #[derive(Clone, Copy)] |
280 | + pub struct Sha256; |
281 | + |
282 | + impl HashImpl for Sha256 { |
283 | + type Context = sha2::Sha256; |
284 | + |
285 | + fn hasher() -> Self::Context { |
286 | + <Self::Context as Digest>::new() |
287 | } |
288 | } |
289 | |
290 | @@ -268,15 +287,15 @@ pub enum HashAlgorithm { |
291 | impl HashAlgorithm { |
292 | pub fn hash(&self, data: &[u8]) -> HashOutput { |
293 | match self { |
294 | - Self::Sha1 => HashOutput::Sha1(Sha1::digest(data)), |
295 | - Self::Sha256 => HashOutput::Sha256(Sha256::digest(data)), |
296 | + Self::Sha1 => HashOutput::Sha1(sha1::Sha1::digest(data)), |
297 | + Self::Sha256 => HashOutput::Sha256(sha2::Sha256::digest(data)), |
298 | } |
299 | } |
300 | } |
301 | |
302 | pub enum HashOutput { |
303 | - Sha1(Output<Sha1>), |
304 | - Sha256(Output<Sha256>), |
305 | + Sha1(Output<sha1::Sha1>), |
306 | + Sha256(Output<sha2::Sha256>), |
307 | } |
308 | |
309 | impl AsRef<[u8]> for HashOutput { |
310 | @@ -293,8 +312,8 @@ impl TryFrom<&ObjectIdentifier> for HashAlgorithm { |
311 | |
312 | fn try_from(oid: &ObjectIdentifier) -> Result<Self> { |
313 | match oid { |
314 | - oid if oid == &Sha256::OID => Ok(HashAlgorithm::Sha256), |
315 | - oid if oid == &Sha1::OID => Ok(HashAlgorithm::Sha1), |
316 | + oid if oid == &sha2::Sha256::OID => Ok(HashAlgorithm::Sha256), |
317 | + oid if oid == &sha1::Sha1::OID => Ok(HashAlgorithm::Sha1), |
318 | _ => Err(Error::CryptoError("Unsupported hash algorithm".to_string())), |
319 | } |
320 | } |
321 | diff --git a/src/common/message.rs b/src/common/message.rs |
322 | index d55b158..0f1ab40 100644 |
323 | --- a/src/common/message.rs |
324 | +++ b/src/common/message.rs |
325 | @@ -9,10 +9,12 @@ |
326 | */ |
327 | |
328 | use mail_parser::{parsers::MessageStream, HeaderValue}; |
329 | - use sha1::Sha1; |
330 | - use sha2::Sha256; |
331 | |
332 | - use crate::{arc, common::crypto::HashAlgorithm, dkim, AuthenticatedMessage}; |
333 | + use crate::{ |
334 | + arc, |
335 | + common::crypto::{HashAlgorithm, Sha1, Sha256}, |
336 | + dkim, AuthenticatedMessage, |
337 | + }; |
338 | |
339 | use super::headers::{AuthenticatedHeader, Header, HeaderParser}; |
340 | |
341 | diff --git a/src/dkim/canonicalize.rs b/src/dkim/canonicalize.rs |
342 | index 7ad70bd..60ab372 100644 |
343 | --- a/src/dkim/canonicalize.rs |
344 | +++ b/src/dkim/canonicalize.rs |
345 | @@ -8,9 +8,10 @@ |
346 | * except according to those terms. |
347 | */ |
348 | |
349 | - use sha1::Digest; |
350 | - |
351 | - use crate::common::headers::{HeaderIterator, Writer}; |
352 | + use crate::common::{ |
353 | + crypto::{HashContext, HashImpl}, |
354 | + headers::{HeaderIterator, Writer}, |
355 | + }; |
356 | |
357 | use super::{Canonicalization, Signature}; |
358 | |
359 | @@ -114,17 +115,17 @@ impl Canonicalization { |
360 | } |
361 | } |
362 | |
363 | - pub fn hash_headers<'x, T: Digest + Writer>( |
364 | + pub fn hash_headers<'x, T: HashImpl>( |
365 | &self, |
366 | headers: &mut dyn Iterator<Item = (&'x [u8], &'x [u8])>, |
367 | ) -> impl AsRef<[u8]> { |
368 | - let mut hasher = T::new(); |
369 | + let mut hasher = T::hasher(); |
370 | self.canonicalize_headers(headers, &mut hasher); |
371 | - hasher.finalize() |
372 | + hasher.finish() |
373 | } |
374 | |
375 | - pub fn hash_body<T: Digest + Writer>(&self, body: &[u8], l: u64) -> impl AsRef<[u8]> { |
376 | - let mut hasher = T::new(); |
377 | + pub fn hash_body<T: HashImpl>(&self, body: &[u8], l: u64) -> impl AsRef<[u8]> { |
378 | + let mut hasher = T::hasher(); |
379 | self.canonicalize_body( |
380 | if l == 0 || body.is_empty() { |
381 | body |
382 | @@ -133,7 +134,7 @@ impl Canonicalization { |
383 | }, |
384 | &mut hasher, |
385 | ); |
386 | - hasher.finalize() |
387 | + hasher.finish() |
388 | } |
389 | |
390 | pub fn serialize_name(&self, writer: &mut impl Writer) { |
391 | diff --git a/src/dkim/sign.rs b/src/dkim/sign.rs |
392 | index 9203449..0e664b2 100644 |
393 | --- a/src/dkim/sign.rs |
394 | +++ b/src/dkim/sign.rs |
395 | @@ -76,12 +76,11 @@ mod test { |
396 | use std::time::{Duration, Instant}; |
397 | |
398 | use mail_parser::decoders::base64::base64_decode; |
399 | - use sha2::Sha256; |
400 | use trust_dns_resolver::proto::op::ResponseCode; |
401 | |
402 | use crate::{ |
403 | common::{ |
404 | - crypto::{Ed25519Key, RsaKey}, |
405 | + crypto::{Ed25519Key, RsaKey, Sha256}, |
406 | parse::TxtRecordParser, |
407 | verify::DomainKey, |
408 | }, |