1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
/*! encrypt_decrypt.rs : test for the XOR random encryption and decryption
 * 
 * Given one flat text file, without special symbols (ASCII only)
 * The `split` function will generate random text file with same length of the given text file
 * Then encrypt the given text file using XOR operator with the randon text file
 * 
 * If we have both random text file and encrypt file
 * The `combine_decrypt` function will generate original text file by
 * XOR operation to the random text file and the encrypt file.
 * 
 * See source code on [GitHub](https://github.com/sinnud/rustbook/tree/encrypt_decrypt)
 */
use std::env;
use rand::prelude::*;

/** # encrypt decrypt example
 * code from [web](https://aml3.github.io/RustTutorial/html/02.html)
 * 
 * Code from web can not be compiled. Need re-write.
 * Call `split` to encrypt file into two files with suffix *.share1* and *.share2*
 * Call `combine_decrypt` to decrypt two files into original file
 */
pub fn main() {
    let args: Vec<String> = env::args().collect();
    if args.len() != 2 {
        println!("Usage: {} <inputfile>", args[0]);
        return;
    } 
    let fname = &args[1];
    split(fname.to_owned());
    let f1 = format!("{}.share1", fname);
    let f2 = format!("{}.share2", fname);
    let out_file = format!("{}.origin", fname);
    combine_decrypt(f1, f2, out_file);
}
/** # decryption
 * arguments: input two file names and output file name
 * 
 * Get contents of two input files
 * XOR of the two contentes
 * write to output file
 */
fn combine_decrypt(in_fn1: String, in_fn2: String, out_fn: String) {
    let rand_str = std::fs::read_to_string(&in_fn1).unwrap();
    let encrypted_str = std::fs::read_to_string(&in_fn2).unwrap();
    // println!("Random string length: {}; contents\n{}", rand_str.len(), rand_str);
    // println!("Encrypted string length: {}; contents\n{}", encrypted_str.len(), encrypted_str);
    let original_str = xor(&encrypted_str, &rand_str);
    // println!("original string length: {}; contents\n{}", original_str.len(), original_str);
    std::fs::write(out_fn, original_str).expect("Unable to write file");
}

/** # decryption
 * arguments: input file name
 * 
 * Get contents of the input file
 * Generate random string with same length of the contents of the input file
 * XOR to encrypt the input contents
 * Write to two share files as outputs
 */
fn split(in_fn: String) {
    let contents = std::fs::read_to_string(&in_fn).unwrap();
    // println!("File length: {}; contents:\n{}", contents.len(), contents);
    let f1 = format!("{}.share1", in_fn);
    let f2 = format!("{}.share2", in_fn);
    // println!("output file names: {} and {}", f1, f2);
    let mut rand_vec: Vec<char> = contents.chars().collect();
    const CHARSET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
                            abcdefghijklmnopqrstuvwxyz\
                            0123456789)(*&^%$#@!~";
    // This is not cryptographically strong randomness! 
    // (For entertainment purposes only.)
    for c in &mut rand_vec {
        let r = random::<u8>();
        let idx = r as u32 % CHARSET.len() as u32;
        // println!("This random value: {} and mod to {}.", r, idx);
     *c = CHARSET[idx as usize] as char;
    }
    let rand_str : String = rand_vec.into_iter().collect();
    let encrypted_str = xor(&contents, &rand_str);
    // println!("Random string length: {}; contents\n{}", rand_str.len(), rand_str);
    // println!("Encrypted string length: {}; contents\n{}", encrypted_str.len(), encrypted_str);
    std::fs::write(f1, rand_str).expect("Unable to write file");
    std::fs::write(f2, encrypted_str).expect("Unable to write file");
}

/** # XOR
 * For given two strings with same length
 * XOR each paired character
 * Collect output
 */
fn xor(a: &str, b: &str) -> String {
    let mut char_vec: Vec<char> = b.chars().collect();
    for i in 0..char_vec.len() {
        let c = char_vec[i];
	    char_vec[i] = ((a.as_bytes())[i] ^ (c as u8)) as char;
        // println!("'{}' xor '{}' to '{}'", a.as_bytes()[i] as char, c, char_vec[i]);
    }
    char_vec.into_iter().collect()
}

/* Looks that code from web does not work. Need re-write
use std::rand::random;
use std::os;
use std::io::File;
use std::env;

pub fn main() {
    let args: Vec<String> = env::args().collect();
    if args.len() != 2 {
        println!("Usage: {:s} <inputfile>", args[0]); 
    } else {
        let fname = args[1];
        let path = Path::new(fname.clone());
        let msg_file = File::open(&path);

        match (msg_file) {
            Some(mut msg) => {
                let msg_bytes: Vec<u8> = msg.read_to_end();
                let share1_file 
                       = File::create(&Path::new(fname + ".share1"));
                let share2_file 
                       = File::create(&Path::new(fname + ".share2"));
                
                match (share1_file, share2_file) {
                    (Some(share1), Some(share2)) => { 
                        split(msg_bytes, share1, share2); 
                        } ,
                    (_, _) => fail!("Error opening output files!"),
                }
            } ,
            None => fail!("Error opening message file: {:s}", fname)
        }
    }
}

fn xor(a: &[u8], b: &[u8]) -> Vec<u8> {
    let mut ret = Vec<u8>;
    for i in range(0, a.len()) {
	ret.push(a[i] ^ b[i]);
    }
    ret
}

fn split(msg_bytes: &[u8], mut share1: File, mut share2: File) {
    let mut random_bytes: ~[u8] = ~[];
    // This is not cryptographically strong randomness! 
    // (For entertainment purposes only.)
    for _ in range(0, msg_bytes.len()) {
	let random_byte = random();
	random_bytes.push(random_byte);
    }
    
    let encrypted_bytes = xor(msg_bytes, random_bytes);
    share1.write(random_bytes);
    share2.write(encrypted_bytes);
}
*/