feat: pgp decrypt
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,3 +1,6 @@
|
||||
test.txt
|
||||
enc.txt
|
||||
enc_key.pem
|
||||
test_key.asc
|
||||
.idea/
|
||||
# ---> Rust
|
||||
|
||||
34
README.md
34
README.md
@@ -2,6 +2,40 @@
|
||||
|
||||
A cli using https://github.com/mozilla/authenticator-rs
|
||||
|
||||
|
||||
# PGP
|
||||
|
||||
## decrypt text
|
||||
|
||||
sample public key
|
||||
```
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEApUM8M+QRMUw0dIvXISFx
|
||||
43j4h9CK38Y9HD6kPcc3Z0dCGPiFy7Ze0OQebPWHyUZ2YmqsdyzFuOQuV9P2pxxj
|
||||
/WLIgRqZV8Jk8tWhtAjOOvm0MTc2rg+EJHfa+zhX4eFEMsj4DvQBMJDXiKnpXTM/
|
||||
j7oMKpIUQHqfXBwsEJHLmHZTLeEBEYKcZXTAmuu3WdxK5jvEc02Xt2hZ1fBs0M9e
|
||||
/2EMe3t69aH4/rabiBjF2h9Jde15wrJMxXaCCWJqYhbBS0CJ3BdjkAqOIpcqPXva
|
||||
xiJN1pNpK8ejA9Q4Nmx7pxnvfv+hCPkWXZS3r/BWZ9lFZc8uErQEbB4gLgko8jOl
|
||||
fQF7cYqtZEs69qY8nnIUBsqZYfAp+bQd2xCFSbEZAl+OrtGzfVjD9YFMPy02+xRg
|
||||
v2N3KT3KHHvuU7WxrvffrshP2fwDuG2MBlmcq1suAKxA0cYPSyajceEqw/3ogSp7
|
||||
7SYx41rT8EWLmTvU0CHzCsuf/O7sDWZRfxatAzWhBBhnKCPqzizpOQOqm8XhCt74
|
||||
FfnabPpHM9XUjoQIPrTssyS3eWqynzJiAqez6v2LK2fhL7IkcLtvt5p59Y+KY4I6
|
||||
YQ09iUh7lKJHRhkgTomUurJHieVHMWFGIHofEC+nU6pGIUh0P7Nr0Gz45GJTwWGd
|
||||
hW53WfImja+b5kwwyqUikyMCAwEAAQ==
|
||||
-----END PUBLIC KEY-----
|
||||
```
|
||||
|
||||
encrypt
|
||||
```
|
||||
openssl rsautl -encrypt -pubin -inkey enc_key.pem -in test.txt -out enc.txt -pkcs
|
||||
```
|
||||
|
||||
decrypt
|
||||
```
|
||||
$ cargo r -- pgp-card-decrypt -c $(cat enc.txt | xxd -ps -c 11111)
|
||||
```
|
||||
|
||||
|
||||
Awesome webauthn:
|
||||
* https://github.com/herrjemand/awesome-webauthn
|
||||
|
||||
|
||||
@@ -11,8 +11,8 @@ impl Command for CommandImpl {
|
||||
|
||||
fn subcommand<'a>(&self) -> App<'a, 'a> {
|
||||
SubCommand::with_name(self.name()).about("Yubikey challenge-response hmac")
|
||||
.arg(Arg::with_name("challenge").long("challenge").takes_value(true).help("Challenge"))
|
||||
.arg(Arg::with_name("challenge-hex").long("challenge-hex").takes_value(true).help("Challenge HEX"))
|
||||
.arg(Arg::with_name("challenge").short("c").long("challenge").takes_value(true).help("Challenge"))
|
||||
.arg(Arg::with_name("challenge-hex").short("x").long("challenge-hex").takes_value(true).help("Challenge HEX"))
|
||||
.arg(Arg::with_name("json").long("json").help("JSON output"))
|
||||
}
|
||||
|
||||
|
||||
@@ -12,8 +12,8 @@ impl Command for CommandImpl {
|
||||
|
||||
fn subcommand<'a>(&self) -> App<'a, 'a> {
|
||||
SubCommand::with_name(self.name()).about("Yubikey challenge-response hmac config")
|
||||
.arg(Arg::with_name("secret").long("secret").takes_value(true).help("Secret"))
|
||||
.arg(Arg::with_name("secret-hex").long("secret-hex").takes_value(true).help("Secret HEX"))
|
||||
.arg(Arg::with_name("secret").short("s").long("secret").takes_value(true).help("Secret"))
|
||||
.arg(Arg::with_name("secret-hex").short("x").long("secret-hex").takes_value(true).help("Secret HEX"))
|
||||
.arg(Arg::with_name("yes-config-chall").long("yes-config-chall").help("Config chall key"))
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ mod pgp;
|
||||
mod pgpcardutil;
|
||||
mod pgpcardlist;
|
||||
mod pgpcardsign;
|
||||
mod pgpcarddecrypt;
|
||||
mod piv;
|
||||
mod chall;
|
||||
mod challconfig;
|
||||
@@ -32,6 +33,7 @@ fn inner_main() -> CommandError {
|
||||
Box::new(pgp::CommandImpl),
|
||||
Box::new(pgpcardlist::CommandImpl),
|
||||
Box::new(pgpcardsign::CommandImpl),
|
||||
Box::new(pgpcarddecrypt::CommandImpl),
|
||||
Box::new(piv::CommandImpl),
|
||||
Box::new(chall::CommandImpl),
|
||||
Box::new(challconfig::CommandImpl),
|
||||
|
||||
@@ -18,7 +18,7 @@ impl Command for CommandImpl {
|
||||
|
||||
fn subcommand<'a>(&self) -> App<'a, 'a> {
|
||||
SubCommand::with_name(self.name()).about("OpenPGP Card List subcommand")
|
||||
.arg(Arg::with_name("in").long("in").takes_value(true).help("File input"))
|
||||
.arg(Arg::with_name("in").short("i").long("in").takes_value(true).help("File input"))
|
||||
.arg(Arg::with_name("detail").long("detail").help("Detail output"))
|
||||
.arg(Arg::with_name("json").long("json").help("JSON output"))
|
||||
}
|
||||
|
||||
61
src/pgpcarddecrypt.rs
Normal file
61
src/pgpcarddecrypt.rs
Normal file
@@ -0,0 +1,61 @@
|
||||
use clap::{ArgMatches, SubCommand, App, Arg};
|
||||
use crate::cmd::{Command, CommandError};
|
||||
use openpgp_card::DecryptMe;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
pub struct CommandImpl;
|
||||
|
||||
impl Command for CommandImpl {
|
||||
fn name(&self) -> &str { "pgp-card-decrypt" }
|
||||
|
||||
fn subcommand<'a>(&self) -> App<'a, 'a> {
|
||||
SubCommand::with_name(self.name()).about("OpenPGP Card List subcommand")
|
||||
.arg(Arg::with_name("pass").short("p").long("pass").takes_value(true).default_value("123456").help("OpenPGP card password"))
|
||||
.arg(Arg::with_name("cipher").short("c").long("cipher").takes_value(true).help("Cipher text HEX"))
|
||||
.arg(Arg::with_name("cipher-base64").short("b").long("cipher-base64").takes_value(true).help("Cipher text base64"))
|
||||
.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 pass = sub_arg_matches.value_of("pass");
|
||||
let pass = match pass {
|
||||
Some(p) => p,
|
||||
None => return simple_error!("Pass must be assigned"),
|
||||
};
|
||||
let cipher = sub_arg_matches.value_of("cipher");
|
||||
let cipher_base64 = sub_arg_matches.value_of("cipher-base64");
|
||||
|
||||
let mut json = BTreeMap::<&'_ str, String>::new();
|
||||
|
||||
let cipher_bytes = if let Some(cipher) = cipher {
|
||||
opt_result!(hex::decode(cipher), "Decode cipher failed: {}")
|
||||
} else if let Some(cipher_base64) = cipher_base64 {
|
||||
opt_result!(base64::decode(cipher_base64), "Decode cipher-base64 failed: {}")
|
||||
} else {
|
||||
return simple_error!("cipher or cipher-base64 must assign one");
|
||||
};
|
||||
|
||||
let user = crate::pgpcardutil::get_card_user_sw1_82(pass)?;
|
||||
let text = user.decrypt(DecryptMe::RSA(&cipher_bytes))?;
|
||||
success!("Clear text HEX: {}", hex::encode(&text));
|
||||
success!("Clear text base64: {}", base64::encode(&text));
|
||||
success!("Clear text UTF-8: {}", String::from_utf8_lossy(&text));
|
||||
if json_output {
|
||||
json.insert("cipher_hex", hex::encode(&cipher_bytes));
|
||||
json.insert("cipher_base64", base64::encode(&cipher_bytes));
|
||||
json.insert("text_hex", hex::encode(&text));
|
||||
json.insert("text_utf8", String::from_utf8_lossy(&text).to_string());
|
||||
}
|
||||
|
||||
|
||||
if json_output {
|
||||
println!("{}", serde_json::to_string_pretty(&json).unwrap());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -11,10 +11,10 @@ impl Command for CommandImpl {
|
||||
|
||||
fn subcommand<'a>(&self) -> App<'a, 'a> {
|
||||
SubCommand::with_name(self.name()).about("OpenPGP Card List subcommand")
|
||||
.arg(Arg::with_name("pass").long("pass").takes_value(true).default_value("123456").help("OpenPGP card password"))
|
||||
.arg(Arg::with_name("sha256").long("sha256").takes_value(true).help("Digest SHA256"))
|
||||
.arg(Arg::with_name("sha384").long("sha384").takes_value(true).help("Digest SHA384"))
|
||||
.arg(Arg::with_name("sha512").long("sha512").takes_value(true).help("Digest SHA512"))
|
||||
.arg(Arg::with_name("pass").short("p").long("pass").takes_value(true).default_value("123456").help("OpenPGP card password"))
|
||||
.arg(Arg::with_name("sha256").short("2").long("sha256").takes_value(true).help("Digest SHA256 HEX"))
|
||||
.arg(Arg::with_name("sha384").short("3").long("sha384").takes_value(true).help("Digest SHA384 HEX"))
|
||||
.arg(Arg::with_name("sha512").short("5").long("sha512").takes_value(true).help("Digest SHA512 HEX"))
|
||||
.arg(Arg::with_name("json").long("json").help("JSON output"))
|
||||
}
|
||||
|
||||
|
||||
@@ -18,3 +18,20 @@ pub fn get_card_user_sw1_81(pass: &str) -> XResult<OpenPGPCardUser> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_card_user_sw1_82(pass: &str) -> XResult<OpenPGPCardUser> {
|
||||
match OpenPGPCard::list_cards() {
|
||||
Ok(list) => {
|
||||
// pw1_82 for decrypt
|
||||
// PKCSv1.5
|
||||
if list.is_empty() {
|
||||
return simple_error!("Cannot find any card");
|
||||
}
|
||||
match list.into_iter().next().unwrap().verify_pw1_82(pass) {
|
||||
Result::Ok(user) => Ok(user),
|
||||
Result::Err(_) => simple_error!("Verify pw1_82 OpenPGP card failed"),
|
||||
}
|
||||
}
|
||||
Err(e) => simple_error!("Read OpenPGP card failed: {}", e),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,8 +15,8 @@ impl Command for CommandImpl {
|
||||
|
||||
fn subcommand<'a>(&self) -> App<'a, 'a> {
|
||||
SubCommand::with_name(self.name()).about("Register subcommand")
|
||||
.arg(Arg::with_name("app-id").long("app-id").default_value("https://example.com").help("App id"))
|
||||
.arg(Arg::with_name("timeout").long("timeout").default_value("10").help("Timeout in seconds"))
|
||||
.arg(Arg::with_name("app-id").short("a").long("app-id").default_value("https://example.com").help("App id"))
|
||||
.arg(Arg::with_name("timeout").short("t").long("timeout").default_value("10").help("Timeout in seconds"))
|
||||
.arg(Arg::with_name("json").long("json").help("JSON output"))
|
||||
}
|
||||
|
||||
|
||||
@@ -14,9 +14,9 @@ impl Command for CommandImpl {
|
||||
fn name(&self) -> &str { "sign" }
|
||||
fn subcommand<'a>(&self) -> App<'a, 'a> {
|
||||
SubCommand::with_name(self.name()).about("Sign subcommand")
|
||||
.arg(Arg::with_name("app-id").long("app-id").default_value("https://example.com").help("App id"))
|
||||
.arg(Arg::with_name("timeout").long("timeout").default_value("10").help("Timeout in seconds"))
|
||||
.arg(Arg::with_name("key-handle").long("key-handle").takes_value(true).multiple(true).help("Key handle"))
|
||||
.arg(Arg::with_name("app-id").short("a").long("app-id").default_value("https://example.com").help("App id"))
|
||||
.arg(Arg::with_name("timeout").short("t").long("timeout").default_value("10").help("Timeout in seconds"))
|
||||
.arg(Arg::with_name("key-handle").short("k").long("key-handle").takes_value(true).multiple(true).help("Key handle"))
|
||||
}
|
||||
fn run(&self, _arg_matches: &ArgMatches, sub_arg_matches: &ArgMatches) -> CommandError {
|
||||
let app_id = sub_arg_matches.value_of("app-id").unwrap();
|
||||
|
||||
Reference in New Issue
Block a user