feat: 1.10.21, add hmac-encrypt, hmac-decrypt
This commit is contained in:
63
Cargo.lock
generated
63
Cargo.lock
generated
@@ -36,6 +36,30 @@ dependencies = [
|
|||||||
"opaque-debug",
|
"opaque-debug",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aes"
|
||||||
|
version = "0.8.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if 1.0.0",
|
||||||
|
"cipher 0.4.4",
|
||||||
|
"cpufeatures",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aes-gcm-stream"
|
||||||
|
version = "0.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d763ade72c376e5db452ec14f4c966fc907c036ef5cd2972a888e69fe2f811e5"
|
||||||
|
dependencies = [
|
||||||
|
"aes 0.8.4",
|
||||||
|
"cipher 0.4.4",
|
||||||
|
"ghash",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aho-corasick"
|
name = "aho-corasick"
|
||||||
version = "0.7.15"
|
version = "0.7.15"
|
||||||
@@ -487,8 +511,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "card-cli"
|
name = "card-cli"
|
||||||
version = "1.10.20"
|
version = "1.10.21"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"aes-gcm-stream",
|
||||||
"authenticator 0.3.1",
|
"authenticator 0.3.1",
|
||||||
"base64 0.21.7",
|
"base64 0.21.7",
|
||||||
"bech32",
|
"bech32",
|
||||||
@@ -1339,6 +1364,16 @@ dependencies = [
|
|||||||
"windows-targets 0.52.6",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ghash"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1"
|
||||||
|
dependencies = [
|
||||||
|
"opaque-debug",
|
||||||
|
"polyval",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gimli"
|
name = "gimli"
|
||||||
version = "0.24.0"
|
version = "0.24.0"
|
||||||
@@ -2662,6 +2697,18 @@ version = "0.3.31"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
|
checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "polyval"
|
||||||
|
version = "0.6.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if 1.0.0",
|
||||||
|
"cpufeatures",
|
||||||
|
"opaque-debug",
|
||||||
|
"universal-hash",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "powerfmt"
|
name = "powerfmt"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
@@ -3565,7 +3612,7 @@ version = "0.13.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "752ad8923d32fb5c117b8a9983266e294edc072401133720aa9af3959d63248d"
|
checksum = "752ad8923d32fb5c117b8a9983266e294edc072401133720aa9af3959d63248d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aes",
|
"aes 0.7.5",
|
||||||
"authenticator 0.4.1",
|
"authenticator 0.4.1",
|
||||||
"base64 0.13.1",
|
"base64 0.13.1",
|
||||||
"bcrypt-pbkdf",
|
"bcrypt-pbkdf",
|
||||||
@@ -4199,6 +4246,16 @@ version = "0.2.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
|
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "universal-hash"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea"
|
||||||
|
dependencies = [
|
||||||
|
"crypto-common",
|
||||||
|
"subtle",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "untrusted"
|
name = "untrusted"
|
||||||
version = "0.7.1"
|
version = "0.7.1"
|
||||||
@@ -4752,7 +4809,7 @@ version = "0.9.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ff64094218f27836b8683bd93fa7f257475d217449eb7629746fa8eaee068eee"
|
checksum = "ff64094218f27836b8683bd93fa7f257475d217449eb7629746fa8eaee068eee"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aes",
|
"aes 0.7.5",
|
||||||
"bitflags 1.3.2",
|
"bitflags 1.3.2",
|
||||||
"block-modes",
|
"block-modes",
|
||||||
"hmac 0.11.0",
|
"hmac 0.11.0",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "card-cli"
|
name = "card-cli"
|
||||||
version = "1.10.20"
|
version = "1.10.21"
|
||||||
authors = ["Hatter Jiang <jht5945@gmail.com>"]
|
authors = ["Hatter Jiang <jht5945@gmail.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
@@ -52,6 +52,7 @@ der-parser = "9.0"
|
|||||||
sshcerts = "0.13"
|
sshcerts = "0.13"
|
||||||
swift-rs = { version = "1.0.7", optional = true }
|
swift-rs = { version = "1.0.7", optional = true }
|
||||||
regex = "1.4.6"
|
regex = "1.4.6"
|
||||||
|
aes-gcm-stream = "0.2.4"
|
||||||
#lazy_static = "1.4.0"
|
#lazy_static = "1.4.0"
|
||||||
#ssh-key = "0.4.0"
|
#ssh-key = "0.4.0"
|
||||||
#ctap-hid-fido2 = "2.1.3"
|
#ctap-hid-fido2 = "2.1.3"
|
||||||
|
|||||||
@@ -1,10 +1,6 @@
|
|||||||
use std::ops::Deref;
|
|
||||||
|
|
||||||
use clap::{App, Arg, ArgMatches, SubCommand};
|
use clap::{App, Arg, ArgMatches, SubCommand};
|
||||||
use rust_util::util_clap::{Command, CommandError};
|
use rust_util::util_clap::{Command, CommandError};
|
||||||
use rust_util::util_msg;
|
use rust_util::util_msg;
|
||||||
use yubico_manager::config::{Config, Mode, Slot};
|
|
||||||
use yubico_manager::Yubico;
|
|
||||||
|
|
||||||
use crate::hmacutil;
|
use crate::hmacutil;
|
||||||
|
|
||||||
@@ -29,28 +25,8 @@ impl Command for CommandImpl {
|
|||||||
if json_output { util_msg::set_logger_std_out(false); }
|
if json_output { util_msg::set_logger_std_out(false); }
|
||||||
|
|
||||||
let challenge_bytes = hmacutil::get_challenge_bytes(sub_arg_matches)?;
|
let challenge_bytes = hmacutil::get_challenge_bytes(sub_arg_matches)?;
|
||||||
|
let hmac_result = hmacutil::compute_yubikey_hmac(&challenge_bytes)?;
|
||||||
let mut yubi = Yubico::new();
|
hmacutil::output_hmac_result(sub_arg_matches, json_output, challenge_bytes, &hmac_result);
|
||||||
let device = match yubi.find_yubikey() {
|
|
||||||
Ok(device) => device,
|
|
||||||
Err(_) => {
|
|
||||||
warning!("YubiKey not found");
|
|
||||||
return Ok(Some(1));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
success!("Found key, Vendor ID: {:?}, Product ID: {:?}", device.vendor_id, device.product_id);
|
|
||||||
let config = Config::default()
|
|
||||||
.set_vendor_id(device.vendor_id)
|
|
||||||
.set_product_id(device.product_id)
|
|
||||||
.set_variable_size(true)
|
|
||||||
.set_mode(Mode::Sha1)
|
|
||||||
.set_slot(Slot::Slot2);
|
|
||||||
|
|
||||||
// In HMAC Mode, the result will always be the SAME for the SAME provided challenge
|
|
||||||
let hmac_result = opt_result!(yubi.challenge_response_hmac(&challenge_bytes, config), "Challenge HMAC failed: {}");
|
|
||||||
|
|
||||||
hmacutil::output_hmac_result(sub_arg_matches, json_output, challenge_bytes, hmac_result.deref());
|
|
||||||
|
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|||||||
49
src/cmd_hmacdecrypt.rs
Normal file
49
src/cmd_hmacdecrypt.rs
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
use clap::{App, Arg, ArgMatches, SubCommand};
|
||||||
|
use rust_util::util_clap::{Command, CommandError};
|
||||||
|
use rust_util::util_msg;
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
|
use crate::hmacutil;
|
||||||
|
|
||||||
|
pub struct CommandImpl;
|
||||||
|
|
||||||
|
impl Command for CommandImpl {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"hmac-decrypt"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn subcommand<'a>(&self) -> App<'a, 'a> {
|
||||||
|
SubCommand::with_name(self.name())
|
||||||
|
.about("Yubikey HMAC decrypt")
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("ciphertext")
|
||||||
|
.long("ciphertext")
|
||||||
|
.takes_value(true)
|
||||||
|
.help("Ciphertext"),
|
||||||
|
)
|
||||||
|
.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 {
|
||||||
|
util_msg::set_logger_std_out(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
let ciphertext = sub_arg_matches.value_of("ciphertext").unwrap();
|
||||||
|
let plaintext = hmacutil::hmac_decrypt_to_string(&ciphertext)?;
|
||||||
|
|
||||||
|
if json_output {
|
||||||
|
let mut json = BTreeMap::<&'_ str, String>::new();
|
||||||
|
json.insert("plaintext", plaintext);
|
||||||
|
println!(
|
||||||
|
"{}",
|
||||||
|
serde_json::to_string_pretty(&json).expect("Convert to JSON failed!")
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
success!("Plaintext: {}", plaintext);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
49
src/cmd_hmacencrypt.rs
Normal file
49
src/cmd_hmacencrypt.rs
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
use clap::{App, Arg, ArgMatches, SubCommand};
|
||||||
|
use rust_util::util_clap::{Command, CommandError};
|
||||||
|
use rust_util::util_msg;
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
|
use crate::hmacutil;
|
||||||
|
|
||||||
|
pub struct CommandImpl;
|
||||||
|
|
||||||
|
impl Command for CommandImpl {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"hmac-encrypt"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn subcommand<'a>(&self) -> App<'a, 'a> {
|
||||||
|
SubCommand::with_name(self.name())
|
||||||
|
.about("Yubikey HMAC encrypt")
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("plaintext")
|
||||||
|
.long("plaintext")
|
||||||
|
.takes_value(true)
|
||||||
|
.help("Plaintext"),
|
||||||
|
)
|
||||||
|
.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 {
|
||||||
|
util_msg::set_logger_std_out(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
let plaintext = sub_arg_matches.value_of("plaintext").unwrap();
|
||||||
|
let hmac_encrypt_ciphertext = hmacutil::hmac_encrypt_from_string(plaintext)?;
|
||||||
|
|
||||||
|
if json_output {
|
||||||
|
let mut json = BTreeMap::<&'_ str, String>::new();
|
||||||
|
json.insert("ciphertext", hmac_encrypt_ciphertext);
|
||||||
|
println!(
|
||||||
|
"{}",
|
||||||
|
serde_json::to_string_pretty(&json).expect("Convert to JSON failed!")
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
success!("HMAC encrypt ciphertext: {}", hmac_encrypt_ciphertext);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,7 +11,7 @@ use yubikey::piv::{sign_data, AlgorithmId, SlotId};
|
|||||||
use yubikey::{Certificate, YubiKey};
|
use yubikey::{Certificate, YubiKey};
|
||||||
|
|
||||||
use crate::ecdsautil::parse_ecdsa_to_rs;
|
use crate::ecdsautil::parse_ecdsa_to_rs;
|
||||||
use crate::{cmd_signjwt, digest, ecdsautil, pivutil, rsautil, util};
|
use crate::{cmd_signjwt, digest, ecdsautil, hmacutil, pivutil, rsautil, util};
|
||||||
|
|
||||||
const SEPARATOR: &str = ".";
|
const SEPARATOR: &str = ".";
|
||||||
|
|
||||||
@@ -45,6 +45,7 @@ impl Command for CommandImpl {
|
|||||||
sub_arg_matches.value_of("private-key"),
|
sub_arg_matches.value_of("private-key"),
|
||||||
"Private key PKCS#8 DER base64 encoded or PEM"
|
"Private key PKCS#8 DER base64 encoded or PEM"
|
||||||
);
|
);
|
||||||
|
let private_key = hmacutil::try_hmac_decrypt_to_string(private_key)?;
|
||||||
|
|
||||||
let key_id = sub_arg_matches.value_of("key-id");
|
let key_id = sub_arg_matches.value_of("key-id");
|
||||||
let claims = sub_arg_matches.values_of("claims");
|
let claims = sub_arg_matches.values_of("claims");
|
||||||
@@ -117,7 +118,7 @@ impl Command for CommandImpl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let token_string = sign_jwt(private_key, header, &payload, &jwt_claims)?;
|
let token_string = sign_jwt(&private_key, header, &payload, &jwt_claims)?;
|
||||||
debugging!("Singed JWT: {}", token_string);
|
debugging!("Singed JWT: {}", token_string);
|
||||||
if json_output {
|
if json_output {
|
||||||
json.insert("token", token_string.clone());
|
json.insert("token", token_string.clone());
|
||||||
|
|||||||
@@ -1,9 +1,100 @@
|
|||||||
use std::collections::BTreeMap;
|
|
||||||
|
|
||||||
use clap::ArgMatches;
|
use clap::ArgMatches;
|
||||||
use rust_util::XResult;
|
use rust_util::XResult;
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
use std::ops::Deref;
|
||||||
|
use aes_gcm_stream::{Aes256GcmStreamDecryptor, Aes256GcmStreamEncryptor};
|
||||||
|
use rand::random;
|
||||||
|
use yubico_manager::config::{Config, Mode, Slot};
|
||||||
use yubico_manager::hmacmode::HmacKey;
|
use yubico_manager::hmacmode::HmacKey;
|
||||||
use yubico_manager::sec::hmac_sha1;
|
use yubico_manager::sec::hmac_sha1;
|
||||||
|
use yubico_manager::Yubico;
|
||||||
|
use crate::digest::{copy_sha256, sha256, sha256_bytes};
|
||||||
|
use crate::util::{base64_decode, base64_encode};
|
||||||
|
|
||||||
|
const HMAC_ENC_PREFIX: &str = "hmac_enc:";
|
||||||
|
|
||||||
|
// hmac encrypt, format: hmac_enc:<HMAC-NONCE>:<AES-GCM-NONCE>:<ENCRYPTED>
|
||||||
|
pub fn hmac_encrypt_from_string(plaintext: &str) -> XResult<String> {
|
||||||
|
hmac_encrypt(plaintext.as_bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn hmac_encrypt(plaintext: &[u8]) -> XResult<String> {
|
||||||
|
let hmac_nonce: [u8; 8] = random();
|
||||||
|
let aes_gcm_nonce: [u8; 16] = random();
|
||||||
|
|
||||||
|
let hmac_key = compute_yubikey_hmac(&hmac_nonce)?;
|
||||||
|
let key = copy_sha256(&sha256_bytes(&hmac_key))?;
|
||||||
|
|
||||||
|
let mut encryptor = Aes256GcmStreamEncryptor::new(key, &aes_gcm_nonce);
|
||||||
|
let mut ciphertext = encryptor.update(plaintext);
|
||||||
|
let (final_part, tag) = encryptor.finalize();
|
||||||
|
ciphertext.extend_from_slice(&final_part);
|
||||||
|
ciphertext.extend_from_slice(&tag);
|
||||||
|
|
||||||
|
Ok(format!("{}{}:{}:{}",
|
||||||
|
HMAC_ENC_PREFIX,
|
||||||
|
hex::encode(&hmac_nonce),
|
||||||
|
hex::encode(&aes_gcm_nonce),
|
||||||
|
base64_encode(&ciphertext)
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_hmac_encrypted(ciphertext: &str) -> bool {
|
||||||
|
ciphertext.starts_with(HMAC_ENC_PREFIX)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_hmac_decrypt_to_string(ciphertext: &str) -> XResult<String> {
|
||||||
|
if is_hmac_encrypted(ciphertext) {
|
||||||
|
hmac_decrypt_to_string(ciphertext)
|
||||||
|
} else {
|
||||||
|
Ok(ciphertext.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn hmac_decrypt_to_string(ciphertext: &str) -> XResult<String> {
|
||||||
|
let plaintext = hmac_decrypt(ciphertext)?;
|
||||||
|
Ok(String::from_utf8(plaintext)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn hmac_decrypt(ciphertext: &str) -> XResult<Vec<u8>> {
|
||||||
|
if !is_hmac_encrypted(ciphertext) {
|
||||||
|
return simple_error!("Invalid ciphertext: {}", ciphertext);
|
||||||
|
}
|
||||||
|
let parts = ciphertext.split(":").collect::<Vec<_>>();
|
||||||
|
let hmac_nonce = hex::decode(parts[1])?;
|
||||||
|
let aes_gcm_nonce = hex::decode(parts[2])?;
|
||||||
|
let ciphertext = base64_decode(parts[3])?;
|
||||||
|
|
||||||
|
let hmac_key = compute_yubikey_hmac(&hmac_nonce)?;
|
||||||
|
let key = copy_sha256(&sha256_bytes(&hmac_key))?;
|
||||||
|
|
||||||
|
let mut decryptor = Aes256GcmStreamDecryptor::new(key, &aes_gcm_nonce);
|
||||||
|
let mut plaintext = decryptor.update(&ciphertext);
|
||||||
|
let final_part = decryptor.finalize()?;
|
||||||
|
plaintext.extend_from_slice(&final_part);
|
||||||
|
|
||||||
|
Ok(plaintext)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn compute_yubikey_hmac(challenge_bytes: &[u8]) -> XResult<Vec<u8>> {
|
||||||
|
let mut yubi = Yubico::new();
|
||||||
|
let device = match yubi.find_yubikey() {
|
||||||
|
Ok(device) => device,
|
||||||
|
Err(_) => {
|
||||||
|
return simple_error!("YubiKey not found");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
debugging!("Found key, Vendor ID: {:?}, Product ID: {:?}", device.vendor_id, device.product_id);
|
||||||
|
let config = Config::default()
|
||||||
|
.set_vendor_id(device.vendor_id)
|
||||||
|
.set_product_id(device.product_id)
|
||||||
|
.set_variable_size(true)
|
||||||
|
.set_mode(Mode::Sha1)
|
||||||
|
.set_slot(Slot::Slot2);
|
||||||
|
|
||||||
|
let hmac_result = opt_result!(yubi.challenge_response_hmac(&challenge_bytes, config), "Challenge HMAC failed: {}");
|
||||||
|
Ok(hmac_result.deref().to_vec())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_challenge_bytes(sub_arg_matches: &ArgMatches) -> XResult<Vec<u8>> {
|
pub fn get_challenge_bytes(sub_arg_matches: &ArgMatches) -> XResult<Vec<u8>> {
|
||||||
let challenge_bytes: Vec<u8> = if let Some(challenge) = sub_arg_matches.value_of("challenge") {
|
let challenge_bytes: Vec<u8> = if let Some(challenge) = sub_arg_matches.value_of("challenge") {
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ mod cmd_chall;
|
|||||||
mod cmd_challconfig;
|
mod cmd_challconfig;
|
||||||
mod cmd_ecverify;
|
mod cmd_ecverify;
|
||||||
mod cmd_hmac_sha1;
|
mod cmd_hmac_sha1;
|
||||||
|
mod cmd_hmacencrypt;
|
||||||
|
mod cmd_hmacdecrypt;
|
||||||
mod cmd_list;
|
mod cmd_list;
|
||||||
#[cfg(feature = "with-sequoia-openpgp")]
|
#[cfg(feature = "with-sequoia-openpgp")]
|
||||||
mod cmd_pgp;
|
mod cmd_pgp;
|
||||||
@@ -101,6 +103,8 @@ fn inner_main() -> CommandError {
|
|||||||
Box::new(cmd_list::CommandImpl),
|
Box::new(cmd_list::CommandImpl),
|
||||||
Box::new(cmd_chall::CommandImpl),
|
Box::new(cmd_chall::CommandImpl),
|
||||||
Box::new(cmd_hmac_sha1::CommandImpl),
|
Box::new(cmd_hmac_sha1::CommandImpl),
|
||||||
|
Box::new(cmd_hmacencrypt::CommandImpl),
|
||||||
|
Box::new(cmd_hmacdecrypt::CommandImpl),
|
||||||
Box::new(cmd_challconfig::CommandImpl),
|
Box::new(cmd_challconfig::CommandImpl),
|
||||||
Box::new(cmd_rsaencrypt::CommandImpl),
|
Box::new(cmd_rsaencrypt::CommandImpl),
|
||||||
Box::new(cmd_rsadecrypt::CommandImpl),
|
Box::new(cmd_rsadecrypt::CommandImpl),
|
||||||
|
|||||||
Reference in New Issue
Block a user