Added CPU optimized client variant.

This commit is contained in:
Kirill Shakirov
2026-04-27 14:06:28 +02:00
parent d6fa6093cb
commit a6e64f4d3d
17 changed files with 2985 additions and 0 deletions
+154
View File
@@ -0,0 +1,154 @@
Need to pass into CMD for opt
```
RUSTFLAGS='--cfg aes_backend="avx512" -Ctarget-feature=+aes,+avx512f,+vaes' cargo build --release
```
```
Passing RUSTFLAGS=-Ctarget-feature=+aes,+ssse3 explicitly at compile-time will override runtime detection and ensure that AES-NI is used or passing RUSTFLAGS=-Ctarget-feature=+aes,+avx512f,+ssse3,+vaes will ensure that AESNI and VAES are always used.
```
# Building nyash_client
Cross-compilation guide for **Ubuntu 24.04 LTS** — produces native Linux binary and Windows `.exe` from a single build server.
## Requirements
- Ubuntu 24.04 LTS (Noble Numbat)
- Internet access on the build server
- No GPU required — OpenCL CPU runtime is provided by the user at runtime
---
## Step 1 — System packages
```bash
sudo apt update && sudo apt install -y \
curl wget git unzip build-essential pkg-config \
gcc-mingw-w64-x86-64 mingw-w64 mingw-w64-tools \
ocl-icd-opencl-dev opencl-headers pocl-opencl-icd \
protobuf-compiler
```
---
## Step 2 — Rust
```bash
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Select: 1 (default)
source $HOME/.cargo/env
rustup target add x86_64-pc-windows-gnu
```
Verify:
```bash
rustc --version
protoc --version
```
---
## Step 3 — OpenCL Windows stub
The build server does not need a GPU or OpenCL runtime. Only a linker stub (`libOpenCL.a`) is required at compile time. The actual OpenCL runtime is provided by the user's OS/drivers at runtime.
```bash
cd ~
wget https://github.com/KhronosGroup/OpenCL-SDK/releases/download/v2023.12.14/OpenCL-SDK-v2023.12.14-Win-x64.zip
unzip OpenCL-SDK-v2023.12.14-Win-x64.zip -d opencl-sdk
SDK=~/opencl-sdk/OpenCL-SDK-v2023.12.14-Win-x64
# Generate .def from DLL
cd $SDK/bin
gendef OpenCL.dll
# Generate libOpenCL.a from .def
x86_64-w64-mingw32-dlltool \
-D OpenCL.dll \
-d OpenCL.def \
-l libOpenCL.a
# Install into MinGW sysroot
sudo cp libOpenCL.a /usr/x86_64-w64-mingw32/lib/
sudo cp -r $SDK/include/CL /usr/x86_64-w64-mingw32/include/
```
Verify:
```bash
ls /usr/x86_64-w64-mingw32/lib/libOpenCL.a
ls /usr/x86_64-w64-mingw32/include/CL/cl.h
```
---
## Step 4 — Clone the repository
```bash
cd ~
git clone https://github.com/Nyanraltotlapun/nyash-aes-xts256-plain64.git
cd nyash-aes-xts256-plain64/nyash_client
```
---
## Step 5 — Cargo config
Create `.cargo/config.toml` in the `nyash_client` directory:
```bash
mkdir -p .cargo
cat > .cargo/config.toml << 'EOF'
[target.x86_64-pc-windows-gnu]
linker = "x86_64-w64-mingw32-gcc"
ar = "x86_64-w64-mingw32-ar"
rustflags = ["-L", "/usr/x86_64-w64-mingw32/lib"]
[target.x86_64-unknown-linux-gnu]
linker = "gcc"
[env]
PROTOC = "/usr/bin/protoc"
EOF
```
---
## Step 6 — Build
```bash
rustup target add x86_64-pc-windows-gnu
# Linux
cargo build --release
# Windows
cargo build --release --target x86_64-pc-windows-gnu
```
---
## Output
| Platform | Path |
|----------|------|
| Linux | `target/release/nyash-client` |
| Windows | `target/x86_64-pc-windows-gnu/release/nyash-client.exe` |
---
## Runtime requirements for end users
The `.exe` does **not** bundle an OpenCL runtime — it is loaded dynamically from the user's system.
| OS | OpenCL source |
|---------|----------------------------------------------------|
| Windows | Intel CPU Runtime for OpenCL — installed automatically with Intel drivers, or download from [intel.com](https://www.intel.com/content/www/us/en/developer/articles/tool/opencl-drivers.html) |
| Linux | `sudo apt install pocl-opencl-icd` (CPU) or vendor GPU driver |
+1231
View File
File diff suppressed because it is too large Load Diff
+31
View File
@@ -0,0 +1,31 @@
[package]
name = "nyash_client"
version = "0.2.0"
edition = "2024"
build = "build.rs"
[[bin]] # Bin to run the HelloWorld gRPC client
name = "nyash-client"
path = "src/client.rs"
[dependencies]
aes = { version = "0.9" }
prost = "0.14.3"
serde = { version = "1.0.228", features = ["derive"] }
serde_json = "1.0.149"
threadpool = "1.8.1"
tokio = { version = "1.50.0", features = ["rt", "macros", "signal"] }
tonic = "0.14.5"
tonic-prost = "0.14.5"
[build-dependencies]
tonic-prost-build = "0.14.5"
[profile.release]
lto = true
codegen-units = 1
opt-level = 3
strip = true
+26
View File
@@ -0,0 +1,26 @@
fn main() -> Result<(), Box<dyn std::error::Error>> {
//compile gRPC
tonic_prost_build::compile_protos("proto/nyash.proto")?;
//******************* compile ocl into spirv64 *********
// let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
// let ocl_src_dir = Path::new(&manifest_dir).join("src/open_cl");
// let spirv_build_script = ocl_src_dir.clone().join("build_spirv.sh");
// let out_dir = env::var("OUT_DIR").unwrap();
// let spirv_bin_path = Path::new(&out_dir).join("nyash_aes_xts256_plain.spv");
// let str_spirv_bit_p = spirv_bin_path.to_str().expect("Error converting spirv out path to str!");
// let _output = Command::new(spirv_build_script)
// .current_dir(ocl_src_dir)
// .arg(str_spirv_bit_p)
// .output()
// .expect("Failed to execute spirv build script!");
// ***************** concat ocl sources to one file and zip it **********************
Ok(())
}
+80
View File
@@ -0,0 +1,80 @@
syntax = "proto3";
package nyash_proto;
// serving key brutforcing for aes xts
service NyashLuks {
// Requesting work, gettin in response work data, error, or message that there is no work currently awaylable.
rpc RequestWork (WorkRequest) returns (WorkReply);
// Commiting work, with work ID. If key was found, sending also discowered key
rpc CommitWork (WorkCommit) returns (CommitReply);
// Request owerall key search progress
rpc RequestProgress (ProgressRequest) returns (ProgressReply);
}
message WorkRequest {
// Request work from server
// Preffered work size in number of keys
uint64 pref_work_size = 1;
}
message WorkReply {
oneof result {
WorkData work_data = 1;
bool no_work = 2;
string error = 3;
}
}
message WorkData {
// work id
uint64 work_id =1;
// work size - number of keys to check
uint64 work_size= 2;
// tweak key is 128 bit. We send it as two uint64 values
uint64 tweak_key0 =3;
uint64 tweak_key1 =4;
// start key is 128 bit. We send it as two uint64 values
uint64 start_key0 =5;
uint64 start_key1 =6;
}
message WorkCommit {
// work id
uint64 work_id =1;
oneof result {
bool no_key = 2;
KeyData found_key = 3;
}
}
message KeyData {
// tweak key is 128 bit. We send it as two uint64 values
uint64 tweak_key0 =3;
uint64 tweak_key1 =4;
// start key is 128 bit. We send it as two uint64 values
uint64 start_key0 =5;
uint64 start_key1 =6;
}
message CommitReply {
// Status code
// 0 - means ok
// 1 - something went wrong on server
// 2 - something wrong with request
uint32 status_code = 1;
// Brutforce progress as ratio from 0 to 1(completed)
double progress = 2;
}
// request total progress
message ProgressRequest {
}
message ProgressReply {
// Brutforce progress as ratio from 0 to 1(completed)
bool key_found = 1;
double progress = 2;
}
+189
View File
@@ -0,0 +1,189 @@
use aes;
use aes::Aes128;
use aes::cipher::array::sizes;
use aes::cipher::{Array, BlockCipherEncrypt, KeyInit};
use std::sync::mpsc;
use threadpool::ThreadPool;
/// Galois field multiplication
/// Multiplies a 128-bit block by x in GF(2^128) for AES-XTS.
/// The irreducible polynomial used is x^128 + x^7 + x^2 + x + 1 (0x87).
// #[inline]
// fn gf128_mul_by_x(block: &mut Array<u8, sizes::U16>) {
// let mut carry = 0u8;
// // Process bytes from most significant (15) to least significant (0)
// for byte in block.iter_mut().rev() {
// let temp = *byte;
// *byte = (*byte << 1) | carry;
// carry = temp >> 7; // The bit that was shifted out
// }
// // If the most significant bit of the original block was 1, apply reduction
// if carry != 0 {
// block[15] ^= 0x87; // XOR with the reduction polynomial
// }
// }
// #[inline]
// fn aes_xts256_gen_tweak(
// tweak_key: &Array<u8, sizes::U16>,
// sector_number: &Array<u8, sizes::U16>,
// block_number: u32,
// tweak_buff: &mut Array<u8, sizes::U16>,
// ) {
// let cipher = Aes128::new(tweak_key);
// cipher.encrypt_block_b2b(sector_number, tweak_buff);
// //Double the tweak value block_n-1 times (since first block is 0)
// for _ in 0..block_number {
// gf128_mul_by_x(tweak_buff);
// }
// }
#[inline]
fn gen_tweak_zero_block(tweak_key: &Array<u8, sizes::U16>) -> Array<u8, sizes::U16> {
let cipher = Aes128::new(tweak_key);
let mut res: Array<u8, sizes::U16> = Array([0u8;16]);
cipher.encrypt_block(&mut res);
res
}
#[inline]
fn add_one_to_block_(block: &mut Array<u8, sizes::U16>) -> bool {
let mut carry = false;
(block[0], carry) = block[0].carrying_add(1u8, carry);
for i in 1..16 {
if carry == false {
break;
}
(block[i], carry) = block[i].carrying_add(0u8, carry);
}
carry
}
#[inline]
fn xor_arrays(
a_arr: &Array<u8, sizes::U16>,
b_arr: &Array<u8, sizes::U16>,
out_arr: &mut Array<u8, sizes::U16>,
) {
out_arr
.iter_mut()
.zip(a_arr.iter().zip(b_arr.iter()))
.for_each(|(o, (a, b))| *o = a ^ b);
}
#[inline]
fn xor_array_(a_arr: &mut Array<u8, sizes::U16>, b_arr: &Array<u8, sizes::U16>) {
a_arr
.iter_mut()
.zip(b_arr.iter())
.for_each(|(o, a)| *o ^= a);
}
// fn add_u64_to_arr_u8(arr: &Array<u8, sizes::U16>, b: u64) -> Array<u8, sizes::U16> {
// let mut res: Array<u8, sizes::U16> = Array([0u8; 16]);
// let b_bytes = b.to_le_bytes();
// let mut carry: bool = false;
// for i in 0..8 {
// (res[i], carry) = arr[i].carrying_add(b_bytes[i], carry);
// }
// for i in 8..16 {
// (res[i], carry) = arr[i].carrying_add(0u8, carry);
// }
// res
// }
fn add_u64_to_arr_u8_(arr: &mut Array<u8, sizes::U16>, b: u64) -> bool {
let b_bytes = b.to_le_bytes();
let mut carry: bool = false;
for i in 0..8 {
(arr[i], carry) = arr[i].carrying_add(b_bytes[i], carry);
}
for i in 8..16 {
(arr[i], carry) = arr[i].carrying_add(0u8, carry);
}
carry
}
pub fn encrypt_and_check(
start_key: &Array<u8, sizes::U16>,
tweak: &Array<u8, sizes::U16>,
batch_size: u64,
in_block: &Array<u8, sizes::U16>,
search_block: &Array<u8, sizes::U16>,
) -> Option<Array<u8, sizes::U16>> {
let mut current_key = start_key.clone();
let mut out_block: Array<u8, sizes::U16> = Array::from([0u8; 16]);
for _b_num in 0..batch_size {
// Initialize cipher
let cipher = Aes128::new(&current_key);
xor_arrays(in_block, tweak, &mut out_block);
// Encrypt block in-place
cipher.encrypt_block(&mut out_block);
xor_array_(&mut out_block, tweak);
if out_block.eq(search_block) {
return Some(current_key);
}
let _ = add_one_to_block_(&mut current_key);
}
return None;
}
pub fn do_work(
pool: &ThreadPool,
batch_size: u64,
start_key: &[u8; 16],
tweak_key: &[u8; 16],
data_block: &[u8; 16],
search_block: &[u8; 16],
) -> Option<Array<u8, sizes::U16>> {
let (tx, rx) = mpsc::channel();
let th_num = pool.max_count();
let mut a_start_key: Array<u8, sizes::U16> = Array::from(start_key.clone());
let a_tweak_key: Array<u8, sizes::U16> = Array::from(tweak_key.clone());
let a_data_block: Array<u8, sizes::U16> = Array::from(data_block.clone());
let a_search_block: Array<u8, sizes::U16> = Array::from(search_block.clone());
let tweak = gen_tweak_zero_block(&a_tweak_key);
for _ in 0..th_num {
let th_start_key = a_start_key.clone();
let tx = tx.clone();
pool.execute(move || {
let result = encrypt_and_check(
&th_start_key,
&tweak,
batch_size,
&a_data_block,
&a_search_block,
);
tx.send(result).unwrap();
});
add_u64_to_arr_u8_(&mut a_start_key, batch_size);
}
drop(tx); // Close the sending end
// Collect all results
let results = rx.iter()
.find(|x| x.is_some())
.unwrap_or(None);
return results;
}
+281
View File
@@ -0,0 +1,281 @@
use std::time::Duration;
use tokio;
use tonic;
use tonic::transport::Channel;
//use tonic::{Request, Response, Status};
pub mod nyash_proto {
tonic::include_proto!("nyash_proto"); // The string specified here must match the proto package name
}
use nyash_proto::nyash_luks_client::NyashLuksClient;
use nyash_proto::{
CommitReply, KeyData, ProgressReply, ProgressRequest, WorkCommit, WorkReply, WorkRequest,
work_commit, work_reply,
};
use std::sync::Arc;
use threadpool::ThreadPool;
use tokio::sync::RwLock as AsyncRwLock;
mod aes_cpu;
pub mod num_utils;
mod search_params;
//mod test_cl;
const S_ADDR: &str = "http://93.113.25.180:37939";
async fn shutdown_signal() {
let ctrl_c = async {
tokio::signal::ctrl_c()
.await
.expect("Failed to install Ctrl+C handler");
};
#[cfg(unix)]
let terminate = async {
tokio::signal::unix::signal(tokio::signal::unix::SignalKind::terminate())
.expect("Failed to install SIGTERM handler")
.recv()
.await;
};
#[cfg(not(unix))]
let terminate = std::future::pending::<()>();
tokio::select! {
_ = ctrl_c => println!("Received Ctrl+C, initiating shutdown"),
_ = terminate => println!("Received SIGTERM, initiating shutdown"),
}
}
// fn key_dat_from_exec_dat(ex_dat: &ExecData) -> KeyData {
// let t_k = num_utils::u128_to_u64arr(num_utils::u32arr_to_u128(num_utils::vec_to_u32_4arr(
// &ex_dat.tweak_key,
// 0,
// )));
// let e_k = num_utils::u128_to_u64arr(ex_dat.get_found_key());
// KeyData {
// start_key0: e_k[0],
// start_key1: e_k[1],
// tweak_key0: t_k[0],
// tweak_key1: t_k[1],
// }
// }
async fn get_progress(chanel: Channel) -> Result<ProgressReply, tonic::Status> {
let mut client = NyashLuksClient::new(chanel);
let request = tonic::Request::new(ProgressRequest {});
let response = client.request_progress(request).await?;
return Ok(response.into_inner());
}
async fn get_work(chanel: Channel, work_size: u64) -> Result<WorkReply, tonic::Status> {
let mut client = NyashLuksClient::new(chanel);
println!("Requesting work {} keys...", work_size);
let request = tonic::Request::new(WorkRequest {
pref_work_size: work_size,
});
let response = client.request_work(request).await?;
return Ok(response.into_inner());
}
async fn commit_work(
chanel: Channel,
commit_data: WorkCommit,
) -> Result<CommitReply, tonic::Status> {
let mut client = NyashLuksClient::new(chanel);
let request = tonic::Request::new(commit_data);
let response = client.commit_work(request).await?;
return Ok(response.into_inner());
}
fn benchmark() -> (u64, usize) {
let total_work: u64 = 1280000000;
let thread_num_list: [usize; 9] = [4, 6, 8, 10, 16, 20, 32, 64, 128];
let mut work_time = [0f64; 9];
let mut preffered_th_num: usize = thread_num_list[0];
let mut preffered_batch_size: u64 = 0;
let start_key = [1u8; 16];
let tweak_key = [2u8; 16];
let data_block = [3u8; 16];
let search_block = [4u8; 16];
for i in 0..9 {
let test_th_num = thread_num_list[i];
let pool = ThreadPool::new(test_th_num);
let batch_size: u64 = total_work / test_th_num as u64;
println!("Benchmarking thread num: {}", test_th_num);
for _j in 0..3 {
println!("Run number {}", _j);
let start_time = std::time::Instant::now();
let res = aes_cpu::do_work(
&pool,
batch_size,
&start_key,
&tweak_key,
&data_block,
&search_block,
);
if res.is_some() {
println!("Key found!")
}
let exec_duration = start_time.elapsed().as_secs_f64();
work_time[i] += exec_duration;
}
work_time[i] = work_time[i] / 3.0;
println!("Average time {}", work_time[i]);
if i > 0 {
//giving 2% error for speed mesure
if (work_time[i] * 1.02) > work_time[i - 1] {
break;
}
}
preffered_th_num = test_th_num;
// calculate batch size so it correspond to 30 sec job
preffered_batch_size = (batch_size as f64 * (10.0 / work_time[i])) as u64;
println!(
"batch_size {}, work_time {}, preffered_batch_size {}, preffered_th_num {}",
batch_size, work_time[i], preffered_batch_size, preffered_th_num
);
}
return (preffered_batch_size, preffered_th_num);
}
#[tokio::main(flavor = "current_thread")]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("Performing banchmark to determine optimal parameters...");
let (pref_batch_size, th_num) = benchmark();
println!("batch_size {}, th_num {}", pref_batch_size, th_num);
let encrypted_data = search_params::get_encrypted_data();
let unencrypt_data = [0u8; 16];
let th_pool = ThreadPool::new(th_num);
// Don't keep connection alive when idle
let nya_channel: tonic::transport::Channel = tonic::transport::Endpoint::from_static(S_ADDR)
.keep_alive_while_idle(false)
.keep_alive_timeout(Duration::from_secs(10))
.connect_timeout(Duration::from_secs(10))
.connect()
.await
.expect("Error connecting to server!");
let key_found = match get_progress(nya_channel.clone()).await {
Err(_) => {
println!("Error getting progress!");
false
}
Ok(p_r) => {
println!("Current progress {:.8}%", p_r.progress * 100.0);
p_r.key_found
}
};
let mut giga_keys_per_second: f64 = 0f64;
let req_work_size: u64 = pref_batch_size * th_num as u64;
let shared_key_found = Arc::new(AsyncRwLock::new(key_found));
// handling program termination
let sh_k_f_clone = shared_key_found.clone();
tokio::spawn(async move {
shutdown_signal().await;
//signaling that we should stop
let mut guard = sh_k_f_clone.write().await;
*guard = true;
});
while *shared_key_found.read().await == false {
let mut work = get_work(nya_channel.clone(), req_work_size).await;
while work.is_err() {
println!("Error getting work, waiting 15 seconds and trying again...");
tokio::time::sleep(Duration::from_secs(15)).await;
work = get_work(nya_channel.clone(), req_work_size).await;
}
let work = work.expect("Error getting work!");
let work_data = match work.result.expect("Error! Expected WorkResult!") {
work_reply::Result::NoWork(_) => {
println!("No work right now, try again later...");
continue;
}
work_reply::Result::Error(ex) => {
println!("Erro getting work: {}", ex);
continue;
}
work_reply::Result::WorkData(wd) => wd,
};
println!("Got work, {} keys...", work_data.work_size);
let start_key = num_utils::u64arr_to_u8arr([work_data.start_key0, work_data.start_key1]);
let tweak_key = num_utils::u64arr_to_u8arr([work_data.tweak_key0, work_data.tweak_key1]);
let mut batch_size = work_data.work_size / th_num as u64;
if (work_data.work_size % th_num as u64) != 0 {
batch_size += 1;
}
println!("Setting batch size to {}", batch_size);
println!("Crunching numbers...");
let start_time = std::time::Instant::now();
let work_res = aes_cpu::do_work(
&th_pool,
batch_size,
&start_key,
&tweak_key,
&unencrypt_data,
&encrypted_data,
);
let exec_duration = start_time.elapsed().as_secs_f64();
let g_k_p_s = (work_data.work_size as f64 / exec_duration) / 1000000000.0;
if giga_keys_per_second != 0f64 {
giga_keys_per_second = giga_keys_per_second * 0.9 + g_k_p_s * 0.1;
} else {
giga_keys_per_second = g_k_p_s;
}
println!("Average speed: {:.3}GigaKeys/Sec", giga_keys_per_second);
let work_c = match work_res {
Some(found_key) => {
println!("We found the key! {:?} {:?}", found_key, tweak_key);
//signaling that key found
let mut guard = shared_key_found.write().await;
*guard = true;
let found_key_u64 = num_utils::u8arr_to_u64arr(found_key.into());
WorkCommit {
work_id: work_data.work_id,
result: Some(work_commit::Result::FoundKey(KeyData {
tweak_key0: work_data.tweak_key0,
tweak_key1: work_data.tweak_key1,
start_key0: found_key_u64[0],
start_key1: found_key_u64[0],
})),
}
}
None => WorkCommit {
work_id: work_data.work_id,
result: Some(work_commit::Result::NoKey(true)),
},
};
let resp = commit_work(nya_channel.clone(), work_c).await;
match resp {
Ok(c_r) => println!("Work commited. Progress: {:.8}%", c_r.progress * 100.0),
Err(_) => println!("Error commiting work..."),
};
}
println!("Exiting!");
Ok(())
}
+356
View File
@@ -0,0 +1,356 @@
// union U64orU32 {
// l: u64,
// i: [u32; 2],
// }
pub fn vec_to_u32_4arr(in_v: &Vec<u32>, start_idx: usize) -> [u32; 4] {
let mut u32_arr_k = [0u32; 4];
for i in 0..4 {
u32_arr_k[0] = in_v[start_idx + i];
}
return u32_arr_k;
}
pub fn u128_to_u64arr(a: u128) -> [u64; 2] {
let mut res = [0u64; 2];
let a_bytes = a.to_le_bytes();
let chunks = a_bytes.as_chunks::<8>().0;
for i in 0..2 {
res[i] = u64::from_le_bytes(chunks[i]);
}
return res;
}
pub fn u64arr_to_u128(a: [u64; 2]) -> u128 {
let mut bytes_data: [u8; 16] = [0u8; 16];
bytes_data[0..8].copy_from_slice(a[0].to_le_bytes().as_slice());
bytes_data[8..].copy_from_slice(a[1].to_le_bytes().as_slice());
return u128::from_le_bytes(bytes_data);
}
pub fn u64arr_to_u8arr(a: [u64; 2]) -> [u8; 16] {
let mut bytes_data: [u8; 16] = [0u8; 16];
bytes_data[0..8].copy_from_slice(a[0].to_le_bytes().as_slice());
bytes_data[8..].copy_from_slice(a[1].to_le_bytes().as_slice());
return bytes_data;
}
pub fn u8arr_to_u64arr(a_bytes: [u8; 16]) -> [u64; 2] {
let mut res = [0u64; 2];
let chunks = a_bytes.as_chunks::<8>().0;
for i in 0..2 {
res[i] = u64::from_le_bytes(chunks[i]);
}
return res;
}
pub fn u128_to_u32arr(a: u128) -> [u32; 4] {
let mut res = [0u32; 4];
let a_bytes = a.to_le_bytes();
let chunks = a_bytes.as_chunks::<4>().0;
for i in 0..4 {
res[i] = u32::from_le_bytes(chunks[i]);
}
return res;
}
pub fn u32arr_to_u128(a: [u32; 4]) -> u128 {
let mut bytes_data: [u8; 16] = [0u8; 16];
bytes_data[0..4].copy_from_slice(a[0].to_le_bytes().as_slice());
bytes_data[4..8].copy_from_slice(a[1].to_le_bytes().as_slice());
bytes_data[8..12].copy_from_slice(a[2].to_le_bytes().as_slice());
bytes_data[12..16].copy_from_slice(a[3].to_le_bytes().as_slice());
return u128::from_le_bytes(bytes_data);
}
// fn add_u32_to_u256(a: &[u32; 8], b: u32) -> ([u32; 8], bool) {
// let mut res: [u32; 8] = [0; 8];
// let mut carry = false;
// (res[0], carry) = a[0].carrying_add(b, carry);
// for idx in 1..8 {
// (res[idx], carry) = a[idx].carrying_add(0, carry);
// }
// return (res, carry);
// }
// fn add_u32_to_u256_(a: &mut [u32; 8], b: u32) -> bool {
// let mut carry = false;
// (a[0], carry) = a[0].carrying_add(b, carry);
// for idx in 1..8 {
// (a[idx], carry) = a[idx].carrying_add(0, carry);
// }
// return carry;
// }
// fn bytes_from_chars(chars_chunk: &[char]) -> [u8; 4] {
// let mut res: [u8; 4] = [0; 4];
// let mut idx: usize = 0;
// chars_chunk.chunks_exact(2).for_each(|b_c| {
// if idx < 4 {
// match u8::from_str_radix(&b_c.iter().collect::<String>(), 16) {
// Ok(n) => res[idx] = n,
// Err(_) => (),
// }
// idx += 1;
// }
// });
// return res;
// }
// fn bignum_from_hex(hex: &str) -> [u32; 8] {
// let mut res: [u32; 8] = [0; 8];
// let mut idx: usize = 0;
// let chars_hex = hex.chars().collect::<Vec<char>>();
// chars_hex
// .chunks_exact(8)
// .rev()
// .map(|chunk| bytes_from_chars(chunk))
// .for_each(|b_arr| {
// if idx < 8 {
// res[idx] = u32::from_be_bytes(b_arr);
// idx += 1;
// }
// });
// return res;
// }
// fn hex_fmt_byte(n: u32) -> String {
// let res: String = n
// .to_be_bytes()
// .iter()
// .map(|b| format!("{:02x}", b))
// .collect();
// return res;
// }
// fn bignum_to_hex(a: &[u32; 8]) -> String {
// let res: String = a
// .iter()
// .rev()
// .map(|n| hex_fmt_byte(*n))
// .collect::<Vec<String>>()
// .join("");
// return res;
// }
// #[cfg(test)]
// mod num_utils_tests {
// use std::io::Read;
// use super::*;
// #[test]
// fn test_add() {
// use std::io::{BufRead, BufReader};
// use std::process::{Command, Stdio};
// let test_gen_cmd = "/home/kira/Development/Rust/nyash-aes-xts256-plain64/nyash_client/src/tests/gen_test_data.py";
// let mut child = Command::new(test_gen_cmd)
// .stdout(Stdio::piped())
// .spawn()
// .unwrap();
// let gen_stdout = child
// .stdout
// .take()
// .ok_or("Failed to capture stdout")
// .unwrap();
// let gen_reader = BufReader::new(gen_stdout);
// for r_line in gen_reader.lines() {
// let test_line: String = r_line.unwrap(); // Handle any I/O errors
// let test_data_line = test_line.split(' ').collect::<Vec<&str>>();
// let num_to_add = u32::from_str_radix(test_data_line[0], 10).unwrap();
// let t0 = bignum_from_hex(test_data_line[1]);
// let t1_test = add_u32_to_u256(&t0, 1).0;
// let t2_test = add_u32_to_u256(&t0, num_to_add).0;
// let res_actual = format!(
// "{} {} {} {}",
// num_to_add,
// bignum_to_hex(&t0),
// bignum_to_hex(&t1_test),
// bignum_to_hex(&t2_test)
// );
// assert_eq!(test_line, res_actual);
// }
// let _ = child.wait().unwrap();
// }
// #[test]
// fn test_cl_add() {
// extern crate ocl;
// use ocl::{Buffer, Context, Device, Kernel, Platform, Program, Queue, flags};
// use std::fs::File;
// use std::io::{BufRead, BufReader};
// use std::process::{Command, Stdio};
// let cl_test_path = "/home/kira/Development/Rust/nyash-aes-xts256-plain64/nyash_client/src/open_cl/test_num_utils.cl";
// let cl_include_opt =
// "-I /home/kira/Development/Rust/nyash-aes-xts256-plain64/nyash_client/src/open_cl";
// let mut cl_src = String::new();
// // read ocl source
// BufReader::new(File::open(cl_test_path).unwrap())
// .read_to_string(&mut cl_src)
// .expect("Error reading cl_src!");
// const G_WORK_SIZE: usize = 4096;
// let cl_platform = Platform::default();
// let cl_device = Device::first(cl_platform).unwrap();
// let cl_context = Context::builder()
// .platform(cl_platform)
// .devices(cl_device.clone())
// .build()
// .unwrap();
// let cl_program = Program::builder()
// .devices(cl_device)
// .src(cl_src)
// .cmplr_opt(cl_include_opt)
// .build(&cl_context)
// .unwrap();
// let cl_queue = Queue::new(&cl_context, cl_device, None).unwrap();
// let cl_buffer_num = Buffer::<u32>::builder()
// .queue(cl_queue.clone())
// .flags(flags::MEM_READ_ONLY)
// .len(G_WORK_SIZE)
// .fill_val(0u32)
// .build()
// .unwrap();
// let cl_buffer_t0 = Buffer::<u32>::builder()
// .queue(cl_queue.clone())
// .flags(flags::MEM_READ_ONLY)
// .len(G_WORK_SIZE * 8)
// .fill_val(0u32)
// .build()
// .unwrap();
// let cl_buffer_t1 = Buffer::<u32>::builder()
// .queue(cl_queue.clone())
// .flags(flags::MEM_WRITE_ONLY)
// .len(G_WORK_SIZE * 8)
// .fill_val(0u32)
// .build()
// .unwrap();
// let cl_buffer_t2 = Buffer::<u32>::builder()
// .queue(cl_queue.clone())
// .flags(flags::MEM_WRITE_ONLY)
// .len(G_WORK_SIZE * 8)
// .fill_val(0u32)
// .build()
// .unwrap();
// // (3) Create a kernel with arguments matching those in the source above:
// let kernel = Kernel::builder()
// .program(&cl_program)
// .name("test_add")
// .queue(cl_queue.clone())
// .global_work_size(G_WORK_SIZE)
// .arg(&cl_buffer_num)
// .arg(&cl_buffer_t0)
// .arg(&cl_buffer_t1)
// .arg(&cl_buffer_t2)
// .build()
// .unwrap();
// let test_gen_cmd = "/home/kira/Development/Rust/nyash-aes-xts256-plain64/nyash_client/src/tests/gen_test_data.py";
// let mut child = Command::new(test_gen_cmd)
// .stdout(Stdio::piped())
// .spawn()
// .unwrap();
// let gen_stdout = child
// .stdout
// .take()
// .ok_or("Failed to capture stdout")
// .unwrap();
// let gen_reader = BufReader::new(gen_stdout);
// let mut buffer_num: Vec<u32> = vec![0u32; G_WORK_SIZE];
// let mut buffer_t0: Vec<u32> = vec![0u32; G_WORK_SIZE * 8];
// let mut exp_buffer_t1: Vec<u32> = vec![0u32; G_WORK_SIZE * 8];
// let mut exp_buffer_t2: Vec<u32> = vec![0u32; G_WORK_SIZE * 8];
// let mut act_buffer_t1: Vec<u32> = vec![0u32; G_WORK_SIZE * 8];
// let mut act_buffer_t2: Vec<u32> = vec![0u32; G_WORK_SIZE * 8];
// let mut w_id: usize = 0;
// for r_line in gen_reader.lines() {
// let test_line: String = r_line.unwrap(); // Handle any I/O errors
// let test_data_line = test_line.split(' ').collect::<Vec<&str>>();
// let num_to_add = u32::from_str_radix(test_data_line[0], 10).unwrap();
// buffer_num[w_id] = num_to_add;
// let slise_id = w_id * 8;
// buffer_t0[slise_id..slise_id + 8].copy_from_slice(&bignum_from_hex(test_data_line[1]));
// exp_buffer_t1[slise_id..slise_id + 8]
// .copy_from_slice(&bignum_from_hex(test_data_line[2]));
// exp_buffer_t2[slise_id..slise_id + 8]
// .copy_from_slice(&bignum_from_hex(test_data_line[3]));
// w_id += 1;
// if w_id >= G_WORK_SIZE {
// w_id = 0; // reset counter
// cl_buffer_num
// .cmd()
// .queue(&cl_queue)
// .offset(0)
// .write(&buffer_num)
// .enq()
// .unwrap();
// cl_buffer_t0
// .cmd()
// .queue(&cl_queue)
// .offset(0)
// .write(&buffer_t0)
// .enq()
// .unwrap();
// // (4) Run the kernel
// unsafe {
// kernel
// .cmd()
// .queue(&cl_queue)
// .global_work_size(G_WORK_SIZE)
// .enq()
// .unwrap();
// }
// cl_buffer_t1
// .cmd()
// .queue(&cl_queue)
// .offset(0)
// .read(&mut act_buffer_t1)
// .enq()
// .unwrap();
// cl_buffer_t2
// .cmd()
// .queue(&cl_queue)
// .offset(0)
// .read(&mut act_buffer_t2)
// .enq()
// .unwrap();
// assert_eq!(exp_buffer_t1, act_buffer_t1);
// assert_eq!(exp_buffer_t2, act_buffer_t2);
// }
// }
// let _ = child.wait().unwrap();
// }
// }
+399
View File
@@ -0,0 +1,399 @@
extern crate ocl;
use ocl::{
Buffer, Context, Device, DeviceType, Kernel, Platform, Program, Queue, SpatialDims, flags,
};
use serde::de::value::Error;
use std::{
io,
str::{self, FromStr},
};
use crate::client_config::{AppConfig, DevConf};
mod client_config;
mod num_utils;
fn dev_type_from_str(s: &str) -> Result<flags::DeviceType, ()> {
match s {
"CPU" => Ok(flags::DeviceType::CPU),
"GPU" => Ok(flags::DeviceType::GPU),
"ALL" => Ok(flags::DeviceType::ALL),
"CUSTOM" => Ok(flags::DeviceType::CUSTOM),
"ACCELERATOR" => Ok(flags::DeviceType::ACCELERATOR),
"DEFAULT" => Ok(flags::DeviceType::DEFAULT),
_ => Err(()),
}
}
fn str_or_empty(r: ocl::error::Result<String>) -> String {
match r {
Ok(s) => s,
Err(_) => "".to_string(),
}
}
fn print_devices(dev_list: &Vec<(Device, Platform)>) {
let mut i = 0;
for (dev, plt) in dev_list.iter() {
let dev_name = str_or_empty(dev.name());
let plt_name = str_or_empty(plt.name());
println!("({i}) device: \"{dev_name}\" ----- platorm: \"{plt_name}\"");
i += 1;
}
}
fn choose_devices(devices_num: usize) -> Result<Vec<usize>, String> {
println!("Please input desired devices to use as a white space separated list of numbers.");
let mut result: Vec<usize> = Vec::new();
let mut s_devs_nums = String::new();
io::stdin()
.read_line(&mut s_devs_nums)
.expect("Failed to read line");
for s_dev_num in s_devs_nums.split(' ') {
let dev_num: usize = match s_dev_num.trim().parse() {
Ok(num) => num,
Err(_) => return Err("You must input a number from device list.".to_string()),
};
if dev_num >= devices_num {
return Err("You must input a number from device list.".to_string());
};
result.push(dev_num);
}
return Ok(result);
}
fn list_devices(dev_type: DeviceType) -> Vec<(Device, Platform)> {
let platforms = Platform::list();
let mut devices: Vec<(Device, Platform)> = Vec::new();
for plt in platforms.iter() {
//let plat_name = str_or_empty(plt.name());
let list_res = Device::list(plt, Some(dev_type));
match list_res {
Ok(dev_l) => devices.extend(dev_l.iter().map(|dev| (*dev, plt.clone()))),
Err(_) => {}
}
}
return devices;
}
// fn init_devices(
// devices: Vec<(Device, Platform, DevConfig)>,
// kern_name: String,
// prog_src: String,
// inc_dirs: Vec<String>,
// ) -> Vec<ExecContext> {
// let mut contexts: Vec<ExecContext> = Vec::with_capacity(devices.len());
// for (dev, plt, dev_cfg) in devices {
// let ctx = match Context::builder()
// .platform(plt)
// .devices(dev.clone())
// .build()
// {
// Ok(c) => c,
// Err(_) => continue,
// };
// let prg = match Program::builder().devices(dev).src(&prog_src).build(&ctx) {
// Ok(p) => p,
// Err(_) => continue,
// };
// let queue = match Queue::new(&ctx, dev, None) {
// Ok(q) => q,
// Err(_) => continue,
// };
// // Create Buffers:
// let start_key_b = match Buffer::<u32>::builder()
// .queue(queue.clone())
// .flags(flags::MEM_READ_ONLY)
// .len(8)
// .fill_val(0u32)
// .build()
// {
// Ok(buf) => buf,
// Err(_) => continue,
// };
// let u_data_b = match Buffer::<u32>::builder()
// .queue(queue.clone())
// .flags(flags::MEM_READ_ONLY)
// .len(4)
// .fill_val(0u32)
// .build()
// {
// Ok(buf) => buf,
// Err(_) => continue,
// };
// let enc_data_b = match Buffer::<u32>::builder()
// .queue(queue.clone())
// .flags(flags::MEM_READ_ONLY)
// .len(4)
// .fill_val(0u32)
// .build()
// {
// Ok(buf) => buf,
// Err(_) => continue,
// };
// let key_found_b = match Buffer::<u32>::builder()
// .queue(queue.clone())
// .flags(flags::MEM_WRITE_ONLY)
// .len(1)
// .fill_val(0u32)
// .build()
// {
// Ok(buf) => buf,
// Err(_) => continue,
// };
// // (3) Create a kernel with arguments matching those in the source above:
// let kernel = match Kernel::builder()
// .program(&prg)
// .name(&kern_name)
// .queue(queue.clone())
// .global_work_size(dev_cfg.global_work_size)
// .arg(&start_key_b)
// .arg(&u_data_b)
// .arg(&enc_data_b)
// .arg(&key_found_b)
// .build()
// {
// Ok(kern) => kern,
// Err(_) => continue,
// };
// contexts.push(ExecContext {
// cfg: dev_cfg,
// ctx: ctx,
// kernel: kernel,
// prog: prg,
// queue: queue,
// buffers: CtxBuffers {
// start_key: start_key_b,
// u_data: u_data_b,
// enc_data: enc_data_b,
// key_found: key_found_b,
// },
// });
// }
// return contexts;
// }
fn dev_sel_dialog(all_devices: &Vec<(Device, Platform)>) -> Vec<usize> {
let devs_nums = loop {
print_devices(&all_devices);
match choose_devices(all_devices.len()) {
Ok(value) => break value,
Err(exc) => {
println!("Error! {exc}\n")
}
}
};
return devs_nums;
}
fn get_devices_conf(file_name: &str) -> Result<(Vec<(Device, Platform)>, AppConfig), String> {
let dev_type = dev_type_from_str("GPU").expect("Unexpected device type!");
// Get devices to be used for key search
let all_devices: Vec<(Device, Platform)> = list_devices(dev_type);
if all_devices.len() == 0 {
return Err("Cannot find any usable devices.".to_string());
};
let app_conf = match client_config::load_config(file_name) {
Ok(readed_config) => {
let dev_found = all_devices
.iter()
.filter(|dp| readed_config.device_exist(&dp.0))
.count();
if dev_found < readed_config.devices.len() {
println!("Devices from config not found in the system!");
let devs_nums = dev_sel_dialog(&all_devices);
let res = AppConfig::from_dev_list(&all_devices, devs_nums);
client_config::save_config(file_name, &res);
res
} else {
readed_config
}
}
Err(_) => {
println!("Cannot find config file {}", file_name);
let devs_nums = dev_sel_dialog(&all_devices);
AppConfig::from_dev_list(&all_devices, devs_nums)
}
};
let selected_devs = all_devices
.iter()
.filter(|dp| app_conf.device_exist(&dp.0))
.cloned()
.collect();
return Ok((selected_devs, app_conf));
}
struct CtxBuffers {
batch_size: u32,
tweak_i: u64,
tweak_j: u32,
start_key: Buffer<u32>,
uenc_data: Buffer<u32>,
target_data: Buffer<u32>,
key_found: Buffer<u32>,
}
struct ExecData {
start_key: Vec<u32>,
uenc_data: Vec<u32>,
target_data: Vec<u32>,
key_found: Vec<u32>,
batch_size: u32,
work_size: usize,
}
struct ExecContext {
ctx: Context,
kernel: Kernel,
prog: Program,
queue: Queue,
buffers: CtxBuffers,
exec_data: ExecData,
}
fn init_program(
cl_device: Device,
cl_platform: Platform,
cl_src: &str,
cl_cmplr_opt: &str,
) -> Result<(Context, Program, Queue), ocl::Error> {
let cl_context = Context::builder()
.platform(cl_platform)
.devices(cl_device.clone())
.build()?;
let cl_program = Program::builder()
.devices(cl_device)
.src(cl_src)
.cmplr_opt(cl_cmplr_opt)
.build(&cl_context)
.unwrap();
let cl_queue: Queue = Queue::new(&cl_context, cl_device, None)?;
return Ok((cl_context, cl_program, cl_queue));
}
fn init_buffers(cl_queue: Queue) -> Result<CtxBuffers, ocl::Error> {
let cl_buffer_start_key = Buffer::<u32>::builder()
.queue(cl_queue.clone())
.flags(flags::MEM_READ_ONLY)
.len(8)
.fill_val(0u32)
.build()?;
let cl_buffer_uenc_data = Buffer::<u32>::builder()
.queue(cl_queue.clone())
.flags(flags::MEM_READ_ONLY)
.len(4)
.fill_val(0u32)
.build()?;
let cl_buffer_target_data = Buffer::<u32>::builder()
.queue(cl_queue.clone())
.flags(flags::MEM_READ_ONLY)
.len(4)
.fill_val(0u32)
.build()?;
let cl_buffer_key_found = Buffer::<u32>::builder()
.queue(cl_queue.clone())
.flags(flags::MEM_WRITE_ONLY)
.len(9)
.fill_val(0u32)
.build()?;
Ok(CtxBuffers {
batch_size: 0,
tweak_i: 0,
tweak_j: 0,
start_key: cl_buffer_start_key,
uenc_data: cl_buffer_uenc_data,
target_data: cl_buffer_target_data,
key_found: cl_buffer_key_found,
})
}
fn init_kernel(
work_size: usize,
cl_program: Program,
cl_queue: Queue,
buffs: &CtxBuffers,
) -> Result<Kernel, ocl::Error> {
Kernel::builder()
.program(&cl_program)
.name("search_key")
.queue(cl_queue.clone())
.global_work_size(work_size)
.arg(&buffs.batch_size)
.arg(&buffs.tweak_i)
.arg(&buffs.tweak_j)
.arg(&buffs.start_key)
.arg(&buffs.uenc_data)
.arg(&buffs.target_data)
.arg(&buffs.key_found)
.build()
}
fn do_work(ex_ctx: &mut ExecContext) -> Result<bool, ocl::Error> {
ex_ctx.buffers.batch_size = ex_ctx.exec_data.batch_size;
ex_ctx
.buffers
.start_key
.cmd()
.queue(&ex_ctx.queue)
.offset(0)
.write(&ex_ctx.exec_data.start_key)
.enq()?;
// (4) Run the kernel
unsafe {
ex_ctx
.kernel
.cmd()
.queue(&ex_ctx.queue)
.global_work_size(ex_ctx.exec_data.work_size)
.enq()?;
}
ex_ctx
.buffers
.key_found
.cmd()
.queue(&ex_ctx.queue)
.offset(0)
.read(&mut ex_ctx.exec_data.key_found)
.enq()?;
if ex_ctx.exec_data.key_found[0] == 0{Ok(false)}
else {Ok(true)}
}
fn main() {
println!("Hello, world nya!");
//use ocl::{Buffer, Context, Device, Kernel, Platform, Program, Queue, flags};
let devices = get_devices_conf("test.json");
println!("{:?}", devices);
// let devices: Vec<_> = platforms.iter().flat_map(|p| Device::list(p, Some(dev_type)).iter()).collect();
// let device = Device::first(platform)?;
// let context = Context::builder()
// .platform(platform)
// .devices(device.clone())
// .build()?;
}
+8
View File
@@ -0,0 +1,8 @@
pub fn get_encrypted_data() -> [u8; 16] {
let enc_data: [u8; 16] = [
10, 51, 110, 227, 194, 181, 104, 65, 151, 47, 69, 37, 66, 223, 71, 137,
];
return enc_data;
}
+79
View File
@@ -0,0 +1,79 @@
#[cfg(test)]
mod test_cl {
#[test]
fn test_encryption() {
use ocl::{Device, Platform};
use crate::ocl_utils;
use crate::num_utils;
const SRC_PATH: &str = "src/open_cl/nyash_aes_xts256_plain.cl";
const OCL_COMP_OPT: &str = "-I src/open_cl";
const ENCRYPTED_DATA: [u8; 16] = [
198, 255, 55, 185, 15, 226, 223, 174, 119, 8, 36, 239, 242, 89, 126, 230
];
const KEY_DATA: [u8; 32] = [
206, 193, 83, 54, 46, 234, 185, 41, 146, 244, 130, 6, 212, 68, 106, 162, 165, 97, 188,
218, 39, 111, 141, 236, 67, 159, 157, 157, 166, 79, 89, 134
];
// let key_bytes_reversed: Vec<u8> = KEY_DATA.iter().rev().map(|e| *e).collect();
// let data_bytes_reversed: Vec<u8> = ENCRYPTED_DATA.iter().rev().map(|e| *e).collect();
let mut tweak_key_b: [u8;16] = [0u8;16];
let mut data_key_b: [u8;16] = [0u8;16];
data_key_b.copy_from_slice(&KEY_DATA[0..16]);
tweak_key_b.copy_from_slice(&KEY_DATA[16..32]);
// getting keys
let data_key = u128::from_le_bytes(data_key_b);
let tweak_key = u128::from_le_bytes(tweak_key_b);
let data_key = num_utils::u128_to_u32arr(data_key);
let tweak_key = num_utils::u128_to_u32arr(tweak_key);
// converting bytes raw data to u32 arr
let mut encrypted_data: [u32; 4] = [0u32; 4];
let (enc_dat_bytes_chunks, _) = ENCRYPTED_DATA.as_chunks::<4>();
for i in 0..4 {
encrypted_data[i] = u32::from_le_bytes(enc_dat_bytes_chunks[i]);
}
// init devices
let platform = Platform::first().expect("Error getting platform!");
let device = Device::first(platform).expect("Error getting device!");
println!("Platform: {:?}, Device: {:?}", platform.name().unwrap(), device.name().unwrap());
// reading ocl program sources
let prog_src = std::fs::read_to_string(SRC_PATH).expect("Error reading program sources!");
let mut nyan_context =
ocl_utils::ExecContext::new(device, platform, prog_src.as_str(), OCL_COMP_OPT, 256)
.expect("Error creating execution nyan context!");
//setting data
let mut nyan_exec_dat = ocl_utils::ExecData {
start_key: data_key.to_vec(),
tweak_key: tweak_key.to_vec(),
uenc_data: vec![0u32;4],
target_data: encrypted_data.to_vec(),
tweak_i: 0,
tweak_j: 0,
key_found: vec![0u32;5],
batch_size: 1000000,
work_size: 256,
};
println!("Set target data");
ocl_utils::set_target_data(&mut nyan_context, &mut nyan_exec_dat).expect("Error set target data!");
let found_flag = ocl_utils::do_work(&mut nyan_context, &mut nyan_exec_dat).expect("Error do work!");
println!("Found?: {}", found_flag);
println!("Key found: {:?}", nyan_exec_dat.key_found);
assert_eq!(true, found_flag);
}
}
@@ -0,0 +1,16 @@
#!/bin/bash
truncate -s 255M test_btrfs.img
dd if=/dev/urandom of=master.key bs=32 count=1
cryptsetup luksFormat --type=luks2 --sector-size 512 --pbkdf=pbkdf2 --pbkdf-force-iterations=1000 --hash=sha256 --key-size=256 --cipher=aes-xts-plain64 --master-key-file ./test_master.key ./test.img
cryptsetup luksFormat --type=luks2 --pbkdf=pbkdf2 --pbkdf-force-iterations=1000 --hash=sha256 --key-size=256 --cipher=aes-xts-plain64 ./luks-container.img
sudo cryptsetup luksOpen ./test.img luks-container-crypt
sudo mkfs.btrfs /dev/mapper/luks-container-crypt
sudo dd if=/dev/mapper/luks-container-crypt of=./test_btrfs_luks_unencrypt.img bs=1M count=255
sudo cryptsetup close luks-container-crypt
@@ -0,0 +1,42 @@
from utils import read_metadata
# Init logger
LUKS_FILE_NAME = "vg1-volume_1.img"
KEY_FILE_NAME = "master.key"
def main():
metadat = read_metadata(LUKS_FILE_NAME)
print(f"metadata:\n{metadat}")
segments_offset_bytes = int(metadat["segments"]["0"]["offset"])
superblock_start_bytes = 0x00010000
superblock_start_sector = superblock_start_bytes//512
magic_offset = 0x40
superblock_lenght_bytes = 0x1000
sector_size = 512
with open(LUKS_FILE_NAME, 'rb') as luks_file:
luks_file.seek(segments_offset_bytes)
enc_data = luks_file.read(16)
print("ENC DATA:")
print("[" + ",".join([format(a, 'd') for a in enc_data])+"]")
#
# print()
# print("KEY DATA:")
# with open(KEY_FILE_NAME, 'rb') as key_file:
# key_data = key_file.read(32)
# print("[" + ",".join([format(a, 'd') for a in key_data])+"]")
if __name__ == '__main__':
main()
+25
View File
@@ -0,0 +1,25 @@
import subprocess
import json
def read_metadata(file_name: str) -> dict:
#cryptsetup luksDump --dump-json-metadata /dev/loop0
luks_cmd: list[str] = ["cryptsetup", "luksDump", "--dump-json-metadata", file_name]
result = subprocess.run(luks_cmd, capture_output=True, encoding="UTF-8")
if result.returncode == 0 and result.stdout is not None:
metadata = json.loads(result.stdout)
return metadata
else:
raise Exception(f"Error executing 'cryptsetup' binary! {result.stderr}")
def read_encrypted_key(f_name: str, metadata: dict, keyslot: int) -> bytes:
stripes = metadata["keyslots"][str(keyslot)]["af"]["stripes"]
offset = int(metadata["keyslots"][str(keyslot)]["area"]["offset"])
# size = int(metadata["keyslots"][str(keyslot)]["area"]["size"])
key_size = metadata["keyslots"][str(keyslot)]["area"]["key_size"]
with open(f_name, 'rb') as luks_file:
luks_file.seek(offset)
data = luks_file.read(key_size*stripes)
return data
+47
View File
@@ -0,0 +1,47 @@
#[cfg(test)]
mod cl_num_utils_tests {
use super::*;
#[test]
fn test_add() {
use std::io::{BufRead, BufReader};
use std::process::{Command, Stdio};
let test_gen_cmd = "/home/kira/Development/Rust/nyash-aes-xts256-plain64/nyash_client/src/tests/gen_test_data.py";
let mut child = Command::new(test_gen_cmd)
.stdout(Stdio::piped())
.spawn()
.unwrap();
let gen_stdout = child
.stdout
.take()
.ok_or("Failed to capture stdout")
.unwrap();
let gen_reader = BufReader::new(gen_stdout);
for r_line in gen_reader.lines() {
let test_line: String = r_line.unwrap(); // Handle any I/O errors
let test_data_line = test_line.split(' ').collect::<Vec<&str>>();
let num_to_add = u32::from_str_radix(test_data_line[0], 10).unwrap();
let t0 = bignum_from_hex(test_data_line[1]);
let t1_test = add_u32_to_u256(&t0, 1).0;
let t2_test = add_u32_to_u256(&t0, num_to_add).0;
let res_actual = format!(
"{} {} {} {}",
num_to_add,
bignum_to_hex(&t0),
bignum_to_hex(&t1_test),
bignum_to_hex(&t2_test)
);
assert_eq!(test_line, res_actual);
}
let _ = child.wait().unwrap();
}
}
+21
View File
@@ -0,0 +1,21 @@
#!/usr/bin/python
import random
def main(iters: int):
for i in range(iters):
rand_u32 = random.randint(1,0xffffffff)
t0 = int.from_bytes(random.randbytes(32))
t1 = t0 + 1
t2 = t0 + rand_u32
print(f"{rand_u32} {t0.to_bytes(32).hex()} {t1.to_bytes(32).hex()} {t2.to_bytes(32).hex()}")
if __name__ == '__main__':
main(1000000)