pub fn xor_slice<'a> (dst : &'a mut [u8], src : &[u8]) -> &'a mut [u8] {
assert_eq!(dst.len(), src.len(),
"xor_slice: dst and src must be the same length" );
for (d,s) in dst.iter_mut().zip(src) {
*d ^= s;
}
dst
}
use std::mem::size_of;
use rand::{thread_rng, Rng};
use sha1::{Sha1, Digest};
pub fn encode_sha1(message : &[u8], public : &[u8]) -> Box<[u8]> {
let blocksize = Sha1::output_size();
assert_eq!(public.len(), blocksize,
"decode_sha1: public length {} != block size {}",
public.len(), blocksize );
let mut buffer = vec![0u8; message.len() + blocksize];
let mut r_in = vec![0u8; blocksize + size_of::<u32>()];
let mut rng = thread_rng();
for elem in r_in.iter_mut().take(blocksize) {
*elem = rng.gen();
}
eprintln!("Generated random parameter: {:?}", r_in);
let mut p_in = vec![0u8; blocksize * 2 + size_of::<u32>()];
p_in[0..blocksize].copy_from_slice(public);
if message.len() % blocksize != 0 {
panic!("Message is not a multiple of block size {}", blocksize);
}
let mut i : u32 = 1;
let mut sum = vec![0u8; blocksize];
for chunk in message.chunks(blocksize) {
buffer[(i as usize - 1) * blocksize..(i as usize * blocksize)].copy_from_slice(chunk);
r_in[blocksize..].copy_from_slice(&i.to_be_bytes());
let dest =
xor_slice(&mut buffer[(i as usize - 1) * blocksize..(i as usize * blocksize)], &Sha1::digest(&r_in));
p_in[blocksize..blocksize * 2].copy_from_slice(dest);
p_in[blocksize * 2..].copy_from_slice(&i.to_be_bytes());
xor_slice(&mut sum, &Sha1::digest(&p_in));
i += 1;
}
let last_block = (i as usize - 1) * blocksize;
xor_slice(&mut sum, &r_in[0..blocksize]);
buffer[last_block..].copy_from_slice(&sum);
buffer.into()
}
pub fn decode_sha1(message : &[u8], public : &[u8]) -> Box<[u8]> {
let blocksize = Sha1::output_size();
let blocks = message.len() / blocksize;
if message.len() % blocksize != 0 {
panic!("Message is not a multiple of block size {}", blocksize);
}
assert_eq!(public.len(), blocksize,
"decode_sha1: public length {} != block size {}",
public.len(), blocksize );
let mut buffer = vec![0u8; message.len() - blocksize];
let mut r_in = vec![0u8; blocksize + size_of::<u32>()];
let mut p_in = vec![0u8; blocksize * 2 + size_of::<u32>()];
p_in[0..blocksize].copy_from_slice(public);
let mut i : u32 = 1;
let mut sum = vec![0u8; blocksize];
for chunk in message.chunks(blocksize) {
if i < blocks as u32 { p_in[blocksize..blocksize * 2].copy_from_slice(chunk);
p_in[blocksize * 2..].copy_from_slice(&i.to_be_bytes());
xor_slice(&mut sum, &Sha1::digest(&p_in));
} else { r_in[0..blocksize].copy_from_slice(chunk);
xor_slice(&mut r_in[0..blocksize], &sum);
eprintln!("Recovered random parameter: {:?}", r_in);
}
i += 1;
}
buffer[0..(blocks - 1) * blocksize].
copy_from_slice(&message[0..(blocks - 1) * blocksize]);
for i in 1..blocks {
let index = (i as usize - 1) * blocksize;
let chunk = &mut buffer[index..index + blocksize];
r_in[blocksize..].copy_from_slice(&(i as u32).to_be_bytes());
xor_slice(chunk, &Sha1::digest(&r_in));
}
buffer.into()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[should_panic]
fn pass_in_str_19_as_bytes() {
let nineteen = "0123456789abcdef012";
let slice = nineteen.as_bytes();
let _boxed = encode_sha1(slice, slice);
}
#[test]
fn pass_in_str_20_as_bytes() {
let twenty = "0123456789abcdef0123";
let slice = twenty.as_bytes();
let boxed = encode_sha1(slice, slice);
assert_ne!(*slice, *boxed);
}
#[test]
fn same_20_bytes_back() {
let twenty = "0123456789abcdef0123";
let slice = twenty.as_bytes();
let boxed = encode_sha1(slice, slice);
assert_ne!(*slice, *boxed);
let back = decode_sha1(&*boxed, slice);
assert_eq!(slice, &*back);
}
#[test]
fn same_40_bytes_back() {
let forty = "0123456789abcdef01230123456789abcdef0123";
let slice = forty.as_bytes();
let boxed = encode_sha1(slice, &slice[0..20]);
assert_ne!(*slice, *boxed);
let back = decode_sha1(&*boxed, &slice[0..20]);
assert_eq!(slice, &*back);
}
#[test]
#[should_panic]
fn public_encode_parameter() {
let forty = "0123456789abcdef01230123456789abcdef0123";
let slice = forty.as_bytes();
let _oxed = encode_sha1(slice, slice);
}
#[test]
#[should_panic]
fn public_decode_parameter() {
let forty = "0123456789abcdef01230123456789abcdef0123";
let slice = forty.as_bytes();
let _boxed = decode_sha1(slice, slice);
}
}