lockbook_shared/
pubkey.rs

1use 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(&timestamped)?;
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        // Just sanity checks
109
110        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        // Just sanity checks
121
122        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}