1
use openssl::{bn::BigNum, dh::Dh, md::Md, pkey::Id, pkey_ctx::PkeyCtx};
2
use zeroize::Zeroizing;
3

            
4
1
pub fn generate_public_key_for_secret_exchange(
5
    private_key: impl AsRef<[u8]>,
6
) -> Result<Vec<u8>, oo7::crypto::Error> {
7
2
    let private_key_bn = BigNum::from_slice(private_key.as_ref()).unwrap();
8
    let dh = Dh::from_pqg(
9
2
        BigNum::get_rfc3526_prime_1536().unwrap(),
10
1
        None,
11
2
        BigNum::from_u32(2).unwrap(),
12
    )?;
13
2
    Ok(dh.set_private_key(private_key_bn)?.public_key().to_vec())
14
}
15

            
16
1
pub fn generate_aes_key_for_secret_exchange(
17
    private_key: impl AsRef<[u8]>,
18
    server_public_key: impl AsRef<[u8]>,
19
) -> Result<Zeroizing<Vec<u8>>, oo7::crypto::Error> {
20
2
    let private_key_bn = BigNum::from_slice(private_key.as_ref()).unwrap();
21
2
    let server_public_key_bn = BigNum::from_slice(server_public_key.as_ref()).unwrap();
22
    let dh = Dh::from_pqg(
23
2
        BigNum::get_rfc3526_prime_1536().unwrap(),
24
1
        None,
25
2
        BigNum::from_u32(2).unwrap(),
26
    )?;
27
3
    let mut common_secret_bytes = dh
28
1
        .set_private_key(private_key_bn)?
29
1
        .compute_key(&server_public_key_bn)?;
30

            
31
1
    let mut common_secret_padded = vec![0; 192 - common_secret_bytes.len()];
32
    // inefficient, but ok for now
33
1
    common_secret_padded.append(&mut common_secret_bytes);
34

            
35
    // hkdf
36
    // input_keying_material
37
1
    let ikm = common_secret_padded;
38

            
39
2
    let mut okm = Zeroizing::new(vec![0; 16]);
40
2
    let mut ctx = PkeyCtx::new_id(Id::HKDF).unwrap();
41
2
    ctx.derive_init().unwrap();
42
1
    ctx.set_hkdf_md(Md::sha256()).unwrap();
43
1
    ctx.set_hkdf_key(&ikm).unwrap();
44
1
    ctx.derive(Some(okm.as_mut()))
45
        .expect("hkdf expand should never fail");
46
1
    Ok(okm)
47
}