1use argon2::Argon2;
8use chacha20poly1305::{
9 aead::{Aead, Payload},
10 AeadCore, ChaCha20Poly1305, Key, KeyInit, Nonce,
11};
12use ed25519_dalek::{Signature, Signer, SigningKey, VerifyingKey};
13use rand_core::OsRng;
14use snafu::Snafu;
15
16use crate::{
17 codec::{CodecError, Decodable, Encodable, Format, WritesEncodable},
18 sized_byte_array,
19 stream::Writes,
20 types::binary::hex_from_bytes,
21};
22
23use super::Coda;
24
25sized_byte_array!(
26 HashBytes,
28 32
29);
30
31sized_byte_array!(
32 PrivateKeyBytes,
34 32
35);
36
37sized_byte_array!(
38 PublicKeyBytes,
40 32
41);
42
43sized_byte_array!(
44 SignatureBytes,
46 64
47);
48
49#[derive(Default)]
51pub struct CryptoHasher {
52 hasher: blake3::Hasher,
53}
54
55impl CryptoHasher {
56 pub fn write(&mut self, bytes: &[u8]) {
58 self.hasher.update(bytes);
59 }
60
61 pub fn finalize(self) -> HashBytes {
63 HashBytes::from(*self.hasher.finalize().as_bytes())
64 }
65
66 pub fn finalize_into_bytes(self, bytes: &mut HashBytes) {
68 bytes.0 = *self.hasher.finalize().as_bytes();
69 }
70}
71
72impl Writes for CryptoHasher {
73 fn write(&mut self, buf: &[u8]) -> Result<usize, crate::stream::StreamError> {
74 self.hasher.update(buf);
75 Ok(buf.len())
76 }
77
78 fn write_all(&mut self, buf: &[u8]) -> Result<(), crate::stream::StreamError> {
79 self.hasher.update(buf);
80 Ok(())
81 }
82}
83
84pub struct CryptoKeys {
88 signer: CryptoSigner,
89 verifier: CryptoVerifier,
90}
91
92impl CryptoKeys {
93 pub fn generate() -> Self {
95 let mut rng = OsRng;
96 let signer = SigningKey::generate(&mut rng);
97 let verifier = signer.verifying_key();
98 CryptoKeys {
99 signer: CryptoSigner {
100 private_key: signer,
101 },
102 verifier: CryptoVerifier {
103 public_key: verifier,
104 },
105 }
106 }
107
108 pub fn from_private(private_key: PrivateKeyBytes) -> Result<Self, CryptoError> {
111 let signer = SigningKey::from_bytes(&private_key.0);
112 let verifier = signer.verifying_key();
113 Ok(CryptoKeys {
114 signer: CryptoSigner {
115 private_key: signer,
116 },
117 verifier: CryptoVerifier {
118 public_key: verifier,
119 },
120 })
121 }
122
123 pub fn into_private(self) -> PrivateKeyBytes {
126 let mut bytes = PrivateKeyBytes::default();
127 let private_key = &self.signer.private_key.to_keypair_bytes()[0..PrivateKeyBytes::SIZE];
128 bytes.copy_from_slice(private_key);
129 bytes
130 }
131}
132
133pub struct CryptoSigner {
136 private_key: SigningKey,
137}
138
139#[derive(Copy, Clone, Debug)]
142pub struct CryptoVerifier {
143 public_key: VerifyingKey,
144}
145
146impl TryFrom<&PublicKeyBytes> for CryptoVerifier {
147 type Error = CryptoError;
148
149 fn try_from(public_key: &PublicKeyBytes) -> Result<Self, Self::Error> {
150 let public_key =
151 VerifyingKey::from_bytes(&public_key.0).map_err(|_| CryptoError::InvalidPublicKey {
152 pub_key: *public_key,
153 })?;
154
155 Ok(CryptoVerifier { public_key })
156 }
157}
158
159#[derive(Copy, Clone, Debug, Default)]
164pub struct CryptoCert {
165 pub public_key: PublicKeyBytes,
168
169 pub signature: SignatureBytes,
171}
172
173impl CryptoCert {
174 pub fn sign(
177 &mut self,
178 signer: &impl CryptoSigns,
179 data: &[&[u8]],
180 ) -> core::result::Result<(), CryptoError> {
181 self.public_key = signer.public_key_bytes();
182 self.signature = signer.sign(data)?;
183
184 Ok(())
185 }
186
187 pub fn verify(&self, data: &[&[u8]]) -> core::result::Result<(), CryptoError> {
190 let key = CryptoVerifier::try_from(&self.public_key)?;
191 key.verify(data, &self.signature)
192 }
193}
194
195impl Eq for CryptoCert {}
196impl PartialEq for CryptoCert {
197 fn eq(&self, other: &Self) -> bool {
198 self.public_key == other.public_key && self.signature == other.signature
199 }
200}
201
202impl Ord for CryptoCert {
203 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
204 self.signature.cmp(&other.signature)
205 }
206}
207
208impl PartialOrd for CryptoCert {
209 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
210 Some(self.cmp(other))
211 }
212}
213
214impl core::hash::Hash for CryptoCert {
215 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
216 self.public_key.hash(state);
217 self.signature.hash(state);
218 }
219}
220
221impl Encodable for CryptoCert {
222 const FORMAT: Format = PublicKeyBytes::FORMAT.with(SignatureBytes::FORMAT);
223
224 fn encode(&self, writer: &mut (impl WritesEncodable + ?Sized)) -> Result<(), CodecError> {
225 writer.write_data(&self.public_key)?;
226 writer.write_data(&self.signature)?;
227 Ok(())
228 }
229}
230
231impl Decodable for CryptoCert {
232 fn decode(
233 &mut self,
234 reader: &mut (impl crate::codec::ReadsDecodable + ?Sized),
235 header: Option<crate::codec::DataHeader>,
236 ) -> Result<(), CodecError> {
237 Self::ensure_no_header(header)?;
238 reader.read_data_into(&mut self.public_key)?;
239 reader.read_data_into(&mut self.signature)?;
240 Ok(())
241 }
242}
243
244pub trait HasCryptoHash {
246 fn crypto_hash_into(&self, hasher: &mut CryptoHasher);
249
250 fn crypto_hasher(&self) -> CryptoHasher {
260 let mut hasher = CryptoHasher::default();
261 self.crypto_hash_into(&mut hasher);
262 hasher
263 }
264}
265
266impl HasCryptoHash for CryptoCert {
267 fn crypto_hash_into(&self, hasher: &mut CryptoHasher) {
268 hasher.write(&self.signature);
269 }
270}
271
272impl HasCryptoHash for Coda {
273 fn crypto_hash_into(&self, hasher: &mut CryptoHasher) {
274 let _ = self.encode(hasher);
275 }
276}
277
278pub trait HasCryptoPublicKey {
280 fn public_key_bytes(&self) -> PublicKeyBytes;
282}
283
284impl HasCryptoPublicKey for CryptoKeys {
285 fn public_key_bytes(&self) -> PublicKeyBytes {
286 self.verifier.public_key_bytes()
287 }
288}
289
290impl HasCryptoPublicKey for CryptoSigner {
291 fn public_key_bytes(&self) -> PublicKeyBytes {
292 (*self.private_key.verifying_key().as_bytes()).into()
293 }
294}
295
296impl HasCryptoPublicKey for CryptoVerifier {
297 fn public_key_bytes(&self) -> PublicKeyBytes {
298 (*self.public_key.as_bytes()).into()
299 }
300}
301
302pub trait CryptoSigns: HasCryptoPublicKey {
304 fn sign(&self, message: &[&[u8]]) -> Result<SignatureBytes, CryptoError>;
307}
308
309impl CryptoSigns for CryptoKeys {
310 fn sign(&self, message: &[&[u8]]) -> Result<SignatureBytes, CryptoError> {
311 self.signer.sign(message)
312 }
313}
314
315impl CryptoSigns for CryptoSigner {
316 fn sign(&self, message: &[&[u8]]) -> Result<SignatureBytes, CryptoError> {
317 let signature = self
318 .private_key
319 .try_sign(message.concat().as_slice())
320 .expect("signing failure");
321 Ok(signature.to_bytes().into())
322 }
323}
324
325pub trait CryptoVerifies: HasCryptoPublicKey {
327 fn verify(&self, message: &[&[u8]], signature: &SignatureBytes) -> Result<(), CryptoError>;
332}
333
334impl CryptoVerifies for CryptoKeys {
335 fn verify(&self, message: &[&[u8]], signature: &SignatureBytes) -> Result<(), CryptoError> {
336 self.verifier.verify(message, signature)
337 }
338}
339
340impl CryptoVerifies for CryptoVerifier {
341 fn verify(&self, message: &[&[u8]], signature: &SignatureBytes) -> Result<(), CryptoError> {
342 let message = message.concat();
343 let message = message.as_slice();
344 let sig = Signature::from_bytes(&signature.0);
345 self.public_key
346 .verify_strict(message, &sig)
347 .map_err(|_| CryptoError::InvalidSignature {
348 signature: *signature,
349 })
350 }
351}
352
353#[derive(Default)]
356pub struct EncryptedData {
357 nonce: [u8; 12],
360
361 data: alloc::vec::Vec<u8>,
363}
364
365impl EncryptedData {
366 pub fn new(key: &[u8], data: &[u8]) -> Result<Self, CryptoError> {
368 let nonce = ChaCha20Poly1305::generate_nonce(&mut OsRng);
370
371 let mut derived_key = [0u8; 32];
373 Argon2::default().hash_password_into(key, nonce.as_ref(), &mut derived_key)?;
374 let cipher = ChaCha20Poly1305::new(&Key::from(derived_key));
375
376 let encrypted = cipher.encrypt(
378 &nonce,
379 Payload {
380 msg: data,
381 aad: &nonce,
382 },
383 )?;
384
385 Ok(Self {
386 nonce: nonce.into(),
387 data: encrypted,
388 })
389 }
390
391 pub fn decrypt(&self, key: &[u8]) -> Result<alloc::vec::Vec<u8>, CryptoError> {
394 let mut derived_key = [0u8; 32];
396 Argon2::default().hash_password_into(key, self.nonce.as_ref(), &mut derived_key)?;
397 let cipher = ChaCha20Poly1305::new(&Key::from(derived_key));
398
399 let decrypted = cipher.decrypt(
401 Nonce::from_slice(&self.nonce),
402 Payload {
403 msg: &self.data,
404 aad: &self.nonce,
405 },
406 )?;
407
408 Ok(decrypted)
409 }
410
411 pub fn to_hex(&self) -> alloc::string::String {
415 alloc::format!(
416 "{}-{}",
417 hex_from_bytes(&self.nonce),
418 hex_from_bytes(&self.data)
419 )
420 }
421
422 pub fn from_hex(hex: &str) -> Result<Self, CryptoError> {
426 let (nonce, key) = hex.split_once('-').ok_or(CryptoError::Malformed)?;
427 let nonce = super::binary::bytes_from_hex(nonce).map_err(|_| CryptoError::Malformed)?;
428 let key = super::binary::bytes_from_hex(key).map_err(|_| CryptoError::Malformed)?;
429
430 Ok(EncryptedData {
431 nonce: nonce.try_into().map_err(|_| CryptoError::Malformed)?,
432 data: key,
433 })
434 }
435}
436
437impl Encodable for EncryptedData {
438 const FORMAT: Format = Format::data(0)
439 .with(<[u8; 12]>::FORMAT)
440 .with(alloc::vec::Vec::<u8>::FORMAT);
441
442 fn encode(&self, writer: &mut (impl WritesEncodable + ?Sized)) -> Result<(), CodecError> {
443 writer.write_data(&self.nonce)?;
444 writer.write_data(&self.data)?;
445 Ok(())
446 }
447}
448
449impl Decodable for EncryptedData {
450 fn decode(
451 &mut self,
452 reader: &mut (impl crate::codec::ReadsDecodable + ?Sized),
453 header: Option<crate::codec::DataHeader>,
454 ) -> Result<(), CodecError> {
455 Self::ensure_header(header, &[0])?;
456 reader.read_data_into(&mut self.nonce)?;
457 reader.read_data_into(&mut self.data)?;
458 Ok(())
459 }
460}
461
462#[derive(Debug, Snafu, Clone)]
464pub enum CryptoError {
465 #[snafu(display("the private key could not be loaded as an Ed25519 private key"))]
466 InvalidPrivateKey,
467
468 #[snafu(display("{pub_key} could not be loaded as an Ed25519 public key"))]
469 InvalidPublicKey { pub_key: PublicKeyBytes },
470
471 #[snafu(display("{signature} was not a valid Ed25519 signature for the provided message"))]
472 InvalidSignature { signature: SignatureBytes },
473
474 #[snafu(display("deriving a cryptographic key failed: {message}"))]
475 KeyDerivationFailure { message: alloc::string::String },
476
477 #[snafu(display("encrypting or decrypting data failed: {message}"))]
478 CipherFailure { message: alloc::string::String },
479
480 #[snafu(display("the provided input was malformed or corrupt"))]
481 Malformed,
482}
483
484impl From<argon2::Error> for CryptoError {
485 fn from(value: argon2::Error) -> Self {
486 Self::KeyDerivationFailure {
487 message: <argon2::Error as crate::alloc::string::ToString>::to_string(&value),
488 }
489 }
490}
491
492impl From<chacha20poly1305::Error> for CryptoError {
493 fn from(value: chacha20poly1305::Error) -> Self {
494 Self::CipherFailure {
495 message: <chacha20poly1305::Error as crate::alloc::string::ToString>::to_string(&value),
496 }
497 }
498}
499
500#[cfg(test)]
501mod tests {
502
503 use crate::codec::ReadsDecodable;
504
505 use super::*;
506
507 #[test]
508 fn encrypted_data() {
509 let key = b"cupc4k3s";
510 let message = b"i'm so secret.";
511
512 let mut encrypted = EncryptedData::new(key, message).unwrap();
514 let decrypted = encrypted.decrypt(key).unwrap();
515 assert_eq!(message, decrypted.as_slice());
516
517 let mut encrypted_too = EncryptedData::new(key, message).unwrap();
519 assert_ne!(encrypted_too.data, encrypted.data);
520 assert_ne!(encrypted_too.nonce, encrypted.nonce);
521
522 encrypted.nonce.fill(0u8);
524 assert!(encrypted.decrypt(key).is_err());
525
526 encrypted_too.data.fill(0u8);
528 assert!(encrypted_too.decrypt(key).is_err());
529 }
530
531 #[test]
532 fn encrypted_data_codas_codec() {
533 let key = b"p4nc4k3s";
534 let message = b"i'm pretty secret.";
535
536 let encrypted = EncryptedData::new(key, message).unwrap();
538
539 let mut encoded = vec![];
541 encoded.write_data(&encrypted).unwrap();
542
543 let decoded: EncryptedData = encoded.as_slice().read_data().unwrap();
545
546 let decrypted = decoded.decrypt(key).unwrap();
548 assert_eq!(message, decrypted.as_slice());
549 }
550
551 #[test]
552 fn encrypted_data_hex_codec() {
553 let key = b"p4nc4k3s";
554 let message = b"i'm pretty secret.";
555
556 let encrypted = EncryptedData::new(key, message).unwrap();
558
559 let encoded = encrypted.to_hex();
561
562 let mut bytes = vec![];
563 bytes.write_data(&encrypted).unwrap();
564 eprintln!("raw hex: {encoded}");
565 eprintln!("\n\ncoda hx: {}", hex_from_bytes(&bytes));
566
567 let decoded = EncryptedData::from_hex(&encoded).unwrap();
569 assert_eq!(encrypted.nonce, decoded.nonce);
570 assert_eq!(encrypted.data, decoded.data);
571 }
572}