1extern crate libc;
16extern crate winapi;
17use libc::c_void;
18#[cfg(not(windows))]
19use libc::size_t;
20use std::ops::{Deref, DerefMut, Index, IndexMut, Range, RangeFrom, RangeFull, RangeTo};
21
22#[derive(Debug)]
25pub struct CryptoVec {
26 p: *mut u8,
27 size: usize,
28 capacity: usize,
29}
30
31impl Unpin for CryptoVec {}
32
33unsafe impl Send for CryptoVec {}
34unsafe impl Sync for CryptoVec {}
35
36impl AsRef<[u8]> for CryptoVec {
37 fn as_ref(&self) -> &[u8] {
38 self.deref()
39 }
40}
41impl AsMut<[u8]> for CryptoVec {
42 fn as_mut(&mut self) -> &mut [u8] {
43 self.deref_mut()
44 }
45}
46impl Deref for CryptoVec {
47 type Target = [u8];
48 fn deref(&self) -> &[u8] {
49 unsafe { std::slice::from_raw_parts(self.p, self.size) }
50 }
51}
52impl DerefMut for CryptoVec {
53 fn deref_mut(&mut self) -> &mut [u8] {
54 unsafe { std::slice::from_raw_parts_mut(self.p, self.size) }
55 }
56}
57
58impl From<String> for CryptoVec {
59 fn from(e: String) -> Self {
60 CryptoVec::from(e.into_bytes())
61 }
62}
63
64impl From<Vec<u8>> for CryptoVec {
65 fn from(e: Vec<u8>) -> Self {
66 let mut c = CryptoVec::new_zeroed(e.len());
67 c.clone_from_slice(&e[..]);
68 c
69 }
70}
71
72impl Index<RangeFrom<usize>> for CryptoVec {
73 type Output = [u8];
74 fn index(&self, index: RangeFrom<usize>) -> &[u8] {
75 self.deref().index(index)
76 }
77}
78impl Index<RangeTo<usize>> for CryptoVec {
79 type Output = [u8];
80 fn index(&self, index: RangeTo<usize>) -> &[u8] {
81 self.deref().index(index)
82 }
83}
84impl Index<Range<usize>> for CryptoVec {
85 type Output = [u8];
86 fn index(&self, index: Range<usize>) -> &[u8] {
87 self.deref().index(index)
88 }
89}
90impl Index<RangeFull> for CryptoVec {
91 type Output = [u8];
92 fn index(&self, _: RangeFull) -> &[u8] {
93 self.deref()
94 }
95}
96impl IndexMut<RangeFull> for CryptoVec {
97 fn index_mut(&mut self, _: RangeFull) -> &mut [u8] {
98 self.deref_mut()
99 }
100}
101
102impl IndexMut<RangeFrom<usize>> for CryptoVec {
103 fn index_mut(&mut self, index: RangeFrom<usize>) -> &mut [u8] {
104 self.deref_mut().index_mut(index)
105 }
106}
107impl IndexMut<RangeTo<usize>> for CryptoVec {
108 fn index_mut(&mut self, index: RangeTo<usize>) -> &mut [u8] {
109 self.deref_mut().index_mut(index)
110 }
111}
112impl IndexMut<Range<usize>> for CryptoVec {
113 fn index_mut(&mut self, index: Range<usize>) -> &mut [u8] {
114 self.deref_mut().index_mut(index)
115 }
116}
117
118impl Index<usize> for CryptoVec {
119 type Output = u8;
120 fn index(&self, index: usize) -> &u8 {
121 self.deref().index(index)
122 }
123}
124
125impl std::io::Write for CryptoVec {
126 fn write(&mut self, buf: &[u8]) -> Result<usize, std::io::Error> {
127 self.extend(buf);
128 Ok(buf.len())
129 }
130 fn flush(&mut self) -> Result<(), std::io::Error> {
131 Ok(())
132 }
133}
134
135impl Default for CryptoVec {
136 fn default() -> Self {
137 CryptoVec {
138 p: std::ptr::NonNull::dangling().as_ptr(),
139 size: 0,
140 capacity: 0,
141 }
142 }
143}
144
145#[cfg(not(windows))]
146unsafe fn mlock(ptr: *const u8, len: usize) {
147 libc::mlock(ptr as *const c_void, len as size_t);
148}
149#[cfg(not(windows))]
150unsafe fn munlock(ptr: *const u8, len: usize) {
151 libc::munlock(ptr as *const c_void, len as size_t);
152}
153
154#[cfg(windows)]
155use winapi::shared::basetsd::SIZE_T;
156#[cfg(windows)]
157use winapi::shared::minwindef::LPVOID;
158#[cfg(windows)]
159use winapi::um::memoryapi::{VirtualLock, VirtualUnlock};
160#[cfg(windows)]
161unsafe fn mlock(ptr: *const u8, len: usize) {
162 VirtualLock(ptr as LPVOID, len as SIZE_T);
163}
164#[cfg(windows)]
165unsafe fn munlock(ptr: *const u8, len: usize) {
166 VirtualUnlock(ptr as LPVOID, len as SIZE_T);
167}
168
169impl Clone for CryptoVec {
170 fn clone(&self) -> Self {
171 let mut v = Self::new();
172 v.extend(self);
173 v
174 }
175}
176
177impl CryptoVec {
178 pub fn new() -> CryptoVec {
180 CryptoVec::default()
181 }
182
183 pub fn new_zeroed(size: usize) -> CryptoVec {
185 unsafe {
186 let capacity = size.next_power_of_two();
187 let layout = std::alloc::Layout::from_size_align_unchecked(capacity, 1);
188 let p = std::alloc::alloc_zeroed(layout);
189 mlock(p, capacity);
190 CryptoVec { p, capacity, size }
191 }
192 }
193
194 pub fn with_capacity(capacity: usize) -> CryptoVec {
196 unsafe {
197 let capacity = capacity.next_power_of_two();
198 let layout = std::alloc::Layout::from_size_align_unchecked(capacity, 1);
199 let p = std::alloc::alloc_zeroed(layout);
200 mlock(p, capacity);
201 CryptoVec {
202 p,
203 capacity,
204 size: 0,
205 }
206 }
207 }
208
209 pub fn len(&self) -> usize {
215 self.size
216 }
217
218 pub fn is_empty(&self) -> bool {
224 self.len() == 0
225 }
226
227 pub fn resize(&mut self, size: usize) {
231 if size <= self.capacity && size > self.size {
232 self.size = size
234 } else if size <= self.size {
235 unsafe {
237 libc::memset(
238 self.p.offset(size as isize) as *mut c_void,
239 0,
240 self.size - size,
241 );
242 }
243 self.size = size;
244 } else {
245 unsafe {
247 let next_capacity = size.next_power_of_two();
248 let old_ptr = self.p;
249 let next_layout = std::alloc::Layout::from_size_align_unchecked(next_capacity, 1);
250 self.p = std::alloc::alloc_zeroed(next_layout);
251 mlock(self.p, next_capacity);
252
253 if self.capacity > 0 {
254 std::ptr::copy_nonoverlapping(old_ptr, self.p, self.size);
255 for i in 0..self.size {
256 std::ptr::write_volatile(old_ptr.offset(i as isize), 0)
257 }
258 munlock(old_ptr, self.capacity);
259 let layout = std::alloc::Layout::from_size_align_unchecked(self.capacity, 1);
260 std::alloc::dealloc(old_ptr, layout);
261 }
262
263 if self.p.is_null() {
264 panic!("Realloc failed, pointer = {:?} {:?}", self, size)
265 } else {
266 self.capacity = next_capacity;
267 self.size = size;
268 }
269 }
270 }
271 }
272
273 pub fn clear(&mut self) {
282 self.resize(0);
283 }
284
285 pub fn push(&mut self, s: u8) {
287 let size = self.size;
288 self.resize(size + 1);
289 unsafe { *(self.p.offset(size as isize)) = s }
290 }
291
292 pub fn push_u32_be(&mut self, s: u32) {
301 let s = s.to_be();
302 let x: [u8; 4] = unsafe { std::mem::transmute(s) };
303 self.extend(&x)
304 }
305
306 pub fn read_u32_be(&self, i: usize) -> u32 {
316 assert!(i + 4 <= self.size);
317 let mut x: u32 = 0;
318 unsafe {
319 libc::memcpy(
320 (&mut x) as *mut u32 as *mut c_void,
321 self.p.offset(i as isize) as *const c_void,
322 4,
323 );
324 }
325 u32::from_be(x)
326 }
327
328 pub fn read<R: std::io::Read>(
331 &mut self,
332 n_bytes: usize,
333 mut r: R,
334 ) -> Result<usize, std::io::Error> {
335 let cur_size = self.size;
336 self.resize(cur_size + n_bytes);
337 let s =
338 unsafe { std::slice::from_raw_parts_mut(self.p.offset(cur_size as isize), n_bytes) };
339 match r.read(s) {
341 Ok(n) => {
342 self.resize(cur_size + n);
343 Ok(n)
344 }
345 Err(e) => {
346 self.resize(cur_size);
347 Err(e)
348 }
349 }
350 }
351
352 pub fn write_all_from<W: std::io::Write>(
362 &self,
363 offset: usize,
364 mut w: W,
365 ) -> Result<usize, std::io::Error> {
366 assert!(offset < self.size);
367 unsafe {
369 let s = std::slice::from_raw_parts(self.p.offset(offset as isize), self.size - offset);
370 w.write(s)
371 }
372 }
373
374 pub fn resize_mut(&mut self, n: usize) -> &mut [u8] {
381 let size = self.size;
382 self.resize(size + n);
383 unsafe { std::slice::from_raw_parts_mut(self.p.offset(size as isize), n) }
384 }
385
386 pub fn extend(&mut self, s: &[u8]) {
393 let size = self.size;
394 self.resize(size + s.len());
395 unsafe {
396 std::ptr::copy_nonoverlapping(s.as_ptr(), self.p.offset(size as isize), s.len());
397 }
398 }
399
400 pub fn from_slice(s: &[u8]) -> CryptoVec {
408 let mut v = CryptoVec::new();
409 v.resize(s.len());
410 unsafe {
411 std::ptr::copy_nonoverlapping(s.as_ptr(), v.p, s.len());
412 }
413 v
414 }
415}
416
417impl Drop for CryptoVec {
418 fn drop(&mut self) {
419 if self.capacity > 0 {
420 unsafe {
421 for i in 0..self.size {
422 std::ptr::write_volatile(self.p.offset(i as isize), 0)
423 }
424 munlock(self.p, self.capacity);
425 let layout = std::alloc::Layout::from_size_align_unchecked(self.capacity, 1);
426 std::alloc::dealloc(self.p, layout);
427 }
428 }
429 }
430}