You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

116 lines
3.4 KiB
Rust

use structopt::StructOpt;
use std::path::PathBuf;
use block_modes::{BlockMode, Ecb, Cbc, Cfb};
use ctr::Ctr128;
use aes::Aes128;
use block_modes::block_padding::ZeroPadding;
use rpassword::read_password_from_tty;
use sha2::{Sha256, Digest};
use rand::Rng;
use std::fs::{read, File};
use std::io::{BufWriter, Write};
use ctr::stream_cipher::{
NewStreamCipher, SyncStreamCipher
};
use ctr::stream_cipher::generic_array::GenericArray;
type Aes128Ecb = Ecb<Aes128, ZeroPadding>;
type Aes128Cbc = Cbc<Aes128, ZeroPadding>;
type Aes128Cfb = Cfb<Aes128, ZeroPadding>;
type Aes128Ctr = Ctr128<Aes128>;
#[derive(StructOpt, Debug)]
struct Opt {
/// Input file for the plain text
#[structopt(parse(from_os_str))]
input: PathBuf,
/// Output file for the ciphertext
#[structopt(parse(from_os_str))]
output: PathBuf,
/// The mode of operation that is being used
/// One of ECB, CBC, CFB, CTR
#[structopt(short, long, default_value = "CFB")]
mode: String,
/// If the output should be an image
#[structopt(short, long)]
image: bool,
}
fn main() {
let opt: Opt = Opt::from_args();
let mut writer = BufWriter::new(File::create(&opt.output).unwrap());
if opt.image {
let decoder = png::Decoder::new(File::open(opt.input).unwrap());
let (info, mut reader) = decoder.read_info().unwrap();
let mut img_buffer = vec![0; info.buffer_size()];
reader.next_frame(&mut img_buffer).unwrap();
let cipher = encrypt(&img_buffer, opt.mode);
let mut encoder = png::Encoder::new(writer, info.width, info.height);
encoder.set_color(info.color_type);
encoder.set_depth(info.bit_depth);
let mut writer = encoder.write_header().unwrap();
writer.write_image_data(&cipher[..img_buffer.len()]).unwrap();
} else {
let contents = read(&opt.input).unwrap();
let cipher = encrypt(&contents, opt.mode);
println!("{:?}", cipher);
writer.write_all(&cipher).unwrap();
writer.flush().unwrap();
}
}
fn encrypt(data: &[u8], mode: String) -> Vec<u8> {
let key = get_key();
match mode.as_str() {
"ECB" => encrypt_ecb(data, &key),
"CBC" => encrypt_cbc(data, &key),
"CFB" => encrypt_cfb(data, &key),
"CTR" => encrypt_ctr(data, &key),
_ => panic!("Unknown Mode")
}
}
fn encrypt_ecb(data: &[u8], key: &[u8]) -> Vec<u8> {
let iv = rand::thread_rng().gen::<[u8; 16]>();
let cipher = Aes128Ecb::new_var(&key, &iv).unwrap();
cipher.encrypt_vec(data)
}
fn encrypt_cbc(data: &[u8], key: &[u8]) -> Vec<u8> {
let iv = rand::thread_rng().gen::<[u8; 16]>();
let cipher = Aes128Cbc::new_var(&key, &iv).unwrap();
cipher.encrypt_vec(data)
}
fn encrypt_cfb(data: &[u8], key: &[u8]) -> Vec<u8> {
let iv = rand::thread_rng().gen::<[u8; 16]>();
let cipher = Aes128Cfb::new_var(&key, &iv).unwrap();
cipher.encrypt_vec(data)
}
fn encrypt_ctr(data: &[u8], key: &[u8]) -> Vec<u8> {
let mut hasher = Sha256::default();
hasher.update( key);
let nonce = hasher.finalize()[0..16].to_vec();
let mut cipher = Aes128Ctr::new(GenericArray::from_slice(&key), GenericArray::from_slice(&nonce));
let mut data = data.to_vec();
cipher.apply_keystream(&mut data);
data.to_vec()
}
fn get_key() -> Vec<u8> {
let pw = read_password_from_tty(Some("Password: ")).unwrap();
let mut hasher = Sha256::default();
hasher.update(pw.as_bytes());
hasher.finalize()[0..16].to_vec()
}