sodium_sys/crypto/utils/secmem.rs
1//! Various utility and memory safety functions.
2use libc::{c_char, c_int, c_uchar, c_void, size_t};
3use std::ffi::{CStr, CString};
4use std::slice;
5use std::str;
6
7extern "C" {
8 fn sodium_memzero(pnt: *mut c_void, len: size_t) -> ();
9 fn sodium_memcmp(b1_: *const c_void, b2_:
10 *const c_void, len: size_t) -> c_int;
11 fn sodium_bin2hex(hex: *mut c_char,
12 hex_maxlen: size_t,
13 bin: *const c_uchar,
14 bin_len: size_t) -> *mut c_char;
15 fn sodium_hex2bin(bin: *mut c_uchar,
16 bin_maxlen: size_t,
17 hex: *const c_char,
18 hex_len: size_t,
19 ignore: *const c_char,
20 bin_len: *mut size_t,
21 hex_end: *mut *const c_char) -> c_int;
22 fn sodium_mlock(addr: *mut c_void, len: size_t) -> c_int;
23 fn sodium_munlock(addr: *mut c_void, len: size_t) -> c_int;
24 fn sodium_malloc(size: size_t) -> *mut c_void;
25 fn sodium_allocarray(count: size_t, size: size_t) -> *mut c_void;
26 fn sodium_free(ptr: *mut c_void) -> ();
27 fn sodium_mprotect_noaccess(ptr: *mut c_void) -> c_int;
28 fn sodium_mprotect_readonly(ptr: *mut c_void) -> c_int;
29 fn sodium_mprotect_readwrite(ptr: *mut c_void) -> c_int;
30 #[cfg(feature = "latest")]
31 fn sodium_increment(n: *mut c_uchar, nlen: size_t) -> ();
32}
33
34/// After use, sensitive data should be overwritten, but *memset()* and
35/// hand-written code can be silently stripped out by an optimizing compiler or
36/// by the linker.
37///
38/// The *memzero()* function tries to effectively zero the bytes in *mem*, even
39/// if optimizations are being applied to the code. This function safely wraps
40/// a call to *sodium_memzero()*.
41///
42/// # Examples
43///
44/// ```
45/// use sodium_sys::crypto::utils::secmem::memzero;
46///
47/// let v = [0, 1, 2, 3, 4, 5, 6, 7];
48/// memzero(&v);
49/// assert!(v == [0; 8]);
50/// ```
51pub fn memzero(mem: &[u8]) {
52 unsafe {
53 sodium_memzero(mem.as_ptr() as *mut c_void,
54 mem.len() as size_t);
55 }
56}
57
58/// When a comparison involves secret data (e.g. key, authentication tag), is it
59/// critical to use a constant-time comparison function in order to mitigate
60/// side-channel attacks.
61///
62/// The *memcmp()* function can be used for this purpose.
63///
64/// The function returns 0 if the bytes pointed to by *m1* match the bytes
65/// pointed to by *m2*. Otherwise, it returns -1.
66///
67/// Note: *memcmp* safely wraps *sodium_memcmp*. *sodium_memcmp()* is not a
68/// lexicographic comparator and is not a generic replacement for *memcmp()*.
69///
70/// # Examples
71///
72/// ```
73/// use sodium_sys::crypto::utils::secmem::memcmp;
74///
75/// let v0 = [0, 1, 2, 3, 4, 5, 6, 7];
76/// let v1 = [0, 1, 2, 3, 4, 5, 6, 7];
77/// let v2 = [7, 6, 5, 4, 3, 2, 1, 0];
78/// assert!(memcmp(&v0,&v1) == 0);
79/// assert!(memcmp(&v0,&v2) == -1);
80/// assert!(memcmp(&v1,&v2) == -1);
81/// ```
82pub fn memcmp(m1: &[u8], m2: &[u8]) -> i32 {
83 if m1.len() == m2.len() {
84 unsafe {
85 sodium_memcmp(m1.as_ptr() as *const c_void,
86 m2.as_ptr() as *const c_void,
87 m1.len() as size_t)
88 }
89 } else {
90 -1
91 }
92}
93
94/// The *bin2hex()* function converts a byte sequence into a hexadecimal string.
95///
96/// The *bin2hex()* function safely wraps the *sodium_bin2hex()* function.
97///
98/// # Examples
99///
100/// ```
101/// use sodium_sys::crypto::utils::secmem::bin2hex;
102///
103/// let v = [0, 1, 254, 255];
104/// assert!(bin2hex(&v).unwrap() == "0001feff");
105/// ```
106pub fn bin2hex(mem: &[u8]) -> Result<String, ::SSError> {
107 let hlen = (mem.len() * 2) + 1;
108 let mut bufvec: Vec<i8> = Vec::with_capacity(hlen);
109 for _ in 0..hlen {
110 bufvec.push(0);
111 }
112 let mut buf = &mut bufvec[..];
113 unsafe {
114 let buf_ptr = sodium_bin2hex(buf.as_mut_ptr(),
115 buf.len() as size_t,
116 mem.as_ptr(),
117 mem.len() as size_t);
118 let slice = CStr::from_ptr(buf_ptr).to_bytes();
119 Ok(try!(str::from_utf8(slice)).to_string())
120 }
121}
122
123/// The *hex2bin()* function parses a hexadecimal string and converts it to a
124/// byte sequence.
125///
126/// *ignore* is a string of characters to skip. For example, the string ": "
127/// allows columns and spaces to be present at any locations in the hexadecimal
128/// string. These characters will just be ignored. As a result, "69:FC",
129/// "69 FC", "69 : FC" and "69FC" will be valid inputs, and will produce the
130/// same output.
131///
132/// *ignore* can be set to None in order to disallow any non-hexadecimal
133/// character.
134///
135/// The function returns -1 on failure. It returns 0 on success and sets
136/// *output* to the byte sequence.
137///
138/// It evaluates in constant time for a given length and format.
139///
140/// *hex2bin()* safely wraps the *sodium_hex2bin()* function.
141///
142/// # Examples
143///
144/// ```
145/// use sodium_sys::crypto::utils::secmem::hex2bin;
146///
147/// let hex = String::from("0001feff");
148/// let mut output = Vec::new();
149/// assert!(hex2bin(hex, &mut output, None) == 0);
150/// assert!(output == [0, 1, 254, 255]);
151///
152/// let hex = String::from("00:01:fe:ff");
153/// let ignore = Some(String::from(":"));
154/// let mut output = Vec::new();
155/// assert!(hex2bin(hex, &mut output, ignore) == 0);
156/// assert!(output == [0, 1, 254, 255]);
157///
158/// let hex = String::from("00 01 fe ff");
159/// let ignore = Some(String::from(" "));
160/// let mut output = Vec::new();
161/// assert!(hex2bin(hex, &mut output, ignore) == 0);
162/// assert!(output == [0, 1, 254, 255]);
163///
164/// let hex = String::from("00 01:fe ff");
165/// let ignore = Some(String::from(": "));
166/// let mut output = Vec::new();
167/// assert!(hex2bin(hex, &mut output, ignore) == 0);
168/// assert!(output == [0, 1, 254, 255]);
169/// ```
170pub fn hex2bin(hex: String,
171 output: &mut Vec<u8>,
172 ignore: Option<String>) -> i32 {
173 let mut base = hex.clone();
174 let igstr = match ignore {
175 Some(i) => {
176 for c in i.chars() {
177 base = base.replace(&c.to_string()[..], "");
178 }
179 CString::new(i).unwrap()
180 },
181 None => CString::new("").unwrap(),
182 };
183
184 let chex_len = hex.len() + 1;
185 let blen = base.len() / 2;
186 let chex = CString::new(hex).unwrap();
187 let mut bufvec: Vec<u8> = Vec::with_capacity(blen);
188 for _ in 0..blen {
189 bufvec.push(0);
190 }
191 let mut buf = &mut bufvec[..];
192 let mut b: [size_t; 1] = [0];
193 let hex_end: [i8; 1] = [0];
194
195 unsafe {
196 let res = sodium_hex2bin(buf.as_mut_ptr(),
197 buf.len() as size_t,
198 chex.as_ptr(),
199 chex_len as size_t,
200 igstr.as_ptr(),
201 b.as_mut_ptr(),
202 hex_end.as_ptr() as *mut *const i8);
203
204 for b in buf.iter() {
205 output.push(*b);
206 }
207
208 res
209 }
210
211
212}
213
214/// The *mlock()* function locks the bytes of the given array. This can help
215/// avoid swapping sensitive data to disk.
216///
217/// In addition, it is recommended to totally disable swap partitions on
218/// machines processing senstive data, or, as a second choice, use encrypted
219/// swap partitions.
220///
221/// For similar reasons, on Unix systems, one should also disable core dumps
222/// when running crypto code outside a development environment. This can be
223/// achieved using a shell built-in such as ulimit or programatically using
224/// ```setrlimit(RLIMIT_CORE, &(struct rlimit) {0, 0})```. On operating systems
225/// where this feature is implemented, kernel crash dumps should also be
226/// disabled.
227///
228/// *mlock()* safely wraps *sodium_mlock()* which wraps *mlock()* and
229/// *VirtualLock()*. Note: Many systems place limits on the amount of memory
230/// that may be locked by a process. Care should be taken to raise those limits
231/// (e.g. Unix ulimits) where neccessary. *mlock()* will return -1 when any
232/// limit is reached.
233///
234/// # Examples
235///
236/// ```
237/// use sodium_sys::crypto::utils::secmem::mlock;
238///
239/// let v = [0, 1, 2, 3, 4, 5, 6, 7];
240/// assert!(mlock(&v) == 0);
241/// ```
242pub fn mlock(mem: &[u8]) -> i32 {
243 unsafe {
244 sodium_mlock(mem.as_ptr() as *mut c_void,
245 mem.len() as size_t)
246 }
247}
248
249/// The *munlock()* function should be called after locked memory is not being
250/// used any more. It will zero the bytes in the array before actually flagging
251/// the pages as swappable again. Calling *memzero()* prior to *munlock()* is
252/// thus not required.
253///
254/// On systems where it is supported, *sodium_mlock()* also wraps *madvise()*
255/// and advises the kernel not to include the locked memory in coredumps.
256/// *ss_unlock()* also undoes this additional protection.
257///
258/// *munlock* safely wraps *sodium_munlock*.
259///
260/// # Examples
261///
262/// ```
263/// use sodium_sys::crypto::utils::secmem::{mlock, munlock};
264///
265/// let v = [0, 1, 2, 3, 4, 5, 6, 7];
266/// assert!(mlock(&v) == 0);
267/// assert!(munlock(&v) == 0);
268/// assert!(v == [0; 8]);
269/// ```
270pub fn munlock(mem: &[u8]) -> i32 {
271 unsafe {
272 sodium_munlock(mem.as_ptr() as *mut c_void,
273 mem.len() as size_t)
274 }
275}
276
277/// The *malloc()* function returns a mutable array of bytes.
278///
279/// The allocated region is placed at the end of a page boundary, immediately
280/// followed by a guard page. As a result, accessing memory past the end of the
281/// region will immediately terminate the application.
282///
283/// A canary is also placed right before the returned pointer. Modification of
284/// this canary are detected when trying to free the allocated region with
285/// *free()*, and also cause the application to immediately terminate.
286///
287/// An additional guard page is placed before this canary to make it less
288/// likely for sensitive data to be accessible when reading past the end of an
289/// unrelated region.
290///
291/// The allocated region is filled with 0xd0 bytes in order to help catch bugs
292/// due to initialized data.
293///
294/// In addition, *sodium_mlock()* is called on the region to help avoid it being
295/// swapped to disk. On operating systems supporting MAP_NOCORE or
296/// MADV_DONTDUMP, memory allocated this way will also not be part of core
297/// dumps.
298///
299/// The returned address will not be aligned if the allocation size is not a
300/// multiple of the
301/// required alignment.
302///
303/// For this reason, *malloc()* should not be used with packed or
304/// variable-length structures, unless the size given to *malloc()* is rounded
305/// up in order to ensure proper alignment.
306///
307/// All the structures used by libsodium can safely be allocated using
308/// *sodium_malloc()*, the only one requiring extra care being
309/// crypto_generichash_state, whose size needs to be rounded up to a multiple
310/// of 64 bytes.
311///
312/// # Examples
313///
314/// ```
315/// use sodium_sys::crypto::utils::init::init;
316/// use sodium_sys::crypto::utils::secmem::{malloc,free};
317///
318/// let _ = init();
319/// let mut v = malloc(64);
320/// v[0] = 1;
321/// assert!(v.len() == 64);
322/// assert!(v[0] == 1);
323/// free(v);
324/// ```
325pub fn malloc<'a>(size: usize) -> &'a mut [u8] {
326 unsafe {
327 let ptr = sodium_malloc(size as size_t) as *mut u8;
328 assert!(!ptr.is_null());
329 slice::from_raw_parts_mut(ptr, size)
330 }
331}
332
333/// The *allocarray()* function returns a mutable byte array.
334///
335/// It provides the same guarantees as *malloc()* but also protects against
336/// arithmetic overflows when count * size exceeds SIZE_MAX.
337///
338/// *allocarray()* safely wraps *sodium_allocarray()*.
339///
340/// # Examples
341///
342/// ```
343/// use sodium_sys::crypto::utils::init::init;
344/// use sodium_sys::crypto::utils::secmem::{allocarray,free};
345///
346/// let _ = init();
347/// let mut v = allocarray(2, 16);
348/// v[0] = 1;
349/// assert!(v.len() == 32);
350/// assert!(v[0] == 1);
351/// free(v);
352/// ```
353pub fn allocarray<'a>(count: size_t,
354 size: size_t) -> &'a mut [u8] {
355 unsafe {
356 let ptr = sodium_allocarray(count, size) as *mut u8;
357 assert!(!ptr.is_null());
358 slice::from_raw_parts_mut(ptr, (count * size) as usize)
359 }
360}
361
362/// The *free()* function unlocks and deallocates memory allocated using
363/// *malloc()* or *allocarray()*.
364///
365/// Prior to this, the canary is checked in order to detect possible buffer
366/// underflows and terminate the process if required.
367///
368/// *free()* also fills the memory region with zeros before the deallocation.
369///
370/// This function can be called even if the region was previously protected
371/// using *mprotect_readonly()*; the protection will automatically be changed
372/// as needed.
373///
374/// The *free()* function safely wraps the *sodium_free* function.
375///
376/// # Examples
377///
378/// ```
379/// use sodium_sys::crypto::utils::init::init;
380/// use sodium_sys::crypto::utils::secmem::{malloc,free};
381///
382/// let _ = init();
383/// let mut v = malloc(128);
384/// v[0] = 1;
385/// v[127] = 255;
386/// assert!(v.len() == 128);
387/// assert!(v[0] == 1);
388/// assert!(v[127] == 255);
389/// free(v);
390/// ```
391pub fn free(mem: &[u8]) {
392 unsafe {
393 sodium_free(mem.as_ptr() as *mut c_void);
394 }
395}
396
397/// The *mprotect_noaccess()* function makes a region allocated using *malloc()*
398/// or *allocarray()* inaccessible. It cannot be read or written, but the data
399/// are preserved.
400///
401/// This function can be used to make confidential data inacessible except when
402/// actually needed for a specific operation.
403///
404/// *mprotect_noaccess()* safely wraps the *sodium_mprotect_noaccess()*
405/// function.
406///
407/// # Examples
408///
409/// ```
410/// use sodium_sys::crypto::utils::init::init;
411/// use sodium_sys::crypto::utils::secmem::{free,malloc,mprotect_noaccess};
412///
413/// let _ = init();
414/// let mut v = malloc(64);
415/// v[0] = 1;
416/// assert!(v.len() == 64);
417/// assert!(v[0] == 1);
418/// mprotect_noaccess(&mut v);
419/// // If you uncomment the following line the program will fail (no read).
420/// // assert!(v[0] == 1);
421/// // If you uncomment the following line the program will fail (no write).
422/// // v[1] = 1;
423/// free(&mut v);
424/// ```
425pub fn mprotect_noaccess(mem: &[u8]) {
426 unsafe {
427 sodium_mprotect_noaccess(mem.as_ptr() as *mut c_void);
428 }
429}
430
431/// The *mprotect_readonly()* function marks a region allocated using *malloc()*
432/// or *allocarray()* as read-only.
433///
434/// Attempting to modify the data will cause the process to terminate.
435///
436/// # Examples
437///
438/// ```
439/// use sodium_sys::crypto::utils::init::init;
440/// use sodium_sys::crypto::utils::secmem::{free,malloc,mprotect_readonly};
441///
442/// let _ = init();
443/// let mut v = malloc(64);
444/// v[0] = 1;
445/// assert!(v.len() == 64);
446/// assert!(v[0] == 1);
447/// mprotect_readonly(&mut v);
448/// assert!(v[0] == 1);
449/// // If you uncomment the following line the program will fail (no write).
450/// // v[1] = 1;
451/// free(&mut v);
452/// ```
453pub fn mprotect_readonly(mem: &[u8]) {
454 unsafe {
455 sodium_mprotect_readonly(mem.as_ptr() as *mut c_void);
456 }
457}
458
459/// The *mprotect_readwrite()* function marks a region allocated using
460/// *malloc()* or *allocarray()* as readable and writable, after having been
461/// protected using *mprotect_readonly()* or *mprotect_noaccess()*.
462///
463/// # Examples
464///
465/// ```
466/// use sodium_sys::crypto::utils::init::init;
467/// use sodium_sys::crypto::utils::secmem::{
468/// free,
469/// malloc,
470/// mprotect_noaccess,
471/// mprotect_readwrite
472/// };
473///
474/// let _ = init();
475/// let mut v = malloc(64);
476/// v[0] = 1;
477/// assert!(v.len() == 64);
478/// assert!(v[0] == 1);
479/// mprotect_noaccess(&mut v);
480/// // If you uncomment the following line the program will fail (no read).
481/// // assert!(v[0] == 1);
482/// // If you uncomment the following line the program will fail (no write).
483/// // v[1] = 1;
484/// mprotect_readwrite(&mut v);
485/// assert!(v[0] == 1);
486/// v[1] = 1;
487/// assert!(v[1] == 1);
488/// free(&mut v);
489/// ```
490pub fn mprotect_readwrite(mem: &[u8]) {
491 unsafe {
492 sodium_mprotect_readwrite(mem.as_ptr() as *mut c_void);
493 }
494}
495
496#[cfg(feature = "latest")]
497/// The *increment()* function takes a pointer to an arbitrary length unsigned
498/// number, and increments it.
499///
500/// It runs in constant-time for a given length, and considers the number to be
501/// encoded in little-endian format.
502///
503/// *increment()* can be used to increment nonces.
504///
505/// # Examples
506///
507/// ```
508/// use sodium_sys::crypto::utils::secmem;
509///
510/// let mut nonce = [0];
511/// secmem::increment(&mut nonce);
512/// assert!(nonce == [1]);
513/// secmem::increment(&mut nonce);
514/// assert!(nonce == [2]);
515/// ```
516pub fn increment(n: &mut [u8]) {
517 unsafe {
518 sodium_increment(n.as_mut_ptr(), n.len() as size_t);
519 }
520}