Commit
Author: Dirkjan Ochtman [dirkjan@ochtman.nl]
Hash: 1de607d68fed9fa1ce3b7c7c0b7a76abf31b1aa4
Timestamp: Thu, 08 Dec 2022 16:34:35 +0000 (2 years ago)

+172 -137 +/-6 browse
Use PrivateKey trait
1diff --git a/examples/arc_seal.rs b/examples/arc_seal.rs
2index 7c519a0..460b898 100644
3--- a/examples/arc_seal.rs
4+++ b/examples/arc_seal.rs
5 @@ -10,9 +10,10 @@
6
7 use mail_auth::{
8 arc::ArcSet,
9- common::{crypto::PrivateKey, headers::HeaderWriter},
10+ common::{crypto::RsaKey, headers::HeaderWriter},
11 AuthenticatedMessage, AuthenticationResults, Resolver,
12 };
13+ use sha2::Sha256;
14
15 const TEST_MESSAGE: &str = include_str!("../resources/arc/001.txt");
16
17 @@ -52,7 +53,7 @@ async fn main() {
18 // Seal message
19 if arc_result.can_be_sealed() {
20 // Seal the e-mail message using RSA-SHA256
21- let pk_rsa = PrivateKey::from_rsa_pkcs1_pem(RSA_PRIVATE_KEY).unwrap();
22+ let pk_rsa = RsaKey::<Sha256>::from_rsa_pkcs1_pem(RSA_PRIVATE_KEY).unwrap();
23 let arc_set = ArcSet::new(&auth_results)
24 .domain("example.org")
25 .selector("default")
26 diff --git a/examples/dkim_sign.rs b/examples/dkim_sign.rs
27index 1ae0e28..9bf3bfe 100644
28--- a/examples/dkim_sign.rs
29+++ b/examples/dkim_sign.rs
30 @@ -9,10 +9,11 @@
31 */
32
33 use mail_auth::{
34- common::{crypto::PrivateKey, headers::HeaderWriter},
35+ common::{crypto::Ed25519Key, crypto::RsaKey, headers::HeaderWriter},
36 dkim::Signature,
37 };
38 use mail_parser::decoders::base64::base64_decode;
39+ use sha2::Sha256;
40
41 const RSA_PRIVATE_KEY: &str = r#"-----BEGIN RSA PRIVATE KEY-----
42 MIICXwIBAAKBgQDwIRP/UC3SBsEmGqZ9ZJW3/DkMoGeLnQg1fWn7/zYtIxN2SnFC
43 @@ -42,7 +43,7 @@ I'm going to need those TPS reports ASAP. So, if you could do that, that'd be gr
44
45 fn main() {
46 // Sign an e-mail message using RSA-SHA256
47- let pk_rsa = PrivateKey::from_rsa_pkcs1_pem(RSA_PRIVATE_KEY).unwrap();
48+ let pk_rsa = RsaKey::<Sha256>::from_rsa_pkcs1_pem(RSA_PRIVATE_KEY).unwrap();
49 let signature_rsa = Signature::new()
50 .headers(["From", "To", "Subject"])
51 .domain("example.com")
52 @@ -51,7 +52,7 @@ fn main() {
53 .unwrap();
54
55 // Sign an e-mail message using ED25519-SHA256
56- let pk_ed = PrivateKey::from_ed25519(
57+ let pk_ed = Ed25519Key::from_bytes(
58 &base64_decode(ED25519_PUBLIC_KEY.as_bytes()).unwrap(),
59 &base64_decode(ED25519_PRIVATE_KEY.as_bytes()).unwrap(),
60 )
61 diff --git a/src/arc/seal.rs b/src/arc/seal.rs
62index 7e9af0a..cada5a8 100644
63--- a/src/arc/seal.rs
64+++ b/src/arc/seal.rs
65 @@ -10,15 +10,12 @@
66
67 use std::{borrow::Cow, io::Write, time::SystemTime};
68
69- use ed25519_dalek::Signer;
70 use mail_builder::encoders::base64::base64_encode;
71- use rsa::PaddingScheme;
72- use sha1::Digest;
73- use sha2::Sha256;
74+ use sha2::{Digest, Sha256};
75
76 use crate::{
77- common::crypto::Algorithm, dkim::Canonicalization, ArcOutput, AuthenticatedMessage,
78- AuthenticationResults, DkimResult, Error, PrivateKey,
79+ common::crypto::SigningKey, dkim::Canonicalization, ArcOutput, AuthenticatedMessage,
80+ AuthenticationResults, DkimResult, Error,
81 };
82
83 use super::{ArcSet, ChainValidation, Seal, Signature};
84 @@ -36,20 +33,15 @@ impl<'x> ArcSet<'x> {
85 mut self,
86 message: &'x AuthenticatedMessage<'x>,
87 arc_output: &ArcOutput,
88- with_key: &PrivateKey,
89+ with_key: &impl SigningKey<Hasher = Sha256>,
90 ) -> crate::Result<Self> {
91 if !arc_output.can_be_sealed() {
92 return Err(Error::ARCInvalidCV);
93 }
94
95 // Set a=
96- if let PrivateKey::Ed25519(_) = with_key {
97- self.signature.a = Algorithm::Ed25519Sha256;
98- self.seal.a = Algorithm::Ed25519Sha256;
99- } else {
100- self.signature.a = Algorithm::RsaSha256;
101- self.seal.a = Algorithm::RsaSha256;
102- }
103+ self.signature.a = with_key.algorithm();
104+ self.seal.a = with_key.algorithm();
105
106 // Set i= and cv=
107 if arc_output.set.is_empty() {
108 @@ -67,8 +59,8 @@ impl<'x> ArcSet<'x> {
109 }
110
111 // Create hashes
112- let mut body_hasher = Sha256::new();
113- let mut header_hasher = Sha256::new();
114+ let mut body_hasher = with_key.hasher();
115+ let mut header_hasher = with_key.hasher();
116
117 // Canonicalize headers and body
118 let (body_len, signed_headers) =
119 @@ -100,17 +92,7 @@ impl<'x> ArcSet<'x> {
120 self.signature.write(&mut header_hasher, false)?;
121
122 // Sign
123- let b = match with_key {
124- PrivateKey::Rsa(private_key) => private_key
125- .sign(
126- PaddingScheme::new_pkcs1v15_sign::<Sha256>(),
127- &header_hasher.finalize(),
128- )
129- .map_err(|err| Error::CryptoError(err.to_string()))?,
130- PrivateKey::Ed25519(key_pair) => {
131- key_pair.sign(&header_hasher.finalize()).to_bytes().to_vec()
132- }
133- };
134+ let b = with_key.sign(&header_hasher.finalize())?;
135 self.signature.b = base64_encode(&b)?;
136
137 // Hash ARC chain
138 @@ -135,17 +117,7 @@ impl<'x> ArcSet<'x> {
139 self.seal.write(&mut header_hasher, false)?;
140
141 // Seal
142- let b = match with_key {
143- PrivateKey::Rsa(private_key) => private_key
144- .sign(
145- PaddingScheme::new_pkcs1v15_sign::<Sha256>(),
146- &header_hasher.finalize(),
147- )
148- .map_err(|err| Error::CryptoError(err.to_string()))?,
149- PrivateKey::Ed25519(key_pair) => {
150- key_pair.sign(&header_hasher.finalize()).to_bytes().to_vec()
151- }
152- };
153+ let b = with_key.sign(&header_hasher.finalize())?;
154 self.seal.b = base64_encode(&b)?;
155
156 Ok(self)
157 @@ -242,12 +214,17 @@ mod test {
158 use std::time::{Duration, Instant};
159
160 use mail_parser::decoders::base64::base64_decode;
161+ use sha2::Sha256;
162
163 use crate::{
164 arc::ArcSet,
165- common::{headers::HeaderWriter, parse::TxtRecordParser},
166+ common::{
167+ crypto::{Ed25519Key, RsaKey, SigningKey},
168+ headers::HeaderWriter,
169+ parse::TxtRecordParser,
170+ },
171 dkim::{DomainKey, Signature},
172- AuthenticatedMessage, AuthenticationResults, DkimResult, PrivateKey, Resolver,
173+ AuthenticatedMessage, AuthenticationResults, DkimResult, Resolver,
174 };
175
176 const RSA_PRIVATE_KEY: &str = r#"-----BEGIN RSA PRIVATE KEY-----
177 @@ -303,8 +280,8 @@ GMot/L2x0IYyMLAz6oLWh2hm7zwtb0CgOrPo1ke44hFYnfc=
178 );
179
180 // Create private keys
181- let pk_rsa = PrivateKey::from_rsa_pkcs1_pem(RSA_PRIVATE_KEY).unwrap();
182- let pk_ed = PrivateKey::from_ed25519(
183+ let pk_rsa = RsaKey::<Sha256>::from_rsa_pkcs1_pem(RSA_PRIVATE_KEY).unwrap();
184+ let pk_ed = Ed25519Key::from_bytes(
185 &base64_decode(ED25519_PUBLIC_KEY.rsplit_once("p=").unwrap().1.as_bytes()).unwrap(),
186 &base64_decode(ED25519_PRIVATE_KEY.as_bytes()).unwrap(),
187 )
188 @@ -336,7 +313,7 @@ GMot/L2x0IYyMLAz6oLWh2hm7zwtb0CgOrPo1ke44hFYnfc=
189 raw_message: &str,
190 d: &str,
191 s: &str,
192- pk: &PrivateKey,
193+ pk: &impl SigningKey<Hasher = Sha256>,
194 ) -> String {
195 let message = AuthenticatedMessage::parse(raw_message.as_bytes()).unwrap();
196 let dkim_result = resolver.verify_dkim(&message).await;
197 diff --git a/src/common/crypto.rs b/src/common/crypto.rs
198index 8edf434..2d4a4d1 100644
199--- a/src/common/crypto.rs
200+++ b/src/common/crypto.rs
201 @@ -1,38 +1,113 @@
202- use rsa::{RsaPrivateKey, pkcs1::DecodeRsaPrivateKey};
203+ use std::{io, marker::PhantomData};
204
205- use crate::Error;
206+ use ed25519_dalek::Signer;
207+ use rsa::{
208+ pkcs1::DecodeRsaPrivateKey,
209+ pkcs8::{AssociatedOid, ObjectIdentifier},
210+ PaddingScheme, RsaPrivateKey,
211+ };
212+ use sha1::{digest::Output, Sha1};
213+ use sha2::{digest::Digest, Sha256};
214+
215+ use crate::{Error, Result};
216+
217+ pub trait SigningKey {
218+ type Hasher: Digest + AssociatedOid + io::Write;
219+
220+ fn sign(&self, data: &Output<Self::Hasher>) -> Result<Vec<u8>>;
221+
222+ fn hasher(&self) -> Self::Hasher {
223+ Self::Hasher::new()
224+ }
225+
226+ fn algorithm(&self) -> Algorithm;
227+ }
228
229 #[derive(Debug)]
230- pub enum PrivateKey {
231- Rsa(RsaPrivateKey),
232- Ed25519(ed25519_dalek::Keypair),
233+ pub struct RsaKey<T> {
234+ inner: RsaPrivateKey,
235+ padding: PhantomData<T>,
236 }
237
238- impl PrivateKey {
239+ impl<T: Digest + AssociatedOid + io::Write> RsaKey<T> {
240 /// Creates a new RSA private key from a PKCS1 PEM string.
241- pub fn from_rsa_pkcs1_pem(private_key_pem: &str) -> crate::Result<Self> {
242- Ok(PrivateKey::Rsa(
243- RsaPrivateKey::from_pkcs1_pem(private_key_pem)
244- .map_err(|err| Error::CryptoError(err.to_string()))?,
245- ))
246+ pub fn from_rsa_pkcs1_pem(private_key_pem: &str) -> Result<Self> {
247+ let inner = RsaPrivateKey::from_pkcs1_pem(private_key_pem)
248+ .map_err(|err| Error::CryptoError(err.to_string()))?;
249+
250+ Ok(RsaKey {
251+ inner,
252+ padding: PhantomData,
253+ })
254 }
255
256 /// Creates a new RSA private key from a PKCS1 binary slice.
257- pub fn from_rsa_pkcs1_der(private_key_bytes: &[u8]) -> crate::Result<Self> {
258- Ok(PrivateKey::Rsa(
259- RsaPrivateKey::from_pkcs1_der(private_key_bytes)
260- .map_err(|err| Error::CryptoError(err.to_string()))?,
261- ))
262+ pub fn from_rsa_pkcs1_der(private_key_bytes: &[u8]) -> Result<Self> {
263+ let inner = RsaPrivateKey::from_pkcs1_der(private_key_bytes)
264+ .map_err(|err| Error::CryptoError(err.to_string()))?;
265+
266+ Ok(RsaKey {
267+ inner,
268+ padding: PhantomData,
269+ })
270+ }
271+ }
272+
273+ impl SigningKey for RsaKey<Sha1> {
274+ type Hasher = Sha1;
275+
276+ fn sign(&self, data: &Output<Self::Hasher>) -> Result<Vec<u8>> {
277+ self.inner
278+ .sign(PaddingScheme::new_pkcs1v15_sign::<Self::Hasher>(), data)
279+ .map_err(|err| Error::CryptoError(err.to_string()))
280+ }
281+
282+ fn algorithm(&self) -> Algorithm {
283+ Algorithm::RsaSha1
284+ }
285+ }
286+
287+ impl SigningKey for RsaKey<Sha256> {
288+ type Hasher = Sha256;
289+
290+ fn sign(&self, data: &Output<Self::Hasher>) -> Result<Vec<u8>> {
291+ self.inner
292+ .sign(PaddingScheme::new_pkcs1v15_sign::<Self::Hasher>(), data)
293+ .map_err(|err| Error::CryptoError(err.to_string()))
294 }
295
296+ fn algorithm(&self) -> Algorithm {
297+ Algorithm::RsaSha256
298+ }
299+ }
300+
301+ pub struct Ed25519Key {
302+ inner: ed25519_dalek::Keypair,
303+ }
304+
305+ impl Ed25519Key {
306 /// Creates an Ed25519 private key
307- pub fn from_ed25519(public_key_bytes: &[u8], private_key_bytes: &[u8]) -> crate::Result<Self> {
308- Ok(PrivateKey::Ed25519(ed25519_dalek::Keypair {
309- public: ed25519_dalek::PublicKey::from_bytes(public_key_bytes)
310- .map_err(|err| Error::CryptoError(err.to_string()))?,
311- secret: ed25519_dalek::SecretKey::from_bytes(private_key_bytes)
312- .map_err(|err| Error::CryptoError(err.to_string()))?,
313- }))
314+ pub fn from_bytes(public_key_bytes: &[u8], private_key_bytes: &[u8]) -> crate::Result<Self> {
315+ Ok(Self {
316+ inner: ed25519_dalek::Keypair {
317+ public: ed25519_dalek::PublicKey::from_bytes(public_key_bytes)
318+ .map_err(|err| Error::CryptoError(err.to_string()))?,
319+ secret: ed25519_dalek::SecretKey::from_bytes(private_key_bytes)
320+ .map_err(|err| Error::CryptoError(err.to_string()))?,
321+ },
322+ })
323+ }
324+ }
325+
326+ impl SigningKey for Ed25519Key {
327+ type Hasher = Sha256;
328+
329+ fn sign(&self, data: &Output<Self::Hasher>) -> Result<Vec<u8>> {
330+ Ok(self.inner.sign(data.as_ref()).to_bytes().to_vec())
331+ }
332+
333+ fn algorithm(&self) -> Algorithm {
334+ Algorithm::Ed25519Sha256
335 }
336 }
337
338 @@ -43,6 +118,18 @@ pub enum HashAlgorithm {
339 Sha256 = R_HASH_SHA256,
340 }
341
342+ impl TryFrom<&ObjectIdentifier> for HashAlgorithm {
343+ type Error = Error;
344+
345+ fn try_from(oid: &ObjectIdentifier) -> Result<Self> {
346+ match oid {
347+ oid if oid == &Sha256::OID => Ok(HashAlgorithm::Sha256),
348+ oid if oid == &Sha1::OID => Ok(HashAlgorithm::Sha1),
349+ _ => Err(Error::CryptoError("Unsupported hash algorithm".to_string())),
350+ }
351+ }
352+ }
353+
354 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
355 pub enum Algorithm {
356 RsaSha1,
357 diff --git a/src/dkim/sign.rs b/src/dkim/sign.rs
358index f20b8d6..cb77dde 100644
359--- a/src/dkim/sign.rs
360+++ b/src/dkim/sign.rs
361 @@ -8,17 +8,13 @@
362 * except according to those terms.
363 */
364
365- use std::{borrow::Cow, io, time::SystemTime};
366+ use std::{borrow::Cow, time::SystemTime};
367
368- use ed25519_dalek::Signer;
369 use mail_builder::encoders::base64::base64_encode;
370- use rsa::{pkcs8::AssociatedOid, PaddingScheme};
371- use sha1::Sha1;
372- use sha2::{Digest, Sha256};
373+ use sha1::Digest;
374
375- use crate::{Error, PrivateKey};
376-
377- use super::{Algorithm, Canonicalization, HashAlgorithm, Signature};
378+ use super::{Canonicalization, HashAlgorithm, Signature};
379+ use crate::{common::crypto::SigningKey, Error};
380
381 impl<'x> Signature<'x> {
382 /// Creates a new DKIM signature.
383 @@ -31,39 +27,28 @@ impl<'x> Signature<'x> {
384
385 /// Signs a message.
386 #[inline(always)]
387- pub fn sign(mut self, message: &'x [u8], with_key: &PrivateKey) -> crate::Result<Self> {
388+ pub fn sign(mut self, message: &'x [u8], with_key: &impl SigningKey) -> crate::Result<Self> {
389 if !self.d.is_empty() && !self.s.is_empty() && !self.h.is_empty() {
390 let now = SystemTime::now()
391 .duration_since(SystemTime::UNIX_EPOCH)
392 .map(|d| d.as_secs())
393 .unwrap_or(0);
394- match (self.a, with_key) {
395- (Algorithm::RsaSha256, PrivateKey::Rsa(_)) => {
396- self.sign_::<Sha256>(message, with_key, now)
397- }
398- (Algorithm::RsaSha1, PrivateKey::Rsa(_)) => {
399- self.sign_::<Sha1>(message, with_key, now)
400- }
401- (_, PrivateKey::Ed25519(_)) => {
402- self.a = Algorithm::Ed25519Sha256;
403- self.sign_::<Sha256>(message, with_key, now)
404- }
405- (_, PrivateKey::Rsa(_)) => {
406- self.a = Algorithm::RsaSha256;
407- self.sign_::<Sha256>(message, with_key, now)
408- }
409- }
410+
411+ self.a = with_key.algorithm();
412+ self.sign_(message, with_key, now)
413 } else {
414 Err(Error::MissingParameters)
415 }
416 }
417
418- fn sign_<T>(mut self, message: &'x [u8], with_key: &PrivateKey, now: u64) -> crate::Result<Self>
419- where
420- T: Digest + AssociatedOid + io::Write,
421- {
422- let mut body_hasher = T::new();
423- let mut header_hasher = T::new();
424+ fn sign_(
425+ mut self,
426+ message: &'x [u8],
427+ with_key: &impl SigningKey,
428+ now: u64,
429+ ) -> crate::Result<Self> {
430+ let mut body_hasher = with_key.hasher();
431+ let mut header_hasher = with_key.hasher();
432
433 // Canonicalize headers and body
434 let (body_len, signed_headers) =
435 @@ -86,17 +71,7 @@ impl<'x> Signature<'x> {
436 self.write(&mut header_hasher, false)?;
437
438 // Sign
439- let b = match with_key {
440- PrivateKey::Rsa(private_key) => private_key
441- .sign(
442- PaddingScheme::new_pkcs1v15_sign::<T>(),
443- &header_hasher.finalize(),
444- )
445- .map_err(|err| Error::CryptoError(err.to_string()))?,
446- PrivateKey::Ed25519(key_pair) => {
447- key_pair.sign(&header_hasher.finalize()).to_bytes().to_vec()
448- }
449- };
450+ let b = with_key.sign(&header_hasher.finalize())?;
451
452 // Encode
453 self.b = base64_encode(&b)?;
454 @@ -146,12 +121,6 @@ impl<'x> Signature<'x> {
455 self
456 }
457
458- /// Sets the algorithm to use (must be compatible with the private key provided).
459- pub fn algorithm(mut self, algorithm: Algorithm) -> Self {
460- self.a = algorithm;
461- self
462- }
463-
464 /// Include the body length in the signature.
465 pub fn body_length(mut self, body_length: bool) -> Self {
466 self.l = u64::from(body_length);
467 @@ -186,9 +155,12 @@ mod test {
468 use trust_dns_resolver::proto::op::ResponseCode;
469
470 use crate::{
471- common::parse::TxtRecordParser,
472+ common::{
473+ crypto::{Ed25519Key, RsaKey},
474+ parse::TxtRecordParser,
475+ },
476 dkim::{Atps, Canonicalization, DomainKey, DomainKeyReport, HashAlgorithm, Signature},
477- AuthenticatedMessage, DkimOutput, DkimResult, PrivateKey, Resolver,
478+ AuthenticatedMessage, DkimOutput, DkimResult, Resolver,
479 };
480
481 const RSA_PRIVATE_KEY: &str = r#"-----BEGIN RSA PRIVATE KEY-----
482 @@ -221,12 +193,12 @@ GMot/L2x0IYyMLAz6oLWh2hm7zwtb0CgOrPo1ke44hFYnfc=
483
484 #[test]
485 fn dkim_sign() {
486- let pk = PrivateKey::from_rsa_pkcs1_pem(RSA_PRIVATE_KEY).unwrap();
487+ let pk = RsaKey::<Sha256>::from_rsa_pkcs1_pem(RSA_PRIVATE_KEY).unwrap();
488 let signature = Signature::new()
489 .headers(["From", "To", "Subject"])
490 .domain("stalw.art")
491 .selector("default")
492- .sign_::<Sha256>(
493+ .sign_(
494 concat!(
495 "From: hello@stalw.art\r\n",
496 "To: dkim@stalw.art\r\n",
497 @@ -277,8 +249,8 @@ GMot/L2x0IYyMLAz6oLWh2hm7zwtb0CgOrPo1ke44hFYnfc=
498 );
499
500 // Create private keys
501- let pk_rsa = PrivateKey::from_rsa_pkcs1_pem(RSA_PRIVATE_KEY).unwrap();
502- let pk_ed = PrivateKey::from_ed25519(
503+ let pk_rsa = RsaKey::<Sha256>::from_rsa_pkcs1_pem(RSA_PRIVATE_KEY).unwrap();
504+ let pk_ed = Ed25519Key::from_bytes(
505 &base64_decode(ED25519_PUBLIC_KEY.rsplit_once("p=").unwrap().1.as_bytes()).unwrap(),
506 &base64_decode(ED25519_PRIVATE_KEY.as_bytes()).unwrap(),
507 )
508 @@ -393,7 +365,7 @@ GMot/L2x0IYyMLAz6oLWh2hm7zwtb0CgOrPo1ke44hFYnfc=
509 .selector("default")
510 .expiration(12345)
511 .reporting(true)
512- .sign_::<Sha256>(message.as_bytes(), &pk_rsa, 12345)
513+ .sign_(message.as_bytes(), &pk_rsa, 12345)
514 .unwrap(),
515 message,
516 Err(super::Error::SignatureExpired),
517 @@ -413,7 +385,7 @@ GMot/L2x0IYyMLAz6oLWh2hm7zwtb0CgOrPo1ke44hFYnfc=
518 .selector("default")
519 .atps("example.com")
520 .atpsh(HashAlgorithm::Sha256)
521- .sign_::<Sha256>(message.as_bytes(), &pk_rsa, 12345)
522+ .sign_(message.as_bytes(), &pk_rsa, 12345)
523 .unwrap(),
524 message,
525 Err(super::Error::DNSRecordNotFound(ResponseCode::NXDomain)),
526 @@ -434,7 +406,7 @@ GMot/L2x0IYyMLAz6oLWh2hm7zwtb0CgOrPo1ke44hFYnfc=
527 .selector("default")
528 .atps("example.com")
529 .atpsh(HashAlgorithm::Sha256)
530- .sign_::<Sha256>(message.as_bytes(), &pk_rsa, 12345)
531+ .sign_(message.as_bytes(), &pk_rsa, 12345)
532 .unwrap(),
533 message,
534 Ok(()),
535 @@ -454,7 +426,7 @@ GMot/L2x0IYyMLAz6oLWh2hm7zwtb0CgOrPo1ke44hFYnfc=
536 .domain("example.com")
537 .selector("default")
538 .atps("example.com")
539- .sign_::<Sha256>(message.as_bytes(), &pk_rsa, 12345)
540+ .sign_(message.as_bytes(), &pk_rsa, 12345)
541 .unwrap(),
542 message,
543 Ok(()),
544 diff --git a/src/lib.rs b/src/lib.rs
545index 01b5e16..3d90e4a 100644
546--- a/src/lib.rs
547+++ b/src/lib.rs
548 @@ -60,7 +60,7 @@
549 //!
550 //! ```rust
551 //! // Sign an e-mail message using RSA-SHA256
552- //! let pk_rsa = PrivateKey::from_rsa_pkcs1_pem(RSA_PRIVATE_KEY).unwrap();
553+ //! let pk_rsa = RsaKey::<Sha256>::from_rsa_pkcs1_pem(RSA_PRIVATE_KEY).unwrap();
554 //! let signature_rsa = Signature::new()
555 //! .headers(["From", "To", "Subject"])
556 //! .domain("example.com")
557 @@ -69,7 +69,7 @@
558 //! .unwrap();
559 //!
560 //! // Sign an e-mail message using ED25519-SHA256
561- //! let pk_ed = PrivateKey::from_ed25519(
562+ //! let pk_ed = Ed25519Key::from_bytes(
563 //! &base64_decode(ED25519_PUBLIC_KEY.as_bytes()).unwrap(),
564 //! &base64_decode(ED25519_PRIVATE_KEY.as_bytes()).unwrap(),
565 //! )
566 @@ -78,6 +78,7 @@
567 //! .headers(["From", "To", "Subject"])
568 //! .domain("example.com")
569 //! .selector("default-ed")
570+ //! .algorithm(Algorithm::Ed25519Sha256)
571 //! .sign(RFC5322_MESSAGE.as_bytes(), &pk_ed)
572 //! .unwrap();
573 //!
574 @@ -127,7 +128,7 @@
575 //! // Seal message
576 //! if arc_result.can_be_sealed() {
577 //! // Seal the e-mail message using RSA-SHA256
578- //! let pk_rsa = PrivateKey::from_rsa_pkcs1_pem(RSA_PRIVATE_KEY).unwrap();
579+ //! let pk_rsa = RsaKey::<Sha256>::from_rsa_pkcs1_pem(RSA_PRIVATE_KEY).unwrap();
580 //! let arc_set = ArcSet::new(&auth_results)
581 //! .domain("example.org")
582 //! .selector("default")
583 @@ -262,11 +263,7 @@ use std::{
584 };
585
586 use arc::Set;
587- use common::{
588- crypto::{HashAlgorithm, PrivateKey},
589- headers::Header,
590- lru::LruCache,
591- };
592+ use common::{crypto::HashAlgorithm, headers::Header, lru::LruCache};
593 use dkim::{Atps, Canonicalization, DomainKey, DomainKeyReport};
594 use dmarc::Dmarc;
595 use spf::{Macro, Spf};