ssh_libsodium/
lib.rs

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