exonum_crypto/lib.rs
1// Copyright 2020 The Exonum Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Cryptography related types, constants, traits and functions. The functions
16//! in this library are used for key generation, hashing, signing and signature
17//! verification.
18//!
19//! The Crypto library makes it possible to potentially change the type of
20//! cryptography applied in the system and add abstractions best
21//! suited for Exonum.
22
23#![warn(
24 missing_debug_implementations,
25 missing_docs,
26 unsafe_code,
27 bare_trait_objects
28)]
29#![warn(clippy::pedantic, clippy::nursery)]
30#![allow(
31 // Next `cast_*` lints don't give alternatives.
32 clippy::cast_possible_wrap, clippy::cast_possible_truncation, clippy::cast_sign_loss,
33 // Next lints produce too much noise/false positives.
34 clippy::module_name_repetitions, clippy::similar_names, clippy::must_use_candidate,
35 clippy::pub_enum_variant_names,
36 // '... may panic' lints.
37 clippy::indexing_slicing,
38 // Too much work to fix.
39 clippy::missing_errors_doc, clippy::missing_const_for_fn
40)]
41
42#[macro_use]
43extern crate serde_derive; // Required for Protobuf.
44
45#[doc(inline)]
46pub use self::crypto_impl::{
47 HASH_SIZE, PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, SEED_LENGTH, SIGNATURE_LENGTH,
48};
49#[cfg(feature = "sodiumoxide-crypto")]
50pub use self::crypto_lib::sodiumoxide::x25519;
51
52#[cfg(feature = "with-protobuf")]
53#[doc(hidden)]
54pub mod proto;
55
56use hex::{encode as encode_hex, FromHex, FromHexError, ToHex};
57use serde::{
58 de::{self, Deserialize, Deserializer, Visitor},
59 Serialize, Serializer,
60};
61
62use std::{
63 default::Default,
64 fmt,
65 ops::{Index, Range, RangeFrom, RangeFull, RangeTo},
66};
67
68// A way to set an active cryptographic backend is to export it as `crypto_impl`.
69#[cfg(feature = "sodiumoxide-crypto")]
70use self::crypto_lib::sodiumoxide as crypto_impl;
71
72#[macro_use]
73mod macros;
74
75pub(crate) mod crypto_lib;
76
77/// The size to crop the string in debug messages.
78const BYTES_IN_DEBUG: usize = 4;
79
80fn write_short_hex(f: &mut fmt::Formatter<'_>, slice: &[u8]) -> fmt::Result {
81 for byte in slice.iter().take(BYTES_IN_DEBUG) {
82 write!(f, "{:02x}", byte)?;
83 }
84 if slice.len() > BYTES_IN_DEBUG {
85 write!(f, "...")?;
86 }
87 Ok(())
88}
89
90/// Signs a slice of bytes using the signer's secret key and returns the
91/// resulting `Signature`.
92///
93/// # Examples
94///
95/// The example below generates a pair of secret and public keys, indicates
96/// certain data, signs the data using the secret key and with the help of
97/// the public key verifies that the data have been signed with the corresponding
98/// secret key.
99///
100/// ```
101/// # exonum_crypto::init();
102/// let (public_key, secret_key) = exonum_crypto::gen_keypair();
103/// let data = [1, 2, 3];
104/// let signature = exonum_crypto::sign(&data, &secret_key);
105/// assert!(exonum_crypto::verify(&signature, &data, &public_key));
106/// ```
107pub fn sign(data: &[u8], secret_key: &SecretKey) -> Signature {
108 let impl_signature = crypto_impl::sign(data, &secret_key.0);
109 Signature(impl_signature)
110}
111
112/// Computes a secret key and a corresponding public key from a `Seed`.
113///
114/// # Examples
115///
116/// The example below generates a keypair that depends on the indicated seed.
117/// Indicating the same seed value always results in the same keypair.
118///
119/// ```
120/// use exonum_crypto::{SEED_LENGTH, Seed};
121///
122/// # exonum_crypto::init();
123/// let (public_key, secret_key) = exonum_crypto::gen_keypair_from_seed(&Seed::new([1; SEED_LENGTH]));
124/// ```
125pub fn gen_keypair_from_seed(seed: &Seed) -> (PublicKey, SecretKey) {
126 let (impl_pub_key, impl_secret_key) = crypto_impl::gen_keypair_from_seed(&seed.0);
127 (PublicKey(impl_pub_key), SecretKey(impl_secret_key))
128}
129
130/// Generates a secret key and a corresponding public key using a cryptographically secure
131/// pseudo-random number generator.
132///
133/// # Examples
134///
135/// The example below generates a unique keypair.
136///
137/// ```
138/// # exonum_crypto::init();
139/// let (public_key, secret_key) = exonum_crypto::gen_keypair();
140/// ```
141pub fn gen_keypair() -> (PublicKey, SecretKey) {
142 let (pubkey, secret_key) = crypto_impl::gen_keypair();
143 (PublicKey(pubkey), SecretKey(secret_key))
144}
145
146/// Verifies that `data` is signed with a secret key corresponding to the
147/// given public key.
148///
149/// # Examples
150///
151/// The example below generates a pair of secret and public keys, indicates
152/// certain data, signs the data using the secret key and with the help of the public key
153/// verifies that the data have been signed with the corresponding secret key.
154///
155/// ```
156/// # exonum_crypto::init();
157/// let (public_key, secret_key) = exonum_crypto::gen_keypair();
158/// let data = [1, 2, 3];
159/// let signature = exonum_crypto::sign(&data, &secret_key);
160/// assert!(exonum_crypto::verify(&signature, &data, &public_key));
161/// ```
162pub fn verify(sig: &Signature, data: &[u8], pubkey: &PublicKey) -> bool {
163 crypto_impl::verify(&sig.0, data, &pubkey.0)
164}
165
166/// Calculates a hash of a bytes slice.
167///
168/// Type of a hash depends on a chosen crypto backend (via `...-crypto` cargo feature).
169///
170/// # Examples
171///
172/// The example below calculates the hash of the indicated data.
173///
174/// ```
175/// # exonum_crypto::init();
176/// let data = [1, 2, 3];
177/// let hash = exonum_crypto::hash(&data);
178/// ```
179pub fn hash(data: &[u8]) -> Hash {
180 let dig = crypto_impl::hash(data);
181 Hash(dig)
182}
183
184/// Initializes the cryptographic backend.
185///
186/// # Panics
187///
188/// Panics if backend initialization is failed.
189///
190/// # Examples
191///
192/// ```
193/// exonum_crypto::init();
194/// ```
195pub fn init() {
196 if !crypto_impl::init() {
197 panic!("Cryptographic library initialization failed.");
198 }
199}
200
201/// This structure provides a possibility to calculate a hash digest
202/// for a stream of data. Unlike the
203/// [`Hash` structure](struct.Hash.html),
204/// the given structure lets the code process several data chunks without
205/// the need to copy them into a single buffer.
206///
207/// # Examples
208///
209/// The example below indicates the data the code is working with; runs the
210/// system hash update as many times as required to process all the data chunks
211/// and calculates the resulting hash of the system.
212///
213/// ```rust
214/// use exonum_crypto::HashStream;
215///
216/// let data: Vec<[u8; 5]> = vec![[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]];
217/// let mut hash_stream = HashStream::new();
218/// for chunk in data {
219/// hash_stream = hash_stream.update(&chunk);
220/// }
221/// let _ = hash_stream.hash();
222/// ```
223#[derive(Debug, Default)]
224pub struct HashStream(crypto_impl::HashState);
225
226impl HashStream {
227 /// Creates a new instance of `HashStream`.
228 pub fn new() -> Self {
229 Self(crypto_impl::HashState::init())
230 }
231
232 /// Processes a chunk of stream and returns a `HashStream` with the updated internal state.
233 pub fn update(mut self, chunk: &[u8]) -> Self {
234 self.0.update(chunk);
235 self
236 }
237
238 /// Returns the resulting hash of the system calculated upon the commit
239 /// of currently supplied data.
240 pub fn hash(self) -> Hash {
241 let dig = self.0.finalize();
242 Hash(dig)
243 }
244}
245
246/// This structure provides a possibility to create and/or verify
247/// digital signatures for a stream of data. If the data are split into several
248/// chunks, the indicated chunks are added to the system and when adding is
249/// complete, the data is signed.
250///
251/// # Examples
252///
253/// The example below adds several data chunks to the system, generates a pair
254/// of random public and secret keys, signs the data and verifies the signature.
255///
256/// ```rust
257/// use exonum_crypto::{SignStream, gen_keypair};
258///
259/// let data: Vec<[u8; 5]> = vec![[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]];
260/// let (public_key, secret_key) = gen_keypair();
261/// let mut create_stream = SignStream::new();
262/// let mut verify_stream = SignStream::new();
263/// for chunk in data {
264/// create_stream = create_stream.update(&chunk);
265/// verify_stream = verify_stream.update(&chunk);
266/// }
267/// let file_sign = create_stream.sign(&secret_key);
268/// assert!(verify_stream.verify(&file_sign, &public_key));
269/// ```
270#[derive(Debug, Default)]
271pub struct SignStream(crypto_impl::SignState);
272
273impl SignStream {
274 /// Creates a new instance of `SignStream`.
275 ///
276 /// # Examples
277 ///
278 /// ```
279 /// use exonum_crypto::SignStream;
280 ///
281 /// let stream = SignStream::new();
282 /// ```
283 pub fn new() -> Self {
284 Self(crypto_impl::SignState::init())
285 }
286
287 /// Adds a new `chunk` to the message that will eventually be signed and/or verified.
288 ///
289 /// # Examples
290 ///
291 /// ```
292 /// use exonum_crypto::SignStream;
293 ///
294 /// let mut stream = SignStream::new();
295 ///
296 /// let data = &[[1, 2, 3], [4, 5, 6], [7, 8, 9]];
297 /// for chunk in data.iter() {
298 /// stream = stream.update(chunk);
299 /// }
300 /// ```
301 pub fn update(mut self, chunk: &[u8]) -> Self {
302 self.0.update(chunk);
303 self
304 }
305
306 /// Computes and returns a signature for the previously supplied message
307 /// using the given `secret_key`.
308 ///
309 /// # Examples
310 ///
311 /// ```
312 /// use exonum_crypto::{SignStream, gen_keypair};
313 ///
314 /// let mut stream = SignStream::new();
315 ///
316 /// let data = &[[1, 2, 3], [4, 5, 6], [7, 8, 9]];
317 /// for chunk in data.iter() {
318 /// stream = stream.update(chunk);
319 /// }
320 ///
321 /// let (public_key, secret_key) = gen_keypair();
322 /// let signature = stream.sign(&secret_key);
323 /// ```
324 pub fn sign(&mut self, secret_key: &SecretKey) -> Signature {
325 Signature(self.0.finalize(&secret_key.0))
326 }
327
328 /// Verifies that `sig` is a valid signature for the previously supplied message
329 /// using the given `public_key`.
330 ///
331 /// # Examples
332 ///
333 /// ```
334 /// use exonum_crypto::{SignStream, gen_keypair};
335 ///
336 /// let mut stream = SignStream::new();
337 /// let mut verify_stream = SignStream::new();
338 ///
339 /// let data = &[[1, 2, 3], [4, 5, 6], [7, 8, 9]];
340 /// for chunk in data.iter() {
341 /// stream = stream.update(chunk);
342 /// verify_stream = verify_stream.update(chunk);
343 /// }
344 ///
345 /// let (public_key, secret_key) = gen_keypair();
346 /// let signature = stream.sign(&secret_key);
347 /// assert!(verify_stream.verify(&signature, &public_key));
348 /// ```
349 pub fn verify(&mut self, sig: &Signature, public_key: &PublicKey) -> bool {
350 self.0.verify(&sig.0, &public_key.0)
351 }
352}
353
354implement_public_crypto_wrapper! {
355/// Ed25519 public key used to verify digital signatures.
356///
357/// In public-key cryptography, the system uses a a mathematically related pair
358/// of keys: a public key, which is openly distributed, and a secret key,
359/// which should remain confidential. For more information, refer to
360/// [Public-key cryptography](https://en.wikipedia.org/wiki/Public-key_cryptography).
361///
362/// Ed25519 is a signature system that ensures fast signing and key generation,
363/// as well as security and collision resilience.
364///
365/// # Examples
366///
367/// In the example below, the function generates a pair of random public and
368/// secret keys.
369///
370/// ```
371/// # exonum_crypto::init();
372/// let (public_key, _) = exonum_crypto::gen_keypair();
373/// ```
374 struct PublicKey, PUBLIC_KEY_LENGTH
375}
376
377implement_private_crypto_wrapper! {
378/// Ed25519 secret key used to create digital signatures over messages.
379///
380/// In public-key cryptography, the system uses a a mathematically related pair
381/// of keys: a public key, which is openly distributed, and a secret key,
382/// which should remain confidential. For more information, refer to
383/// [Public-key cryptography](https://en.wikipedia.org/wiki/Public-key_cryptography).
384///
385/// Ed25519 is a signature system that ensures fast signing and key generation,
386/// as well as security and collision resilience.
387///
388/// # Examples
389///
390/// In the example below, the function generates a pair of random public and
391/// secret keys.
392///
393/// ```
394/// # exonum_crypto::init();
395/// let (_, secret_key) = exonum_crypto::gen_keypair();
396/// ```
397 struct SecretKey, SECRET_KEY_LENGTH
398}
399
400implement_public_crypto_wrapper! {
401/// The result of applying the SHA-256 hash function to data.
402///
403/// This function splits the input data into blocks and runs each block
404/// through a cycle of 64 iterations. The result of the function is a hash
405/// 256 bits or 32 bytes in length.
406///
407/// # Examples
408///
409/// The example below generates the hash of the indicated data.
410///
411/// ```
412/// use exonum_crypto::Hash;
413///
414/// let data = [1, 2, 3];
415/// let hash_from_data = exonum_crypto::hash(&data);
416/// let default_hash = Hash::default();
417/// ```
418 struct Hash, HASH_SIZE
419}
420
421implement_public_crypto_wrapper! {
422/// Ed25519 digital signature. This structure creates a signature over data
423/// using a secret key. Later it is possible to verify, using the corresponding
424/// public key, that the data have indeed been signed with that secret key.
425///
426/// Ed25519 is a signature system that ensures fast signing and key generation,
427/// as well as security and collision resilience.
428///
429/// # Examples
430///
431/// The example below generates a pair of random public and secret keys,
432/// adds certain data, signs the data using the secret key and verifies
433/// that the data have been signed with that secret key.
434///
435/// ```
436/// # exonum_crypto::init();
437/// let (public_key, secret_key) = exonum_crypto::gen_keypair();
438/// let data = [1, 2, 3];
439/// let signature = exonum_crypto::sign(&data, &secret_key);
440/// assert!(exonum_crypto::verify(&signature, &data, &public_key));
441/// ```
442 struct Signature, SIGNATURE_LENGTH
443}
444
445implement_private_crypto_wrapper! {
446/// Ed25519 seed representing a succession of bytes that can be used for
447/// deterministic keypair generation. If the same seed is indicated in the
448/// generator multiple times, the generated keys will be the same each time.
449///
450/// Note that this is not the seed added to Exonum transactions for additional
451/// security, this is a separate entity. This structure is useful for testing,
452/// to receive repeatable results. The seed in this structure is either set
453/// manually or selected using the methods below.
454///
455/// # Examples
456///
457/// The example below generates a pair of public and secret keys taking
458/// into account the selected seed. The same seed will always lead to
459/// generation of the same keypair.
460///
461/// ```
462/// use exonum_crypto::{SEED_LENGTH, Seed};
463///
464/// # exonum_crypto::init();
465/// let (public_key, secret_key) = exonum_crypto::gen_keypair_from_seed(&Seed::new([1; SEED_LENGTH]));
466/// ```
467 struct Seed, SEED_LENGTH
468}
469
470implement_serde! {Hash}
471implement_serde! {PublicKey}
472implement_serde! {SecretKey}
473implement_serde! {Seed}
474implement_serde! {Signature}
475
476implement_index_traits! {Hash}
477implement_index_traits! {PublicKey}
478implement_index_traits! {SecretKey}
479implement_index_traits! {Seed}
480implement_index_traits! {Signature}
481
482/// Pair of matching secret and public keys.
483///
484/// Prefer using this struct to `(PublicKey, SecretKey)`, since it asserts that public
485/// and secret keys necessarily match.
486#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
487pub struct KeyPair {
488 public_key: PublicKey,
489 secret_key: SecretKey,
490}
491
492impl KeyPair {
493 /// Creates a keypair from the provided keys, checking that they correspond to each other.
494 ///
495 /// # Panics
496 ///
497 /// - If the keys do not match.
498 pub fn from_keys(public_key: PublicKey, secret_key: SecretKey) -> Self {
499 assert!(
500 verify_keys_match(&public_key, &secret_key),
501 "Public key does not match the secret key."
502 );
503
504 Self {
505 public_key,
506 secret_key,
507 }
508 }
509
510 /// Generates a random keypair using the random number generator provided by the crypto backend.
511 pub fn random() -> Self {
512 let (public_key, secret_key) = gen_keypair();
513 Self {
514 public_key,
515 secret_key,
516 }
517 }
518
519 /// Generates a keypair from the provided seed.
520 pub fn from_seed(seed: &Seed) -> Self {
521 let (public_key, secret_key) = gen_keypair_from_seed(seed);
522 Self {
523 public_key,
524 secret_key,
525 }
526 }
527
528 /// Gets the public key.
529 pub fn public_key(&self) -> PublicKey {
530 self.public_key
531 }
532
533 /// Gets a reference to the secret key.
534 pub fn secret_key(&self) -> &SecretKey {
535 &self.secret_key
536 }
537}
538
539impl From<(PublicKey, SecretKey)> for KeyPair {
540 fn from(keys: (PublicKey, SecretKey)) -> Self {
541 Self::from_keys(keys.0, keys.1)
542 }
543}
544
545fn verify_keys_match(public_key: &PublicKey, secret_key: &SecretKey) -> bool {
546 crypto_impl::verify_keys_match(&public_key.0, &secret_key.0)
547}
548
549#[cfg(test)]
550mod tests {
551 use super::*;
552
553 use serde::de::DeserializeOwned;
554
555 use hex::FromHex;
556
557 #[test]
558 fn to_from_hex_hash() {
559 let original = hash(&[]);
560 let from_hex = Hash::from_hex(original.to_hex()).unwrap();
561 assert_eq!(original, from_hex);
562 }
563
564 #[test]
565 fn zero_hash() {
566 let hash = Hash::zero();
567 assert_eq!(hash.as_ref(), [0; HASH_SIZE]);
568 }
569
570 #[test]
571 fn to_from_hex_keys() {
572 let (p, s) = gen_keypair();
573
574 let ph = PublicKey::from_hex(p.to_hex()).unwrap();
575 assert_eq!(p, ph);
576
577 let sh = SecretKey::from_hex(s.to_hex()).unwrap();
578 assert_eq!(s, sh);
579 }
580
581 #[test]
582 fn serialize_deserialize_hash() {
583 assert_serialize_deserialize(&Hash::new([207; HASH_SIZE]));
584 }
585
586 #[test]
587 fn serialize_deserialize_public_key() {
588 assert_serialize_deserialize(&PublicKey::new([208; PUBLIC_KEY_LENGTH]));
589 }
590
591 #[test]
592 fn serialize_deserialize_signature() {
593 assert_serialize_deserialize(&Signature::new([209; SIGNATURE_LENGTH]));
594 }
595
596 #[test]
597 fn serialize_deserialize_seed() {
598 assert_serialize_deserialize(&Seed::new([210; SEED_LENGTH]));
599 }
600
601 #[test]
602 fn serialize_deserialize_secret_key() {
603 assert_serialize_deserialize(&SecretKey::new([211; SECRET_KEY_LENGTH]));
604 }
605
606 #[test]
607 fn debug_format() {
608 // Check zero padding.
609 let hash = Hash::new([1; HASH_SIZE]);
610 assert_eq!(format!("{:?}", &hash), "Hash(01010101...)");
611
612 let pk = PublicKey::new([15; PUBLIC_KEY_LENGTH]);
613 assert_eq!(format!("{:?}", &pk), "PublicKey(0f0f0f0f...)");
614 let sk = SecretKey::new([8; SECRET_KEY_LENGTH]);
615 assert_eq!(format!("{:?}", &sk), "SecretKey(08080808...)");
616 let signature = Signature::new([10; SIGNATURE_LENGTH]);
617 assert_eq!(format!("{:?}", &signature), "Signature(0a0a0a0a...)");
618 let seed = Seed::new([4; SEED_LENGTH]);
619 assert_eq!(format!("{:?}", &seed), "Seed(04040404...)");
620
621 // Check no padding.
622 let hash = Hash::new([128; HASH_SIZE]);
623 assert_eq!(format!("{:?}", &hash), "Hash(80808080...)");
624 let sk = SecretKey::new([255; SECRET_KEY_LENGTH]);
625 assert_eq!(format!("{:?}", &sk), "SecretKey(ffffffff...)");
626 }
627
628 // Note that only public values have Display impl.
629 #[test]
630 fn display_format() {
631 // Check zero padding.
632 let hash = Hash::new([1; HASH_SIZE]);
633 assert_eq!(format!("{}", &hash), "01010101...");
634
635 let pk = PublicKey::new([15; PUBLIC_KEY_LENGTH]);
636 assert_eq!(format!("{}", &pk), "0f0f0f0f...");
637 let signature = Signature::new([10; SIGNATURE_LENGTH]);
638 assert_eq!(format!("{}", &signature), "0a0a0a0a...");
639
640 // Check no padding.
641 let hash = Hash::new([128; HASH_SIZE]);
642 assert_eq!(format!("{}", &hash), "80808080...");
643 }
644
645 #[test]
646 fn hash_streaming_zero() {
647 let h1 = hash(&[]);
648 let state = HashStream::new();
649 let h2 = state.update(&[]).hash();
650 assert_eq!(h1, h2);
651 }
652
653 #[test]
654 fn hash_streaming_chunks() {
655 let data: [u8; 10] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
656 let h1 = hash(&data);
657 let state = HashStream::new();
658 let h2 = state.update(&data[..5]).update(&data[5..]).hash();
659 assert_eq!(h1, h2);
660 }
661
662 #[test]
663 fn sign_streaming_zero() {
664 let (pk, sk) = gen_keypair();
665 let mut creation_stream = SignStream::new().update(&[]);
666 let sig = creation_stream.sign(&sk);
667 let mut verified_stream = SignStream::new().update(&[]);
668 assert!(verified_stream.verify(&sig, &pk));
669 }
670
671 #[test]
672 fn sign_streaming_chunks() {
673 let data: [u8; 10] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
674 let (pk, sk) = gen_keypair();
675 let mut creation_stream = SignStream::new().update(&data[..5]).update(&data[5..]);
676 let sig = creation_stream.sign(&sk);
677 let mut verified_stream = SignStream::new().update(&data[..5]).update(&data[5..]);
678 assert!(verified_stream.verify(&sig, &pk));
679 }
680
681 fn assert_serialize_deserialize<T>(original_value: &T)
682 where
683 T: Serialize + DeserializeOwned + PartialEq + fmt::Debug,
684 {
685 let json = serde_json::to_string(original_value).unwrap();
686 let deserialized_value: T = serde_json::from_str(&json).unwrap();
687 assert_eq!(*original_value, deserialized_value);
688 }
689
690 #[test]
691 fn valid_keypair() {
692 let (pk, sk) = gen_keypair();
693 let _ = KeyPair::from_keys(pk, sk);
694 }
695
696 #[test]
697 #[should_panic]
698 fn not_valid_keypair() {
699 let (pk, _) = gen_keypair();
700 let (_, sk) = gen_keypair();
701 let _ = KeyPair::from_keys(pk, sk);
702 }
703}