libsodium_rs/utils/mod.rs
1//! # Cryptographic Utilities
2//!
3//! This module provides various utility functions for cryptographic operations, including
4//! secure memory management, constant-time comparisons, and encoding/decoding functions.
5//! These utilities are designed to help implement cryptographic protocols securely and
6//! efficiently.
7//!
8//! ## Security Considerations
9//!
10//! - Many functions in this module are specifically designed to prevent side-channel attacks
11//! and other security vulnerabilities.
12//! - The memory management functions help prevent sensitive data from being leaked or
13//! swapped to disk.
14//! - Always use these utilities when handling sensitive cryptographic material.
15//!
16//! ## Key Features
17//!
18//! - **Secure Memory Management**: Functions for securely allocating, protecting, and
19//! clearing memory containing sensitive data.
20//! - **Constant-Time Operations**: Functions for comparing data in constant time to prevent
21//! timing attacks.
22//! - **Encoding/Decoding**: Functions for converting between binary data and hexadecimal or
23//! Base64 representations.
24//! - **Arithmetic Operations**: Functions for performing arithmetic on big-endian encoded
25//! numbers, useful for nonce management.
26//!
27//! ## Example
28//!
29//! ```rust
30//! use libsodium_rs as sodium;
31//! use sodium::utils;
32//! use sodium::ensure_init;
33//!
34//! fn main() -> Result<(), Box<dyn std::error::Error>> {
35//! ensure_init()?;
36//!
37//! // Secure memory operations
38//! let mut sensitive_data = [0x01, 0x02, 0x03, 0x04];
39//!
40//! // Lock memory to prevent it from being swapped to disk
41//! utils::mlock(&mut sensitive_data).expect("Failed to lock memory");
42//!
43//! // Use the sensitive data...
44//!
45//! // Securely zero the memory when done
46//! utils::memzero(&mut sensitive_data);
47//! assert_eq!(sensitive_data, [0, 0, 0, 0]);
48//!
49//! // Unlock the memory
50//! utils::munlock(&mut sensitive_data).expect("Failed to unlock memory");
51//!
52//! // Constant-time comparison
53//! let tag1 = [0x01, 0x02, 0x03, 0x04];
54//! let tag2 = [0x01, 0x02, 0x03, 0x04];
55//! assert!(utils::memcmp(&tag1, &tag2));
56//!
57//! // Encoding/decoding
58//! let binary = [0xDE, 0xAD, 0xBE, 0xEF];
59//! let hex = utils::bin2hex(&binary);
60//! assert_eq!(hex, "deadbeef");
61//!
62//! Ok(())
63//! }
64//! ```
65//!
66
67use crate::Result;
68use libsodium_sys;
69
70/// Base64 encoding variant: original (standard) Base64 encoding
71pub const BASE64_VARIANT_ORIGINAL: i32 = libsodium_sys::sodium_base64_VARIANT_ORIGINAL as i32;
72
73/// Base64 encoding variant: original (standard) Base64 encoding without padding
74pub const BASE64_VARIANT_ORIGINAL_NO_PADDING: i32 =
75 libsodium_sys::sodium_base64_VARIANT_ORIGINAL_NO_PADDING as i32;
76
77/// Base64 encoding variant: URL-safe Base64 encoding
78pub const BASE64_VARIANT_URLSAFE: i32 = libsodium_sys::sodium_base64_VARIANT_URLSAFE as i32;
79
80/// Base64 encoding variant: URL-safe Base64 encoding without padding
81pub const BASE64_VARIANT_URLSAFE_NO_PADDING: i32 =
82 libsodium_sys::sodium_base64_VARIANT_URLSAFE_NO_PADDING as i32;
83
84/// Compare two byte slices in constant time
85///
86/// This function compares two byte slices in constant time, which is important for
87/// comparing secret data like authentication tags or passwords. It returns true if
88/// the slices are equal, false otherwise.
89///
90/// ## Security Considerations
91///
92/// - This function is designed to prevent timing attacks that could leak information
93/// about the contents of the slices being compared.
94/// - It should be used whenever comparing sensitive data like authentication tags,
95/// MACs, or password hashes.
96/// - Regular comparison operators (==) should NOT be used for comparing secret data
97/// as they may be vulnerable to timing attacks.
98///
99/// ## Example
100///
101/// ```rust
102/// use libsodium_rs as sodium;
103/// use sodium::utils;
104///
105/// let tag1 = [0x01, 0x02, 0x03, 0x04];
106/// let tag2 = [0x01, 0x02, 0x03, 0x04];
107/// let tag3 = [0x01, 0x02, 0x03, 0x05];
108///
109/// // Compare in constant time
110/// assert!(utils::memcmp(&tag1, &tag2)); // Equal
111/// assert!(!utils::memcmp(&tag1, &tag3)); // Not equal
112/// ```
113///
114/// # Arguments
115/// * `a` - First byte slice to compare
116/// * `b` - Second byte slice to compare
117///
118/// # Returns
119/// * `bool` - `true` if the slices are equal, `false` otherwise
120pub fn memcmp(a: &[u8], b: &[u8]) -> bool {
121 if a.len() != b.len() {
122 return false;
123 }
124
125 unsafe {
126 libsodium_sys::sodium_memcmp(a.as_ptr() as *const _, b.as_ptr() as *const _, a.len()) == 0
127 }
128}
129
130/// Zero a byte slice in a way that won't be optimized out
131///
132/// This function securely zeroes a byte slice, ensuring that the operation
133/// won't be optimized out by the compiler. This is important for securely
134/// clearing sensitive data from memory.
135///
136/// ## Security Considerations
137///
138/// - This function ensures that the memory is actually zeroed, even if the compiler
139/// would normally optimize out the operation
140/// - It should be used whenever a byte slice containing sensitive data (like cryptographic
141/// keys or passwords) is no longer needed
142/// - Regular assignment (e.g., `slice = [0; len]`) might be optimized out by the
143/// compiler and not actually clear the memory
144///
145/// ## Example
146///
147/// ```rust
148/// use libsodium_rs as sodium;
149/// use sodium::utils;
150///
151/// // Create a slice with sensitive data
152/// let mut secret_key = [0x01, 0x02, 0x03, 0x04];
153///
154/// // Use the key for some operation...
155///
156/// // Securely clear the key from memory when done
157/// utils::memzero(&mut secret_key);
158/// assert_eq!(secret_key, [0, 0, 0, 0]);
159/// ```
160///
161/// # Arguments
162/// * `buf` - The byte slice to zero
163pub fn memzero(buf: &mut [u8]) {
164 unsafe {
165 libsodium_sys::sodium_memzero(buf.as_mut_ptr() as *mut _, buf.len());
166 }
167}
168
169/// Zero a region of the stack in a way that won't be optimized out
170///
171/// This function securely zeroes a region of the stack, ensuring that the operation
172/// won't be optimized out by the compiler. This is useful for clearing sensitive
173/// data from the stack before returning from a function.
174///
175/// ## Security Considerations
176///
177/// - This function ensures that the stack memory is actually zeroed, even if the compiler
178/// would normally optimize out the operation
179/// - It should be used when sensitive data is stored on the stack and needs to be cleared
180/// before returning from a function
181///
182/// ## Example
183///
184/// ```rust
185/// use libsodium_rs as sodium;
186/// use sodium::utils;
187///
188/// fn process_sensitive_data() {
189/// // Create sensitive data on the stack
190/// let sensitive_data = [0x01, 0x02, 0x03, 0x04];
191///
192/// // Use the data for some operation...
193///
194/// // Securely clear the data from the stack
195/// utils::stackzero(sensitive_data.len());
196/// }
197/// ```
198///
199/// # Arguments
200/// * `len` - The number of bytes to zero on the stack
201pub fn stackzero(len: usize) {
202 unsafe {
203 libsodium_sys::sodium_stackzero(len);
204 }
205}
206
207/// Lock memory pages containing this slice, preventing them from being swapped to disk
208///
209/// This function locks the memory pages containing the provided byte slice, preventing
210/// them from being swapped to disk. This is important for protecting sensitive
211/// cryptographic material from being written to disk where it might be recovered later.
212///
213/// ## Security Considerations
214///
215/// - Locked memory is not swapped to disk, reducing the risk of sensitive data leakage
216/// - This function should be used for byte slices containing highly sensitive data like
217/// cryptographic keys or passwords
218/// - Remember to call `munlock` when the byte slice is no longer needed
219/// - There may be system-wide limits on the amount of memory that can be locked
220///
221/// ## Example
222///
223/// ```rust
224/// use libsodium_rs as sodium;
225/// use sodium::utils;
226///
227/// let mut sensitive_data = [0x01, 0x02, 0x03, 0x04];
228/// utils::mlock(&mut sensitive_data).expect("Failed to lock memory");
229/// // Use the sensitive data...
230/// utils::munlock(&mut sensitive_data).expect("Failed to unlock memory");
231/// ```
232pub fn mlock(buf: &mut [u8]) -> std::io::Result<()> {
233 let result = unsafe { libsodium_sys::sodium_mlock(buf.as_mut_ptr() as *mut _, buf.len()) };
234
235 if result == 0 {
236 Ok(())
237 } else {
238 Err(std::io::Error::last_os_error())
239 }
240}
241
242/// Unlock previously locked memory pages
243///
244/// This function unlocks memory pages that were previously locked with `mlock`.
245/// It should be called when the sensitive data is no longer needed.
246///
247/// # Returns
248///
249/// * `io::Result<()>` - Success or an error if the memory couldn't be unlocked
250///
251/// ## Example
252///
253/// ```rust
254/// use libsodium_rs as sodium;
255/// use sodium::utils;
256///
257/// let mut sensitive_data = [0x01, 0x02, 0x03, 0x04];
258/// utils::mlock(&mut sensitive_data).expect("Failed to lock memory");
259/// // Use the sensitive data...
260/// utils::munlock(&mut sensitive_data).expect("Failed to unlock memory");
261/// ```
262pub fn munlock(buf: &mut [u8]) -> std::io::Result<()> {
263 let result = unsafe { libsodium_sys::sodium_munlock(buf.as_mut_ptr() as *mut _, buf.len()) };
264
265 if result == 0 {
266 Ok(())
267 } else {
268 Err(std::io::Error::last_os_error())
269 }
270}
271
272/// Increment a number (usually a nonce) stored as big-endian bytes
273pub fn increment_be(n: &mut [u8]) {
274 unsafe {
275 libsodium_sys::sodium_increment(n.as_mut_ptr(), n.len());
276 }
277}
278
279/// Add two numbers stored as big-endian bytes
280///
281/// This function adds two numbers stored as big-endian byte arrays. The result
282/// is stored in the first array (`a`).
283///
284/// ## Example
285///
286/// ```rust
287/// use libsodium_rs as sodium;
288/// use sodium::utils;
289///
290/// let mut a = [0x01, 0x02, 0x03, 0x04];
291/// let b = [0x00, 0x01, 0x00, 0x01];
292/// utils::add_be(&mut a, &b);
293/// assert_eq!(a, [0x01, 0x03, 0x03, 0x05]);
294/// ```
295///
296/// # Arguments
297/// * `a` - First number as big-endian bytes (will be modified to store the result)
298/// * `b` - Second number as big-endian bytes
299pub fn add_be(a: &mut [u8], b: &[u8]) {
300 unsafe {
301 libsodium_sys::sodium_add(a.as_mut_ptr(), b.as_ptr(), a.len().min(b.len()));
302 }
303}
304
305/// Subtract one number from another, both stored as big-endian bytes
306///
307/// This function subtracts the second number (`b`) from the first number (`a`),
308/// both stored as big-endian byte arrays. The result is stored in the first array (`a`).
309///
310/// ## Example
311///
312/// ```rust
313/// use libsodium_rs as sodium;
314/// use sodium::utils;
315///
316/// let mut a = [0x01, 0x03, 0x03, 0x05];
317/// let b = [0x00, 0x01, 0x00, 0x01];
318/// utils::sub_be(&mut a, &b);
319/// assert_eq!(a, [0x01, 0x02, 0x03, 0x04]);
320/// ```
321///
322/// # Arguments
323/// * `a` - First number as big-endian bytes (will be modified to store the result)
324/// * `b` - Second number as big-endian bytes (will be subtracted from `a`)
325pub fn sub_be(a: &mut [u8], b: &[u8]) {
326 unsafe {
327 libsodium_sys::sodium_sub(a.as_mut_ptr(), b.as_ptr(), a.len().min(b.len()));
328 }
329}
330
331/// Check if a byte array is all zeros
332///
333/// This function checks if a byte array contains only zeros. It is designed to be
334/// constant-time regardless of the input data, which is important for security-sensitive
335/// applications.
336///
337/// ## Example
338///
339/// ```rust
340/// use libsodium_rs as sodium;
341/// use sodium::utils;
342///
343/// let zeros = [0, 0, 0, 0];
344/// let non_zeros = [0, 0, 1, 0];
345///
346/// assert!(utils::is_zero(&zeros));
347/// assert!(!utils::is_zero(&non_zeros));
348/// ```
349///
350/// # Arguments
351/// * `n` - The byte array to check
352///
353/// # Returns
354/// * `bool` - `true` if the array contains only zeros, `false` otherwise
355pub fn is_zero(n: &[u8]) -> bool {
356 unsafe { libsodium_sys::sodium_is_zero(n.as_ptr(), n.len()) == 1 }
357}
358
359/// Compare two byte arrays in lexicographical order
360///
361/// This function compares two byte arrays in lexicographical order. It returns -1 if
362/// the first array is less than the second, 1 if the first array is greater than the
363/// second, and 0 if the arrays are equal.
364///
365/// ## Security Considerations
366///
367/// - This function is constant-time, which is important for security-sensitive applications
368/// - It should be used when comparing sensitive data that requires a lexicographical
369/// comparison rather than just equality testing
370///
371/// ## Example
372///
373/// ```rust
374/// use libsodium_rs as sodium;
375/// use sodium::utils;
376///
377/// let a = [0x01, 0x02, 0x03, 0x04];
378/// let b = [0x01, 0x02, 0x03, 0x05];
379/// let c = [0x01, 0x02, 0x03, 0x03];
380///
381/// assert_eq!(utils::compare(&a, &b), -1); // a < b
382/// assert_eq!(utils::compare(&b, &a), 1); // b > a
383/// assert_eq!(utils::compare(&a, &a), 0); // a == a
384/// assert_eq!(utils::compare(&a, &c), 1); // a > c
385/// ```
386///
387/// # Arguments
388/// * `a` - First byte array to compare
389/// * `b` - Second byte array to compare
390///
391/// # Returns
392/// * `i32` - -1 if a < b, 1 if a > b, 0 if a == b
393pub fn compare(a: &[u8], b: &[u8]) -> i32 {
394 unsafe { libsodium_sys::sodium_compare(a.as_ptr(), b.as_ptr(), a.len().min(b.len())) }
395}
396
397/// Convert binary data to a hexadecimal string
398///
399/// This function converts a byte array to a hexadecimal string representation.
400///
401/// ## Example
402///
403/// ```rust
404/// use libsodium_rs as sodium;
405/// use sodium::utils;
406///
407/// let binary = [0xDE, 0xAD, 0xBE, 0xEF];
408/// let hex = utils::bin2hex(&binary);
409/// assert_eq!(hex, "deadbeef");
410/// ```
411///
412/// # Arguments
413/// * `bin` - The binary data to convert
414///
415/// # Returns
416/// * `String` - The hexadecimal representation of the binary data
417pub fn bin2hex(bin: &[u8]) -> String {
418 let hex_len = bin.len() * 2 + 1;
419 let mut hex = vec![0u8; hex_len];
420
421 unsafe {
422 libsodium_sys::sodium_bin2hex(hex.as_mut_ptr() as *mut _, hex_len, bin.as_ptr(), bin.len());
423 }
424
425 // Remove the null terminator
426 hex.pop();
427
428 // Convert to a String
429 String::from_utf8(hex).unwrap_or_else(|_| String::new())
430}
431
432/// Calculate the length of a hexadecimal string needed to encode binary data
433///
434/// This function calculates the length of a hexadecimal string needed to encode
435/// binary data of a given length.
436///
437/// # Arguments
438/// * `bin_len` - The length of the binary data
439///
440/// # Returns
441/// * `usize` - The length of the hexadecimal string, including the null terminator
442pub fn hex_encoded_len(bin_len: usize) -> usize {
443 bin_len * 2 + 1
444}
445
446/// Convert a hexadecimal string to binary data
447///
448/// This function converts a hexadecimal string to binary data.
449///
450/// ## Example
451///
452/// ```rust
453/// use libsodium_rs as sodium;
454/// use sodium::utils;
455///
456/// let hex = "deadbeef";
457/// let binary = utils::hex2bin(hex).unwrap();
458/// assert_eq!(binary, [0xDE, 0xAD, 0xBE, 0xEF]);
459/// ```
460///
461/// # Arguments
462/// * `hex` - The hexadecimal string to convert
463///
464/// # Returns
465/// * `Result<Vec<u8>>` - The binary data or an error if the string is not valid hexadecimal
466pub fn hex2bin(hex: &str) -> Result<Vec<u8>> {
467 let hex_bytes = hex.as_bytes();
468 let bin_len = (hex_bytes.len() + 1) / 2;
469 let mut bin = vec![0u8; bin_len];
470 let mut bin_len_ptr = bin_len;
471
472 let result = unsafe {
473 libsodium_sys::sodium_hex2bin(
474 bin.as_mut_ptr(),
475 bin_len,
476 hex_bytes.as_ptr() as *const _,
477 hex_bytes.len(),
478 std::ptr::null_mut(),
479 &mut bin_len_ptr,
480 std::ptr::null_mut(),
481 )
482 };
483
484 if result != 0 {
485 return Err(crate::SodiumError::HexDecodingFailed);
486 }
487
488 bin.truncate(bin_len_ptr);
489 Ok(bin)
490}
491
492/// Convert a hexadecimal string to binary data, ignoring specified characters
493///
494/// This function converts a hexadecimal string to binary data, ignoring any characters
495/// specified in the `ignore` parameter.
496///
497/// ## Example
498///
499/// ```rust
500/// use libsodium_rs as sodium;
501/// use sodium::utils;
502///
503/// let hex = "de:ad:be:ef";
504/// let binary = utils::hex2bin_ignore(hex, ":").unwrap();
505/// assert_eq!(binary, [0xDE, 0xAD, 0xBE, 0xEF]);
506/// ```
507///
508/// # Arguments
509/// * `hex` - The hexadecimal string to convert
510/// * `ignore` - Characters to ignore in the hexadecimal string
511///
512/// # Returns
513/// * `Result<Vec<u8>>` - The binary data or an error if the string is not valid hexadecimal
514pub fn hex2bin_ignore(hex: &str, ignore: &str) -> Result<Vec<u8>> {
515 let hex_bytes = hex.as_bytes();
516 let ignore_bytes = ignore.as_bytes();
517 let bin_len = (hex_bytes.len() + 1) / 2;
518 let mut bin = vec![0u8; bin_len];
519 let mut bin_len_ptr = bin_len;
520
521 let result = unsafe {
522 libsodium_sys::sodium_hex2bin(
523 bin.as_mut_ptr(),
524 bin_len,
525 hex_bytes.as_ptr() as *const _,
526 hex_bytes.len(),
527 ignore_bytes.as_ptr() as *const _,
528 &mut bin_len_ptr,
529 std::ptr::null_mut(),
530 )
531 };
532
533 if result != 0 {
534 return Err(crate::SodiumError::HexDecodingFailed);
535 }
536
537 bin.truncate(bin_len_ptr);
538 Ok(bin)
539}
540
541/// Calculate the length of a Base64 string needed to encode binary data
542///
543/// This function calculates the length of a Base64 string needed to encode
544/// binary data of a given length, using the specified variant.
545///
546/// # Arguments
547/// * `bin_len` - The length of the binary data
548/// * `variant` - The Base64 variant to use
549///
550/// # Returns
551/// * `usize` - The length of the Base64 string, including the null terminator
552pub fn base64_encoded_len(bin_len: usize, variant: i32) -> usize {
553 unsafe { libsodium_sys::sodium_base64_encoded_len(bin_len, variant) }
554}
555
556/// Convert binary data to a Base64 string
557///
558/// This function converts a byte array to a Base64 string representation,
559/// using the specified variant.
560///
561/// ## Example
562///
563/// ```rust
564/// use libsodium_rs as sodium;
565/// use sodium::utils;
566///
567/// let binary = [0xDE, 0xAD, 0xBE, 0xEF];
568/// let b64 = utils::bin2base64(&binary, utils::BASE64_VARIANT_ORIGINAL);
569/// assert_eq!(b64, "3q2+7w==");
570/// ```
571///
572/// # Arguments
573/// * `bin` - The binary data to convert
574/// * `variant` - The Base64 variant to use
575///
576/// # Returns
577/// * `String` - The Base64 representation of the binary data
578pub fn bin2base64(bin: &[u8], variant: i32) -> String {
579 let b64_len = base64_encoded_len(bin.len(), variant);
580 let mut b64 = vec![0u8; b64_len];
581
582 unsafe {
583 libsodium_sys::sodium_bin2base64(
584 b64.as_mut_ptr() as *mut _,
585 b64_len,
586 bin.as_ptr(),
587 bin.len(),
588 variant,
589 );
590 }
591
592 // Find the null terminator
593 let null_pos = b64.iter().position(|&x| x == 0).unwrap_or(b64.len());
594 b64.truncate(null_pos);
595
596 // Convert to a String
597 String::from_utf8(b64).unwrap_or_else(|_| String::new())
598}
599
600/// Convert a Base64 string to binary data
601///
602/// This function converts a Base64 string to binary data, using the specified variant.
603///
604/// ## Example
605///
606/// ```rust
607/// use libsodium_rs as sodium;
608/// use sodium::utils;
609///
610/// let b64 = "3q2+7w==";
611/// let binary = utils::base642bin(b64, utils::BASE64_VARIANT_ORIGINAL).unwrap();
612/// assert_eq!(binary, [0xDE, 0xAD, 0xBE, 0xEF]);
613/// ```
614///
615/// # Arguments
616/// * `b64` - The Base64 string to convert
617/// * `variant` - The Base64 variant to use
618///
619/// # Returns
620/// * `Result<Vec<u8>>` - The binary data or an error if the string is not valid Base64
621pub fn base642bin(b64: &str, variant: i32) -> Result<Vec<u8>> {
622 let b64_bytes = b64.as_bytes();
623 let bin_len = (b64_bytes.len() * 3) / 4 + 1;
624 let mut bin = vec![0u8; bin_len];
625 let mut bin_len_ptr = bin_len;
626
627 let result = unsafe {
628 libsodium_sys::sodium_base642bin(
629 bin.as_mut_ptr(),
630 bin_len,
631 b64_bytes.as_ptr() as *const _,
632 b64_bytes.len(),
633 std::ptr::null_mut(),
634 &mut bin_len_ptr,
635 std::ptr::null_mut(),
636 variant,
637 )
638 };
639
640 if result != 0 {
641 return Err(crate::SodiumError::Base64DecodingFailed);
642 }
643
644 bin.truncate(bin_len_ptr);
645 Ok(bin)
646}
647
648/// Secure memory allocation
649///
650/// This function allocates memory with extra protection, including:
651/// - Protection against buffer overflows
652/// - Protection against access after the memory is freed
653/// - Automatic zeroing when freed
654/// - Guarded pages to detect over/underflows
655///
656/// ## Security Considerations
657///
658/// - The allocated memory is automatically zeroed when freed
659/// - The memory is protected from being swapped to disk
660/// - This should be used for storing sensitive data like keys
661///
662/// ## Example
663///
664/// ```no_run
665/// use libsodium_rs as sodium;
666/// use sodium::utils;
667/// use std::slice;
668///
669/// // Allocate 32 bytes of secure memory
670/// let ptr = utils::malloc(32);
671/// assert!(!ptr.is_null());
672///
673/// // Use the memory
674/// unsafe {
675/// let buf = slice::from_raw_parts_mut(ptr as *mut u8, 32);
676/// // Fill with data...
677/// for i in 0..32 {
678/// buf[i] = i as u8;
679/// }
680/// }
681///
682/// // Free the memory (automatically zeroes it)
683/// unsafe {
684/// utils::free(ptr);
685/// }
686/// ```
687///
688/// # Arguments
689/// * `size` - The number of bytes to allocate
690///
691/// # Returns
692/// * `*mut libc::c_void` - A pointer to the allocated memory, or null if allocation failed
693pub fn malloc(size: usize) -> *mut libc::c_void {
694 unsafe { libsodium_sys::sodium_malloc(size) }
695}
696
697/// Allocate an array of elements with secure memory
698///
699/// This function allocates an array of elements with secure memory protection.
700/// It is similar to `malloc`, but allocates an array of elements instead of a
701/// single block of memory.
702///
703/// ## Safety
704/// This function is unsafe because it returns a raw pointer.
705/// The caller is responsible for freeing the memory with `free`.
706///
707/// ## Arguments
708/// * `count` - The number of elements to allocate
709/// * `size` - The size of each element
710///
711/// ## Returns
712/// * `*mut libc::c_void` - A pointer to the allocated memory, or null if allocation failed
713pub fn allocarray(count: usize, size: usize) -> *mut libc::c_void {
714 unsafe { libsodium_sys::sodium_allocarray(count, size) }
715}
716
717/// Free memory allocated by sodium_malloc or sodium_allocarray
718///
719/// This function frees memory that was allocated by `malloc` or `allocarray`.
720/// The memory is automatically zeroed before being freed.
721///
722/// ## Safety
723/// This function is unsafe because it dereferences a raw pointer.
724/// The caller must ensure that the pointer is valid and was allocated by `malloc` or `allocarray`.
725///
726/// ## Arguments
727/// * `ptr` - A pointer to the memory to free
728pub unsafe fn free(ptr: *mut libc::c_void) {
729 unsafe { libsodium_sys::sodium_free(ptr) }
730}
731
732/// Make a region of memory inaccessible
733///
734/// This function makes a region of memory allocated with `malloc` or `allocarray`
735/// inaccessible. It can be made accessible again with `mprotect_readwrite`.
736///
737/// ## Safety
738/// This function is unsafe because it dereferences a raw pointer.
739/// The caller must ensure that the pointer is valid and was allocated by `malloc` or `allocarray`.
740///
741/// ## Arguments
742/// * `ptr` - A pointer to the memory region
743///
744/// ## Returns
745/// * `i32` - 0 on success, -1 on failure
746pub unsafe fn mprotect_noaccess(ptr: *mut libc::c_void) -> i32 {
747 unsafe { libsodium_sys::sodium_mprotect_noaccess(ptr) }
748}
749
750/// Make a region of memory read-only
751///
752/// This function makes a region of memory allocated with `malloc` or `allocarray`
753/// read-only. It can be made writable again with `mprotect_readwrite`.
754///
755/// ## Safety
756/// This function is unsafe because it dereferences a raw pointer.
757/// The caller must ensure that the pointer is valid and was allocated by `malloc` or `allocarray`.
758///
759/// ## Arguments
760/// * `ptr` - A pointer to the memory region
761///
762/// ## Returns
763/// * `i32` - 0 on success, -1 on failure
764pub unsafe fn mprotect_readonly(ptr: *mut libc::c_void) -> i32 {
765 unsafe { libsodium_sys::sodium_mprotect_readonly(ptr) }
766}
767
768/// Make a region of memory readable and writable
769///
770/// This function makes a region of memory allocated with `malloc` or `allocarray`
771/// readable and writable.
772///
773/// ## Safety
774/// This function is unsafe because it dereferences a raw pointer.
775/// The caller must ensure that the pointer is valid and was allocated by `malloc` or `allocarray`.
776///
777/// ## Arguments
778/// * `ptr` - A pointer to the memory region
779///
780/// ## Returns
781/// * `i32` - 0 on success, -1 on failure
782pub unsafe fn mprotect_readwrite(ptr: *mut libc::c_void) -> i32 {
783 unsafe { libsodium_sys::sodium_mprotect_readwrite(ptr) }
784}
785
786// Export the vec_utils module
787pub mod vec_utils;
788
789// Re-export SecureVec and secure_vec from vec_utils
790pub use vec_utils::{secure_vec, SecureVec};