sphinx_packet/crypto/
mod.rs

1// Copyright 2020 Nym Technologies SA
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
15use aes::{
16    cipher::{KeyIvInit, StreamCipher},
17    Aes128,
18};
19use digest::{
20    block_buffer::Eager,
21    consts::U256,
22    core_api::{BlockSizeUser, BufferKindUser, CoreProxy, FixedOutputCore},
23    generic_array::GenericArray,
24    typenum::{IsLess, Le, NonZero},
25    CtOutput, HashMarker,
26};
27use hmac::{Hmac, Mac};
28
29//type export and aliasing to keep compatibility
30pub use x25519_dalek::PublicKey;
31pub type PrivateKey = x25519_dalek::StaticSecret;
32
33pub const STREAM_CIPHER_KEY_SIZE: usize = 16;
34pub const STREAM_CIPHER_INIT_VECTOR: [u8; 16] = [0u8; 16];
35
36// Type alias for ease of use
37pub type HmacOutput<D> = CtOutput<Hmac<D>>;
38type Aes128Ctr = ctr::Ctr64BE<Aes128>;
39
40pub fn generate_pseudorandom_bytes(
41    // TODO: those should use proper generic arrays to begin with!!
42    // ^ will be done in next PR
43    key: &[u8; STREAM_CIPHER_KEY_SIZE],
44    iv: &[u8; STREAM_CIPHER_KEY_SIZE],
45    length: usize,
46) -> Vec<u8> {
47    let cipher_key = GenericArray::from_slice(&key[..]);
48    let cipher_nonce = GenericArray::from_slice(&iv[..]);
49
50    // generate a random string as an output of a PRNG, which we implement using stream cipher AES_CTR
51    let mut cipher = Aes128Ctr::new(cipher_key, cipher_nonce);
52    let mut data = vec![0u8; length];
53    cipher.apply_keystream(&mut data);
54    data
55}
56
57/// Compute keyed hmac
58pub fn compute_keyed_hmac<D>(key: &[u8], data: &[u8]) -> HmacOutput<D>
59where
60    D: CoreProxy,
61    D::Core: HashMarker + FixedOutputCore + BufferKindUser<BufferKind = Eager> + Default + Clone,
62    <D::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
63    Le<<D::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
64{
65    #[allow(clippy::expect_used)]
66    let mut hmac =
67        Hmac::<D>::new_from_slice(key).expect("HMAC should be able to take key of any size!");
68    hmac.update(data);
69    hmac.finalize()
70}
71
72#[cfg(test)]
73mod generating_pseudorandom_bytes {
74    use super::*;
75
76    // TODO: 10,000 is the wrong number, @aniap what is correct here?
77    #[test]
78    fn it_generates_output_of_size_10000() {
79        let key: [u8; STREAM_CIPHER_KEY_SIZE] =
80            [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
81        let iv: [u8; STREAM_CIPHER_KEY_SIZE] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
82
83        let rand_bytes = generate_pseudorandom_bytes(&key, &iv, 10000);
84        assert_eq!(10000, rand_bytes.len());
85    }
86}