feat: v1.9.6
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -368,7 +368,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "card-cli"
|
name = "card-cli"
|
||||||
version = "1.9.5"
|
version = "1.9.6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"authenticator",
|
"authenticator",
|
||||||
"base64 0.21.7",
|
"base64 0.21.7",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "card-cli"
|
name = "card-cli"
|
||||||
version = "1.9.5"
|
version = "1.9.6"
|
||||||
authors = ["Hatter Jiang <jht5945@gmail.com>"]
|
authors = ["Hatter Jiang <jht5945@gmail.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use rust_util::{util_msg, XResult};
|
|||||||
use rust_util::util_clap::{Command, CommandError};
|
use rust_util::util_clap::{Command, CommandError};
|
||||||
|
|
||||||
use crate::pgpcardutil;
|
use crate::pgpcardutil;
|
||||||
use crate::util::{base64_encode, try_decode};
|
use crate::util::{base64_encode, read_stdin, try_decode};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
enum EncryptAlgo {
|
enum EncryptAlgo {
|
||||||
@@ -34,6 +34,7 @@ impl Command for CommandImpl {
|
|||||||
.arg(Arg::with_name("pin").short("p").long("pin").takes_value(true).default_value("123456").help("OpenPGP card user pin"))
|
.arg(Arg::with_name("pin").short("p").long("pin").takes_value(true).default_value("123456").help("OpenPGP card user pin"))
|
||||||
.arg(Arg::with_name("pass").long("pass").takes_value(true).help("[deprecated] now OpenPGP card user pin"))
|
.arg(Arg::with_name("pass").long("pass").takes_value(true).help("[deprecated] now OpenPGP card user pin"))
|
||||||
.arg(Arg::with_name("ciphertext").short("c").long("ciphertext").takes_value(true).help("Cipher text (HEX or Base64)"))
|
.arg(Arg::with_name("ciphertext").short("c").long("ciphertext").takes_value(true).help("Cipher text (HEX or Base64)"))
|
||||||
|
.arg(Arg::with_name("stdin").long("stdin").help("Standard input (Ciphertext)"))
|
||||||
.arg(Arg::with_name("algo").long("algo").takes_value(true).help("Algo: RSA, X25519/ECDH"))
|
.arg(Arg::with_name("algo").long("algo").takes_value(true).help("Algo: RSA, X25519/ECDH"))
|
||||||
.arg(Arg::with_name("json").long("json").help("JSON output"))
|
.arg(Arg::with_name("json").long("json").help("JSON output"))
|
||||||
}
|
}
|
||||||
@@ -53,6 +54,8 @@ impl Command for CommandImpl {
|
|||||||
|
|
||||||
let ciphertext_bytes = if let Some(ciphertext) = ciphertext {
|
let ciphertext_bytes = if let Some(ciphertext) = ciphertext {
|
||||||
opt_result!(try_decode(ciphertext), "Decode cipher failed: {}")
|
opt_result!(try_decode(ciphertext), "Decode cipher failed: {}")
|
||||||
|
} else if sub_arg_matches.is_present("stdin") {
|
||||||
|
read_stdin()?
|
||||||
} else {
|
} else {
|
||||||
return simple_error!("--ciphertext must be assigned");
|
return simple_error!("--ciphertext must be assigned");
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use yubikey::piv::AlgorithmId;
|
|||||||
use yubikey::YubiKey;
|
use yubikey::YubiKey;
|
||||||
|
|
||||||
use crate::pivutil;
|
use crate::pivutil;
|
||||||
use crate::util::try_decode;
|
use crate::util::{read_stdin, try_decode};
|
||||||
|
|
||||||
pub struct CommandImpl;
|
pub struct CommandImpl;
|
||||||
|
|
||||||
@@ -19,6 +19,7 @@ impl Command for CommandImpl {
|
|||||||
.arg(Arg::with_name("slot").short("s").long("slot").takes_value(true).help("PIV slot, e.g. 82, 83 ... 95, 9a, 9c, 9d, 9e"))
|
.arg(Arg::with_name("slot").short("s").long("slot").takes_value(true).help("PIV slot, e.g. 82, 83 ... 95, 9a, 9c, 9d, 9e"))
|
||||||
.arg(Arg::with_name("pin").short("p").long("pin").takes_value(true).default_value("123456").help("OpenPGP card user pin"))
|
.arg(Arg::with_name("pin").short("p").long("pin").takes_value(true).default_value("123456").help("OpenPGP card user pin"))
|
||||||
.arg(Arg::with_name("ciphertext").long("ciphertext").short("c").takes_value(true).help("Encrypted data (HEX or Base64)"))
|
.arg(Arg::with_name("ciphertext").long("ciphertext").short("c").takes_value(true).help("Encrypted data (HEX or Base64)"))
|
||||||
|
.arg(Arg::with_name("stdin").long("stdin").help("Standard input (Ciphertext)"))
|
||||||
.arg(Arg::with_name("json").long("json").help("JSON output"))
|
.arg(Arg::with_name("json").long("json").help("JSON output"))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,6 +34,8 @@ impl Command for CommandImpl {
|
|||||||
|
|
||||||
let encrypted_data = if let Some(ciphertext) = sub_arg_matches.value_of("ciphertext") {
|
let encrypted_data = if let Some(ciphertext) = sub_arg_matches.value_of("ciphertext") {
|
||||||
opt_result!(try_decode(ciphertext), "Decode --ciphertext failed: {}")
|
opt_result!(try_decode(ciphertext), "Decode --ciphertext failed: {}")
|
||||||
|
} else if sub_arg_matches.is_present("stdin") {
|
||||||
|
read_stdin()?
|
||||||
} else {
|
} else {
|
||||||
return simple_error!("Argument --ciphertext must be assigned");
|
return simple_error!("Argument --ciphertext must be assigned");
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ use rust_util::util_clap::{Command, CommandError};
|
|||||||
use rust_util::util_msg;
|
use rust_util::util_msg;
|
||||||
use rust_util::util_msg::MessageType;
|
use rust_util::util_msg::MessageType;
|
||||||
|
|
||||||
|
use crate::util::{read_stdin, try_decode};
|
||||||
|
|
||||||
pub struct CommandImpl;
|
pub struct CommandImpl;
|
||||||
|
|
||||||
// https://docs.rs/openssl/0.10.36/openssl/encrypt/index.html
|
// https://docs.rs/openssl/0.10.36/openssl/encrypt/index.html
|
||||||
@@ -19,6 +21,8 @@ impl Command for CommandImpl {
|
|||||||
SubCommand::with_name(self.name()).about("RSA decrypt subcommand")
|
SubCommand::with_name(self.name()).about("RSA decrypt subcommand")
|
||||||
.arg(Arg::with_name("pri-key-in").long("pri-key-in").takes_value(true).help("Private key in"))
|
.arg(Arg::with_name("pri-key-in").long("pri-key-in").takes_value(true).help("Private key in"))
|
||||||
.arg(Arg::with_name("encrypted").long("encrypted").takes_value(true).help("Encrypted data"))
|
.arg(Arg::with_name("encrypted").long("encrypted").takes_value(true).help("Encrypted data"))
|
||||||
|
.arg(Arg::with_name("ciphertext").long("ciphertext").takes_value(true).help("Encrypted data"))
|
||||||
|
.arg(Arg::with_name("stdin").long("stdin").help("Standard input (Ciphertext)"))
|
||||||
.arg(Arg::with_name("padding").long("padding").takes_value(true)
|
.arg(Arg::with_name("padding").long("padding").takes_value(true)
|
||||||
.possible_values(&["pkcs1", "oaep", "pss", "none"]).help("Padding"))
|
.possible_values(&["pkcs1", "oaep", "pss", "none"]).help("Padding"))
|
||||||
.arg(Arg::with_name("json").long("json").help("JSON output"))
|
.arg(Arg::with_name("json").long("json").help("JSON output"))
|
||||||
@@ -40,17 +44,21 @@ impl Command for CommandImpl {
|
|||||||
let keypair = opt_result!(Rsa::private_key_from_pem(&pri_key_bytes), "Parse RSA failed: {}");
|
let keypair = opt_result!(Rsa::private_key_from_pem(&pri_key_bytes), "Parse RSA failed: {}");
|
||||||
let keypair = opt_result!(PKey::from_rsa(keypair), "RSA to PKey failed: {}");
|
let keypair = opt_result!(PKey::from_rsa(keypair), "RSA to PKey failed: {}");
|
||||||
|
|
||||||
let encrypted = if let Some(encrypted) = sub_arg_matches.value_of("encrypted") {
|
let ciphertext_opt = sub_arg_matches.value_of("encrypted")
|
||||||
opt_result!(hex::decode(encrypted), "Decode encrypted HEX failed: {}")
|
.or_else(|| sub_arg_matches.value_of("ciphertext"));
|
||||||
|
let ciphertext = if let Some(ciphertext) = ciphertext_opt {
|
||||||
|
opt_result!(try_decode(ciphertext), "Decode ciphertext HEX or Base64 failed: {}")
|
||||||
|
} else if sub_arg_matches.is_present("stdin") {
|
||||||
|
read_stdin()?
|
||||||
} else {
|
} else {
|
||||||
return simple_error!("Data is required, --data-hex or --data argument!");
|
return simple_error!("Data is required, --ciphertext or --encrypted argument!");
|
||||||
};
|
};
|
||||||
|
|
||||||
util_msg::when(MessageType::DEBUG, || {
|
util_msg::when(MessageType::DEBUG, || {
|
||||||
let rsa = keypair.rsa().unwrap();
|
let rsa = keypair.rsa().unwrap();
|
||||||
let n = rsa.n();
|
let n = rsa.n();
|
||||||
let d = rsa.d();
|
let d = rsa.d();
|
||||||
let m = BigNum::from_slice(&encrypted).unwrap();
|
let m = BigNum::from_slice(&ciphertext).unwrap();
|
||||||
let mut r = BigNum::new().unwrap();
|
let mut r = BigNum::new().unwrap();
|
||||||
r.mod_exp(&m, d, n, &mut BigNumContext::new().unwrap()).unwrap();
|
r.mod_exp(&m, d, n, &mut BigNumContext::new().unwrap()).unwrap();
|
||||||
let v = r.to_vec();
|
let v = r.to_vec();
|
||||||
@@ -63,12 +71,12 @@ impl Command for CommandImpl {
|
|||||||
|
|
||||||
let mut decrypter = opt_result!(Decrypter::new(&keypair), "Decrypter new failed: {}");
|
let mut decrypter = opt_result!(Decrypter::new(&keypair), "Decrypter new failed: {}");
|
||||||
opt_result!(decrypter.set_rsa_padding(padding), "Set RSA padding failed: {}");
|
opt_result!(decrypter.set_rsa_padding(padding), "Set RSA padding failed: {}");
|
||||||
let buffer_len = opt_result!(decrypter.decrypt_len(&encrypted), "Decrypt len failed: {}");
|
let buffer_len = opt_result!(decrypter.decrypt_len(&ciphertext), "Decrypt len failed: {}");
|
||||||
let mut data = vec![0; buffer_len];
|
let mut data = vec![0; buffer_len];
|
||||||
let decrypted_len = opt_result!(decrypter.decrypt(&encrypted, &mut data), "Decrypt failed: {}");
|
let decrypted_len = opt_result!(decrypter.decrypt(&ciphertext, &mut data), "Decrypt failed: {}");
|
||||||
data.truncate(decrypted_len);
|
data.truncate(decrypted_len);
|
||||||
|
|
||||||
let encrypted_hex = hex::encode(&encrypted);
|
let encrypted_hex = hex::encode(&ciphertext);
|
||||||
information!("Padding: {}", padding_str);
|
information!("Padding: {}", padding_str);
|
||||||
success!("Message HEX: {}", hex::encode(&data));
|
success!("Message HEX: {}", hex::encode(&data));
|
||||||
success!("Message: {}", String::from_utf8_lossy(&data));
|
success!("Message: {}", String::from_utf8_lossy(&data));
|
||||||
|
|||||||
13
src/util.rs
13
src/util.rs
@@ -1,3 +1,5 @@
|
|||||||
|
use std::io::Read;
|
||||||
|
|
||||||
use base64::{DecodeError, Engine};
|
use base64::{DecodeError, Engine};
|
||||||
use base64::engine::general_purpose::{STANDARD, URL_SAFE_NO_PAD};
|
use base64::engine::general_purpose::{STANDARD, URL_SAFE_NO_PAD};
|
||||||
use rust_util::XResult;
|
use rust_util::XResult;
|
||||||
@@ -15,11 +17,18 @@ pub fn base64_decode<T: AsRef<[u8]>>(input: T) -> Result<Vec<u8>, DecodeError> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn try_decode(input: &str) -> XResult<Vec<u8>> {
|
pub fn try_decode(input: &str) -> XResult<Vec<u8>> {
|
||||||
return match hex::decode(input) {
|
match hex::decode(input) {
|
||||||
Ok(v) => Ok(v),
|
Ok(v) => Ok(v),
|
||||||
Err(_) => match base64_decode(input) {
|
Err(_) => match base64_decode(input) {
|
||||||
Ok(v) => Ok(v),
|
Ok(v) => Ok(v),
|
||||||
Err(e) => simple_error!("decode hex or base64 error: {}", e),
|
Err(e) => simple_error!("decode hex or base64 error: {}", e),
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_stdin() -> XResult<Vec<u8>> {
|
||||||
|
let mut buffer = vec![];
|
||||||
|
let mut stdin = std::io::stdin();
|
||||||
|
opt_result!(stdin.read_to_end(&mut buffer), "Read stdin failed: {}");
|
||||||
|
Ok(buffer)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user