encrypt using chacha
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
shimunn 2019-09-07 21:24:58 +02:00
parent 0ba80e7314
commit 141f048d13
Signed by: shimun
GPG Key ID: E81D8382DC2F971B
5 changed files with 144 additions and 30 deletions

36
Cargo.lock generated
View File

@ -164,12 +164,15 @@ name = "brownpaper"
version = "0.1.0"
dependencies = [
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)",
"hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"iron 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
"sequoia-openpgp 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"snap 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -216,6 +219,17 @@ dependencies = [
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "c2-chacha"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"stream-cipher 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "cc"
version = "1.0.42"
@ -433,6 +447,11 @@ dependencies = [
"scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "hex"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "httparse"
version = "1.3.3"
@ -771,6 +790,11 @@ dependencies = [
"typemap 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ppv-lite86"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "precomputed-hash"
version = "0.1.1"
@ -1077,6 +1101,14 @@ dependencies = [
"lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "stream-cipher"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "string_cache"
version = "0.7.3"
@ -1334,6 +1366,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5"
"checksum bzip2 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "42b7c3cbf0fa9c1b82308d57191728ca0256cb821220f4e2fd410a72ade26e3b"
"checksum bzip2-sys 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6584aa36f5ad4c9247f5323b0a42f37802b37a836f0ad87084d7a33961abe25f"
"checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101"
"checksum cc 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)" = "a61c7bce55cd2fae6ec8cb935ebd76256c2959a1f95790f6118a441c2cd5b406"
"checksum cexpr 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a7fa24eb00d5ffab90eaeaf1092ac85c04c64aaf358ea6f84505b8116d24c6af"
"checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4"
@ -1361,6 +1394,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "473a1265acc8ff1e808cd0a1af8cee3c2ee5200916058a2ca113c29f2d903571"
"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
"checksum hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3bae29b6653b3412c2e71e9d486db9f9df5d701941d86683005efb9f2d28e3da"
"checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77"
"checksum httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e8734b0cfd3bc3e101ec59100e101c2eecd19282202e87808b3037b442777a83"
"checksum hyper 0.10.15 (registry+https://github.com/rust-lang/crates.io-index)" = "df0caae6b71d266b91b4a83111a61d2b94ed2e2bea024c532b933dcff867e58c"
"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e"
@ -1403,6 +1437,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum phf_shared 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)" = "234f71a15de2288bcb7e3b6515828d22af7ec8598ee6d24c3b526fa0a80b67a0"
"checksum pkg-config 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c1d2cfa5a714db3b5f24f0915e74fcdf91d09d496ba61329705dda7774d2af"
"checksum plugin 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1a6a0dc3910bc8db877ffed8e457763b317cf880df4ae19109b9f77d277cf6e0"
"checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b"
"checksum precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
"checksum proc-macro2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "175a40b9cf564ce9bf050654633dbf339978706b8ead1a907bb970b63185dd95"
@ -1438,6 +1473,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum siphasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac"
"checksum smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c4488ae950c49d403731982257768f48fada354a5203fe81f9bb6f43ca9002be"
"checksum snap 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "37877bedec5e9d6b3324b4f99886f118844903a4e7532e5e59c7afd264da7b4f"
"checksum stream-cipher 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8131256a5896cabcf5eb04f4d6dacbe1aefda854b0d9896e09cb58829ec5638c"
"checksum string_cache 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "25d70109977172b127fe834e5449e5ab1740b9ba49fa18a2020f509174f25423"
"checksum string_cache_codegen 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1eea1eee654ef80933142157fdad9dd8bc43cf7c74e999e369263496f04ff4da"
"checksum string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b1884d1bc09741d466d9b14e6d37ac89d6909cbcac41dd9ae982d4d063bbedfc"

View File

@ -18,3 +18,6 @@ byteorder = "1.3.2"
chrono = "0.4.9"
sequoia-openpgp = "0.9.0"
lazy_static = "1.4.0"
c2-chacha = "0.2.2"
sha2 = "0.8.0"
hex = "0.3.2"

45
src/chacha_io.rs Normal file
View File

@ -0,0 +1,45 @@
use c2_chacha::stream_cipher::{NewStreamCipher, SyncStreamCipher, SyncStreamCipherSeek};
use c2_chacha::{ChaCha12, ChaCha20};
use std::convert::TryInto;
use std::io::{Read, Result, Write};
pub struct ChaChaReader<'a>(ChaCha20, &'a mut Read);
impl<'a> ChaChaReader<'a> {
pub fn new(key: &[u8], nonce: &[u8], source: &'a mut Read) -> ChaChaReader<'a> {
ChaChaReader(ChaCha20::new_var(key, nonce).unwrap(), source)
}
}
impl<'a> Read for ChaChaReader<'a> {
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
let red = self.1.read(buf)?;
self.0.apply_keystream(buf);
Ok(red)
}
}
pub struct ChaChaWriter<'a>(ChaCha20, &'a mut Write);
impl<'a> ChaChaWriter<'a> {
pub fn new(key: &[u8], nonce: &[u8], sink: &'a mut Write) -> ChaChaWriter<'a> {
ChaChaWriter(ChaCha20::new_var(key, nonce).unwrap(), sink)
}
}
impl<'a> Write for ChaChaWriter<'a> {
fn write(&mut self, buf: &[u8]) -> Result<usize> {
let mut cipher_text = [0u8; 256];
let mut written = 0usize;
for chunk in buf.chunks(cipher_text.len()) {
cipher_text[0..chunk.len()].copy_from_slice(&chunk);
self.0.apply_keystream(&mut cipher_text[0..chunk.len()]);
written += self.1.write(&cipher_text[0..chunk.len()])?;
}
Ok(written)
}
fn flush(&mut self) -> Result<()> {
self.1.flush()
}
}

View File

@ -6,10 +6,12 @@ extern crate rand;
extern crate sequoia_openpgp as openpgp;
extern crate snap;
mod chacha_io;
mod pgp;
use crate::pgp::KnownKeys;
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use chacha_io::{ChaChaReader, ChaChaWriter};
use chrono::*;
use core::cell::RefCell;
use iron::method::Method;
@ -17,7 +19,9 @@ use iron::modifiers::Redirect;
use iron::prelude::*;
use iron::url::Url;
use rand::Rng;
use sha2::{Digest, Sha256};
use std::borrow::BorrowMut;
use std::convert::TryInto;
use std::fs;
use std::fs::File;
use std::io;
@ -46,7 +50,7 @@ impl<'a> Snippet<'a> {
Snippet::new(
&rand::thread_rng()
.gen_ascii_chars()
.take(6)
.take(8)
.collect::<String>(),
storage,
)
@ -59,13 +63,30 @@ impl<'a> Snippet<'a> {
}
}
pub fn file_id(&self) -> String {
SnippetStorage::file_id(&self.id)
}
pub fn passphrase(&self) -> ([u8; 8], [u8; 32]) {
let mut hasher = Sha256::new();
hasher.input(self.id.as_bytes());
let res = hasher.result();
let nonce: [u8; 8] = res[0..8].try_into().unwrap();
let mut hasher = Sha256::new();
hasher.input(self.id.as_bytes());
hasher.input(b"pass");
let pass: [u8; 32] = res[0..32].try_into().unwrap();
(nonce, pass)
}
pub fn path(&self) -> PathBuf {
self.storage.directory.join(&self.id)
self.storage.directory.join(&self.file_id())
}
pub fn metadata(&self) -> Result<SnippetMeta, io::Error> {
let mut file = File::open(self.path())?;
self.metadata_via_handle(&mut file)
let (nonce, key) = self.passphrase();
self.metadata_via_handle(&mut ChaChaReader::new(&key, &nonce, &mut file))
}
fn metadata_via_handle(&self, hdl: &mut impl Read) -> Result<SnippetMeta, io::Error> {
@ -83,38 +104,42 @@ impl<'a> Snippet<'a> {
fn contents(&self) -> Result<String, io::Error> {
let mut file = File::open(self.path())?;
let meta = self.metadata_via_handle(&mut file)?;
let (nonce, key) = self.passphrase();
let mut reader = ChaChaReader::new(&key, &nonce, &mut file);
let meta = self.metadata_via_handle(&mut reader)?;
fn read_string(r: &mut impl Read) -> Result<String, io::Error> {
let mut text = String::new();
r.read_to_string(&mut text)?;
Ok(text)
}
dbg!((&meta.compression, &meta.created));
dbg!((&meta.compression, &meta.created, self.file_id()));
match meta.compression {
Some(ref comp) if comp == "snap" => {
let mut r = snap::Reader::new(&mut file);
let mut r = snap::Reader::new(&mut reader);
read_string(&mut r)
}
_ => read_string(&mut file),
_ => read_string(&mut reader),
}
}
fn write(self, content: &str) -> Result<Snippet<'a>, io::Error> {
let mut file = File::create(self.path())?;
file.write_i64::<BigEndian>(Utc::now().timestamp())?;
let (nonce, key) = self.passphrase();
let mut writer = ChaChaWriter::new(&key, &nonce, &mut file);
writer.write_i64::<BigEndian>(Utc::now().timestamp())?;
let comp = if content.len() > 2048 {
Some("snap")
} else {
None
};
file.write_u16::<BigEndian>(comp.map(|s| s.len() as u16).unwrap_or(0u16))?;
file.write(comp.map(|s| s.as_bytes()).unwrap_or(&[0u8; 0]))?;
writer.write_u16::<BigEndian>(comp.map(|s| s.len() as u16).unwrap_or(0u16))?;
writer.write(comp.map(|s| s.as_bytes()).unwrap_or(&[0u8; 0]))?;
match comp {
Some(ref comp) if comp == &"snap" => {
let mut w = snap::Writer::new(&mut file);
let mut w = snap::Writer::new(&mut writer);
w.write_all(content.as_bytes())?
}
_ => file.write_all(content.as_bytes())?,
_ => writer.write_all(content.as_bytes())?,
};
Ok(Snippet::new(&self.id, self.storage))
}
@ -126,9 +151,13 @@ impl<'a> SnippetStorage<'a> {
directory: directory,
}
}
pub fn file_id(id: &str) -> String {
let mut hasher = Sha256::new();
hasher.input(id.as_bytes());
hex::encode(&hasher.result()[0..12])
}
fn has(&self, id: &str) -> bool {
self.directory.join(id).exists()
self.directory.join(Self::file_id(id)).exists()
}
fn open(&self, id: &str) -> Option<Snippet> {
@ -174,7 +203,8 @@ fn handle(req: &mut Request) -> IronResult<Response> {
.map_err(|err| IronError::new(err, "Invalid utf8"))?
};
let b_text = KNOWN_KEYS
.lock().unwrap()//.map_err(|_| IronError::new(std::error::Error::from("Mutex Err"), "PGP Context unavailable"))?
.lock()
.unwrap() //.map_err(|_| IronError::new(std::error::Error::from("Mutex Err"), "PGP Context unavailable"))?
.verify(pgp_text.as_bytes())
.map_err(|err| IronError::new(err, "Untrusted signature"))?;
let text = String::from_utf8(b_text).unwrap();

View File

@ -1,18 +1,16 @@
use std::io;
use std::fs;
use std::fs::{File};
use std::path::Path;
use std::io::prelude::*;
use openpgp::parse::stream::*;
use openpgp::parse::Parse;
use openpgp::*;
use openpgp::parse::stream::*;
use std::fs;
use std::fs::File;
use std::io;
use std::io::prelude::*;
use std::path::Path;
pub struct KnownKeys {
keys: Vec<openpgp::TPK>
keys: Vec<openpgp::TPK>,
}
impl VerificationHelper for &KnownKeys {
fn get_public_keys(&mut self, _ids: &[KeyID]) -> Result<Vec<TPK>> {
Ok(self.keys.clone())
}
@ -33,19 +31,21 @@ impl KnownKeys {
println!("Fingerprint: {}", tpk.fingerprint());
keys.push(tpk);
}
Ok(KnownKeys{
keys: keys
})
Ok(KnownKeys { keys: keys })
}
pub fn verify(&mut self, r: impl Read) -> io::Result<Vec<u8>> {
let mut content = Vec::with_capacity(2048);
let helper = &*self;
let mut v = Verifier::<&KnownKeys>::from_reader(r, helper, None).map_err(|e| dbg!(e)).unwrap();
let mut v = Verifier::<&KnownKeys>::from_reader(r, helper, None)
.map_err(|e| dbg!(e))
.unwrap();
if v.read_to_end(&mut content).is_err() {
return Err(io::Error::new(io::ErrorKind::InvalidData, "Signature Mismatch"));
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"Signature Mismatch",
));
}
Ok(content)
}
}