lockbook_shared/
pubkey.rs1use std::convert::TryInto;
2
3use libsecp256k1::Message;
4use libsecp256k1::{PublicKey, SecretKey, SharedSecret, Signature};
5use rand::rngs::OsRng;
6use serde::Serialize;
7use sha2::{Digest, Sha256};
8
9use crate::crypto::*;
10
11use crate::clock::{timestamp, TimeGetter};
12use crate::{SharedErrorKind, SharedResult};
13
14pub fn generate_key() -> SecretKey {
15 SecretKey::random(&mut OsRng)
16}
17
18pub fn sign<T: Serialize>(
19 sk: &SecretKey, to_sign: T, time_getter: TimeGetter,
20) -> SharedResult<ECSigned<T>> {
21 let timestamped = timestamp(to_sign, time_getter);
22 let serialized = bincode::serialize(×tamped)?;
23 let digest = Sha256::digest(&serialized);
24 let message = &Message::parse_slice(&digest).map_err(SharedErrorKind::ParseError)?;
25 let (signature, _) = libsecp256k1::sign(message, sk);
26 Ok(ECSigned {
27 timestamped_value: timestamped,
28 signature: signature.serialize().to_vec(),
29 public_key: PublicKey::from_secret_key(sk),
30 })
31}
32
33pub fn verify<T: Serialize>(
34 pk: &PublicKey, signed: &ECSigned<T>, max_delay_ms: u64, max_skew_ms: u64,
35 time_getter: TimeGetter,
36) -> SharedResult<()> {
37 if &signed.public_key != pk {
38 return Err(SharedErrorKind::WrongPublicKey.into());
39 }
40
41 let auth_time = signed.timestamped_value.timestamp;
42 let current_time = time_getter().0;
43 let max_skew_ms = max_skew_ms as i64;
44 let max_delay_ms = max_delay_ms as i64;
45
46 if current_time < auth_time - max_skew_ms {
47 return Err(SharedErrorKind::SignatureInTheFuture(
48 (current_time - (auth_time - max_delay_ms)) as u64,
49 )
50 .into());
51 }
52
53 if current_time > auth_time + max_delay_ms {
54 return Err(SharedErrorKind::SignatureExpired(
55 (auth_time + max_delay_ms - current_time) as u64,
56 )
57 .into());
58 }
59
60 let serialized = bincode::serialize(&signed.timestamped_value)?;
61
62 let digest = Sha256::digest(&serialized).to_vec();
63 let message = &Message::parse_slice(&digest).map_err(SharedErrorKind::ParseError)?;
64 let signature =
65 Signature::parse_standard_slice(&signed.signature).map_err(SharedErrorKind::ParseError)?;
66
67 if libsecp256k1::verify(message, &signature, &signed.public_key) {
68 Ok(())
69 } else {
70 Err(SharedErrorKind::SignatureInvalid.into())
71 }
72}
73
74pub fn get_aes_key(sk: &SecretKey, pk: &PublicKey) -> SharedResult<AESKey> {
75 SharedSecret::<Sha256>::new(pk, sk)
76 .map_err(SharedErrorKind::SharedSecretError)?
77 .as_ref()
78 .try_into()
79 .map_err(|_| SharedErrorKind::SharedSecretUnexpectedSize.into())
80}
81
82#[cfg(test)]
83mod unit_tests {
84 use libsecp256k1::PublicKey;
85
86 use crate::clock::Timestamp;
87 use crate::pubkey::*;
88
89 static EARLY_CLOCK: fn() -> Timestamp = || Timestamp(500);
90 static LATE_CLOCK: fn() -> Timestamp = || Timestamp(520);
91
92 #[test]
93 fn ec_test_sign_verify() {
94 let key = generate_key();
95 let value = sign(&key, "Test", EARLY_CLOCK).unwrap();
96 verify(&PublicKey::from_secret_key(&key), &value, 20, 20, LATE_CLOCK).unwrap();
97 }
98
99 #[test]
100 fn ec_test_sign_verify_late() {
101 let key = generate_key();
102 let value = sign(&key, "Test", EARLY_CLOCK).unwrap();
103 verify(&PublicKey::from_secret_key(&key), &value, 10, 10, LATE_CLOCK).unwrap_err();
104 }
105
106 #[test]
107 fn ec_test_shared_secret_one_party() {
108 let key = generate_key();
111 let shared_secret1 = get_aes_key(&key, &PublicKey::from_secret_key(&key)).unwrap();
112
113 let shared_secret2 = get_aes_key(&key, &PublicKey::from_secret_key(&key)).unwrap();
114
115 assert_eq!(shared_secret1, shared_secret2);
116 }
117
118 #[test]
119 fn ec_test_shared_secret_two_parties() {
120 let key1 = generate_key();
123 let key2 = generate_key();
124
125 let shared_secret1 = get_aes_key(&key1, &PublicKey::from_secret_key(&key2)).unwrap();
126
127 let shared_secret2 = get_aes_key(&key2, &PublicKey::from_secret_key(&key1)).unwrap();
128
129 assert_eq!(shared_secret1, shared_secret2);
130 }
131
132 #[test]
133 fn same_sk_same_pk_sanity_check() {
134 let key1 = generate_key();
135 let key2 = SecretKey::parse(&key1.serialize()).unwrap();
136
137 assert_eq!(key1, key2);
138
139 assert_eq!(PublicKey::from_secret_key(&key1), PublicKey::from_secret_key(&key2));
140 }
141}