static_dh_ecdh/dh/
dh.rs

1use num_bigint_dig::{BigUint, RandBigInt};
2use rand;
3
4use core::convert::TryInto;
5
6use crate::constants;
7
8/// A function to convert (i.e. unhexlify) a hex-string to a byte array. (Didnt want to use a full-blown crate 
9/// for this.)
10///
11/// Note: this function uses a generic constant `N` via `const-generics`. At the time of this writing,
12/// `c-g` is not yet stable but will be in 2 weeks from now.
13pub fn unhexlify_to_bytearray<const N: usize>(prime: &str) -> [u8; N] {
14    let mut bytearray = [0; N];
15    let hex_string = prime;
16    for i in (0..hex_string.len()).step_by(2) {
17        if i > (2 * N - 2) {
18            break;
19        }
20        let substring = &hex_string[i..i + 2];
21        let z = (u8::from_str_radix(substring, 16)).unwrap();
22        bytearray[(i - (i / 2))] = z;
23    }
24    return bytearray;
25}
26
27/// Returns supported DH_GROUPS or an 'Unsupported' error string. 
28pub fn get_dh(group: u8) -> DH {
29    if group == constants::SUPPORTED_DH_GROUPS[0] {
30        return DH::Dh5(DH5::new());
31    } else if group == constants::SUPPORTED_DH_GROUPS[1] {
32        return DH::Dh15(DH15::new());
33    } else {
34        return DH::UnSupported("UnSupported DH_GROUP");
35    }
36}
37
38/// Only DH5 and DH15 are supported as per the RFC 
39#[derive(Debug, PartialEq, Clone)]
40pub enum DH {
41    /// An enum to represent DH5 Group
42    Dh5(DH5),
43    /// An enum to represent DH14 Group
44    Dh14(DH14),
45    /// An enum to represent DH15 Group
46    Dh15(DH15),
47    /// An enum to represent DH16 Group
48    Dh16(DH16),
49    /// An enum to represent DH17 Group
50    Dh17(DH17),
51    /// An enum to represent DH18 Group
52    Dh18(DH18),
53    /// An enum to represent UnSupported Group
54    UnSupported(&'static str),
55}
56/// A data struct to hold state for DH_GROUP_ID 5 as per RFC - https://tools.ietf.org/html/rfc3526
57#[derive(Debug, PartialEq, Clone)]
58pub struct DH5 {
59    prime_num: BigUint,
60    generator: usize,
61    exp_size: usize,
62    private_key: BigUint, // should be private but marked pub for testing
63    public_key: BigUint,
64    shared_secret: BigUint, // should be private but marked pub for testing
65}
66
67impl DH5 {
68    /// Create a new DH5 group with a prime value `DH_GROUP_5_PRIME`, generator `2`, and exp_size `192`
69    pub fn new() -> Self {
70        DH5 {
71            prime_num: BigUint::default(),
72            generator: 0,
73            exp_size: 0,
74            private_key: BigUint::default(),
75            public_key: BigUint::default(),
76            shared_secret: BigUint::default(),
77        }
78    }
79
80    /// Initialize the DH5 group
81    pub fn init_dh5(&mut self) {
82        let prime_byte_arr = unhexlify_to_bytearray::<192>(
83            &constants::DH_GROUP_5_PRIME
84                .replace(" ", "")
85                .replace("\n\t", ""),
86        );
87        self.prime_num = BigUint::from_bytes_be(&prime_byte_arr);
88        self.generator = constants::DH_GROUP_5_GENERATOR;
89        self.exp_size = constants::DH_GROUP_5_EXPONENT_LENGTH;
90    }
91
92    /// Generate the private key
93    pub fn generate_private_key(&mut self) -> BigUint {
94        let mut rng = rand::thread_rng();
95        self.private_key = rng.gen_biguint((self.exp_size * 8 as usize) as usize);
96        // let bytes = Math::bigint_to_bytes(unsigned);
97        // self.private_key = Math::bytes_to_bigint(&bytes)
98        return self.private_key.clone(); // Need to change the return type to () after testing
99    }
100
101    /// Generate the public key
102    pub fn generate_pubic_key(&mut self) -> BigUint {
103        self.public_key = BigUint::from(self.generator).modpow(&self.private_key, &self.prime_num);
104        return self.public_key.clone(); // Need to change the return type to () after testing
105    }
106
107    /// Compute the shared secret
108    pub fn compute_shared_secret(&mut self, other_public_key: BigUint) -> BigUint {
109        self.shared_secret = other_public_key.modpow(&self.private_key, &self.prime_num);
110        self.shared_secret.clone() // Need to change the return type to () after testing
111    }
112
113    /// Returns the derived public key in a bytearray.
114    pub fn encode_public_key<const N: usize>(&self) -> [u8; N] {
115        let pub_key_bytes: [u8; N] = BigUint::to_bytes_be(&self.public_key).try_into().unwrap();
116        pub_key_bytes
117    }
118
119    /// Given a bytearray representation of the public key, returns a `Bigint`
120    pub fn decode_public_key(buffer: &[u8]) -> BigUint {
121        BigUint::from_bytes_be(buffer)
122    }
123}
124
125/// A data struct to hold state for DH_GROUP_ID 14 as per RFC - https://tools.ietf.org/html/rfc3526
126#[derive(Debug, PartialEq, Clone)]
127pub struct DH14 {
128    prime_num: BigUint,
129    generator: usize,
130    exp_size: usize,
131    private_key: BigUint, // should be private but marked pub for testing
132    public_key: BigUint,
133    shared_secret: BigUint, // should be private but marked pub for testing
134}
135
136impl DH14 {
137    /// Create a new DH14 group with a prime value `DH_GROUP_14_PRIME`, generator `2`, and exp_size `256`
138    pub fn new() -> Self {
139        DH14 {
140            prime_num: BigUint::default(),
141            generator: 0,
142            exp_size: 0,
143            private_key: BigUint::default(),
144            public_key: BigUint::default(),
145            shared_secret: BigUint::default(),
146        }
147    }
148
149    /// Initialize the DH14 group
150    pub fn init_dh14(&mut self) {
151        let prime_byte_arr = unhexlify_to_bytearray::<256>(
152            &constants::DH_GROUP_14_PRIME
153                .replace(" ", "")
154                .replace("\n", "")
155                .replace("\t", ""),
156        );
157        self.prime_num = BigUint::from_bytes_le(&prime_byte_arr);
158        self.generator = constants::DH_GROUP_14_GENERATOR;
159        self.exp_size = constants::DH_GROUP_14_EXPONENT_LENGTH;
160    }
161
162    /// Generate the private key
163    pub fn generate_private_key(&mut self) -> BigUint {
164        let mut rng = rand::thread_rng();
165        self.private_key = rng.gen_biguint((self.exp_size * 8 as usize) as usize);
166        // let bytes = Math::bigint_to_bytes(unsigned);
167        // self.private_key = Math::bytes_to_bigint(&bytes)
168        return self.private_key.clone(); // Need to change the return type to () after testing
169    }
170
171    /// Generate the public key
172    pub fn generate_pubic_key(&mut self) -> BigUint {
173        self.public_key = BigUint::from(self.generator).modpow(&self.private_key, &self.prime_num);
174        return self.public_key.clone(); // Need to change the return type to () after testing
175    }
176
177    /// Compute the shared secret
178    pub fn compute_shared_secret(&mut self, other_public_key: BigUint) -> BigUint {
179        self.shared_secret = other_public_key.modpow(&self.private_key, &self.prime_num);
180        self.shared_secret.clone() // Need to change the return type to () after testing
181    }
182
183    /// Returns the derived public key in an bytearray.
184    pub fn encode_public_key<const N: usize>(&self) -> [u8; N] {
185        let pub_key_bytes: [u8; N] = BigUint::to_bytes_be(&self.public_key).try_into().unwrap();
186        pub_key_bytes
187    }
188
189    /// Given a bytearray representation of the public key, returns a `Bigint`
190    pub fn decode_public_key(buffer: &[u8]) -> BigUint {
191        BigUint::from_bytes_be(buffer)
192    }
193}
194
195/// A data struct to hold state for DH_GROUP_ID 15 as per RFC - https://tools.ietf.org/html/rfc3526
196#[derive(Debug, PartialEq, Clone)]
197pub struct DH15 {
198    prime_num: BigUint,
199    generator: usize,
200    exp_size: usize,
201    private_key: BigUint, // should be private but marked pub for testing
202    public_key: BigUint,
203    shared_secret: BigUint, // should be private but marked pub for testing
204}
205
206impl DH15 {
207    /// Create a new DH15 group with a prime value `DH_GROUP_15_PRIME`, generator `2`, and exp_size `384`
208    pub fn new() -> Self {
209        DH15 {
210            prime_num: BigUint::default(),
211            generator: 0,
212            exp_size: 0,
213            private_key: BigUint::default(),
214            public_key: BigUint::default(),
215            shared_secret: BigUint::default(),
216        }
217    }
218
219    /// Initialize the DH15 group
220    pub fn init_dh15(&mut self) {
221        let prime_byte_arr = unhexlify_to_bytearray::<384>(
222            &constants::DH_GROUP_15_PRIME
223                .replace(" ", "")
224                .replace("\n", "")
225                .replace("\t", ""),
226        );
227        self.prime_num = BigUint::from_bytes_le(&prime_byte_arr);
228        self.generator = constants::DH_GROUP_15_GENERATOR;
229        self.exp_size = constants::DH_GROUP_15_EXPONENT_LENGTH;
230    }
231
232    /// Generate the private key
233    pub fn generate_private_key(&mut self) -> BigUint {
234        let mut rng = rand::thread_rng();
235        self.private_key = rng.gen_biguint((self.exp_size * 8 as usize) as usize);
236        // let bytes = Math::bigint_to_bytes(unsigned);
237        // self.private_key = Math::bytes_to_bigint(&bytes)
238        return self.private_key.clone(); // Need to change the return type to () after testing
239    }
240
241    /// Generate the public key
242    pub fn generate_pubic_key(&mut self) -> BigUint {
243        self.public_key = BigUint::from(self.generator).modpow(&self.private_key, &self.prime_num);
244        return self.public_key.clone(); // Need to change the return type to () after testing
245    }
246
247    /// Compute the shared secret
248    pub fn compute_shared_secret(&mut self, other_public_key: BigUint) -> BigUint {
249        self.shared_secret = other_public_key.modpow(&self.private_key, &self.prime_num);
250        self.shared_secret.clone() // Need to change the return type to () after testing
251    }
252
253    /// Returns the derived public key in an bytearray.
254    pub fn encode_public_key<const N: usize>(&self) -> [u8; N] {
255        let pub_key_bytes: [u8; N] = BigUint::to_bytes_be(&self.public_key).try_into().unwrap();
256        pub_key_bytes
257    }
258
259    /// Given a bytearray representation of the public key, returns a `Bigint`
260    pub fn decode_public_key(buffer: &[u8]) -> BigUint {
261        BigUint::from_bytes_be(buffer)
262    }
263}
264
265/// A data struct to hold state for DH_GROUP_ID 16 as per RFC - https://tools.ietf.org/html/rfc3526
266#[derive(Debug, PartialEq, Clone)]
267pub struct DH16 {
268    prime_num: BigUint,
269    generator: usize,
270    exp_size: usize,
271    private_key: BigUint, // should be private but marked pub for testing
272    public_key: BigUint,
273    shared_secret: BigUint, // should be private but marked pub for testing
274}
275
276impl DH16 {
277    /// Create a new DH16 group with a prime value `DH_GROUP_16_PRIME`, generator `2`, and exp_size `512`
278    pub fn new() -> Self {
279        DH16 {
280            prime_num: BigUint::default(),
281            generator: 0,
282            exp_size: 0,
283            private_key: BigUint::default(),
284            public_key: BigUint::default(),
285            shared_secret: BigUint::default(),
286        }
287    }
288
289    /// Initialize the DH16 group
290    pub fn init_dh16(&mut self) {
291        let prime_byte_arr = unhexlify_to_bytearray::<512>(
292            &constants::DH_GROUP_16_PRIME
293                .replace(" ", "")
294                .replace("\n", "")
295                .replace("\t", ""),
296        );
297        self.prime_num = BigUint::from_bytes_le(&prime_byte_arr);
298        self.generator = constants::DH_GROUP_16_GENERATOR;
299        self.exp_size = constants::DH_GROUP_16_EXPONENT_LENGTH;
300    }
301
302    /// Generate the private key
303    pub fn generate_private_key(&mut self) -> BigUint {
304        let mut rng = rand::thread_rng();
305        self.private_key = rng.gen_biguint((self.exp_size * 8 as usize) as usize);
306        // let bytes = Math::bigint_to_bytes(unsigned);
307        // self.private_key = Math::bytes_to_bigint(&bytes)
308        return self.private_key.clone(); // Need to change the return type to () after testing
309    }
310
311    /// Generate the public key
312    pub fn generate_pubic_key(&mut self) -> BigUint {
313        self.public_key = BigUint::from(self.generator).modpow(&self.private_key, &self.prime_num);
314        return self.public_key.clone(); // Need to change the return type to () after testing
315    }
316
317    /// Compute the shared secret
318    pub fn compute_shared_secret(&mut self, other_public_key: BigUint) -> BigUint {
319        self.shared_secret = other_public_key.modpow(&self.private_key, &self.prime_num);
320        self.shared_secret.clone() // Need to change the return type to () after testing
321    }
322
323    /// Returns the derived public key in an bytearray.
324    pub fn encode_public_key<const N: usize>(&self) -> [u8; N] {
325        let pub_key_bytes: [u8; N] = BigUint::to_bytes_be(&self.public_key).try_into().unwrap();
326        pub_key_bytes
327    }
328
329    /// Given a bytearray representation of the public key, returns a `Bigint`
330    pub fn decode_public_key(buffer: &[u8]) -> BigUint {
331        BigUint::from_bytes_be(buffer)
332    }
333}
334
335/// A data struct to hold state for DH_GROUP_ID 17 as per RFC - https://tools.ietf.org/html/rfc3526
336#[derive(Debug, PartialEq, Clone)]
337pub struct DH17 {
338    prime_num: BigUint,
339    generator: usize,
340    exp_size: usize,
341    private_key: BigUint, // should be private but marked pub for testing
342    public_key: BigUint,
343    shared_secret: BigUint, // should be private but marked pub for testing
344}
345
346impl DH17 {
347    /// Create a new DH17 group with a prime value `DH_GROUP_17_PRIME`, generator `2`, and exp_size `768`
348    pub fn new() -> Self {
349        DH17 {
350            prime_num: BigUint::default(),
351            generator: 0,
352            exp_size: 0,
353            private_key: BigUint::default(),
354            public_key: BigUint::default(),
355            shared_secret: BigUint::default(),
356        }
357    }
358
359    /// Initialize the DH17 group
360    pub fn init_dh17(&mut self) {
361        let prime_byte_arr = unhexlify_to_bytearray::<768>(
362            &constants::DH_GROUP_17_PRIME
363                .replace(" ", "")
364                .replace("\n", "")
365                .replace("\t", ""),
366        );
367        self.prime_num = BigUint::from_bytes_le(&prime_byte_arr);
368        self.generator = constants::DH_GROUP_17_GENERATOR;
369        self.exp_size = constants::DH_GROUP_17_EXPONENT_LENGTH;
370    }
371
372    /// Generate the private key
373    pub fn generate_private_key(&mut self) -> BigUint {
374        let mut rng = rand::thread_rng();
375        self.private_key = rng.gen_biguint((self.exp_size * 8 as usize) as usize);
376        // let bytes = Math::bigint_to_bytes(unsigned);
377        // self.private_key = Math::bytes_to_bigint(&bytes)
378        return self.private_key.clone(); // Need to change the return type to () after testing
379    }
380
381    /// Generate the public key
382    pub fn generate_pubic_key(&mut self) -> BigUint {
383        self.public_key = BigUint::from(self.generator).modpow(&self.private_key, &self.prime_num);
384        return self.public_key.clone(); // Need to change the return type to () after testing
385    }
386
387    /// Compute the shared secret
388    pub fn compute_shared_secret(&mut self, other_public_key: BigUint) -> BigUint {
389        self.shared_secret = other_public_key.modpow(&self.private_key, &self.prime_num);
390        self.shared_secret.clone() // Need to change the return type to () after testing
391    }
392
393    /// Returns the derived public key in an bytearray.
394    pub fn encode_public_key<const N: usize>(&self) -> [u8; N] {
395        let pub_key_bytes: [u8; N] = BigUint::to_bytes_be(&self.public_key).try_into().unwrap();
396        pub_key_bytes
397    }
398
399    /// Given a bytearray representation of the public key, returns a `Bigint`
400    pub fn decode_public_key(buffer: &[u8]) -> BigUint {
401        BigUint::from_bytes_be(buffer)
402    }
403}
404
405/// A data struct to hold state for DH_GROUP_ID 18 as per RFC - https://tools.ietf.org/html/rfc3526
406#[derive(Debug, PartialEq, Clone)]
407pub struct DH18 {
408    prime_num: BigUint,
409    generator: usize,
410    exp_size: usize,
411    private_key: BigUint, // should be private but marked pub for testing
412    public_key: BigUint,
413    shared_secret: BigUint, // should be private but marked pub for testing
414}
415
416impl DH18 {
417    /// Create a new DH18 group with a prime value `DH_GROUP_18_PRIME`, generator `2`, and exp_size `1024`
418    pub fn new() -> Self {
419        DH18 {
420            prime_num: BigUint::default(),
421            generator: 0,
422            exp_size: 0,
423            private_key: BigUint::default(),
424            public_key: BigUint::default(),
425            shared_secret: BigUint::default(),
426        }
427    }
428
429    /// Initialize the DH18 group
430    pub fn init_dh18(&mut self) {
431        let prime_byte_arr = unhexlify_to_bytearray::<1024>(
432            &constants::DH_GROUP_18_PRIME
433                .replace(" ", "")
434                .replace("\n", "")
435                .replace("\t", ""),
436        );
437        self.prime_num = BigUint::from_bytes_le(&prime_byte_arr);
438        self.generator = constants::DH_GROUP_18_GENERATOR;
439        self.exp_size = constants::DH_GROUP_18_EXPONENT_LENGTH;
440    }
441
442    /// Generate the private key
443    pub fn generate_private_key(&mut self) -> BigUint {
444        let mut rng = rand::thread_rng();
445        self.private_key = rng.gen_biguint((self.exp_size * 8 as usize) as usize);
446        // let bytes = Math::bigint_to_bytes(unsigned);
447        // self.private_key = Math::bytes_to_bigint(&bytes)
448        return self.private_key.clone(); // Need to change the return type to () after testing
449    }
450
451    /// Generate the public key
452    pub fn generate_pubic_key(&mut self) -> BigUint {
453        self.public_key = BigUint::from(self.generator).modpow(&self.private_key, &self.prime_num);
454        return self.public_key.clone(); // Need to change the return type to () after testing
455    }
456
457    /// Compute the shared secret
458    pub fn compute_shared_secret(&mut self, other_public_key: BigUint) -> BigUint {
459        self.shared_secret = other_public_key.modpow(&self.private_key, &self.prime_num);
460        self.shared_secret.clone() // Need to change the return type to () after testing
461    }
462
463    /// Returns the derived public key in an bytearray.
464    pub fn encode_public_key<const N: usize>(&self) -> [u8; N] {
465        let pub_key_bytes: [u8; N] = BigUint::to_bytes_be(&self.public_key).try_into().unwrap();
466        pub_key_bytes
467    }
468
469    /// Given a bytearray representation of the public key, returns a `Bigint`
470    pub fn decode_public_key(buffer: &[u8]) -> BigUint {
471        BigUint::from_bytes_be(buffer)
472    }
473}