matc/
spake2p.rs

1use anyhow::Result;
2use byteorder::{LittleEndian, WriteBytesExt};
3use p256::elliptic_curve::{
4    scalar::FromUintUnchecked,
5    sec1::{FromEncodedPoint, ToEncodedPoint},
6    Curve, Field,
7};
8use std::ops::Mul;
9
10use crate::util::cryptoutil;
11
12pub struct Context {
13    w0: p256::Scalar,
14    w1: p256::Scalar,
15    x_random: p256::Scalar,
16    pub x: p256::EncodedPoint,
17    pub y: p256::EncodedPoint,
18    pub ca: Option<Vec<u8>>,
19    pub decrypt_key: Option<Vec<u8>>,
20    pub encrypt_key: Option<Vec<u8>>,
21}
22
23pub struct Engine {
24    m: p256::AffinePoint,
25    n: p256::AffinePoint,
26}
27
28impl Engine {
29    fn p256_scalar_from_40_bytes(bytes: &[u8]) -> p256::Scalar {
30        let int = crypto_bigint::U320::from_be_slice(bytes);
31        let modulo = int.rem(&crypto_bigint::NonZero::from_uint(
32            crypto_bigint::U320::from(&p256::NistP256::ORDER),
33        ));
34        let u256 = crypto_bigint::U256::from(&modulo);
35        p256::Scalar::from_uint_unchecked(u256)
36    }
37
38    fn encoded_point_to_affine(e: &p256::EncodedPoint) -> Result<p256::AffinePoint> {
39        let res = p256::AffinePoint::from_encoded_point(e).into_option();
40        if let Some(r) = res {
41            Ok(r)
42        } else {
43            Err(anyhow::anyhow!("can't convert point to affine {:?}", e))
44        }
45    }
46    fn encoded_point_to_projective(e: &p256::EncodedPoint) -> Result<p256::ProjectivePoint> {
47        let res = p256::ProjectivePoint::from_encoded_point(e).into_option();
48        if let Some(r) = res {
49            Ok(r)
50        } else {
51            Err(anyhow::anyhow!(format!(
52                "can't convert point to projective {:?}",
53                e
54            )))
55        }
56    }
57
58    pub fn create_passcode_verifier(key: &[u8], salt: &[u8], iterations: u32) -> Vec<u8> {
59        let mut kdf = [0; 80];
60        pbkdf2::pbkdf2_hmac::<sha2::Sha256>(key, salt, iterations, &mut kdf);
61        let w0 = Self::p256_scalar_from_40_bytes(&kdf[..40]);
62        let w1 = Self::p256_scalar_from_40_bytes(&kdf[40..]);
63        let l = p256::ProjectivePoint::GENERATOR.mul(w1);
64        let mut out = Vec::new();
65        out.extend_from_slice(w0.to_bytes().as_slice());
66        out.extend_from_slice(l.to_encoded_point(false).as_bytes());
67        out
68    }
69
70    pub fn start(&self, key: &[u8], salt: &[u8], iterations: u32) -> Result<Context> {
71        let mut kdf = [0; 80];
72        pbkdf2::pbkdf2_hmac::<sha2::Sha256>(key, salt, iterations, &mut kdf);
73
74        let w0_scalar = Self::p256_scalar_from_40_bytes(&kdf.as_slice()[..40]);
75        let w1_scalar = Self::p256_scalar_from_40_bytes(&kdf[40..80]);
76
77        let x_random_scalar = p256::Scalar::random(rand::thread_rng());
78
79        let t_pp = p256::ProjectivePoint::GENERATOR.mul(x_random_scalar);
80
81        let p = self.m.mul(&w0_scalar);
82        let px2 = p.add(&t_pp);
83
84        let px2enc = px2.to_encoded_point(false);
85        Ok(Context {
86            w0: w0_scalar,
87            w1: w1_scalar,
88            x_random: x_random_scalar,
89            x: px2enc,
90            y: p256::EncodedPoint::identity(),
91            ca: None,
92            decrypt_key: None,
93            encrypt_key: None,
94        })
95    }
96
97    fn append_to_tt(buf: &mut Vec<u8>, data: &[u8]) -> Result<()> {
98        buf.write_u64::<LittleEndian>(data.len() as u64)?;
99        buf.extend_from_slice(data);
100        Ok(())
101    }
102
103    pub fn finish(&self, ctx: &mut Context, seed: &[u8]) -> Result<()> {
104        let wn = self.n.mul(ctx.w0);
105        let wn = wn.neg();
106        let zn = Self::encoded_point_to_projective(&ctx.y)?.add(&wn);
107        let z = zn.mul(ctx.x_random);
108        let v = zn.mul(ctx.w1);
109
110        let result = cryptoutil::sha256(seed);
111
112        let mut tt = Vec::with_capacity(1024);
113        Self::append_to_tt(&mut tt, &result)?;
114        Self::append_to_tt(&mut tt, &[])?;
115        Self::append_to_tt(&mut tt, &[])?;
116        Self::append_to_tt(&mut tt, self.m.to_encoded_point(false).as_bytes())?;
117        Self::append_to_tt(&mut tt, self.n.to_encoded_point(false).as_bytes())?;
118        Self::append_to_tt(&mut tt, ctx.x.as_bytes())?;
119        Self::append_to_tt(&mut tt, ctx.y.as_bytes())?;
120        Self::append_to_tt(&mut tt, z.to_encoded_point(false).as_bytes())?;
121        Self::append_to_tt(&mut tt, v.to_encoded_point(false).as_bytes())?;
122        Self::append_to_tt(&mut tt, ctx.w0.to_bytes().as_slice())?;
123
124        let result = cryptoutil::sha256(&tt);
125        let ka = &result[..16];
126        let ke = &result[16..32];
127
128        let okm = cryptoutil::hkdf_sha256(&[], ka, "ConfirmationKeys".as_bytes(), 32)?;
129
130        ctx.ca = Some(cryptoutil::hmac_sha256(ctx.y.as_bytes(), &okm[..16])?);
131        let _cb = cryptoutil::hmac_sha256(ctx.x.as_bytes(), &okm[16..])?;
132
133        let xcrypt = cryptoutil::hkdf_sha256(&[], ke, "SessionKeys".as_bytes(), 16 * 3)?;
134        ctx.decrypt_key = Some(xcrypt[16..32].to_vec());
135        ctx.encrypt_key = Some(xcrypt[..16].to_vec());
136
137        Ok(())
138    }
139
140    pub fn new() -> Result<Self> {
141        let mhex = "02886e2f97ace46e55ba9dd7242579f2993b64e16ef3dcab95afd497333d8fa12f";
142        let mbin = hex::decode(mhex)?;
143        let m = p256::EncodedPoint::from_bytes(mbin)?;
144        let m = Self::encoded_point_to_affine(&m)?;
145
146        let nhex = "03d8bbd6c639c62937b04d997f38c3770719c629d7014d49a24b4f98baa1292b49";
147        let nbin = hex::decode(nhex)?;
148        let n = p256::EncodedPoint::from_bytes(nbin)?;
149        let n = Self::encoded_point_to_affine(&n)?;
150        Ok(Self { m, n })
151    }
152}