I wrote an actually secure file encryption program in Rust:
use std::cmp::min;
use std::fmt::Display;
use std::io::{self, Read, Write};
use std::ops::{Deref, DerefMut};
const RATE: usize = 16;
const CHUNK_LEN: usize = RATE * 256;
const USAGE: &str = "Usage: decrypt|encrypt <password>";
struct Wrapper(State);
#[derive(Default)] struct State([u32; 32]);
impl Wrapper {
fn new(mut key: &[u8]) -> Self {
let mut state = State::default();
loop {
let len = min(RATE, key.len()); xor(&mut state[..len], &key[..len]);
if len < RATE { state[len] ^= 1; }
state[RATE] ^= 0x80; state.permute();
key = &key[len..]; if key.is_empty() { break; }
} Wrapper(state)
}
fn wrap(&mut self, data: &mut [u8]) -> &[u8] { self.wrap_impl(data, <[u8]>::copy_from_slice) }
fn unwrap(&mut self, data: &mut [u8], tag: &[u8]) -> Result<(), ()> { assert!(tag.len() == RATE);
if tag == self.wrap_impl(data, xor) { Ok(()) } else { Err(()) }
}
fn wrap_impl(&mut self, data: &mut [u8], f: fn(&mut [u8], &[u8])) -> &[u8] {
let index = if !data.is_empty() {
let mut chunks = data.chunks_mut(RATE); let last_chunk = chunks.next_back().unwrap();
for chunk in chunks {
xor(chunk, &self.0[..RATE]); f(&mut self.0[..RATE], chunk);
self.0[RATE] ^= 0x80; self.0.permute();
}
let len = last_chunk.len();
xor(last_chunk, &self.0[..len]); f(&mut self.0[..len], last_chunk); len
} else { 0 };
self.0[index] ^= 1; self.0[RATE] ^= 0x80; self.0.permute(); &self.0[..RATE]
}
}
impl State {
fn permute(&mut self) {
macro_rules! i { ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr) => { ($a << 4) | ($b << 3) | ($c << 2) | ($d << 1) | $e } }
macro_rules! s { ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr) => { self.0[i!($a, $b, $c, $d, $e)] } }
for _ in 0..32 { for j in 0..1 { for k in 0..1 { for l in 0..1 { for m in 0..1 {
s!(1, j, k, l, m) = s!(1, j, k, l, m).wrapping_add(s!(0, j, k, l, m));
s!(0, j, k, l, m) = s!(0, j, k, l, m).rotate_left(7);
self.0.swap(i!(0, 0, k, l, m), i!(0, 1, k, l, m));
s!(0, j, k, l, m) ^= s!(1, j, k, l, m);
self.0.swap(i!(1, j, k, 0, m), i!(1, j, k, 1, m));
s!(1, j, k, l, m) = s!(1, j, k, l, m).wrapping_add(s!(0, j, k, l, m));
s!(0, j, k, l, m) = s!(0, j, k, l, m).rotate_left(11);
self.0.swap(i!(0, j, 0, l, m), i!(0, j, 1, l, m));
s!(0, j, k, l, m) ^= s!(1, j, k, l, m);
self.0.swap(i!(1, j, k, l, 0), i!(1, j, k, l, 1));
}}}}}
}
}
impl Deref for State { type Target = [u8];
fn deref(&self) -> &Self::Target { unsafe { &*(self.0.as_ptr() as *const [u32; 32] as *const [u8; 128]) } }
}
impl DerefMut for State {
fn deref_mut(&mut self) -> &mut Self::Target { unsafe { &mut *(self.0.as_mut_ptr() as *mut [u32; 32] as *mut [u8; 128]) } }
}
fn main() {
let args = std::env::args().skip(1); if args.len() != 2 { eprintln!("{}", USAGE); return; }
if let Err(e) = run(args) { eprintln!("{}", e); }
}
fn run<I: Iterator<Item = String>>(mut args: I) -> Result<(), Box<Display>> {
let f = match &*args.next().unwrap() { "decrypt" => { decrypt } "encrypt" => { encrypt } _ => { return Err(Box::new(USAGE)); } };
if let Err(e) = f(&mut Wrapper::new(args.next().unwrap().as_bytes()), &mut io::stdin(), &mut io::stdout()) { return Err(Box::new(e)); }
Ok(())
}
fn decrypt<R: Read, W: Write>(wrapper: &mut Wrapper, reader: &mut R, writer: &mut W) -> io::Result<()> {
let mut buf = [0; CHUNK_LEN];
loop {
let len = fill_buf(reader, &mut buf)?; if len < RATE { return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "")); }
{
let (data, tag) = buf.split_at_mut(len - RATE);
wrapper.unwrap(data, &tag[..RATE]).map_err(|()| io::Error::new(io::ErrorKind::InvalidData, "tag mismatch"))?;
}
writer.write_all(&buf[..len - RATE])?; if len < CHUNK_LEN { return Ok(()); }
}
}
fn encrypt<R: Read, W: Write>(wrapper: &mut Wrapper, reader: &mut R, writer: &mut W) -> io::Result<()> {
let mut buf = [0; CHUNK_LEN];
loop {
let len = fill_buf(reader, &mut buf[..CHUNK_LEN - RATE])?;
let tag = wrapper.wrap(&mut buf[..len]); buf[len..][..RATE].copy_from_slice(tag);
writer.write_all(&buf[..len + RATE])?; if len < CHUNK_LEN - RATE { return Ok(()); }
}
}
fn fill_buf<R: Read>(reader: &mut R, mut buf: &mut [u8]) -> io::Result<usize> {
let len = buf.len();
while !buf.is_empty() {
match reader.read(buf) {
Ok(0) => { break; } Ok(n) => { let tmp = buf; buf = &mut tmp[n..]; }
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} Err(e) => { return Err(e); }
}
}
Ok(len - buf.len())
}
fn xor(dst: &mut [u8], src: &[u8]) {
assert!(dst.len() == src.len());
unsafe { for i in 0..dst.len() { *dst.get_unchecked_mut(i) ^= *src.get_unchecked(i); } }
}