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}
100
101#[cfg(not(feature = "std"))]
102#[derive(Debug)]
103pub enum Error {
104 AllocationFailed,
105 NullAllocation,
106}
107
108#[cfg(all(feature = "std", test, windows))]
109use windows_sys::Win32::Foundation::GetLastError;
110#[cfg(all(feature = "std", windows))]
111use windows_sys::Win32::Security::Cryptography::{
112 CRYPTPROTECTMEMORY_BLOCK_SIZE, CRYPTPROTECTMEMORY_SAME_PROCESS, CryptProtectMemory,
113 CryptUnprotectMemory,
114};
115#[cfg(all(feature = "std", windows))]
116use windows_sys::Win32::System::SystemInformation::GetSystemInfo;
117
118#[cfg(feature = "std")]
119pub fn page_size() -> usize {
120 #[cfg(unix)]
121 {
122 unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize }
123 }
124
125 #[cfg(windows)]
126 {
127 let mut si = core::mem::MaybeUninit::uninit();
128 unsafe {
129 GetSystemInfo(si.as_mut_ptr());
130 (*si.as_ptr()).dwPageSize as usize
131 }
132 }
133}
134
135#[cfg(feature = "std")]
136pub fn mprotect<T>(ptr: NonNull<T>, prot: Prot::Ty) -> bool {
137 let success = unsafe { memsec::mprotect(ptr, prot) };
138 if !success {
139 #[cfg(test)]
140 eprintln!("mprotect failed");
141 }
142 success
143}
144
145#[cfg(all(feature = "std", windows))]
146pub fn crypt_protect_memory(ptr: *mut u8, size_in_bytes: usize) -> bool {
147 if size_in_bytes == 0 {
148 return true; }
150
151 if size_in_bytes % (CRYPTPROTECTMEMORY_BLOCK_SIZE as usize) != 0 {
152 return false;
154 }
155
156 if size_in_bytes > u32::MAX as usize {
157 return false;
158 }
159
160 let result = unsafe {
161 CryptProtectMemory(
162 ptr as *mut core::ffi::c_void,
163 size_in_bytes as u32,
164 CRYPTPROTECTMEMORY_SAME_PROCESS,
165 )
166 };
167
168 if result == 0 {
169 #[cfg(test)]
170 {
171 let error_code = unsafe { GetLastError() };
172 eprintln!(
173 "CryptProtectMemory failed with error code: {}",
174 error_code
175 );
176 }
177 return false;
178 } else {
179 true
180 }
181}
182
183#[cfg(all(feature = "std", windows))]
184pub fn crypt_unprotect_memory(ptr: *mut u8, size_in_bytes: usize) -> bool {
185 if size_in_bytes == 0 {
186 return true;
187 }
188
189 if size_in_bytes % (CRYPTPROTECTMEMORY_BLOCK_SIZE as usize) != 0 {
190 return false;
191 }
192
193 if size_in_bytes > u32::MAX as usize {
194 return false;
195 }
196
197 let result = unsafe {
198 CryptUnprotectMemory(
199 ptr as *mut core::ffi::c_void,
200 size_in_bytes as u32,
201 CRYPTPROTECTMEMORY_SAME_PROCESS,
202 )
203 };
204
205 if result == 0 {
206 #[cfg(test)]
207 {
208 let error_code = unsafe { GetLastError() };
209 eprintln!(
210 "CryptUnprotectMemory failed with error code: {}",
211 error_code
212 );
213 }
214 return false;
215 } else {
216 true
217 }
218}