Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions parity-crypto/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ authors = ["Parity Technologies <admin@parity.io>"]
ethereum-types = "0.3"
quick-error = "1.2.2"
ring = "0.12"
rust-crypto = "0.2.36"
tiny-keccak = "1.4"

scrypt = "0.1.1"
ripemd160 = "0.7.0"
digest = "0.7"
aes = "0.2.0"
aes-ctr = "0.1.0"
block-modes = "0.1.0"
160 changes: 147 additions & 13 deletions parity-crypto/src/aes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,40 +14,174 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.

use block_modes::{ BlockMode, BlockModeIv };
use block_modes::block_padding::Pkcs7;
use block_modes::block_padding::ZeroPadding;
use block_modes::{ Cbc, Ecb };
use raes::{ Aes128, Aes256 };
use aes_ctr::{ Aes128Ctr, Aes256Ctr };
use aes_ctr::stream_cipher::{ NewFixStreamCipher, StreamCipherCore };
use error::SymmError;
use rcrypto::blockmodes::{CtrMode, CbcDecryptor, PkcsPadding};
use rcrypto::aessafe::{AesSafe128Encryptor, AesSafe128Decryptor};
use rcrypto::symmetriccipher::{Encryptor, Decryptor};
use rcrypto::buffer::{RefReadBuffer, RefWriteBuffer, WriteBuffer};
use raes::block_cipher_trait::generic_array::GenericArray;


/// Reusable encoder/decoder for Ecb mode Aes256 with zero padding
pub struct AesEcb256(Ecb<Aes256, ZeroPadding>);

impl AesEcb256 {

/// New encoder/decoder, no iv for ecb
#[inline]
pub fn new(key: &[u8]) -> Result<Self, SymmError> {
Ok(AesEcb256(Ecb::new_varkey(key)?))
}

#[inline]
pub fn encrypt(&mut self, content: &mut [u8]) -> Result<(), SymmError> {
self.0.encrypt_nopad(content)?;
Ok(())
}

#[inline]
pub fn decrypt(&mut self, content: &mut [u8]) -> Result<(), SymmError> {
self.0.decrypt_nopad(content)?;
Ok(())
}
}


/// Reusable encoder/decoder for Aes256 in Ctr mode and no padding
pub struct AesCtr256(Aes256Ctr);

impl AesCtr256 {

/// New encoder/decoder
#[inline]
pub fn new(key: &[u8], iv: &[u8]) -> Result<Self, SymmError> {
Ok(AesCtr256(
Aes256Ctr::new(GenericArray::from_slice(key), GenericArray::from_slice(iv))
))
}

#[inline]
pub fn encrypt(&mut self, content: &mut[u8]) -> Result<(), SymmError> {
self.0.try_apply_keystream(content)?;
Ok(())
}

#[inline]
pub fn decrypt(&mut self, content: &mut[u8]) -> Result<(), SymmError> {
self.0.try_apply_keystream(content)?;
Ok(())
}
}

/// Encrypt a message (CTR mode).
///
/// Key (`k`) length and initialisation vector (`iv`) length have to be 16 bytes each.
/// An error is returned if the input lengths are invalid.
/// If possible please use `inplace_encrypt_128_ctr` to avoid a slice copy.
pub fn encrypt_128_ctr(k: &[u8], iv: &[u8], plain: &[u8], dest: &mut [u8]) -> Result<(), SymmError> {
let mut encryptor = CtrMode::new(AesSafe128Encryptor::new(k), iv.to_vec());
encryptor.encrypt(&mut RefReadBuffer::new(plain), &mut RefWriteBuffer::new(dest), true)?;
let mut encryptor = Aes128Ctr::new(
GenericArray::from_slice(k),
GenericArray::from_slice(iv),
);
&mut dest[..plain.len()].copy_from_slice(plain);
encryptor.try_apply_keystream(dest)?;
Ok(())

}

/// An error is returned if the input lengths are invalid.
pub fn inplace_encrypt_128_ctr(k: &[u8], iv: &[u8], data: &mut [u8]) -> Result<(), SymmError> {
let mut encryptor = Aes128Ctr::new(
GenericArray::from_slice(k),
GenericArray::from_slice(iv),
);
encryptor.try_apply_keystream(data)?;
Ok(())

}

/// Decrypt a message (CTR mode).
///
/// Key (`k`) length and initialisation vector (`iv`) length have to be 16 bytes each.
/// An error is returned if the input lengths are invalid.
/// If possible please use `inplace_decrypt_128_ctr` instead.
pub fn decrypt_128_ctr(k: &[u8], iv: &[u8], encrypted: &[u8], dest: &mut [u8]) -> Result<(), SymmError> {
let mut encryptor = CtrMode::new(AesSafe128Encryptor::new(k), iv.to_vec());
encryptor.decrypt(&mut RefReadBuffer::new(encrypted), &mut RefWriteBuffer::new(dest), true)?;
let mut encryptor = Aes128Ctr::new(
GenericArray::from_slice(k),
GenericArray::from_slice(iv),
);

&mut dest[..encrypted.len()].copy_from_slice(encrypted);
encryptor.try_apply_keystream(dest)?;
Ok(())
}

/// Decrypt a message (CTR mode).
///
/// Key (`k`) length and initialisation vector (`iv`) length have to be 16 bytes each.
/// An error is returned if the input lengths are invalid.
pub fn inplace_decrypt_128_ctr(k: &[u8], iv: &[u8], data: &mut [u8]) -> Result<(), SymmError> {
let mut encryptor = Aes128Ctr::new(
GenericArray::from_slice(k),
GenericArray::from_slice(iv),
);

encryptor.try_apply_keystream(data)?;
Ok(())
}


#[cfg(test)]
fn encrypt_128_cbc(k: &[u8], iv: &[u8], plain: &[u8], dest: &mut [u8]) -> Result<(), SymmError> {
let encryptor = Cbc::<Aes128, Pkcs7>::new_varkey(k, GenericArray::from_slice(iv))?;
&mut dest[..plain.len()].copy_from_slice(plain);
encryptor.encrypt_pad(dest, plain.len())?;
Ok(())
}


/// Decrypt a message (CBC mode).
///
/// Key (`k`) length and initialisation vector (`iv`) length have to be 16 bytes each.
/// An error is returned if the input lengths are invalid.
pub fn decrypt_128_cbc(k: &[u8], iv: &[u8], encrypted: &[u8], dest: &mut [u8]) -> Result<usize, SymmError> {
let mut encryptor = CbcDecryptor::new(AesSafe128Decryptor::new(k), PkcsPadding, iv.to_vec());
let len = dest.len();
let mut buffer = RefWriteBuffer::new(dest);
encryptor.decrypt(&mut RefReadBuffer::new(encrypted), &mut buffer, true)?;
Ok(len - buffer.remaining())
let encryptor = Cbc::<Aes128, Pkcs7>::new_varkey(k, GenericArray::from_slice(iv))?;
&mut dest[..encrypted.len()].copy_from_slice(encrypted);
let unpad_length = {
encryptor.decrypt_pad(&mut dest[..encrypted.len()])?.len()
};
Ok(unpad_length)
}


// retrocomptibility test
#[test]
pub fn test_aes_short() -> Result<(),SymmError> {
let key = include_bytes!("../test/key1");
let salt = include_bytes!("../test/salt1");
let content = include_bytes!("../test/content");
let ctr_enc = include_bytes!("../test/result_128_ctr");
let cbc_enc = include_bytes!("../test/result_128_cbc");
let mut dest = vec![0;110];
let mut dest_padded = vec![0;112];
let mut dest_padded2 = vec![0;128]; // TODO RustLib need an extra 16bytes in dest : looks extra buggy but function is not currently use (keep it private for now)
encrypt_128_cbc(&key[..16], &salt[..16], content, &mut dest_padded2)?;
assert!(&dest_padded2[..112] == &cbc_enc[..]);
// buffer2.write_all(&dest1[..]).unwrap();
encrypt_128_ctr(&key[..16], &salt[..16], content, &mut dest)?;
assert!(&dest[..] == &ctr_enc[..]);
let mut content_data = content.to_vec();
inplace_encrypt_128_ctr(&key[..16], &salt[..16], &mut content_data[..])?;
assert!(&content_data[..] == &ctr_enc[..]);
decrypt_128_ctr(&key[..16], &salt[..16], &ctr_enc[..], &mut dest)?;
assert!(&dest[..] == &content[..]);
let mut content_data = ctr_enc.to_vec();
inplace_decrypt_128_ctr(&key[..16], &salt[..16], &mut content_data[..])?;
assert!(&content_data[..] == &content[..]);
let l = decrypt_128_cbc(&key[..16], &salt[..16], &cbc_enc[..], &mut dest_padded)?;
assert!(&dest_padded[..l] == &content[..]);
Ok(())
}
23 changes: 12 additions & 11 deletions parity-crypto/src/digest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,20 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.

use rcrypto::ripemd160;
use rripemd160;
use ring::digest::{self, Context, SHA256, SHA512};
use std::marker::PhantomData;
use std::ops::Deref;
use rdigest::generic_array::GenericArray;
use rdigest::generic_array::typenum::U20;


/// The message digest.
pub struct Digest<T>(InnerDigest, PhantomData<T>);

enum InnerDigest {
Ring(digest::Digest),
Ripemd160([u8; 20]),
Ripemd160(GenericArray<u8, U20>),
}

impl<T> Deref for Digest<T> {
Expand Down Expand Up @@ -63,7 +66,7 @@ pub struct Hasher<T>(Inner, PhantomData<T>);

enum Inner {
Ring(Context),
Ripemd160(ripemd160::Ripemd160)
Ripemd160(rripemd160::Ripemd160)
}

impl Hasher<Sha256> {
Expand All @@ -80,7 +83,7 @@ impl Hasher<Sha512> {

impl Hasher<Ripemd160> {
pub fn ripemd160() -> Hasher<Ripemd160> {
Hasher(Inner::Ripemd160(ripemd160::Ripemd160::new()), PhantomData)
Hasher(Inner::Ripemd160(rripemd160::Ripemd160::default()), PhantomData)
}
}

Expand All @@ -89,20 +92,18 @@ impl<T> Hasher<T> {
match self.0 {
Inner::Ring(ref mut ctx) => ctx.update(data),
Inner::Ripemd160(ref mut ctx) => {
use rcrypto::digest::Digest;
ctx.input(data)
use rdigest::Input;
ctx.process(data)
}
}
}

pub fn finish(self) -> Digest<T> {
match self.0 {
Inner::Ring(ctx) => Digest(InnerDigest::Ring(ctx.finish()), PhantomData),
Inner::Ripemd160(mut ctx) => {
use rcrypto::digest::Digest;
let mut d = [0; 20];
ctx.result(&mut d);
Digest(InnerDigest::Ripemd160(d), PhantomData)
Inner::Ripemd160(ctx) => {
use rdigest::Digest;
Digest(InnerDigest::Ripemd160(ctx.result()), PhantomData)
}
}
}
Expand Down
49 changes: 41 additions & 8 deletions parity-crypto/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,11 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.

use rcrypto;
use ring;
use rscrypt;
use block_modes;
use raes;
use aes_ctr;

quick_error! {
#[derive(Debug)]
Expand All @@ -42,16 +45,22 @@ quick_error! {
InvalidP {
display("Invalid p argument of the scrypt encryption")
}
ScryptParam(e: rscrypt::errors::InvalidParams) {
display("invalid params for scrypt: {}", e)
cause(e)
from()
}
ScryptLength(e: rscrypt::errors::InvalidOutputLen) {
display("invalid scrypt output length: {}", e)
cause(e)
from()
}
}
}

quick_error! {
#[derive(Debug)]
pub enum SymmError wraps PrivSymmErr {
RustCrypto(e: rcrypto::symmetriccipher::SymmetricCipherError) {
display("symmetric crypto error")
from()
}
Ring(e: ring::error::Unspecified) {
display("symmetric crypto error")
cause(e)
Expand All @@ -60,6 +69,18 @@ quick_error! {
Offset(x: usize) {
display("offset {} greater than slice length", x)
}
BlockMode(e: block_modes::BlockModeError) {
display("symmetric crypto error")
from()
}
KeyStream(e: aes_ctr::stream_cipher::LoopError) {
display("ctr key stream ended")
from()
}
InvalidKeyLength(e: raes::block_cipher_trait::InvalidKeyLength) {
display("Error with RustCrypto key length : {}", e)
from()
}
}
}

Expand All @@ -75,8 +96,20 @@ impl From<ring::error::Unspecified> for SymmError {
}
}

impl From<rcrypto::symmetriccipher::SymmetricCipherError> for SymmError {
fn from(e: rcrypto::symmetriccipher::SymmetricCipherError) -> SymmError {
SymmError(PrivSymmErr::RustCrypto(e))
impl From<block_modes::BlockModeError> for SymmError {
fn from(e: block_modes::BlockModeError) -> SymmError {
SymmError(PrivSymmErr::BlockMode(e))
}
}

impl From<raes::block_cipher_trait::InvalidKeyLength> for SymmError {
fn from(e: raes::block_cipher_trait::InvalidKeyLength) -> SymmError {
SymmError(PrivSymmErr::InvalidKeyLength(e))
}
}

impl From<aes_ctr::stream_cipher::LoopError> for SymmError {
fn from(e: aes_ctr::stream_cipher::LoopError) -> SymmError {
SymmError(PrivSymmErr::KeyStream(e))
}
}
7 changes: 6 additions & 1 deletion parity-crypto/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,17 @@

//! Crypto utils used ethstore and network.

extern crate crypto as rcrypto;
extern crate ethereum_types;
#[macro_use]
extern crate quick_error;
extern crate ring;
extern crate tiny_keccak;
extern crate scrypt as rscrypt;
extern crate ripemd160 as rripemd160;
extern crate digest as rdigest;
extern crate aes as raes;
extern crate aes_ctr;
extern crate block_modes;

pub mod aes;
pub mod aes_gcm;
Expand Down
Loading