diff --git a/.gitignore b/.gitignore
index 03314f7..43e1cc2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,4 @@
Cargo.lock
+
+# Generated by Cargo
+**/target/
\ No newline at end of file
diff --git a/Cargo.toml b/Cargo.toml
index 82b3d21..093722b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -7,8 +7,18 @@ edition = "2018"
[dependencies]
ring = "0.14.6"
quick-error = "1.2"
-rust-crypto = "0.2.36"
primitives = { git = "https://github.com/CodeChain-io/rust-codechain-primitives.git", version = "0.4" }
+sha-1 = "0.8.2"
+sha2 = "0.8.1"
+sha3 = "0.8.2"
+ripemd160 = "0.8.0"
+digest = "0.8"
+blake2 = "0.8.1"
+block-modes = "0.3.3"
+aes = "0.3.2"
+ctr = "0.3.2"
+hex = "0.4.0"
+scrypt = { version = "0.2", default-features = false }
[dev-dependencies]
rand = "0.6.1"
diff --git a/src/aes.rs b/src/aes.rs
index be2d6a9..1cad8db 100644
--- a/src/aes.rs
+++ b/src/aes.rs
@@ -14,59 +14,35 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
+use aes::{Aes128, Aes256};
+use block_modes::block_padding::Pkcs7;
+use block_modes::InvalidKeyIvLength;
+use block_modes::{BlockMode, Cbc};
+use ctr;
+use ctr::stream_cipher::generic_array::GenericArray;
+use ctr::stream_cipher::{NewStreamCipher, SyncStreamCipher, SyncStreamCipherSeek};
use primitives::H256;
-use rcrypto::aes::KeySize::KeySize256;
-use rcrypto::aes::{cbc_decryptor, cbc_encryptor};
-use rcrypto::aessafe::AesSafe128Encryptor;
-use rcrypto::blockmodes::{CtrMode, PkcsPadding};
-use rcrypto::buffer::{BufferResult, ReadBuffer, RefReadBuffer, RefWriteBuffer, WriteBuffer};
-pub use rcrypto::symmetriccipher::SymmetricCipherError;
-use rcrypto::symmetriccipher::{Decryptor, Encryptor};
use super::error::SymmError;
-fn is_underflow(result: BufferResult) -> bool {
- match result {
- BufferResult::BufferUnderflow => true,
- BufferResult::BufferOverflow => false,
- }
-}
-
-// AES-256/CBC/Pkcs encryption.
-pub fn encrypt(data: &[u8], key: &H256, iv: &u128) -> Result, SymmetricCipherError> {
- let mut encryptor = cbc_encryptor(KeySize256, key, &iv.to_be_bytes(), PkcsPadding);
-
- let mut final_result = Vec::::new();
- let mut read_buffer = RefReadBuffer::new(data);
- let mut buffer = [0; 4096];
- let mut write_buffer = RefWriteBuffer::new(&mut buffer);
+type Aes256Cbc = Cbc;
+type Aes128Ctr = ctr::Ctr128;
- let mut finish = false;
- while !finish {
- finish = is_underflow(encryptor.encrypt(&mut read_buffer, &mut write_buffer, true)?);
- final_result.extend(write_buffer.take_read_buffer().take_remaining().iter().cloned());
- }
+// AES-256/CBC/Pkcs encryption.
+pub fn encrypt(data: &[u8], key: &H256, iv: &u128) -> Result, InvalidKeyIvLength> {
+ let cipher = Aes256Cbc::new_var(&key, &iv.to_be_bytes())?;
+ let result = cipher.encrypt_vec(data);
- Ok(final_result)
+ Ok(result)
}
// AES-256/CBC/Pkcs decryption.
-pub fn decrypt(encrypted_data: &[u8], key: &H256, iv: &u128) -> Result, SymmetricCipherError> {
- let mut decryptor = cbc_decryptor(KeySize256, key, &iv.to_be_bytes(), PkcsPadding);
-
- let mut final_result = Vec::::new();
- let mut read_buffer = RefReadBuffer::new(encrypted_data);
- let mut buffer = [0; 4096];
- let mut write_buffer = RefWriteBuffer::new(&mut buffer);
-
- let mut finish = false;
- while !finish {
- finish = is_underflow(decryptor.decrypt(&mut read_buffer, &mut write_buffer, true)?);
- final_result.extend(write_buffer.take_read_buffer().take_remaining().iter().cloned());
- }
+pub fn decrypt(encrypted_data: &[u8], key: &H256, iv: &u128) -> Result, InvalidKeyIvLength> {
+ let cipher = Aes256Cbc::new_var(&key, &iv.to_be_bytes())?;
+ let result = cipher.decrypt_vec(&encrypted_data.to_vec()).unwrap();
- Ok(final_result)
+ Ok(result)
}
/// Encrypt a message (CTR mode).
@@ -74,8 +50,9 @@ pub fn decrypt(encrypted_data: &[u8], key: &H256, iv: &u128) -> Result,
/// 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 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 cipher = Aes128Ctr::new(&GenericArray::from_slice(k), &GenericArray::from_slice(iv));
+ dest.copy_from_slice(plain);
+ cipher.apply_keystream(dest);
Ok(())
}
@@ -84,8 +61,10 @@ pub fn encrypt_128_ctr(k: &[u8], iv: &[u8], plain: &[u8], dest: &mut [u8]) -> Re
/// 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_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 cipher = Aes128Ctr::new(&GenericArray::from_slice(k), &GenericArray::from_slice(iv));
+ dest.copy_from_slice(encrypted);
+ cipher.seek(0);
+ cipher.apply_keystream(dest);
Ok(())
}
@@ -146,4 +125,32 @@ mod tests {
let decrypted = decrypt(&encrypted, &key, &iv).unwrap();
assert_eq!(input, decrypted);
}
+
+ #[test]
+ fn aes_256_cbc_encrypt_decrypt() {
+ let message = [1, 2, 3, 4, 5, 6, 7, 8];
+ let key = H256([0; 32]);
+ let iv = 0;
+
+ let encrypted_data = encrypt(&message, &key, &iv).ok().unwrap();
+ assert_eq!(encrypted_data, [45, 34, 87, 122, 38, 50, 190, 242, 253, 245, 138, 7, 196, 24, 58, 91]);
+
+ let decrypted_data = decrypt(&encrypted_data[..], &key, &iv).ok().unwrap();
+ assert_eq!(message, &decrypted_data[..]);
+ }
+
+ #[test]
+ fn aes_128_ctr_encrypt_decrypt() {
+ let plaintext = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
+ let key = [1; 16];
+ let iv = [1; 16];
+ let mut dest = [0; 10];
+
+ let _ = encrypt_128_ctr(&key, &iv, &plaintext, &mut dest);
+ assert_eq!(dest, [94, 118, 231, 156, 139, 128, 146, 51, 129, 171]);
+
+ let ciphertext = dest;
+ let _ = decrypt_128_ctr(&key, &iv, &ciphertext, &mut dest);
+ assert_eq!(plaintext, dest);
+ }
}
diff --git a/src/blake.rs b/src/blake.rs
index 27324fc..63edd46 100644
--- a/src/blake.rs
+++ b/src/blake.rs
@@ -14,9 +14,9 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
+use blake2::digest::{Input, VariableOutput};
+use blake2::VarBlake2b;
use primitives::{H128, H160, H256, H512};
-use rcrypto::blake2b::Blake2b;
-use rcrypto::digest::Digest;
/// BLAKE128
pub fn blake128>(s: T) -> H128 {
@@ -51,32 +51,27 @@ pub trait Blake {
}
macro_rules! implement_blake {
- ($self:ident) => {
+ ($self:ident, $size:expr) => {
impl Blake for $self {
fn blake>(s: T) -> Self {
- let input = s.as_ref();
- let mut result = Self::default();
- let mut hasher = Blake2b::new(result.len());
- hasher.input(input);
- hasher.result(&mut *result);
- result
+ Self::blake_with_key(s, &[])
}
fn blake_with_key>(s: T, key: &[u8]) -> Self {
let input = s.as_ref();
- let mut result = Self::default();
- let mut hasher = Blake2b::new_keyed(result.len(), &key);
+ let mut hasher = VarBlake2b::new_keyed(&key, $size);
hasher.input(input);
- hasher.result(&mut *result);
- result
+ let mut result: [u8; $size] = [0; $size];
+ result.copy_from_slice(&hasher.vec_result());
+ Self(result)
}
}
};
}
-implement_blake!(H128);
-implement_blake!(H160);
-implement_blake!(H256);
-implement_blake!(H512);
+implement_blake!(H128, 16);
+implement_blake!(H160, 20);
+implement_blake!(H256, 32);
+implement_blake!(H512, 64);
/// Get the 256-bits BLAKE2b hash of the empty bytes string.
pub const BLAKE_EMPTY: H256 = H256([
diff --git a/src/error.rs b/src/error.rs
index 6677c1b..56073c3 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -42,18 +42,24 @@ quick_error! {
InvalidP {
display("Invalid p argument of the scrypt encryption")
}
+ InvalidOutputLen {
+ display("Invalid length of output")
+ }
+ InvalidParams {
+ display("Invalid parameters")
+ }
}
}
#[allow(deprecated)]
mod errors {
- use rcrypto;
+ use crate::error::ScryptError;
use ring;
quick_error! {
#[derive(Debug)]
pub enum SymmError wraps PrivSymmErr {
- RustCrypto(e: rcrypto::symmetriccipher::SymmetricCipherError) {
+ RustCrypto(e: block_modes::InvalidKeyIvLength) {
display("symmetric crypto error")
from()
}
@@ -74,10 +80,22 @@ mod errors {
}
}
- impl From for SymmError {
- fn from(e: rcrypto::symmetriccipher::SymmetricCipherError) -> SymmError {
+ impl From for SymmError {
+ fn from(e: block_modes::InvalidKeyIvLength) -> SymmError {
SymmError(PrivSymmErr::RustCrypto(e))
}
}
+
+ impl From for ScryptError {
+ fn from(_e: scrypt::errors::InvalidOutputLen) -> ScryptError {
+ ScryptError::InvalidOutputLen
+ }
+ }
+
+ impl From for ScryptError {
+ fn from(_e: scrypt::errors::InvalidParams) -> ScryptError {
+ ScryptError::InvalidParams
+ }
+ }
}
pub use self::errors::SymmError;
diff --git a/src/hash.rs b/src/hash.rs
index f258d3d..38a871c 100644
--- a/src/hash.rs
+++ b/src/hash.rs
@@ -14,55 +14,55 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
+use digest::Digest;
use primitives::{H160, H256};
-use rcrypto::digest::Digest;
-use rcrypto::ripemd160::Ripemd160;
-use rcrypto::sha1::Sha1;
-use rcrypto::sha2::Sha256;
-use rcrypto::sha3::Sha3;
+use ripemd160::Ripemd160;
+use sha1::Sha1;
+use sha2::Sha256;
+use sha3::Keccak256;
/// RIPEMD160
#[inline]
pub fn ripemd160>(s: T) -> H160 {
let input = s.as_ref();
- let mut result = H160::default();
let mut hasher = Ripemd160::new();
hasher.input(input);
- hasher.result(&mut *result);
- result
+ let mut array: [u8; 20] = [0; 20];
+ array.copy_from_slice(&hasher.result());
+ H160(array)
}
/// SHA-1
#[inline]
pub fn sha1>(s: T) -> H160 {
let input = s.as_ref();
- let mut result = H160::default();
let mut hasher = Sha1::new();
hasher.input(input);
- hasher.result(&mut *result);
- result
+ let mut array: [u8; 20] = [0; 20];
+ array.copy_from_slice(&hasher.result());
+ H160(array)
}
/// SHA-256
#[inline]
pub fn sha256>(s: T) -> H256 {
let input = s.as_ref();
- let mut result = H256::default();
let mut hasher = Sha256::new();
hasher.input(input);
- hasher.result(&mut *result);
- result
+ let mut array: [u8; 32] = [0; 32];
+ array.copy_from_slice(&hasher.result());
+ H256(array)
}
/// KECCAK256
#[inline]
pub fn keccak256>(s: T) -> H256 {
let input = s.as_ref();
- let mut result = H256::default();
- let mut hasher = Sha3::keccak256();
+ let mut hasher = Keccak256::new();
hasher.input(input);
- hasher.result(&mut result);
- result
+ let mut array: [u8; 32] = [0; 32];
+ array.copy_from_slice(&hasher.result());
+ H256(array)
}
#[cfg(test)]
diff --git a/src/lib.rs b/src/lib.rs
index eb487f5..4c62dc2 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -31,7 +31,6 @@
// along with Parity. If not, see .
-extern crate crypto as rcrypto;
extern crate primitives;
#[macro_use]
extern crate quick_error;
diff --git a/src/scrypt.rs b/src/scrypt.rs
index 333f8b4..d18d40c 100644
--- a/src/scrypt.rs
+++ b/src/scrypt.rs
@@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see .
-use rcrypto::scrypt::{scrypt, ScryptParams};
+use scrypt::{scrypt, ScryptParams};
use crate::error::ScryptError;
use crate::{Password, KEY_LENGTH, KEY_LENGTH_AES};
@@ -32,9 +32,43 @@ pub fn derive_key(pass: &Password, salt: &[u8; 32], n: u32, p: u32, r: u32) -> R
}
let mut derived_key = vec![0u8; KEY_LENGTH];
- let scrypt_params = ScryptParams::new(log_n, r, p);
- scrypt(pass.as_bytes(), salt, &scrypt_params, &mut derived_key);
+ let scrypt_params = ScryptParams::new(log_n, r, p)?;
+ scrypt(pass.as_bytes(), salt, &scrypt_params, &mut derived_key)?;
let derived_right_bits = &derived_key[0..KEY_LENGTH_AES];
let derived_left_bits = &derived_key[KEY_LENGTH_AES..KEY_LENGTH];
Ok((derived_right_bits.to_vec(), derived_left_bits.to_vec()))
}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::password::Password;
+
+ #[test]
+ fn scrypt_test() {
+ let mut password = Password("rust-crypto-codechain");
+ let mut salt = [1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8];
+ let mut n: u32 = 8;
+ let mut p: u32 = 16;
+ let mut r: u32 = 8;
+
+ let mut result = derive_key(&password, &salt, n, p, r).unwrap();
+ let mut right_bits = [229, 222, 150, 129, 167, 152, 151, 149, 110, 135, 118, 252, 139, 12, 227, 29];
+ let mut left_bits = [111, 69, 216, 187, 101, 33, 114, 185, 126, 184, 57, 98, 243, 60, 174, 249];
+ assert_eq!(&result.0[..], right_bits);
+ assert_eq!(&result.1[..], left_bits);
+
+
+ password = Password("Codechain and Foundry");
+ salt = [0; 32];
+ n = 16;
+ p = 1;
+ r = 1;
+
+ result = derive_key(&password, &salt, n, p, r).unwrap();
+ right_bits = [144, 79, 151, 99, 185, 187, 191, 74, 135, 222, 178, 102, 32, 179, 194, 170];
+ left_bits = [179, 96, 63, 181, 115, 192, 159, 237, 20, 181, 18, 253, 164, 77, 199, 136];
+ assert_eq!(&result.0[..], right_bits);
+ assert_eq!(&result.1[..], left_bits);
+ }
+}