extern crate libc;
extern crate winapi;
use libc::c_void;
#[cfg(not(windows))]
use libc::size_t;
use std::ops::{Deref, DerefMut, Index, IndexMut, Range, RangeFrom, RangeFull, RangeTo};
#[derive(Debug)]
pub struct CryptoVec {
p: *mut u8,
size: usize,
capacity: usize,
}
impl Unpin for CryptoVec {}
unsafe impl Send for CryptoVec {}
unsafe impl Sync for CryptoVec {}
impl AsRef<[u8]> for CryptoVec {
fn as_ref(&self) -> &[u8] {
self.deref()
}
}
impl AsMut<[u8]> for CryptoVec {
fn as_mut(&mut self) -> &mut [u8] {
self.deref_mut()
}
}
impl Deref for CryptoVec {
type Target = [u8];
fn deref(&self) -> &[u8] {
unsafe { std::slice::from_raw_parts(self.p, self.size) }
}
}
impl DerefMut for CryptoVec {
fn deref_mut(&mut self) -> &mut [u8] {
unsafe { std::slice::from_raw_parts_mut(self.p, self.size) }
}
}
impl From<String> for CryptoVec {
fn from(e: String) -> Self {
CryptoVec::from(e.into_bytes())
}
}
impl From<Vec<u8>> for CryptoVec {
fn from(e: Vec<u8>) -> Self {
let mut c = CryptoVec::new_zeroed(e.len());
c.clone_from_slice(&e[..]);
c
}
}
impl Index<RangeFrom<usize>> for CryptoVec {
type Output = [u8];
fn index(&self, index: RangeFrom<usize>) -> &[u8] {
self.deref().index(index)
}
}
impl Index<RangeTo<usize>> for CryptoVec {
type Output = [u8];
fn index(&self, index: RangeTo<usize>) -> &[u8] {
self.deref().index(index)
}
}
impl Index<Range<usize>> for CryptoVec {
type Output = [u8];
fn index(&self, index: Range<usize>) -> &[u8] {
self.deref().index(index)
}
}
impl Index<RangeFull> for CryptoVec {
type Output = [u8];
fn index(&self, _: RangeFull) -> &[u8] {
self.deref()
}
}
impl IndexMut<RangeFull> for CryptoVec {
fn index_mut(&mut self, _: RangeFull) -> &mut [u8] {
self.deref_mut()
}
}
impl IndexMut<RangeFrom<usize>> for CryptoVec {
fn index_mut(&mut self, index: RangeFrom<usize>) -> &mut [u8] {
self.deref_mut().index_mut(index)
}
}
impl IndexMut<RangeTo<usize>> for CryptoVec {
fn index_mut(&mut self, index: RangeTo<usize>) -> &mut [u8] {
self.deref_mut().index_mut(index)
}
}
impl IndexMut<Range<usize>> for CryptoVec {
fn index_mut(&mut self, index: Range<usize>) -> &mut [u8] {
self.deref_mut().index_mut(index)
}
}
impl Index<usize> for CryptoVec {
type Output = u8;
fn index(&self, index: usize) -> &u8 {
self.deref().index(index)
}
}
impl std::io::Write for CryptoVec {
fn write(&mut self, buf: &[u8]) -> Result<usize, std::io::Error> {
self.extend(buf);
Ok(buf.len())
}
fn flush(&mut self) -> Result<(), std::io::Error> {
Ok(())
}
}
impl Default for CryptoVec {
fn default() -> Self {
CryptoVec {
p: std::ptr::NonNull::dangling().as_ptr(),
size: 0,
capacity: 0,
}
}
}
#[cfg(not(windows))]
unsafe fn mlock(ptr: *const u8, len: usize) {
libc::mlock(ptr as *const c_void, len as size_t);
}
#[cfg(not(windows))]
unsafe fn munlock(ptr: *const u8, len: usize) {
libc::munlock(ptr as *const c_void, len as size_t);
}
#[cfg(windows)]
use winapi::shared::basetsd::SIZE_T;
#[cfg(windows)]
use winapi::shared::minwindef::LPVOID;
#[cfg(windows)]
use winapi::um::memoryapi::{VirtualLock, VirtualUnlock};
#[cfg(windows)]
unsafe fn mlock(ptr: *const u8, len: usize) {
VirtualLock(ptr as LPVOID, len as SIZE_T);
}
#[cfg(windows)]
unsafe fn munlock(ptr: *const u8, len: usize) {
VirtualUnlock(ptr as LPVOID, len as SIZE_T);
}
impl Clone for CryptoVec {
fn clone(&self) -> Self {
let mut v = Self::new();
v.extend(self);
v
}
}
impl CryptoVec {
pub fn new() -> CryptoVec {
CryptoVec::default()
}
pub fn new_zeroed(size: usize) -> CryptoVec {
unsafe {
let capacity = size.next_power_of_two();
let layout = std::alloc::Layout::from_size_align_unchecked(capacity, 1);
let p = std::alloc::alloc_zeroed(layout);
mlock(p, capacity);
CryptoVec { p, capacity, size }
}
}
pub fn with_capacity(capacity: usize) -> CryptoVec {
unsafe {
let capacity = capacity.next_power_of_two();
let layout = std::alloc::Layout::from_size_align_unchecked(capacity, 1);
let p = std::alloc::alloc_zeroed(layout);
mlock(p, capacity);
CryptoVec {
p,
capacity,
size: 0,
}
}
}
pub fn len(&self) -> usize {
self.size
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn resize(&mut self, size: usize) {
if size <= self.capacity && size > self.size {
self.size = size
} else if size <= self.size {
unsafe {
libc::memset(
self.p.offset(size as isize) as *mut c_void,
0,
self.size - size,
);
}
self.size = size;
} else {
unsafe {
let next_capacity = size.next_power_of_two();
let old_ptr = self.p;
let next_layout = std::alloc::Layout::from_size_align_unchecked(next_capacity, 1);
self.p = std::alloc::alloc_zeroed(next_layout);
mlock(self.p, next_capacity);
if self.capacity > 0 {
std::ptr::copy_nonoverlapping(old_ptr, self.p, self.size);
for i in 0..self.size {
std::ptr::write_volatile(old_ptr.offset(i as isize), 0)
}
munlock(old_ptr, self.capacity);
let layout = std::alloc::Layout::from_size_align_unchecked(self.capacity, 1);
std::alloc::dealloc(old_ptr, layout);
}
if self.p.is_null() {
panic!("Realloc failed, pointer = {:?} {:?}", self, size)
} else {
self.capacity = next_capacity;
self.size = size;
}
}
}
}
pub fn clear(&mut self) {
self.resize(0);
}
pub fn push(&mut self, s: u8) {
let size = self.size;
self.resize(size + 1);
unsafe { *(self.p.offset(size as isize)) = s }
}
pub fn push_u32_be(&mut self, s: u32) {
let s = s.to_be();
let x: [u8; 4] = unsafe { std::mem::transmute(s) };
self.extend(&x)
}
pub fn read_u32_be(&self, i: usize) -> u32 {
assert!(i + 4 <= self.size);
let mut x: u32 = 0;
unsafe {
libc::memcpy(
(&mut x) as *mut u32 as *mut c_void,
self.p.offset(i as isize) as *const c_void,
4,
);
}
u32::from_be(x)
}
pub fn read<R: std::io::Read>(
&mut self,
n_bytes: usize,
mut r: R,
) -> Result<usize, std::io::Error> {
let cur_size = self.size;
self.resize(cur_size + n_bytes);
let s =
unsafe { std::slice::from_raw_parts_mut(self.p.offset(cur_size as isize), n_bytes) };
match r.read(s) {
Ok(n) => {
self.resize(cur_size + n);
Ok(n)
}
Err(e) => {
self.resize(cur_size);
Err(e)
}
}
}
pub fn write_all_from<W: std::io::Write>(
&self,
offset: usize,
mut w: W,
) -> Result<usize, std::io::Error> {
assert!(offset < self.size);
unsafe {
let s = std::slice::from_raw_parts(self.p.offset(offset as isize), self.size - offset);
w.write(s)
}
}
pub fn resize_mut(&mut self, n: usize) -> &mut [u8] {
let size = self.size;
self.resize(size + n);
unsafe { std::slice::from_raw_parts_mut(self.p.offset(size as isize), n) }
}
pub fn extend(&mut self, s: &[u8]) {
let size = self.size;
self.resize(size + s.len());
unsafe {
std::ptr::copy_nonoverlapping(s.as_ptr(), self.p.offset(size as isize), s.len());
}
}
pub fn from_slice(s: &[u8]) -> CryptoVec {
let mut v = CryptoVec::new();
v.resize(s.len());
unsafe {
std::ptr::copy_nonoverlapping(s.as_ptr(), v.p, s.len());
}
v
}
}
impl Drop for CryptoVec {
fn drop(&mut self) {
if self.capacity > 0 {
unsafe {
for i in 0..self.size {
std::ptr::write_volatile(self.p.offset(i as isize), 0)
}
munlock(self.p, self.capacity);
let layout = std::alloc::Layout::from_size_align_unchecked(self.capacity, 1);
std::alloc::dealloc(self.p, layout);
}
}
}
}