aboutsummaryrefslogtreecommitdiffstats
path: root/src/crypto.rs
diff options
context:
space:
mode:
authorbnewbold <bnewbold@robocracy.org>2016-05-30 01:49:18 -0400
committerbnewbold <bnewbold@robocracy.org>2016-05-30 01:49:24 -0400
commit3a51fef71337f9e6683a3fe972e69cee92e1c097 (patch)
tree347a800b1519be2b79157e13708f5bef1d2c917f /src/crypto.rs
parent37fb8945fad0a034d1565bc4f79f9ab524587fc0 (diff)
downloaducp-3a51fef71337f9e6683a3fe972e69cee92e1c097.tar.gz
ucp-3a51fef71337f9e6683a3fe972e69cee92e1c097.zip
BROKEN: initial implementation of crypto
I think it's going to be necessary to implement buffered reading after all.
Diffstat (limited to 'src/crypto.rs')
-rw-r--r--src/crypto.rs78
1 files changed, 78 insertions, 0 deletions
diff --git a/src/crypto.rs b/src/crypto.rs
new file mode 100644
index 0000000..726a420
--- /dev/null
+++ b/src/crypto.rs
@@ -0,0 +1,78 @@
+
+use std::{u8, u32};
+use std::io;
+use std::io::{Read,Write, ErrorKind};
+use sodiumoxide::crypto::secretbox;
+use sodiumoxide::crypto::secretbox::{Key, Nonce};
+use rustc_serialize::base64::{ToBase64, FromBase64, STANDARD};
+use std::mem::transmute;
+
+// TODO: handle case of splitting up writes > 2^32 bytes into multiple small writes
+
+pub struct SecretStream<S: Read+Write> {
+ read_nonce: Nonce,
+ write_nonce: Nonce,
+ pub key: Key,
+ inner: S,
+}
+
+impl<S: Read+Write> SecretStream<S> {
+ pub fn new(stream: S) -> SecretStream<S> {
+ SecretStream {
+ inner: stream,
+ read_nonce: secretbox::gen_nonce(),
+ write_nonce: secretbox::gen_nonce(),
+ key: secretbox::gen_key(),
+ }
+ }
+}
+
+impl<S: Read+Write> Read for SecretStream<S> {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ let mut header_buf = [0; 4];
+ try!(self.inner.read_exact(&mut header_buf));
+ let len: u32 = unsafe { transmute(header_buf) };
+ let len = len.to_be();
+ if len as usize > buf.len() {
+ return Err(io::Error::new(ErrorKind::Other,
+ format!("Buffer not big enough ({} < {})", buf.len(), len)));
+ }
+ try!(self.inner.read_exact(buf));
+ let cleartext = match secretbox::open(buf, &self.read_nonce, &self.key) {
+ Ok(cleartext) => cleartext,
+ Err(_) => { return Err(io::Error::new(ErrorKind::InvalidData,
+ "Failed to decrypt message (could mean corruption or malicious attack"))},
+ };
+ self.read_nonce.increment_le_inplace();
+ let len = len as usize;
+ buf.clone_from_slice(&cleartext[..len]);
+ return Ok(len as usize);
+ }
+}
+
+impl<S: Read+Write> Write for SecretStream<S> {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ assert!(buf.len() < u32::MAX as usize);
+ let len = buf.len() as u32;
+ let header_buf: [u8; 4] = unsafe { transmute(len.to_be()) };
+ try!(self.inner.write_all(&header_buf));
+ let ciphertext = secretbox::seal(buf, &self.write_nonce, &self.key);
+ self.write_nonce.increment_le_inplace();
+ try!(self.inner.write_all(&ciphertext[..]));
+ return Ok(len as usize);
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ return self.inner.flush();
+ }
+}
+
+pub fn key2string(key: &Key) -> String {
+ return (&(key[..])).to_base64(STANDARD);
+}
+
+pub fn string2key(s: &str) -> Result<Key, String> {
+ println!("KEYBYTES: {}", secretbox::KEYBYTES);
+ return Ok(Key::from_slice(&s.as_bytes().from_base64().unwrap()).unwrap());
+}
+