russh_libsodium/
lib.rs

1#![deny(clippy::unwrap_used, clippy::expect_used, clippy::indexing_slicing, clippy::panic)]
2extern crate libc;
3#[macro_use]
4extern crate lazy_static;
5use libc::c_ulonglong;
6use libsodium_sys::*;
7
8lazy_static! {
9    static ref SODIUM: i32 = unsafe { sodium_init() };
10}
11
12pub mod chacha20 {
13    use super::*;
14    pub const NONCE_BYTES: usize = 8;
15    pub const KEY_BYTES: usize = 32;
16    pub struct Nonce(pub [u8; NONCE_BYTES]);
17    pub struct Key(pub [u8; KEY_BYTES]);
18    pub fn chacha20_xor(c: &mut [u8], n: &Nonce, k: &Key) {
19        lazy_static::initialize(&super::SODIUM);
20        unsafe {
21            crypto_stream_chacha20_xor(
22                c.as_mut_ptr(),
23                c.as_ptr(),
24                c.len() as c_ulonglong,
25                n.0.as_ptr(),
26                k.0.as_ptr(),
27            );
28        }
29    }
30
31    pub fn chacha20_xor_ic(c: &mut [u8], n: &Nonce, ic: u64, k: &Key) {
32        lazy_static::initialize(&super::SODIUM);
33        unsafe {
34            crypto_stream_chacha20_xor_ic(
35                c.as_mut_ptr(),
36                c.as_ptr(),
37                c.len() as c_ulonglong,
38                n.0.as_ptr(),
39                ic,
40                k.0.as_ptr(),
41            );
42        }
43    }
44}
45
46pub mod poly1305 {
47    use super::*;
48    pub const KEY_BYTES: usize = 32;
49    pub const TAG_BYTES: usize = 16;
50    pub struct Key(pub [u8; KEY_BYTES]);
51    pub struct Tag(pub [u8; TAG_BYTES]);
52    pub fn poly1305_auth(m: &[u8], key: &Key) -> Tag {
53        lazy_static::initialize(&super::SODIUM);
54        let mut tag = Tag([0; TAG_BYTES]);
55        unsafe {
56            crypto_onetimeauth(
57                tag.0.as_mut_ptr(),
58                m.as_ptr(),
59                m.len() as c_ulonglong,
60                key.0.as_ptr(),
61            );
62        }
63        tag
64    }
65    pub fn poly1305_verify(tag: &[u8], m: &[u8], key: &Key) -> bool {
66        lazy_static::initialize(&super::SODIUM);
67        if tag.len() != TAG_BYTES {
68            false
69        } else {
70            unsafe {
71                crypto_onetimeauth_verify(
72                    tag.as_ptr(),
73                    m.as_ptr(),
74                    m.len() as c_ulonglong,
75                    key.0.as_ptr(),
76                ) == 0
77            }
78        }
79    }
80}
81
82pub mod ed25519 {
83    use super::*;
84    pub const PUBLICKEY_BYTES: usize = 32;
85    pub const SECRETKEY_BYTES: usize = 64;
86    pub const SIGNATURE_BYTES: usize = 64;
87
88    /// Ed25519 public key.
89    #[derive(Debug, PartialEq, Eq, Clone)]
90    pub struct PublicKey {
91        /// Actual key
92        pub key: [u8; PUBLICKEY_BYTES],
93    }
94
95    impl PublicKey {
96        pub fn new_zeroed() -> Self {
97            PublicKey {
98                key: [0; PUBLICKEY_BYTES],
99            }
100        }
101    }
102
103    /// Ed25519 secret key.
104    #[derive(Clone)]
105    pub struct SecretKey {
106        /// Actual key
107        pub key: [u8; SECRETKEY_BYTES],
108    }
109
110    impl SecretKey {
111        pub fn new_zeroed() -> Self {
112            SecretKey {
113                key: [0; SECRETKEY_BYTES],
114            }
115        }
116    }
117
118    pub struct Signature(pub [u8; SIGNATURE_BYTES]);
119
120    /// Generate a key pair.
121    pub fn keypair() -> (PublicKey, SecretKey) {
122        unsafe {
123            lazy_static::initialize(&super::SODIUM);
124            let mut pk = PublicKey {
125                key: [0; PUBLICKEY_BYTES],
126            };
127            let mut sk = SecretKey {
128                key: [0; SECRETKEY_BYTES],
129            };
130            crypto_sign_keypair(pk.key.as_mut_ptr(), sk.key.as_mut_ptr());
131            (pk, sk)
132        }
133    }
134
135    /// Verify a signature, `sig` could as well be a `Signature`.
136    pub fn verify_detached(sig: &[u8], m: &[u8], pk: &PublicKey) -> bool {
137        lazy_static::initialize(&super::SODIUM);
138        if sig.len() == SIGNATURE_BYTES {
139            unsafe {
140                crypto_sign_verify_detached(
141                    sig.as_ptr(),
142                    m.as_ptr(),
143                    m.len() as c_ulonglong,
144                    pk.key.as_ptr(),
145                ) == 0
146            }
147        } else {
148            false
149        }
150    }
151
152    /// Sign a message with a secret key.
153    pub fn sign_detached(m: &[u8], sk: &SecretKey) -> Signature {
154        lazy_static::initialize(&super::SODIUM);
155        let mut sig = Signature([0; SIGNATURE_BYTES]);
156        let mut sig_len = 0;
157        unsafe {
158            crypto_sign_detached(
159                sig.0.as_mut_ptr(),
160                &mut sig_len,
161                m.as_ptr(),
162                m.len() as c_ulonglong,
163                sk.key.as_ptr(),
164            );
165        }
166        sig
167    }
168}
169
170pub mod aes256gcm {
171    use super::*;
172    pub const NONCE_BYTES: usize = crypto_aead_aes256gcm_NPUBBYTES as usize;
173    pub const KEY_BYTES: usize = crypto_aead_aes256gcm_KEYBYTES as usize;
174    pub const TAG_BYTES: usize = crypto_aead_aes256gcm_ABYTES as usize;
175    pub struct Key(pub [u8; KEY_BYTES]);
176    pub struct Nonce(pub [u8; NONCE_BYTES]);
177    pub struct Tag(pub [u8; TAG_BYTES]);
178
179    pub fn aes256gcm_encrypt(ciphertext: &mut [u8], tag: &mut [u8], message: &[u8], ad: &[u8], nonce: &Nonce, key: &Key) -> bool {
180        lazy_static::initialize(&super::SODIUM);
181        if tag.len() != TAG_BYTES {
182            false
183        } else {
184            unsafe {
185                let ret = crypto_aead_aes256gcm_encrypt_detached(
186                    ciphertext.as_mut_ptr(),
187                    tag.as_mut_ptr(),
188                    std::ptr::null_mut(),
189                    message.as_ptr(),
190                    message.len() as c_ulonglong,
191                    ad.as_ptr(),
192                    ad.len() as c_ulonglong,
193                    std::ptr::null_mut(),
194                    nonce.0.as_ptr(),
195                    key.0.as_ptr(),
196                );
197                ret == 0
198            }
199        }
200    }
201
202    pub fn aes256gcm_decrypt(message: &mut [u8], tag: &[u8], ciphertext: &[u8], ad: &[u8], nonce: &Nonce, key: &Key) -> bool {
203        lazy_static::initialize(&super::SODIUM);
204        if tag.len() != TAG_BYTES {
205            false
206        } else {
207            unsafe {
208                crypto_aead_aes256gcm_decrypt_detached(
209                    message.as_mut_ptr(),
210                    std::ptr::null_mut(),
211                    ciphertext.as_ptr(),
212                    ciphertext.len() as c_ulonglong,
213                    tag.as_ptr(),
214                    ad.as_ptr(),
215                    ad.len() as c_ulonglong,
216                    nonce.0.as_ptr(),
217                    key.0.as_ptr(),
218                ) == 0
219            }
220        }
221    }
222}
223
224pub mod scalarmult {
225    use super::*;
226    pub const BYTES: usize = 32;
227
228    #[derive(Debug)]
229    pub struct Scalar(pub [u8; BYTES]);
230    #[derive(Debug)]
231    pub struct GroupElement(pub [u8; BYTES]);
232
233    pub fn scalarmult_base(n: &Scalar) -> GroupElement {
234        lazy_static::initialize(&super::SODIUM);
235        let mut q = GroupElement([0; BYTES]);
236        unsafe {
237            crypto_scalarmult_curve25519_base(q.0.as_mut_ptr(), n.0.as_ptr());
238        }
239        q
240    }
241
242    pub fn scalarmult(n: &Scalar, p: &GroupElement) -> GroupElement {
243        lazy_static::initialize(&super::SODIUM);
244        let mut q = GroupElement([0; BYTES]);
245        unsafe {
246            crypto_scalarmult_curve25519(q.0.as_mut_ptr(), n.0.as_ptr(), p.0.as_ptr());
247        }
248        q
249    }
250}
251
252pub mod random {
253    use libc::c_void;
254    use libsodium_sys::randombytes_buf;
255
256    pub fn randombytes(buf: &mut [u8]) {
257        unsafe {
258            randombytes_buf(buf.as_mut_ptr() as *mut c_void, buf.len());
259        }
260    }
261}