From 851a6ecf5b775dbaaee3ae7d0a5ef676dd74ee68 Mon Sep 17 00:00:00 2001 From: zhl Date: Tue, 9 May 2023 18:36:14 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0aes=E5=8A=A0=E8=A7=A3?= =?UTF-8?q?=E5=AF=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 2 + Cargo.toml | 2 + examples/test.rs | 12 +++- src/lib.rs | 31 ++++++++-- src/utils/crypto_utils.rs | 121 ++++++++++++++++++++++++++++++++++++++ src/utils/mod.rs | 2 +- src/utils/pass_utils.rs | 52 ---------------- src/wallet/wallet_impl.rs | 55 +++++++++-------- 8 files changed, 189 insertions(+), 88 deletions(-) create mode 100644 src/utils/crypto_utils.rs delete mode 100644 src/utils/pass_utils.rs diff --git a/Cargo.lock b/Cargo.lock index c455e41..05d2819 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -722,6 +722,7 @@ checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" name = "rustwallet" version = "0.1.0" dependencies = [ + "aes-gcm", "anyhow", "argon2", "base64 0.21.0", @@ -729,6 +730,7 @@ dependencies = [ "ecies", "hex", "primitive-types", + "rand 0.8.5", "scrypt", "secp256k1", "serde", diff --git a/Cargo.toml b/Cargo.toml index f5b7f5a..2283434 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,3 +27,5 @@ ecies = {version = "0.2", default-features = false, features = ["pure"]} base64 = "0.21.0" scrypt = { version = "0.11.0", default-features = false, features = ["simple"] } argon2 = { version = "0.5.0" } +aes-gcm = "0.10.1" +rand = "0.8.5" diff --git a/examples/test.rs b/examples/test.rs index c28feab..ef7d954 100644 --- a/examples/test.rs +++ b/examples/test.rs @@ -5,9 +5,9 @@ // use rustwallet::{ - free_cwallet, generate_sec_key, get_address, get_public_key, hash_pass_svr, hex_deflate, - hex_inflate, keccak256_hash, new_wallet, rencrypt, sign, sign_for_tran, wallet_decrypt, - wallet_encrypt, CWallet, + aes_decrypt, aes_encrypt, free_cwallet, generate_sec_key, get_address, get_public_key, + hash_pass_svr, hex_deflate, hex_inflate, keccak256_hash, new_wallet, rencrypt, sign, + sign_for_tran, wallet_decrypt, wallet_encrypt, CWallet, }; use std::ffi::{CStr, CString}; use std::os::raw::c_char; @@ -147,5 +147,11 @@ fn main() { let pass = "111111"; let hash_pass = hash_pass_svr(str_to_cchar!(pass)); print_cchar!(hash_pass); + + let str_encrypt = aes_encrypt(str_to_cchar!(pass)); + print_cchar!(str_encrypt); + + let str_plain = aes_decrypt(str_encrypt); + print_cchar!(str_plain); } } diff --git a/src/lib.rs b/src/lib.rs index 7d7efff..55db649 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,7 +11,7 @@ use std::str::FromStr; mod wallet; use secp256k1::PublicKey; -use wallet::wallet_impl::zencrypt; +use wallet::wallet_impl::{zdecrypt, zencrypt}; use wallet_impl::Wallet; use crate::wallet::*; @@ -224,7 +224,8 @@ pub unsafe extern "C" fn wallet_decrypt( ) -> *mut c_char { let rwallet = generate_rwallet(msg_key, master_key, second_key, backup_key); let msg_str = cchar_to_str!(msg); - let msg_decrypt = match rwallet.zdecrypt(msg_str) { + let sk = rwallet.get_secret_key(); + let msg_decrypt = match zdecrypt(sk, msg_str) { Ok(v) => v, Err(err) => panic!("error decrypt: {:?}", err), }; @@ -248,13 +249,35 @@ pub unsafe extern "C" fn hex_inflate(content: *const c_char) -> *mut c_char { #[no_mangle] pub unsafe extern "C" fn hash_pass_svr(content: *const c_char) -> *mut c_char { let content_str = cchar_to_str!(content); - let msg_hex = utils::pass_utils::hash_pass_svr(&content_str); + let msg_hex = utils::crypto_utils::hash_pass_svr(&content_str); + str_to_cchar!(msg_hex) +} +#[no_mangle] +pub unsafe extern "C" fn hash_pass_client(content: *const c_char) -> *mut c_char { + let content_str = cchar_to_str!(content); + let msg_hex = utils::crypto_utils::hash_pass_client(&content_str); str_to_cchar!(msg_hex) } #[no_mangle] pub unsafe extern "C" fn keccak256_hash(content: *const c_char) -> *mut c_char { let content_str = cchar_to_str!(content); - let msg_hex = utils::pass_utils::keccak256_hash(&content_str); + let msg_hex = utils::crypto_utils::keccak256_hash(&content_str); + str_to_cchar!(msg_hex) +} + +#[no_mangle] +pub unsafe extern "C" fn aes_encrypt(content: *const c_char) -> *mut c_char { + let content_str = cchar_to_str!(content); + let pass = "2a3a6e3ef5e6e4617a09d91014cb54dcdc0dd6dcb1809d3f5701779651e51cf2"; + let msg_hex = utils::crypto_utils::aes_encrypt(&content_str, &pass); + str_to_cchar!(msg_hex) +} + +#[no_mangle] +pub unsafe extern "C" fn aes_decrypt(content: *const c_char) -> *mut c_char { + let content_str = cchar_to_str!(content); + let pass = "2a3a6e3ef5e6e4617a09d91014cb54dcdc0dd6dcb1809d3f5701779651e51cf2"; + let msg_hex = utils::crypto_utils::aes_decrypt(&content_str, &pass); str_to_cchar!(msg_hex) } diff --git a/src/utils/crypto_utils.rs b/src/utils/crypto_utils.rs new file mode 100644 index 0000000..eb633a6 --- /dev/null +++ b/src/utils/crypto_utils.rs @@ -0,0 +1,121 @@ +use aes_gcm::{ + aead::{generic_array::GenericArray, Aead, KeyInit}, + Aes256Gcm, + Nonce, // Or `Aes128Gcm` +}; +use argon2::{ + password_hash::{rand_core::OsRng, PasswordHash, PasswordHasher, PasswordVerifier, SaltString}, + Argon2, +}; +use base64::{engine::general_purpose, Engine as _}; +use rand::prelude::*; +use std::str; +use tiny_keccak::keccak256; + +pub fn hash_password(pass: &str) -> String { + let salt: SaltString = SaltString::generate(&mut OsRng); + let password = pass.as_bytes(); + let password_hash: String = match Argon2::default().hash_password(password, &salt) { + Ok(v) => v.to_string(), + Err(e) => panic!("error hash password: {}", e), + }; + general_purpose::STANDARD_NO_PAD.encode(&password_hash) +} + +pub fn verify_password(pass: &str, password_hash: &str) -> bool { + let str_tmp = match general_purpose::STANDARD_NO_PAD.decode(password_hash) { + Ok(v) => v, + Err(e) => panic!("error decode base64 str: {}", e), + }; + let s = match str::from_utf8(&str_tmp) { + Ok(v) => v, + Err(e) => panic!("Invalid UTF-8 sequence: {}", e), + }; + let parsed_hash = match PasswordHash::new(&s) { + Ok(v) => v, + Err(e) => panic!("error parse password hash: {}", e), + }; + + let password = pass.as_bytes(); + Argon2::default() + .verify_password(password, &parsed_hash) + .is_ok() +} + +pub fn keccak256_hash(str: &str) -> String { + let data = str.as_bytes(); + let hasher = keccak256(data); + hex::encode(&hasher) +} + +pub fn hash_pass_client(str: &str) -> String { + let message = str.as_bytes(); + let mut eth_message = format!("\x22cebg password pre hash:\n{}", message.len()).into_bytes(); + eth_message.extend_from_slice(message); + + let hasher = keccak256(ð_message); + hex::encode(&hasher) +} + +pub fn hash_pass_svr(str: &str) -> String { + let message = str.as_bytes(); + let mut eth_message = format!("\x23cebg email regist:\n{}", message.len()).into_bytes(); + eth_message.extend_from_slice(message); + + let hasher = keccak256(ð_message); + hex::encode(&hasher) +} +// +// This function is used to encrypt a string using AES-256-GCM algorithm +pub fn aes_encrypt(str: &str, key: &str) -> String { + // Convert the input string to bytes + let str_data = str.as_bytes(); + + // Decode the input key from hex to bytes and create a GenericArray object + let key = hex::decode(&key).expect("Invalid hex string"); + let key = GenericArray::from_slice(&key); + + // Create an AES-256-GCM cipher with the specified key + let cipher = Aes256Gcm::new(&key); + + // Generate a random nonce of 96 bits (12 bytes) + let mut nonce_data = [0u8; 12]; + thread_rng().fill_bytes(&mut nonce_data); + let nonce = GenericArray::from_slice(&nonce_data); + + // Encrypt the data using the cipher and nonce + let ciphertext = match cipher.encrypt(nonce, str_data) { + Ok(v) => v, + Err(e) => panic!("error encrypt: {}", e), + }; + // Encode the ciphertext and nonce as base64 strings + let cipher_str = general_purpose::STANDARD_NO_PAD.encode(&ciphertext); + let nonce_str = general_purpose::STANDARD_NO_PAD.encode(&nonce_data); + // Concatenate the encoded ciphertext and nonce with a period separator and return the result + nonce_str + cipher_str.as_str() +} + +pub fn aes_decrypt(str: &str, key: &str) -> String { + let str_data = match general_purpose::STANDARD_NO_PAD.decode(str) { + Ok(v) => v, + Err(e) => panic!("error decode base64 str: {}", e), + }; + if str_data.len() < 12 { + panic!("error decrypt: invalid data"); + } + let v = 12; + let nonce_data = &str_data[..v]; + let cipher_data = &str_data[v..]; + + let nonce = GenericArray::from_slice(&nonce_data); + let key = hex::decode(&key).expect("Invalid hex string"); + let key = GenericArray::from_slice(&key); + let cipher = Aes256Gcm::new(&key); + + let plaintext = match cipher.decrypt(nonce, cipher_data) { + Ok(v) => v, + Err(e) => panic!("error decrypt: {}", e), + }; + let plaintext = str::from_utf8(&plaintext).expect("err convert to utf8"); + plaintext.to_string() +} diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 25d5f55..e143402 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1,2 +1,2 @@ -pub mod pass_utils; +pub mod crypto_utils; pub mod str_utils; diff --git a/src/utils/pass_utils.rs b/src/utils/pass_utils.rs deleted file mode 100644 index 9fd8bcb..0000000 --- a/src/utils/pass_utils.rs +++ /dev/null @@ -1,52 +0,0 @@ -use argon2::{ - password_hash::{rand_core::OsRng, PasswordHash, PasswordHasher, PasswordVerifier, SaltString}, - Argon2, -}; -use base64::{engine::general_purpose, Engine as _}; -use std::str; -use tiny_keccak::keccak256; - -pub fn hash_password(pass: &str) -> String { - let salt: SaltString = SaltString::generate(&mut OsRng); - let password = pass.as_bytes(); - let password_hash: String = match Argon2::default().hash_password(password, &salt) { - Ok(v) => v.to_string(), - Err(e) => panic!("error hash password: {}", e), - }; - general_purpose::STANDARD_NO_PAD.encode(&password_hash) -} - -pub fn verify_password(pass: &str, password_hash: &str) -> bool { - let str_tmp = match general_purpose::STANDARD_NO_PAD.decode(password_hash) { - Ok(v) => v, - Err(e) => panic!("error decode base64 str: {}", e), - }; - let s = match str::from_utf8(&str_tmp) { - Ok(v) => v, - Err(e) => panic!("Invalid UTF-8 sequence: {}", e), - }; - let parsed_hash = match PasswordHash::new(&s) { - Ok(v) => v, - Err(e) => panic!("error parse password hash: {}", e), - }; - - let password = pass.as_bytes(); - Argon2::default() - .verify_password(password, &parsed_hash) - .is_ok() -} - -pub fn keccak256_hash(str: &str) -> String { - let data = str.as_bytes(); - let hasher = keccak256(data); - hex::encode(&hasher) -} - -pub fn hash_pass_svr(str: &str) -> String { - let message = str.as_bytes(); - let mut eth_message = format!("\x23cebg email regist:\n{}", message.len()).into_bytes(); - eth_message.extend_from_slice(message); - - let hasher = keccak256(ð_message); - hex::encode(&hasher) -} diff --git a/src/wallet/wallet_impl.rs b/src/wallet/wallet_impl.rs index ccab53f..df35294 100644 --- a/src/wallet/wallet_impl.rs +++ b/src/wallet/wallet_impl.rs @@ -32,6 +32,32 @@ pub fn zencrypt(pk: PublicKey, msg: &str) -> Result { Ok(str_encrypt) } +pub fn zdecrypt(sk: SecretKey, msg1: &str) -> Result { + let sk = sk.secret_bytes(); + let mut msg: String = msg1.clone().to_string(); + if msg.len() % 2 == 1 { + msg = "0".to_owned() + &msg; + } + println!("msg to decrypt: {:?}", &msg); + let msg = match hex::decode(&msg) { + Ok(v) => v, + Err(e) => panic!("error decode hex str: {}", e), + }; + let msg_decrypt = match decrypt(&sk, &msg) { + Ok(v) => v, + Err(e) => panic!("error decrypt content: {}", e), + }; + // println!("msg after decrypt: {:?}", &msg_decrypt); + // let msg_decrypt = hex::encode(msg_decrypt); + let str_decrypt = match str::from_utf8(&msg_decrypt) { + Ok(v) => v, + Err(e) => panic!("Invalid UTF-8 sequence: {}", e), + }; + let result = str_decrypt.to_string(); + + Ok(result) +} + pub fn public_key_address(public_key: &PublicKey) -> H160 { let public_key = public_key.serialize_uncompressed(); debug_assert_eq!(public_key[0], 0x04); @@ -119,7 +145,7 @@ impl Wallet { } } - fn get_secret_key(&self) -> SecretKey { + pub fn get_secret_key(&self) -> SecretKey { let key_str_0: &str = &self.master_key; let key0 = BigInt::parse_bytes(&key_str_0.as_bytes(), 16).unwrap(); let kp0: (usize, BigInt) = (1, key0); @@ -197,31 +223,4 @@ impl Wallet { let recid = _recovery_id.to_i32(); Ok((s, recid)) } - - pub fn zdecrypt(&self, msg1: &str) -> Result { - let sk = self.get_secret_key(); - let sk = sk.secret_bytes(); - let mut msg: String = msg1.clone().to_string(); - if msg.len() % 2 == 1 { - msg = "0".to_owned() + &msg; - } - println!("msg to decrypt: {:?}", &msg); - let msg = match hex::decode(&msg) { - Ok(v) => v, - Err(e) => panic!("error decode hex str: {}", e), - }; - let msg_decrypt = match decrypt(&sk, &msg) { - Ok(v) => v, - Err(e) => panic!("error decrypt content: {}", e), - }; - // println!("msg after decrypt: {:?}", &msg_decrypt); - // let msg_decrypt = hex::encode(msg_decrypt); - let str_decrypt = match str::from_utf8(&msg_decrypt) { - Ok(v) => v, - Err(e) => panic!("Invalid UTF-8 sequence: {}", e), - }; - let result = str_decrypt.to_string(); - - Ok(result) - } }