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};