feat: v1.1.7, add rsa-encrypt sub command
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -384,7 +384,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "card-cli"
|
||||
version = "1.1.6"
|
||||
version = "1.1.7"
|
||||
dependencies = [
|
||||
"authenticator",
|
||||
"base64 0.13.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "card-cli"
|
||||
version = "1.1.6"
|
||||
version = "1.1.7"
|
||||
authors = ["Hatter Jiang <jht5945@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
|
||||
92
src/cmd_rsaencrypt.rs
Normal file
92
src/cmd_rsaencrypt.rs
Normal file
@@ -0,0 +1,92 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use clap::{App, Arg, ArgMatches, SubCommand};
|
||||
use openssl::encrypt::Encrypter;
|
||||
use openssl::pkey::PKey;
|
||||
use openssl::rsa::{Padding, Rsa};
|
||||
use rust_util::util_clap::{Command, CommandError};
|
||||
|
||||
use crate::digest::sha256_bytes;
|
||||
|
||||
pub struct CommandImpl;
|
||||
|
||||
// https://docs.rs/openssl/0.10.36/openssl/encrypt/index.html
|
||||
impl Command for CommandImpl {
|
||||
fn name(&self) -> &str { "rsa-encrypt" }
|
||||
|
||||
fn subcommand<'a>(&self) -> App<'a, 'a> {
|
||||
SubCommand::with_name(self.name()).about("RSA Encrypt subcommand")
|
||||
.arg(Arg::with_name("pub-key-in").long("pub-key-in").takes_value(true).help("Public key in"))
|
||||
.arg(Arg::with_name("data").long("data").takes_value(true).help("Data"))
|
||||
.arg(Arg::with_name("data-hex").long("data-hex").takes_value(true).help("Data in HEX"))
|
||||
.arg(Arg::with_name("padding").long("padding").takes_value(true)
|
||||
.possible_values(&["pkcs1", "oaep", "pss", "none"]).help("Padding"))
|
||||
.arg(Arg::with_name("json").long("json").help("JSON output"))
|
||||
}
|
||||
|
||||
fn run(&self, _arg_matches: &ArgMatches, sub_arg_matches: &ArgMatches) -> CommandError {
|
||||
let json_output = sub_arg_matches.is_present("json");
|
||||
if json_output { rust_util::util_msg::set_logger_std_out(false); }
|
||||
|
||||
let pub_key_in = opt_value_result!(sub_arg_matches.value_of("pub-key-in"), "Require public key in");
|
||||
let pub_key_bytes = opt_result!(std::fs::read(pub_key_in), "Read file: {}, failed: {}", pub_key_in);
|
||||
|
||||
let padding_opt = sub_arg_matches.value_of("padding");
|
||||
|
||||
let padding = match padding_opt {
|
||||
Some("oaep") | Some("pkcs1_oaep") => Padding::PKCS1_OAEP,
|
||||
Some("pss") | Some("pkcs1_pss") => Padding::PKCS1_PSS,
|
||||
Some("none") => Padding::NONE,
|
||||
Some("pkcs1") | None => Padding::PKCS1,
|
||||
Some(p) => return simple_error!("Not supported padding: {}", p),
|
||||
};
|
||||
let padding_str = match padding {
|
||||
Padding::NONE => "none",
|
||||
Padding::PKCS1 => "pkcs1",
|
||||
Padding::PKCS1_PSS => "pkcs1_pss",
|
||||
Padding::PKCS1_OAEP => "pkcs1_oaep",
|
||||
_ => "unknown",
|
||||
};
|
||||
|
||||
let mut json = BTreeMap::new();
|
||||
|
||||
let keypair = opt_result!(Rsa::public_key_from_pem(&pub_key_bytes), "Parse RSA failed: {}");
|
||||
let pub_key_der = opt_result!(keypair.public_key_to_der(), "RSA public key to der failed: {}");
|
||||
let pub_key_fingerprint = hex::encode(sha256_bytes(&pub_key_der));
|
||||
let keypair = opt_result!(PKey::from_rsa(keypair), "RSA to PKey failed: {}");
|
||||
|
||||
let data = if let Some(data_hex) = sub_arg_matches.value_of("data-hex") {
|
||||
opt_result!(hex::decode(data_hex), "Decode data HEX failed: {}")
|
||||
} else if let Some(data) = sub_arg_matches.value_of("data") {
|
||||
data.as_bytes().to_vec()
|
||||
} else {
|
||||
return simple_error!("Data is required, --data-hex or --data argument!");
|
||||
};
|
||||
|
||||
let mut encrypter = opt_result!(Encrypter::new(&keypair), "Encrypter new failed: {}");
|
||||
opt_result!(encrypter.set_rsa_padding(padding), "Set RSA padding failed: {}");
|
||||
let buffer_len = opt_result!(encrypter.encrypt_len(&data), "Encrypt len failed: {}");
|
||||
let mut encrypted = vec![0; buffer_len];
|
||||
let encrypted_len = opt_result!(encrypter.encrypt(&data, &mut encrypted), "Encrypt failed: {}");
|
||||
encrypted.truncate(encrypted_len);
|
||||
|
||||
let encrypted_hex = hex::encode(&encrypted);
|
||||
information!("Message: {}", String::from_utf8_lossy(&data));
|
||||
information!("Message HEX: {}", hex::encode(&data));
|
||||
information!("Padding: {}", padding_str);
|
||||
information!("Public key fingerprint: {}", pub_key_fingerprint);
|
||||
success!("Encrypted message: {}", encrypted_hex);
|
||||
if json_output {
|
||||
json.insert("data", hex::encode(&data));
|
||||
json.insert("public_key_fingerprint", pub_key_fingerprint);
|
||||
json.insert("padding", padding_str.to_string());
|
||||
json.insert("encrypted", encrypted_hex);
|
||||
}
|
||||
|
||||
if json_output {
|
||||
println!("{}", serde_json::to_string_pretty(&json).unwrap());
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ mod pkiutil;
|
||||
mod pgpcardutil;
|
||||
mod cmd_u2fregister;
|
||||
mod cmd_u2fsign;
|
||||
mod cmd_rsaencrypt;
|
||||
mod cmd_pgp;
|
||||
mod cmd_pgpcardadmin;
|
||||
mod cmd_pgpcardlist;
|
||||
@@ -44,6 +45,7 @@ fn inner_main() -> CommandError {
|
||||
let commands: Vec<Box<dyn Command>> = vec![
|
||||
Box::new(cmd_chall::CommandImpl),
|
||||
Box::new(cmd_challconfig::CommandImpl),
|
||||
Box::new(cmd_rsaencrypt::CommandImpl),
|
||||
Box::new(cmd_pgp::CommandImpl),
|
||||
Box::new(cmd_pgpcardadmin::CommandImpl),
|
||||
Box::new(cmd_pgpcardlist::CommandImpl),
|
||||
|
||||
Reference in New Issue
Block a user