Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
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.14.3"
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.3.3"
ring = "0.14.6"

[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]
);

}
181 changes: 168 additions & 13 deletions parity-crypto/src/aes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,40 +14,195 @@
// 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};
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;


/// One time 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_var(key, &[])?))
}

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

/// Decrypt data in place without padding. The data length must be a multiple
/// of the block size.
pub fn decrypt(self, content: &mut [u8]) -> Result<(), SymmError> {
self.0.decrypt(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_var(k, iv)?;
&mut dest[..encrypted.len()].copy_from_slice(encrypted);
let unpad_length = {
encryptor.decrypt(&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_var(k, iv)?;
&mut dest[..plain.len()].copy_from_slice(plain);
encryptor.encrypt(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