1#![cfg_attr(feature = "no_std", no_std)]
61
62#[cfg(feature = "no_std")]
63extern crate alloc;
64
65pub mod array;
66pub mod string;
67pub mod vec;
68
69pub use array::SecureArray;
70pub use string::SecureString;
71pub use vec::{SecureBytes, SecureVec};
72
73use core::ptr::NonNull;
74pub use zeroize::Zeroize;
75
76#[cfg(feature = "std")]
77pub use memsec;
78#[cfg(feature = "std")]
79use memsec::Prot;
80
81use thiserror::Error as ThisError;
82
83#[cfg(feature = "std")]
84#[derive(ThisError, Debug)]
85#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
86pub enum Error {
87 #[error("Failed to allocate secure memory")]
88 AllocationFailed,
89 #[error("Allocated Ptr is null")]
90 NullAllocation,
91 #[error("CryptProtectMemory failed")]
92 CryptProtectMemoryFailed,
93 #[error("CryptUnprotectMemory failed")]
94 CryptUnprotectMemoryFailed,
95 #[error("Failed to lock memory")]
96 LockFailed,
97 #[error("Failed to unlock memory")]
98 UnlockFailed,
99 #[error("Source length does not match the fixed size of the destination array")]
100 LengthMismatch,
101}
102
103#[cfg(not(feature = "std"))]
104#[derive(Debug)]
105pub enum Error {
106 AllocationFailed,
107 NullAllocation,
108}
109
110#[cfg(all(feature = "std", test, windows))]
111use windows_sys::Win32::Foundation::GetLastError;
112#[cfg(all(feature = "std", windows))]
113use windows_sys::Win32::Security::Cryptography::{
114 CRYPTPROTECTMEMORY_BLOCK_SIZE, CRYPTPROTECTMEMORY_SAME_PROCESS, CryptProtectMemory,
115 CryptUnprotectMemory,
116};
117#[cfg(all(feature = "std", windows))]
118use windows_sys::Win32::System::SystemInformation::GetSystemInfo;
119
120#[cfg(feature = "std")]
121pub fn page_size() -> usize {
122 #[cfg(unix)]
123 {
124 unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize }
125 }
126
127 #[cfg(windows)]
128 {
129 let mut si = core::mem::MaybeUninit::uninit();
130 unsafe {
131 GetSystemInfo(si.as_mut_ptr());
132 (*si.as_ptr()).dwPageSize as usize
133 }
134 }
135}
136
137#[cfg(feature = "std")]
138pub fn mprotect<T>(ptr: NonNull<T>, prot: Prot::Ty) -> bool {
139 let success = unsafe { memsec::mprotect(ptr, prot) };
140 if !success {
141 #[cfg(test)]
142 eprintln!("mprotect failed");
143 }
144 success
145}
146
147#[cfg(all(feature = "std", windows))]
148pub fn crypt_protect_memory(ptr: *mut u8, size_in_bytes: usize) -> bool {
149 if size_in_bytes == 0 {
150 return true; }
152
153 if size_in_bytes % (CRYPTPROTECTMEMORY_BLOCK_SIZE as usize) != 0 {
154 return false;
156 }
157
158 if size_in_bytes > u32::MAX as usize {
159 return false;
160 }
161
162 let result = unsafe {
163 CryptProtectMemory(
164 ptr as *mut core::ffi::c_void,
165 size_in_bytes as u32,
166 CRYPTPROTECTMEMORY_SAME_PROCESS,
167 )
168 };
169
170 if result == 0 {
171 #[cfg(test)]
172 {
173 let error_code = unsafe { GetLastError() };
174 eprintln!(
175 "CryptProtectMemory failed with error code: {}",
176 error_code
177 );
178 }
179 return false;
180 } else {
181 true
182 }
183}
184
185#[cfg(all(feature = "std", windows))]
186pub fn crypt_unprotect_memory(ptr: *mut u8, size_in_bytes: usize) -> bool {
187 if size_in_bytes == 0 {
188 return true;
189 }
190
191 if size_in_bytes % (CRYPTPROTECTMEMORY_BLOCK_SIZE as usize) != 0 {
192 return false;
193 }
194
195 if size_in_bytes > u32::MAX as usize {
196 return false;
197 }
198
199 let result = unsafe {
200 CryptUnprotectMemory(
201 ptr as *mut core::ffi::c_void,
202 size_in_bytes as u32,
203 CRYPTPROTECTMEMORY_SAME_PROCESS,
204 )
205 };
206
207 if result == 0 {
208 #[cfg(test)]
209 {
210 let error_code = unsafe { GetLastError() };
211 eprintln!(
212 "CryptUnprotectMemory failed with error code: {}",
213 error_code
214 );
215 }
216 return false;
217 } else {
218 true
219 }
220}