dsf_core/crypto/
sodium.rs

1//! Crypto module provides cryptographic interfaces and implementations for DSF
2//!
3
4use sodiumoxide::crypto::sign;
5use sodiumoxide::crypto::sign::ed25519::PublicKey as SodiumPublicKey;
6use sodiumoxide::crypto::sign::ed25519::SecretKey as SodiumPrivateKey;
7
8use sodiumoxide::crypto::secretbox;
9use sodiumoxide::crypto::secretbox::xsalsa20poly1305::Key as SodiumSecretKey;
10use sodiumoxide::crypto::secretbox::xsalsa20poly1305::Nonce as SodiumSecretNonce;
11use sodiumoxide::crypto::secretbox::xsalsa20poly1305::Tag as SodiumSecretTag;
12use sodiumoxide::crypto::secretbox::xsalsa20poly1305::{MACBYTES, NONCEBYTES};
13
14use sodiumoxide::crypto::hash::sha256;
15
16use crate::types::{CryptoHash, PrivateKey, PublicKey, SecretKey, Signature};
17
18/// new_pk creates a new public/private key pair
19pub fn new_pk() -> Result<(PublicKey, PrivateKey), ()> {
20    let (public_key, private_key) = sign::gen_keypair();
21    Ok((public_key.0.into(), private_key.0.into()))
22}
23
24/// pk_sign generates a signature for the provided slice of data
25pub fn pk_sign(private_key: &PrivateKey, data: &[u8]) -> Result<Signature, ()> {
26    // Parse key from provided slice
27    let private_key = SodiumPrivateKey::from_slice(private_key).unwrap();
28    // Generate signature
29    let sig = sign::sign_detached(data, &private_key);
30    // Return signature object
31    Ok(sig.0.into())
32}
33
34/// pk_validate checks a provided signature against a public key and slice of data
35pub fn pk_validate(public_key: &PublicKey, signature: &Signature, data: &[u8]) -> Result<bool, ()> {
36    // Parse key from provided slice
37    let public_key = SodiumPublicKey::from_slice(public_key).unwrap();
38    // Parse signature from provided slice
39    let sig = sign::ed25519::Signature::from_slice(signature).unwrap();
40    // Verify signature (returns true or)
41    Ok(sign::verify_detached(&sig, data, &public_key))
42}
43
44pub const SK_META: usize = MACBYTES + NONCEBYTES;
45
46/// new_sk creates a new secret key for symmetric encryption and decryption
47pub fn new_sk() -> Result<SecretKey, ()> {
48    let key = secretbox::gen_key();
49    Ok(key.0.into())
50}
51
52pub fn sk_encrypt(secret_key: &SecretKey, message: &mut [u8]) -> Result<[u8; SK_META], ()> {
53    let secret_key = SodiumSecretKey::from_slice(secret_key).unwrap();
54    let nonce = secretbox::gen_nonce();
55
56    // Perform in-place encryption
57    let tag = secretbox::seal_detached(message, &nonce, &secret_key);
58
59    // Generate encryption metadata
60    let mut meta = [0u8; SK_META];
61    (&mut meta[..MACBYTES]).copy_from_slice(&tag.0);
62    (&mut meta[MACBYTES..]).copy_from_slice(&nonce.0);
63
64    Ok(meta)
65}
66
67pub fn sk_decrypt(secret_key: &SecretKey, meta: &[u8], message: &mut [u8]) -> Result<(), ()> {
68    let secret_key = SodiumSecretKey::from_slice(secret_key).unwrap();
69
70    // Parse encryption metadata
71    let tag = SodiumSecretTag::from_slice(&meta[..MACBYTES]).unwrap();
72    let nonce = SodiumSecretNonce::from_slice(&meta[MACBYTES..]).unwrap();
73
74    // Perform in-place decryption
75    secretbox::open_detached(message, &tag, &nonce, &secret_key)
76}
77
78/// sk_encrypt2 encrypts data_len bytes of the data in-place in the provided buffer,
79/// appends NONCE and TAG information to the buffer, and returns the complete length (encrypted data + overheads)
80pub fn sk_encrypt2<T>(secret_key: &SecretKey, mut buff: T, data_len: usize) -> Result<usize, ()>
81where
82    T: AsRef<[u8]> + AsMut<[u8]>,
83{
84    let data = buff.as_mut();
85
86    let secret_key = SodiumSecretKey::from_slice(secret_key).unwrap();
87    let nonce = secretbox::gen_nonce();
88
89    // Perform in-place encryption
90    let tag = secretbox::seal_detached(&mut data[..data_len], &nonce, &secret_key);
91
92    // Append encryption metadata
93    let mut i = data_len;
94    (&mut data[i..i + MACBYTES]).copy_from_slice(&tag.0);
95    i += MACBYTES;
96    (&mut data[i..i + NONCEBYTES]).copy_from_slice(&nonce.0);
97
98    Ok(data_len + MACBYTES + NONCEBYTES)
99}
100
101/// sk_decrypt2 decrypts the data in-place in the provided buffer,
102/// this will strip NONCE and TAG information, and returns the data length (decrypted data w/out overheads)
103pub fn sk_decrypt2<T>(secret_key: &SecretKey, mut buff: T) -> Result<usize, ()>
104where
105    T: AsRef<[u8]> + AsMut<[u8]>,
106{
107    let data = buff.as_mut();
108    let len = data.len() - NONCEBYTES - MACBYTES;
109
110    let secret_key = SodiumSecretKey::from_slice(secret_key).unwrap();
111
112    // Parse encryption metadata
113    let mut i = len;
114    let tag = SodiumSecretTag::from_slice(&data[i..i + MACBYTES]).unwrap();
115    i += MACBYTES;
116    let nonce = SodiumSecretNonce::from_slice(&data[i..i + NONCEBYTES]).unwrap();
117
118    // Perform in-place decryption
119    secretbox::open_detached(&mut data[..len], &tag, &nonce, &secret_key)?;
120
121    Ok(len)
122}
123
124/// Hash performs a hash function over the provided slice
125pub fn hash(data: &[u8]) -> Result<CryptoHash, ()> {
126    let digest = sha256::hash(data);
127    Ok(digest.0.into())
128}
129
130#[cfg(test)]
131mod test {
132
133    use super::*;
134
135    #[test]
136    fn test_sign_verify() {
137        let (public, private) = new_pk().expect("Error generating public/private keypair");
138        let mut data = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
139
140        let signature = pk_sign(&private, &data).expect("Error generating signature");
141
142        let valid = pk_validate(&public, &signature, &data).expect("Error validating signature");
143        assert_eq!(true, valid);
144
145        data[3] = 100;
146        let valid = pk_validate(&public, &signature, &data).expect("Error validating signature");
147        assert_eq!(false, valid);
148    }
149
150    #[test]
151    fn test_encrypt_decrypt() {
152        let secret = new_sk().expect("Error generating secret key");
153        let data = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
154        let mut message = data.clone();
155
156        let meta = sk_encrypt(&secret, &mut message).expect("Error encrypting data");
157        assert!(data != message);
158
159        sk_decrypt(&secret, &meta, &mut message).expect("Error decrypting data");
160        assert_eq!(data, message);
161    }
162
163    #[test]
164    fn test_encrypt_decrypt2() {
165        let secret = new_sk().expect("Error generating secret key");
166        let data = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
167
168        let mut buff = data.clone();
169        buff.append(&mut vec![0u8; 128]);
170
171        let n = sk_encrypt2(&secret, &mut buff, data.len()).expect("Error encrypting data");
172        assert_eq!(n, data.len() + NONCEBYTES + MACBYTES);
173        assert!(data != &buff[..data.len()]);
174
175        let m = sk_decrypt2(&secret, &mut buff[..n]).expect("Error decrypting data");
176        assert_eq!(m, data.len());
177        assert_eq!(data, &buff[..m]);
178    }
179}