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
//! [`Read`]/[`Write`] implementation that Xor's the bytes that come through it and wraps around //! another [`Read`] or [`Write`]. //! //! # Examples //! //! ## Writing //! //! ```no_run //! # use xorio::Xor; //! # use std::fs::File; //! # use std::io::Write; //! let mut file = File::create("my_xored_file.bin").unwrap(); //! let mut writer = Xor::new(file); //! writer.write_all("Hello World".as_bytes()); //! ``` //! //! ## Reading //! //! ```no_run //! # use xorio::Xor; //! # use std::fs::File; //! # use std::io::Read; //! let mut file = File::open("my_xored_file.bin").unwrap(); //! let mut reader = Xor::new(file); //! let mut content = String::new(); //! reader.read_to_string(&mut content); //! ``` //! //! ## Custom Xor Bytes //! //! You can also customize the bytes that it will XOR the stream with. By default it uses a single //! byte `0b01010101` to calculate the XOR. //! //! ```no_run //! # use xorio::Xor; //! # use std::fs::File; //! # use std::io::Write; //! let mut file = File::create("my_xored_file.bin").unwrap(); //! let mut writer = Xor::new_with_xor_bytes(file, vec![1, 2, 3]); //! writer.write_all("Hello World".as_bytes()); //! ``` //! //! # License //! //! This crate is licensed under the [Katharos License][k_license] which places certain //! restrictions on what you are allowed to use it for. Please read and understand the terms before //! using this crate for your project. //! //! [k_license]: https://github.com/katharostech/katharos-license use std::io::{Read, Seek, Write}; /// [`Read`]/[`Write`] implementation that Xor's the bytes that come through it and wraps around /// another [`Read`] or [`Write`]. pub struct Xor<T> { inner: T, xor_bytes: Vec<u8>, } impl<T> Xor<T> { /// Create a new [`Xor`] wrapped around the given IO type. pub fn new(inner: T) -> Self { Xor { inner, xor_bytes: vec![0b01010101], } } /// Create a new [`Xor`] wrapped around the given IO type, with custom `xor_bytes` that will be /// used when XOR-ing the stream. The default `xor_bytes` is one `0b01010101` byte. pub fn new_with_xor_bytes(inner: T, xor_bytes: Vec<u8>) -> Self { Xor { inner, xor_bytes } } } impl<R: Read> Read for Xor<R> { fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> { // Read bytes into buf let count = self.inner.read(buf)?; // Xor the bytes in the buffer for byte in buf { for xor_byte in &self.xor_bytes { *byte = *byte ^ xor_byte; } } Ok(count) } } impl<W: Write> Write for Xor<W> { fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> { self.inner.write( // Write the buffer with each byte XOR-ed buf.iter() .map(|x| { let mut byte = *x; for xor_byte in &self.xor_bytes { byte = byte ^ xor_byte } byte }) .collect::<Vec<_>>() .as_slice(), ) } fn flush(&mut self) -> std::io::Result<()> { self.inner.flush() } } impl<S: Seek> Seek for Xor<S> { fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> { self.inner.seek(pos) } }