Skip to content
Merged
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
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,5 @@ members = [
"trace-time",
"trie-standardmap",
"triehash",
"uint"
"uint",
]
19 changes: 17 additions & 2 deletions parity-crypto/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,24 @@ authors = ["Parity Technologies <admin@parity.io>"]
repository = "https://github.com/paritytech/parity-common"
description = "Crypto utils used by ethstore and network."
license = "GPL-3.0"
autobenches = false

[[bench]]
name = "bench"
harness = false


[dependencies]
quick-error = "1.2.2"
ring = "0.13"
rust-crypto = "0.2.36"
tiny-keccak = "1.4"
scrypt = { version = "0.1.1", default-features = false }
ripemd160 = "0.8.0"
sha2 = "0.8.0"
digest = "0.8"
aes = "0.3.2"
aes-ctr = "0.3.0"
block-modes = "0.2.0"
ring = "0.13"

[dev-dependencies]
criterion = "0.2"
56 changes: 56 additions & 0 deletions parity-crypto/benches/bench.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright 2015-2018 Parity Technologies (UK) Ltd.
// This file is part of Parity.

// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.


extern crate parity_crypto;

#[macro_use]
extern crate criterion;

use criterion::{Criterion, Bencher};

criterion_group!(benches, input_len);

criterion_main!(benches);

/// general benches for multiple input size
fn input_len(c: &mut Criterion) {

c.bench_function_over_inputs("ripemd",
|b: &mut Bencher, size: &usize| {
let data = vec![0u8; *size];
b.iter(|| parity_crypto::digest::ripemd160(&data[..]));
},
vec![100, 500, 1_000, 10_000, 100_000]
);

c.bench_function_over_inputs("aes_ctr",
|b: &mut Bencher, size: &usize| {
let data = vec![0u8; *size];
let mut dest = vec![0; *size];
let k = [0; 16];
let iv = [0; 16];

b.iter(||{
parity_crypto::aes::encrypt_128_ctr(&k[..], &iv[..], &data[..], &mut dest[..]).unwrap();
// same as encrypt but add it just in case
parity_crypto::aes::decrypt_128_ctr(&k[..], &iv[..], &data[..], &mut dest[..]).unwrap();
});
},
vec![100, 500, 1_000, 10_000, 100_000]
);

}
180 changes: 167 additions & 13 deletions parity-crypto/src/aes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,40 +14,194 @@
// 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::{ NewStreamCipher, SyncStreamCipher };
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
pub fn new(key: &[u8]) -> Result<Self, SymmError> {
Ok(AesEcb256(Ecb::new_varkey(key)?))
}

/// Encrypt data in place without padding. The data length must be a multiple
/// of the block size.
pub fn encrypt(&mut self, content: &mut [u8]) -> Result<(), SymmError> {
self.0.encrypt_nopad(content)?;
Ok(())
}

/// Decrypt data in place without padding. The data length must be a multiple
/// of the block size.
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
pub fn new(key: &[u8], iv: &[u8]) -> Result<Self, SymmError> {
Ok(AesCtr256(
Aes256Ctr::new(GenericArray::from_slice(key), GenericArray::from_slice(iv))
))
}

/// In place encrypt a content without padding, the content length must be a multiple
/// of the block size.
pub fn encrypt(&mut self, content: &mut[u8]) -> Result<(), SymmError> {
self.0.try_apply_keystream(content)?;
Ok(())
}

/// In place decrypt a content without padding, the content length must be a multiple
/// of the block size.
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 prefer `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(())

}

/// 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.
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 prefer `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(())
}


/// 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)
}


#[cfg(test)]
mod tests {

use super::*;

// only use for test could be expose in the future
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(())
}

#[test]
pub fn test_aes_short() -> Result<(),SymmError> {
let key = [97, 110, 121, 99, 111, 110, 116, 101, 110, 116, 116, 111, 114, 101, 97, 99, 104, 49, 50, 56, 98, 105, 116, 115, 105, 122, 101, 10];
let salt = [109, 121, 115, 97, 108, 116, 115, 104, 111, 117, 108, 100, 102, 105, 108, 108, 115, 111, 109, 109, 101, 98, 121, 116, 101, 108, 101, 110, 103, 116, 104, 10];
let content = [83, 111, 109, 101, 32, 99, 111, 110, 116, 101, 110, 116, 32, 116, 111, 32, 116, 101, 115, 116,
32, 97, 101, 115, 44, 10, 110, 111, 116, 32, 116, 111, 32, 109, 117, 99, 104, 32, 44, 32, 111, 110, 108, 121,
32, 118, 101, 114, 121, 32, 98, 97, 115, 105, 99, 32, 116, 101, 115, 116, 32, 116, 111, 32, 97, 118, 111, 105,
100, 32, 111, 98, 118, 105, 111, 117, 115, 32, 114, 101, 103, 114, 101, 115, 115, 105, 111, 110, 32, 119, 104,
101, 110, 32, 115, 119, 105, 116, 99, 104, 105, 110, 103, 32, 108, 105, 98, 115, 46, 10];
let ctr_enc = [65, 55, 246, 75, 24, 117, 30, 233, 218, 139, 91, 251, 251, 179, 171, 69, 60, 244, 249, 44, 238, 60,
10, 66, 71, 10, 199, 111, 54, 24, 124, 223, 153, 250, 159, 154, 164, 109, 232, 82, 20, 199, 182, 40, 174, 104, 64,
203, 236, 94, 222, 184, 117, 54, 234, 189, 253, 122, 135, 121, 100, 44, 227, 241, 123, 120, 110, 188, 109, 148, 112,
160, 131, 205, 116, 104, 232, 8, 22, 170, 80, 231, 155, 246, 255, 115, 101, 5, 234, 104, 220, 199, 192, 166, 181, 156,
113, 255, 187, 51, 38, 128, 75, 29, 237, 178, 205, 98, 101, 110];
let cbc_enc = [167, 248, 5, 90, 11, 140, 215, 138, 165, 125, 137, 76, 47, 243, 191, 48, 183, 247, 109, 86, 24, 45,
81, 215, 0, 51, 221, 185, 131, 97, 234, 189, 244, 255, 107, 210, 70, 60, 41, 221, 43, 137, 185, 166, 42, 65, 18, 200,
151, 233, 255, 192, 109, 25, 105, 115, 161, 209, 126, 235, 99, 192, 241, 241, 19, 249, 87, 244, 28, 146, 186, 189, 108,
9, 243, 132, 4, 105, 53, 162, 8, 235, 84, 107, 213, 59, 158, 113, 227, 120, 162, 50, 237, 123, 70, 187, 83, 73, 146, 13,
44, 191, 53, 4, 125, 207, 176, 45, 8, 153, 175, 198];
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[..]);
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(())
}
}
Loading