wormsign/
lib.rs

1use std::error::Error as StdError;
2use std::os::unix::fs::PermissionsExt;
3use std::fs::{set_permissions, File};
4use std::io::{self, Write};
5use rpassword::read_password;
6use zeroize::Zeroize;
7
8#[cfg(feature = "aes")]
9mod aes256ctr;
10mod api;
11mod fips202;
12mod ntt;
13mod packing;
14mod params;
15mod poly;
16mod polyvec;
17mod randombytes;
18mod reduce;
19mod rounding;
20mod sign;
21mod symmetric;
22mod aesrest;
23
24pub use params::*;
25pub use api::*;
26pub use aesrest::*;
27
28/// This function generates new Dilithium keys, keeping the private protected.
29/// The protection is from AES256 on the private key, writing only the ciphertext to disk for re-use.
30/// The secret key for the secret key (AES256 key) is generated using password input as key material
31/// generated by Argon2 hashing with a fixed salt. See the aesrest module (aesrest.rs) for more related
32/// to this private key protection cryptogaphy.
33#[allow(unused)]
34pub fn keygen(key_path: &str, pub_path: &str) -> Result<(), Box<dyn StdError>> {
35  let keys = Keypair::generate();
36    let _ = File::create(key_path)
37        .map_err(|e| io::Error::new(io::ErrorKind::Other, format!("Failed to create key file {}: {}", key_path, e)))?;
38    set_permissions(&key_path, PermissionsExt::from_mode(0o600))
39        .map_err(|e| io::Error::new(io::ErrorKind::Other, format!("Failed to set permissions on {}: {}", key_path, e)))?;
40    let mut puboutput = File::create(pub_path)
41        .map_err(|e| io::Error::new(io::ErrorKind::Other, format!("Failed to create public key file {}: {}", pub_path, e)))?;
42    puboutput.write_all(&keys.public)
43        .map_err(|e| io::Error::new(io::ErrorKind::Other, format!("Failed to write public key: {}", e)))?;
44    std::io::stdout().flush().map_err(|e| io::Error::new(io::ErrorKind::Other, format!("Failed to flush stdout: {}", e)))?;
45    // STDERR on prompt so that output stays valid JSON, useful for redirects etc
46    eprintln!("Enter key password then press enter (will not be displayed):");
47    let mut password = read_password().map_err(|e| io::Error::new(io::ErrorKind::Other, format!("Failed to read password: {}", e)))?;
48    let mut keymaterial = aesrest::derive_key(password.as_bytes(), 32);
49    aesrest::encrypt_key(keys.expose_secret().to_vec(), key_path, &keymaterial)
50        .map_err(|e| io::Error::new(io::ErrorKind::Other, format!("Failed to encrypt key file: {}", e)))?;
51    keymaterial.zeroize();
52    password.zeroize();
53    Ok(())
54}
55
56#[cfg(test)]
57mod tests {
58    #[test]
59    fn datetest() {
60      use chrono::prelude::*;
61      assert_eq!(Utc::now().to_string().is_empty(), false);
62      let dt_nano = NaiveDate::from_ymd_opt(2014, 11, 28).unwrap().and_hms_nano_opt(12, 0, 9, 1).unwrap().and_local_timezone(Utc).unwrap();
63      assert_eq!(format!("{:?}", dt_nano), "2014-11-28T12:00:09.000000001Z");
64    }
65
66    #[test]
67    fn encrypttest() {
68      use crate::Keypair;
69      use crate::aesrest;
70      use std::os::unix::fs::PermissionsExt;
71      use std::fs::{set_permissions, File};
72      use std::io::{self, Write};
73      use zeroize::Zeroize;
74
75      let keys = Keypair::generate();
76      let key_path = "/tmp/wormsign_test.key";
77      let pub_path = "/tmp/wormsign_test.pub";
78      let _ = File::create(key_path).map_err(|e| io::Error::new(io::ErrorKind::Other, format!("Failed to create key file {}: {}", key_path, e)));
79      let _ = set_permissions(&key_path, PermissionsExt::from_mode(0o600)).map_err(|e| io::Error::new(io::ErrorKind::Other, format!("Failed to set permissions on {}: {}", key_path, e)));
80      let mut puboutput = File::create(pub_path).map_err(|e| io::Error::new(io::ErrorKind::Other, format!("Failed to create public key file {}: {}", pub_path, e))).expect("failed to create public key");
81      let _ = puboutput.write_all(&keys.public).map_err(|e| io::Error::new(io::ErrorKind::Other, format!("Failed to write public key: {}", e)));
82      let _ = std::io::stdout().flush().map_err(|e| io::Error::new(io::ErrorKind::Other, format!("Failed to flush stdout: {}", e)));
83      let password = "000000999999888888777777666666555555";
84      let mut keymaterial = aesrest::derive_key(password.as_bytes(), 32);
85      let results = aesrest::encrypt_key(keys.expose_secret().to_vec(), key_path, &keymaterial).map_err(|e| io::Error::new(io::ErrorKind::Other, format!("Failed to encrypt key file: {}", e)));
86      keymaterial.zeroize();
87      assert!(results.is_ok());
88    }
89
90    #[test]
91    fn decrypttest() {
92      use crate::Keypair;
93      use crate::aesrest;
94      use std::os::unix::fs::PermissionsExt;
95      use std::fs::{set_permissions, File};
96      use std::io::{self,  Write};
97      use zeroize::Zeroize;
98
99      let keys = Keypair::generate();
100      let key_path = "/tmp/wormsign_test.key";
101      let pub_path = "/tmp/wormsign_test.pub";
102      let _ = File::create(key_path).map_err(|e| io::Error::new(io::ErrorKind::Other, format!("Failed to create key file {}: {}", key_path, e)));
103      let _ = set_permissions(&key_path, PermissionsExt::from_mode(0o600)).map_err(|e| io::Error::new(io::ErrorKind::Other, format!("Failed to set permissions on {}: {}", key_path, e)));
104      let mut puboutput = File::create(pub_path).map_err(|e| io::Error::new(io::ErrorKind::Other, format!("Failed to create public key file {}: {}", pub_path, e))).expect("failed to create public key");
105      let _ = puboutput.write_all(&keys.public).map_err(|e| io::Error::new(io::ErrorKind::Other, format!("Failed to write public key: {}", e)));
106      let _ = std::io::stdout().flush().map_err(|e| io::Error::new(io::ErrorKind::Other, format!("Failed to flush stdout: {}", e)));
107      let password = "000000999999888888777777666666555555";
108      let mut keymaterial = aesrest::derive_key(password.as_bytes(), 32);
109      let _ = aesrest::encrypt_key(keys.expose_secret().to_vec(), key_path, &keymaterial).map_err(|e| io::Error::new(io::ErrorKind::Other, format!("Failed to encrypt key file: {}", e)));
110      let results = aesrest::decrypt_key(key_path, &keymaterial);
111      keymaterial.zeroize();
112      assert!(results.is_ok());
113    }
114
115    #[test]
116    fn dilithiumtest() {
117      use crate::verify;
118      use crate::Keypair;
119
120      let keys = Keypair::generate();
121      let msg = [0u8; 32];
122      let sig = keys.sign(&msg);
123      let sig_verify = verify(&sig, &msg, &keys.public);
124      assert!(sig_verify.is_ok());
125    }
126}