1
0
Fork 0
mirror of https://github.com/TransparentLC/opencl_vanity_gpg.git synced 2025-10-20 15:24:08 +00:00

chore: clippy

This commit is contained in:
GZTime 2025-01-08 23:19:16 +08:00
parent f53ffd1c60
commit e224d84f1c
No known key found for this signature in database
GPG key ID: 373640C748EA3E19
2 changed files with 237 additions and 178 deletions

View file

@ -1,21 +1,12 @@
mod vanity_gpg; mod vanity_gpg;
use vanity_gpg::{CipherSuite, VanitySecretKey};
use clap::Parser; use clap::Parser;
use std::{ use log::{debug, info, warn};
fs,
io,
io::Write,
mem,
path::Path,
sync::mpsc::channel,
thread,
time::Instant,
};
use ocl::{Buffer, Device, Platform, ProQue}; use ocl::{Buffer, Device, Platform, ProQue};
use rand::thread_rng;
use pgp::types::PublicKeyTrait; use pgp::types::PublicKeyTrait;
use log::{warn, info, debug}; use rand::thread_rng;
use std::{fs, io, io::Write, mem, path::Path, sync::mpsc::channel, thread, time::Instant};
use vanity_gpg::{CipherSuite, VanitySecretKey};
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
#[command(version, about, long_about = None)] #[command(version, about, long_about = None)]
@ -44,9 +35,11 @@ struct Args {
/// OpenCL kernel function for uint h[5] for matching fingerprints /// OpenCL kernel function for uint h[5] for matching fingerprints
/// Ignore the pattern and no estimate is given if this has been set /// Ignore the pattern and no estimate is given if this has been set
/// Example: ///
/// * (h[4] & 0xFFFF) == 0x1234 outputs a fingerprint ends with 1234 /// Example:
/// * (h[0] & 0xFFFF0000) == 0xABCD0000 outputs a fingerprint starts with ABCD ///
/// * (h[4] & 0xFFFF) == 0x1234 outputs a fingerprint ends with 1234
/// * (h[0] & 0xFFFF0000) == 0xABCD0000 outputs a fingerprint starts with ABCD
#[arg(short, long, verbatim_doc_comment)] #[arg(short, long, verbatim_doc_comment)]
filter: Option<String>, filter: Option<String>,
@ -87,17 +80,19 @@ struct Args {
device_list: bool, device_list: bool,
} }
/// 手动进行SHA-1的填充操作 /// Do SHA-1 padding manually
/// SHA-1的一个数据块是512 bit因此输出的Vec<u32>长度是16的倍数 /// A SHA-1 block is 512 bit, so the output Vec<u32> length is a multiple of 16
fn manually_prepare_sha1(hashdata: Vec<u8>) -> Vec<u32> { fn manually_prepare_sha1(hashdata: Vec<u8>) -> Vec<u32> {
// 填充后的长度 // Length after padding
// 用80 00 ...填充到448 mod 512 bit即56 mod 64 bytes加上u64的8 bytes后长度是64的倍数 // Fill with 0x80 0x00 ... to 448 mod 512 bit, which is 56 mod 64 bytes
// plus u64's 8 bytes, the length is a multiple of 64
let padded_length = hashdata.len() + (64 - ((hashdata.len() + 8) % 64)) + 8; let padded_length = hashdata.len() + (64 - ((hashdata.len() + 8) % 64)) + 8;
let mut result_u8 = Vec::with_capacity(padded_length); let mut result_u8 = Vec::with_capacity(padded_length);
result_u8.extend_from_slice(&hashdata); result_u8.extend_from_slice(&hashdata);
result_u8.push(0x80); result_u8.push(0x80);
result_u8.resize(padded_length, 0); result_u8.resize(padded_length, 0);
// 需要把Vec<u8>直接转换成Vec<u32>
// convert Vec<u8> to Vec<u32>
// https://stackoverflow.com/questions/49690459/converting-a-vecu32-to-vecu8-in-place-and-with-minimal-overhead // https://stackoverflow.com/questions/49690459/converting-a-vecu32-to-vecu8-in-place-and-with-minimal-overhead
let mut result_u32 = unsafe { let mut result_u32 = unsafe {
let ptr = result_u8.as_mut_ptr() as *mut u32; let ptr = result_u8.as_mut_ptr() as *mut u32;
@ -106,13 +101,15 @@ fn manually_prepare_sha1(hashdata: Vec<u8>) -> Vec<u32> {
mem::forget(result_u8); mem::forget(result_u8);
Vec::from_raw_parts(ptr, length, capacity) Vec::from_raw_parts(ptr, length, capacity)
}; };
// assert_eq!(result_u32.len() % 16, 0); // assert_eq!(result_u32.len() % 16, 0);
// SHA-1的word和length使用大端序 // SHA-1 uses big-endian words and length
for i in 0..result_u32.len() { for pos in &mut result_u32 {
result_u32[i] = result_u32[i].to_be(); *pos = pos.to_be();
} }
let bit_length = hashdata.len() * 8; let bit_length = hashdata.len() * 8;
result_u32[padded_length / 4 - 1] = (bit_length ) as u32; result_u32[padded_length / 4 - 1] = (bit_length) as u32;
result_u32[padded_length / 4 - 2] = (bit_length >> 32) as u32; result_u32[padded_length / 4 - 2] = (bit_length >> 32) as u32;
result_u32 result_u32
} }
@ -123,7 +120,8 @@ fn parse_pattern(pattern: String) -> (String, f64) {
_ => panic!("Invalid pattern"), _ => panic!("Invalid pattern"),
}; };
let mut parts: Vec<String> = vec![]; let mut parts: Vec<String> = vec![];
// 处理0-9A-F
// Handle fixed 0-9A-F
let mut fixed_pos_count: usize = 0; let mut fixed_pos_count: usize = 0;
for i in 0..=4 { for i in 0..=4 {
let mut mask = String::new(); let mut mask = String::new();
@ -145,8 +143,10 @@ fn parse_pattern(pattern: String) -> (String, f64) {
parts.push(format!("(h[{i}] & 0x{mask}) == 0x{value}")); parts.push(format!("(h[{i}] & 0x{mask}) == 0x{value}"));
} }
} }
// 处理通配符G-Z
let mut wildcard_pos_all: [Vec<usize>; (b'Z' - b'G' + 1) as usize] = std::default::Default::default(); // Handle wildcard G-Z
let mut wildcard_pos_all: [Vec<usize>; (b'Z' - b'G' + 1) as usize] =
std::default::Default::default();
for (i, wildcard) in pattern.chars().enumerate() { for (i, wildcard) in pattern.chars().enumerate() {
if ('G'..='Z').contains(&wildcard) { if ('G'..='Z').contains(&wildcard) {
wildcard_pos_all[((wildcard as u8) - b'G') as usize].push(i); wildcard_pos_all[((wildcard as u8) - b'G') as usize].push(i);
@ -179,27 +179,38 @@ fn parse_pattern(pattern: String) -> (String, f64) {
wildcard_pos_count += wildcard_pos.len() - 1; wildcard_pos_count += wildcard_pos.len() - 1;
} }
} }
let filter = if parts.len() != 0 { let filter = if !parts.is_empty() {
parts.join(" && ") parts.join(" && ")
} else { } else {
String::from("true") String::from("true")
}; };
(filter, (16f64).powi((fixed_pos_count + wildcard_pos_count) as i32)) (
filter,
(16f64).powi((fixed_pos_count + wildcard_pos_count) as i32),
)
} }
fn format_number(v: impl Into<f64>) -> String { fn format_number(v: impl Into<f64>) -> String {
match Into::<f64>::into(v) { match Into::<f64>::into(v) {
// v if v >= 1e9f64 => { return format!("{:.02}g", v / 1e9f64); }, // v if v >= 1e9f64 => { return format!("{:.02}g", v / 1e9f64); },
v if v >= 1e6f64 => { return format!("{:.02}m", v / 1e6f64); }, v if v >= 1e6f64 => {
v if v >= 1e3f64 => { return format!("{:.02}k", v / 1e3f64); }, format!("{:.02}m", v / 1e6f64)
v => { return format!("{v:.02}"); }, }
v if v >= 1e3f64 => {
format!("{:.02}k", v / 1e3f64)
}
v => {
format!("{v:.02}")
}
} }
} }
fn main() -> Result<(), Box<dyn std::error::Error>> { fn main() -> Result<(), Box<dyn std::error::Error>> {
env_logger::Builder::from_env(env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, "info")) env_logger::Builder::from_env(
.format_indent(None) env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, "info"),
.init(); )
.format_indent(None)
.init();
let args = if cfg!(debug_assertions) { let args = if cfg!(debug_assertions) {
Args { Args {
@ -222,40 +233,36 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
}; };
debug!("{:?}", &args); debug!("{:?}", &args);
let device_list: Vec<(Platform, Device)> = Platform::list() let device_list: Vec<(Platform, Device)> =
.iter() Platform::list()
.rfold( .iter()
Vec::new(), .rfold(Vec::new(), |mut list, platform| {
|mut list, platform| { if let Ok(devices) = Device::list_all(platform) {
match Device::list_all(platform) { let mut devices = devices.iter().map(|device| (*platform, *device)).collect();
Ok(devices) => { list.append(&mut devices);
let mut devices = devices
.iter()
.map(|device| (*platform, *device))
.collect();
list.append(&mut devices);
},
Err(_) => {},
} }
list list
}, });
);
if args.device_list { if args.device_list {
for (index, (platform, device)) in device_list.iter().enumerate() { for (index, (platform, device)) in device_list.iter().enumerate() {
info!("Device #{} - {}", index, format!( info!(
"{} ({}, MaxWorkGroupSize={}, MaxWorkItemSizes={}, MaxWorkItemDimensions={})", "Device #{} - {}",
device.name()?, index,
platform.name()?, format!(
device.info(ocl::core::DeviceInfo::MaxWorkGroupSize)?, "{} ({}, MaxWorkGroupSize={}, MaxWorkItemSizes={}, MaxWorkItemDimensions={})",
device.info(ocl::core::DeviceInfo::MaxWorkItemSizes)?, device.name()?,
device.info(ocl::core::DeviceInfo::MaxWorkItemDimensions)?, platform.name()?,
)); device.info(ocl::core::DeviceInfo::MaxWorkGroupSize)?,
device.info(ocl::core::DeviceInfo::MaxWorkItemSizes)?,
device.info(ocl::core::DeviceInfo::MaxWorkItemDimensions)?,
)
);
} }
return Ok(()); return Ok(());
} }
let device = match args.device { let device = match args.device {
Some(i) => device_list[i].1, Some(i) => device_list[i].1,
None => Device::first(Platform::default())?, None => Device::first(Platform::default())?,
}; };
info!("Using device: {}", device.name()?); info!("Using device: {}", device.name()?);
@ -274,10 +281,11 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
info!( info!(
"You will get vanity keys created after {}", "You will get vanity keys created after {}",
chrono::Utc::now() chrono::Utc::now()
.checked_sub_signed(chrono::TimeDelta::seconds((dimension * iteration) as i64)).unwrap() .checked_sub_signed(chrono::TimeDelta::seconds((dimension * iteration) as i64))
.unwrap()
.to_rfc3339_opts(chrono::SecondsFormat::Millis, true), .to_rfc3339_opts(chrono::SecondsFormat::Millis, true),
); );
if let None = args.output { if args.output.is_none() {
if args.no_secret_key_logging { if args.no_secret_key_logging {
warn!("No output dir given and you disabled secret key logging. You have no chance to save generated vanity keys."); warn!("No output dir given and you disabled secret key logging. You have no chance to save generated vanity keys.");
} else { } else {
@ -291,7 +299,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
Some(pattern) => { Some(pattern) => {
let (filter, estimate) = parse_pattern(pattern); let (filter, estimate) = parse_pattern(pattern);
(filter, Some(estimate)) (filter, Some(estimate))
}, }
None => panic!("No filter or pattern given"), None => panic!("No filter or pattern given"),
}, },
}; };
@ -300,7 +308,9 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut rng = thread_rng(); let mut rng = thread_rng();
match args.cipher_suite { match args.cipher_suite {
CipherSuite::RSA2048 | CipherSuite::RSA3072 | CipherSuite::RSA4096 => warn!("Generating RSA vanity keys is not recommended. Too slow!"), CipherSuite::RSA2048 | CipherSuite::RSA3072 | CipherSuite::RSA4096 => {
warn!("Generating RSA vanity keys is not recommended. Too slow!")
}
_ => (), _ => (),
}; };
@ -308,13 +318,16 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut hashdata = manually_prepare_sha1(vanity_key.hashdata()); let mut hashdata = manually_prepare_sha1(vanity_key.hashdata());
let pro_que = ProQue::builder() let pro_que = ProQue::builder()
.src(std::include_str!("shader.cl").replace( .src(
"#define __INJECTS__", std::include_str!("shader.cl").replace(
&[ "#define __INJECTS__",
format!("#define FILTER(h) ({filter})"), &[
format!("#define CHUNK ({})", hashdata.len() / 16), format!("#define FILTER(h) ({filter})"),
].join("\n"), format!("#define CHUNK ({})", hashdata.len() / 16),
)) ]
.join("\n"),
),
)
.device(device) .device(device)
.dims(dimension) .dims(dimension)
.build()?; .build()?;
@ -341,21 +354,27 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
.queue(pro_que.queue().clone()) .queue(pro_que.queue().clone())
.len(hashdata.len()) .len(hashdata.len())
.copy_host_slice(&hashdata) .copy_host_slice(&hashdata)
.build().unwrap(); .build()
.unwrap();
let kernel = pro_que let kernel = pro_que
.kernel_builder("vanity_sha1") .kernel_builder("vanity_sha1")
.arg(&buffer_hashdata) .arg(&buffer_hashdata)
.arg(&buffer_result) .arg(&buffer_result)
.arg(iteration as u64) .arg(iteration as u64)
.build().unwrap(); .build()
.unwrap();
unsafe { kernel.enq().unwrap(); } unsafe {
kernel.enq().unwrap();
}
buffer_result.read(&mut vec).enq().unwrap(); buffer_result.read(&mut vec).enq().unwrap();
tx_result.send(match vec[0] { tx_result
0 => None, .send(match vec[0] {
x => Some(x), 0 => None,
}).unwrap(); x => Some(x),
})
.unwrap();
} }
debug!("OpenCL thread quit"); debug!("OpenCL thread quit");
}); });
@ -363,7 +382,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
loop { loop {
debug!("Send key to OpenCL thread"); debug!("Send key to OpenCL thread");
tx_hashdata.send(hashdata)?; tx_hashdata.send(hashdata)?;
let vanity_key_next = VanitySecretKey::new(args.cipher_suite, args.user_id.clone(), &mut rng); let vanity_key_next =
VanitySecretKey::new(args.cipher_suite, args.user_id.clone(), &mut rng);
let hashdata_next = manually_prepare_sha1(vanity_key_next.hashdata()); let hashdata_next = manually_prepare_sha1(vanity_key_next.hashdata());
debug!("Receive result from OpenCL thread"); debug!("Receive result from OpenCL thread");
@ -376,8 +396,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
Some(estimate) => print!( Some(estimate) => print!(
"[{}] {}/{} {:.02}x {:.02}s {} hash/s \r", "[{}] {}/{} {:.02}x {:.02}s {} hash/s \r",
match hashed_count % 16 { match hashed_count % 16 {
x if x < 8 => format!("{}>))'>{}", " ".repeat( x), " ".repeat(7 - x)), x if x < 8 => format!("{}>))'>{}", " ".repeat(x), " ".repeat(7 - x)),
x => format!("{}<'((<{}", " ".repeat(15 - x), " ".repeat(x - 8)), x => format!("{}<'((<{}", " ".repeat(15 - x), " ".repeat(x - 8)),
}, },
format_number(hashed as f64), format_number(hashed as f64),
format_number(estimate), format_number(estimate),
@ -388,8 +408,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
None => print!( None => print!(
"[{}] {} {:.02}s {} hash/s \r", "[{}] {} {:.02}s {} hash/s \r",
match hashed_count % 16 { match hashed_count % 16 {
x if x < 8 => format!("{}>))'>{}", " ".repeat( x), " ".repeat(7 - x)), x if x < 8 => format!("{}>))'>{}", " ".repeat(x), " ".repeat(7 - x)),
x => format!("{}<'((<{}", " ".repeat(15 - x), " ".repeat(x - 8)), x => format!("{}<'((<{}", " ".repeat(15 - x), " ".repeat(x - 8)),
}, },
format_number(hashed as f64), format_number(hashed as f64),
elapsed, elapsed,
@ -399,51 +419,62 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
io::stdout().flush()?; io::stdout().flush()?;
} }
match vanity_timestamp { if let Some(vanity_timestamp) = vanity_timestamp {
Some(vanity_timestamp) => { vanity_key.edit_timestamp(vanity_timestamp, &mut rng);
vanity_key.edit_timestamp(vanity_timestamp, &mut rng); if args.no_secret_key_logging {
if args.no_secret_key_logging { info!("Get a vanity key!");
info!("Get a vanity key!"); } else {
} else { info!("Get a vanity key: \n{}", vanity_key.to_armored_string()?);
info!("Get a vanity key: \n{}", vanity_key.to_armored_string()?); }
} info!(
"Created at: {} ({})",
vanity_key
.secret_key
.created_at()
.to_rfc3339_opts(chrono::SecondsFormat::Millis, true),
vanity_key.secret_key.created_at().timestamp(),
);
info!(
"Fingerprint #0: {}",
hex::encode_upper(vanity_key.secret_key.fingerprint().as_bytes())
);
for (i, subkey) in vanity_key.secret_key.secret_subkeys.iter().enumerate() {
info!( info!(
"Created at: {} ({})", "Fingerprint #{}: {}",
vanity_key.secret_key.created_at().to_rfc3339_opts(chrono::SecondsFormat::Millis, true), i + 1,
vanity_key.secret_key.created_at().timestamp(), hex::encode_upper(subkey.fingerprint().as_bytes())
); );
info!("Fingerprint #0: {}", hex::encode_upper(vanity_key.secret_key.fingerprint().as_bytes())); }
for (i, subkey) in vanity_key.secret_key.secret_subkeys.iter().enumerate() { match estimate {
info!("Fingerprint #{}: {}", i + 1, hex::encode_upper(subkey.fingerprint().as_bytes())); Some(estimate) => info!(
} "Hashed: {} ({:.02}x) Time: {:.02}s Speed: {} hash/s",
match estimate { format_number(hashed as f64),
Some(estimate) => info!( (hashed as f64) / estimate,
"Hashed: {} ({:.02}x) Time: {:.02}s Speed: {} hash/s", elapsed,
format_number(hashed as f64), format_number((hashed as f64) / elapsed),
(hashed as f64) / estimate, ),
elapsed, None => info!(
format_number((hashed as f64) / elapsed), "Hashed: {} Time: {:.02}s Speed: {} hash/s",
), format_number(hashed as f64),
None => info!( elapsed,
"Hashed: {} Time: {:.02}s Speed: {} hash/s", format_number((hashed as f64) / elapsed),
format_number(hashed as f64), ),
elapsed, }
format_number((hashed as f64) / elapsed), if let Some(ref output_dir) = args.output {
), fs::write(
} Path::new(output_dir).join(format!(
if let Some(ref output_dir) = args.output { "{}-sec.asc",
fs::write( hex::encode_upper(vanity_key.secret_key.fingerprint().as_bytes())
Path::new(output_dir).join(format!("{}-sec.asc", hex::encode_upper(vanity_key.secret_key.fingerprint().as_bytes()))), )),
vanity_key.to_armored_string()?, vanity_key.to_armored_string()?,
).unwrap(); )
} .unwrap();
if args.oneshot { }
break; if args.oneshot {
} break;
hashed = 0; }
start = Instant::now(); hashed = 0;
}, start = Instant::now();
None => {},
} }
if let Some(timeout) = args.timeout { if let Some(timeout) = args.timeout {
if elapsed > timeout { if elapsed > timeout {

View file

@ -1,34 +1,24 @@
use byteorder::{BigEndian, ByteOrder};
use clap::ValueEnum; use clap::ValueEnum;
use byteorder::{ByteOrder, BigEndian}; use log::debug;
use rand::{Rng, CryptoRng};
use pgp::{ use pgp::{
composed::{key::SecretKeyParamsBuilder, KeyType}, composed::{key::SecretKeyParamsBuilder, KeyType},
crypto::{ crypto::{ecc_curve::ECCCurve, hash::HashAlgorithm, sym::SymmetricKeyAlgorithm},
hash::HashAlgorithm,
sym::SymmetricKeyAlgorithm,
ecc_curve::ECCCurve,
},
ser::Serialize,
packet::KeyFlags, packet::KeyFlags,
types::{ ser::Serialize,
CompressionAlgorithm, types::{CompressionAlgorithm, KeyVersion, PublicKeyTrait, SecretKeyTrait},
PublicKeyTrait, Deserializable, SecretKey, SecretSubkey, SignedSecretKey, SubkeyParamsBuilder,
SecretKeyTrait,
KeyVersion,
},
Deserializable,
SecretKey,
SecretSubkey,
SignedSecretKey,
SubkeyParamsBuilder,
}; };
use rand::{CryptoRng, Rng};
use smallvec::smallvec; use smallvec::smallvec;
use log::debug;
/// 获取用于计算一个私钥的指纹的数据 /// Get the data used to calculate the fingerprint of a private key
fn build_secret_key_hashdata(secret_key: impl SecretKeyTrait) -> Vec<u8> { fn build_secret_key_hashdata(secret_key: impl SecretKeyTrait) -> Vec<u8> {
let mut hashdata = vec![0x99, 0, 0, 0x04, 0, 0, 0, 0]; let mut hashdata = vec![0x99, 0, 0, 0x04, 0, 0, 0, 0];
BigEndian::write_u32(&mut hashdata[4..8], secret_key.created_at().timestamp() as u32); BigEndian::write_u32(
&mut hashdata[4..8],
secret_key.created_at().timestamp() as u32,
);
hashdata.push(secret_key.algorithm().into()); hashdata.push(secret_key.algorithm().into());
secret_key.public_params().to_writer(&mut hashdata).unwrap(); secret_key.public_params().to_writer(&mut hashdata).unwrap();
let packet_len = (hashdata.len() - 3) as u16; let packet_len = (hashdata.len() - 3) as u16;
@ -36,7 +26,7 @@ fn build_secret_key_hashdata(secret_key: impl SecretKeyTrait) -> Vec<u8> {
hashdata hashdata
} }
/// 需要被修改的密钥类型 /// Cipher Suites
#[derive(ValueEnum, Default, Clone, Copy, Debug)] #[derive(ValueEnum, Default, Clone, Copy, Debug)]
#[clap(rename_all = "kebab_case")] #[clap(rename_all = "kebab_case")]
pub enum CipherSuite { pub enum CipherSuite {
@ -53,6 +43,7 @@ pub enum CipherSuite {
EcdsaP384, EcdsaP384,
EcdsaP521, EcdsaP521,
} }
pub struct VanitySecretKey { pub struct VanitySecretKey {
pub cipher_suite: CipherSuite, pub cipher_suite: CipherSuite,
pub secret_key: SignedSecretKey, pub secret_key: SignedSecretKey,
@ -92,10 +83,13 @@ impl VanitySecretKey {
secret_key_params_builder secret_key_params_builder
.key_type(KeyType::EdDSALegacy) .key_type(KeyType::EdDSALegacy)
.subkey(subkey_params_builder.build().unwrap()); .subkey(subkey_params_builder.build().unwrap());
}, }
CipherSuite::EcdhP256 | CipherSuite::EcdsaP256 | CipherSuite::EcdhP256
CipherSuite::EcdhP384 | CipherSuite::EcdsaP384 | | CipherSuite::EcdsaP256
CipherSuite::EcdhP521 | CipherSuite::EcdsaP521 => { | CipherSuite::EcdhP384
| CipherSuite::EcdsaP384
| CipherSuite::EcdhP521
| CipherSuite::EcdsaP521 => {
let curve = match cipher_suite { let curve = match cipher_suite {
CipherSuite::EcdhP256 | CipherSuite::EcdsaP256 => ECCCurve::P256, CipherSuite::EcdhP256 | CipherSuite::EcdsaP256 => ECCCurve::P256,
CipherSuite::EcdhP384 | CipherSuite::EcdsaP384 => ECCCurve::P384, CipherSuite::EcdhP384 | CipherSuite::EcdsaP384 => ECCCurve::P384,
@ -109,7 +103,7 @@ impl VanitySecretKey {
secret_key_params_builder secret_key_params_builder
.key_type(KeyType::ECDSA(curve.clone())) .key_type(KeyType::ECDSA(curve.clone()))
.subkey(subkey_params_builder.build().unwrap()); .subkey(subkey_params_builder.build().unwrap());
}, }
CipherSuite::RSA2048 | CipherSuite::RSA3072 | CipherSuite::RSA4096 => { CipherSuite::RSA2048 | CipherSuite::RSA3072 | CipherSuite::RSA4096 => {
let bits = match cipher_suite { let bits = match cipher_suite {
CipherSuite::RSA2048 => 2048, CipherSuite::RSA2048 => 2048,
@ -120,13 +114,15 @@ impl VanitySecretKey {
secret_key_params_builder secret_key_params_builder
.key_type(KeyType::Rsa(bits)) .key_type(KeyType::Rsa(bits))
.can_encrypt(true); .can_encrypt(true);
}, }
} }
let secret_key_params = secret_key_params_builder.build().unwrap(); let secret_key_params = secret_key_params_builder.build().unwrap();
let secret_key = secret_key_params let secret_key = secret_key_params
.generate(&mut rng).unwrap() .generate(&mut rng)
.sign(&mut rng, || String::new()).unwrap(); .unwrap()
.sign(&mut rng, String::new)
.unwrap();
assert_eq!(secret_key.version(), KeyVersion::V4); assert_eq!(secret_key.version(), KeyVersion::V4);
Self { Self {
@ -139,7 +135,7 @@ impl VanitySecretKey {
// RFC 9580 - OpenPGP // RFC 9580 - OpenPGP
// 4. Packet Syntax // 4. Packet Syntax
// https://datatracker.ietf.org/doc/html/rfc9580#name-packet-syntax // https://datatracker.ietf.org/doc/html/rfc9580#name-packet-syntax
let mut secret_key_bytes = Vec::from(self.secret_key.to_bytes().unwrap()); let mut secret_key_bytes = self.secret_key.to_bytes().unwrap();
let mut packet_read_pos: usize = 0; let mut packet_read_pos: usize = 0;
while packet_read_pos < secret_key_bytes.len() { while packet_read_pos < secret_key_bytes.len() {
let cipher_type_byte = secret_key_bytes[packet_read_pos]; let cipher_type_byte = secret_key_bytes[packet_read_pos];
@ -148,15 +144,33 @@ impl VanitySecretKey {
let (size, size_length) = match cipher_type_byte >> 6 { let (size, size_length) = match cipher_type_byte >> 6 {
0b10 => match cipher_type_byte & 0b00000011 { 0b10 => match cipher_type_byte & 0b00000011 {
0 => (secret_key_bytes[packet_read_pos] as usize, 1), 0 => (secret_key_bytes[packet_read_pos] as usize, 1),
1 => (BigEndian::read_u16(&secret_key_bytes[packet_read_pos..packet_read_pos + 2]) as usize, 2), 1 => (
2 => (BigEndian::read_u32(&secret_key_bytes[packet_read_pos..packet_read_pos + 4]) as usize, 4), BigEndian::read_u16(&secret_key_bytes[packet_read_pos..packet_read_pos + 2])
as usize,
2,
),
2 => (
BigEndian::read_u32(&secret_key_bytes[packet_read_pos..packet_read_pos + 4])
as usize,
4,
),
3 => unimplemented!("Indeterminate length"), 3 => unimplemented!("Indeterminate length"),
_ => unreachable!(), _ => unreachable!(),
}, },
0b11 => match secret_key_bytes[packet_read_pos] { 0b11 => match secret_key_bytes[packet_read_pos] {
x if x < 192 => (secret_key_bytes[packet_read_pos] as usize, 1), x if x < 192 => (secret_key_bytes[packet_read_pos] as usize, 1),
x if x < 224 => ((((secret_key_bytes[packet_read_pos] - 192) as usize) << 8) + (secret_key_bytes[packet_read_pos + 1] as usize) + 192, 2), x if x < 224 => (
x if x == 255 => (BigEndian::read_u32(&secret_key_bytes[packet_read_pos + 1..packet_read_pos + 5]) as usize, 5), (((secret_key_bytes[packet_read_pos] - 192) as usize) << 8)
+ (secret_key_bytes[packet_read_pos + 1] as usize)
+ 192,
2,
),
255 => (
BigEndian::read_u32(
&secret_key_bytes[packet_read_pos + 1..packet_read_pos + 5],
) as usize,
5,
),
_ => unimplemented!("Partial body length"), _ => unimplemented!("Partial body length"),
}, },
_ => unreachable!(), _ => unreachable!(),
@ -172,45 +186,59 @@ impl VanitySecretKey {
// 0x05 => Secret-Key Packet // 0x05 => Secret-Key Packet
// 0x07 => Secret-Subkey Packet // 0x07 => Secret-Subkey Packet
if [0x05, 0x07].contains(&packet_type) { if [0x05, 0x07].contains(&packet_type) {
BigEndian::write_u32(&mut secret_key_bytes[packet_read_pos + 1..packet_read_pos + 5], timestamp); BigEndian::write_u32(
&mut secret_key_bytes[packet_read_pos + 1..packet_read_pos + 5],
timestamp,
);
} }
packet_read_pos += size; packet_read_pos += size;
} }
// 只修改了时间因此这个key的签名是无效的
// The signature of this key is invalid because only the timestamp is modified
let edited_key = SignedSecretKey::from_bytes(&secret_key_bytes[..]).unwrap(); let edited_key = SignedSecretKey::from_bytes(&secret_key_bytes[..]).unwrap();
// 重新对key签名 // Re-sign the key
let mut subkey_flags = KeyFlags::default(); let mut subkey_flags = KeyFlags::default();
subkey_flags.set_encrypt_storage(true); subkey_flags.set_encrypt_storage(true);
subkey_flags.set_encrypt_comms(true); subkey_flags.set_encrypt_comms(true);
self.secret_key = SecretKey::new( self.secret_key = SecretKey::new(
edited_key.primary_key, edited_key.primary_key,
edited_key.details.as_unsigned(), edited_key.details.as_unsigned(),
edited_key.public_subkeys edited_key
.public_subkeys
.iter() .iter()
.map(|e| e.as_unsigned()) .map(|e| e.as_unsigned())
.collect(), .collect(),
edited_key.secret_subkeys edited_key
.secret_subkeys
.iter() .iter()
.map(|e| SecretSubkey::new(e.key.clone(), subkey_flags)) .map(|e| SecretSubkey::new(e.key.clone(), subkey_flags))
.collect(), .collect(),
).sign(&mut rng, || String::new()).unwrap(); )
// self.secret_key.verify().unwrap(); .sign(&mut rng, String::new)
.unwrap();
} }
pub fn hashdata(&self) -> Vec<u8> { pub fn hashdata(&self) -> Vec<u8> {
match self.cipher_suite { match self.cipher_suite {
CipherSuite::Ed25519 | CipherSuite::Ed25519
CipherSuite::EcdsaP256 | CipherSuite::EcdsaP384 | CipherSuite::EcdsaP521 | | CipherSuite::EcdsaP256
CipherSuite::RSA2048 | CipherSuite::RSA3072 | CipherSuite::RSA4096 | CipherSuite::EcdsaP384
=> build_secret_key_hashdata(&self.secret_key), | CipherSuite::EcdsaP521
CipherSuite::Cv25519 | | CipherSuite::RSA2048
CipherSuite::EcdhP256 | CipherSuite::EcdhP384 | CipherSuite::EcdhP521 | CipherSuite::RSA3072
=> build_secret_key_hashdata(&self.secret_key.secret_subkeys[0]), | CipherSuite::RSA4096 => build_secret_key_hashdata(&self.secret_key),
CipherSuite::Cv25519
| CipherSuite::EcdhP256
| CipherSuite::EcdhP384
| CipherSuite::EcdhP521 => {
build_secret_key_hashdata(&self.secret_key.secret_subkeys[0])
}
} }
} }
pub fn to_armored_string(&self) -> Result<String, pgp::errors::Error> { pub fn to_armored_string(&self) -> Result<String, pgp::errors::Error> {
self.secret_key.to_armored_string(pgp::ArmorOptions::default()) self.secret_key
.to_armored_string(pgp::ArmorOptions::default())
} }
} }