summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStuart Stock <stuart@int08h.com>2019-02-01 18:15:42 -0600
committerStuart Stock <stuart@int08h.com>2019-02-01 18:15:42 -0600
commit9d7d18b8593a2ffd8426b94c2469709cf48996cb (patch)
treefb765e92bbb098f0a06ea3d6c6ffda8e81a15995
parent9515a562754b81a3d499f6ab39b1b4810076ff2c (diff)
downloadroughenough-9d7d18b8593a2ffd8426b94c2469709cf48996cb.zip
Add decryption to 'roughenough-kms'
-rw-r--r--CHANGELOG.md4
-rw-r--r--Cargo.toml2
-rw-r--r--src/bin/roughenough-kms.rs108
-rw-r--r--src/lib.rs2
4 files changed, 77 insertions, 39 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 86b8175..228f110 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+## Version 1.1.3
+
+* Add decrypt option to `roughenough-kms`
+
## Version 1.1.2
* Add client request statistics tracking.
diff --git a/Cargo.toml b/Cargo.toml
index d7e75ca..f9f07fd 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "roughenough"
-version = "1.1.2"
+version = "1.1.3"
repository = "https://github.com/int08h/roughenough"
authors = ["Stuart Stock <stuart@int08h.com>", "Aaron Hill <aa1ronham@gmail.com>"]
license = "Apache-2.0"
diff --git a/src/bin/roughenough-kms.rs b/src/bin/roughenough-kms.rs
index a5eaac1..f7b012e 100644
--- a/src/bin/roughenough-kms.rs
+++ b/src/bin/roughenough-kms.rs
@@ -13,22 +13,36 @@
// limitations under the License.
//!
-//! CLI used to encrypt the Roughenough long-term key using one of the KMS implementations
+//! CLI used to encrypt and decrypt the Roughenough long-term key
+//! using one of the KMS implementations
//!
#[macro_use]
extern crate log;
use clap::{App, Arg};
+
+#[allow(unused_imports)]
+use roughenough::kms::{EnvelopeEncryption, KmsProvider};
use roughenough::roughenough_version;
-#[cfg(feature = "awskms")]
-fn aws_kms(kms_key: &str, plaintext_seed: &[u8]) {
- use roughenough::kms::{AwsKms, EnvelopeEncryption};
+#[cfg(not(any(feature = "awskms", feature = "gcpkms")))]
+fn encrypt_seed(_: &str, _: &str) {
+ // main() will exit if kms support is not enabled, making this unreachable
+ unreachable!()
+}
+
+#[cfg(any(feature = "awskms", feature = "gcpkms"))]
+fn encrypt_seed(kms_key: &str, hex_seed: &str) {
+ let kms_client = get_kms(kms_key);
- let client = AwsKms::from_arn(kms_key).unwrap();
+ let plaintext_seed = hex::decode(hex_seed).expect("Error decoding hex seed value");
+
+ if plaintext_seed.len() != 32 {
+ panic!("Seed must be 32 bytes long; provided seed is {}", plaintext_seed.len());
+ }
- match EnvelopeEncryption::encrypt_seed(&client, &plaintext_seed) {
+ match EnvelopeEncryption::encrypt_seed(&kms_client, &plaintext_seed) {
Ok(encrypted_blob) => {
println!("kms_protection: \"{}\"", kms_key);
println!("seed: {}", hex::encode(&encrypted_blob));
@@ -39,16 +53,20 @@ fn aws_kms(kms_key: &str, plaintext_seed: &[u8]) {
}
}
-#[cfg(feature = "gcpkms")]
-fn gcp_kms(kms_key: &str, plaintext_seed: &[u8]) {
- use roughenough::kms::{EnvelopeEncryption, GcpKms};
+#[cfg(not(any(feature = "awskms", feature = "gcpkms")))]
+fn decrypt_blob(_: &str, _: &str) {
+ // main() will exit if kms support is not enabled, making this unreachable
+ unreachable!()
+}
- let client = GcpKms::from_resource_id(kms_key).unwrap();
+#[cfg(any(feature = "awskms", feature = "gcpkms"))]
+fn decrypt_blob(kms_key: &str, hex_blob: &str) {
+ let kms_client = get_kms(kms_key);
+ let ciphertext = hex::decode(hex_blob).expect("Error decoding hex blob value");
- match EnvelopeEncryption::encrypt_seed(&client, &plaintext_seed) {
- Ok(encrypted_blob) => {
- println!("kms_protection: \"{}\"", kms_key);
- println!("seed: {}", hex::encode(&encrypted_blob));
+ match EnvelopeEncryption::decrypt_seed(&kms_client, ciphertext.as_ref()) {
+ Ok(plaintext) => {
+ println!("{}", hex::encode(plaintext));
}
Err(e) => {
error!("Error: {:?}", e);
@@ -56,6 +74,18 @@ fn gcp_kms(kms_key: &str, plaintext_seed: &[u8]) {
}
}
+#[cfg(feature = "awskms")]
+fn get_kms(kms_key: &str) -> impl KmsProvider {
+ use roughenough::kms::AwsKms;
+ AwsKms::from_arn(kms_key).unwrap()
+}
+
+#[cfg(feature = "gcpkms")]
+fn get_kms(kms_key: &str) -> impl KmsProvider {
+ use roughenough::kms::GcpKms;
+ GcpKms::from_resource_id(kms_key).unwrap()
+}
+
#[allow(unused_variables)]
pub fn main() {
use log::Level;
@@ -64,45 +94,49 @@ pub fn main() {
let matches = App::new("roughenough-kms")
.version(roughenough_version().as_ref())
- .long_about("Encrypt a Roughenough server's long-term seed using a KMS")
+ .long_about("Encrypt and decrypt Roughenough long-term server seeds using a KMS")
.arg(
Arg::with_name("KEY_ID")
.short("k")
.long("kms-key")
.takes_value(true)
.required(true)
- .help("Identity of the KMS key to be used"),
+ .help("Identity of the KMS key to be used")
+ ).arg(
+ Arg::with_name("DECRYPT")
+ .short("d")
+ .long("decrypt")
+ .takes_value(true)
+ .required(false)
+ .help("Previously encrypted blob to decrypt to plaintext"),
).arg(
Arg::with_name("SEED")
.short("s")
.long("seed")
.takes_value(true)
- .required(true)
+ .required(false)
.help("32 byte hex seed for the server's long-term identity"),
).get_matches();
- let kms_key = matches.value_of("KEY_ID").unwrap();
- let plaintext_seed = matches
- .value_of("SEED")
- .map(|seed| hex::decode(seed).expect("Error parsing seed value"))
- .unwrap();
-
- if plaintext_seed.len() != 32 {
- error!(
- "Seed must be 32 bytes long; provided seed is {}",
- plaintext_seed.len()
- );
- return;
+ if !(cfg!(feature = "gcpkms") || cfg!(feature = "awskms")) {
+ warn!("KMS support was not compiled into this build; nothing to do.");
+ warn!("See the Roughenough documentation for information on KMS support.");
+ warn!(" https://github.com/int08h/roughenough/blob/master/doc/OPTIONAL-FEATURES.md");
+ return
}
- if cfg!(feature = "awskms") {
- #[cfg(feature = "awskms")]
- aws_kms(kms_key, &plaintext_seed);
- } else if cfg!(feature = "gcpkms") {
- #[cfg(feature = "gcpkms")]
- gcp_kms(kms_key, &plaintext_seed);
+ let kms_key = matches.value_of("KEY_ID").expect("Invalid KMS key id");
+
+ if matches.is_present("SEED") {
+ let hex_seed = matches.value_of("SEED").expect("Invalid seed value");
+ encrypt_seed(kms_key, hex_seed);
+
+ } else if matches.is_present("DECRYPT") {
+ let hex_blob = matches.value_of("DECRYPT").expect("Invalid blob value");
+ decrypt_blob(kms_key, hex_blob);
+
} else {
- warn!("KMS support was not compiled, nothing to do.");
- warn!("For information on KMS support see the Roughenough documentation.");
+ error!("Neither seed encryption (-s) or blob decryption (-d) was specified.");
+ error!("One of them is required.");
}
}
diff --git a/src/lib.rs b/src/lib.rs
index 9a21dfa..5cda7bc 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -75,7 +75,7 @@ pub use crate::message::RtMessage;
pub use crate::tag::Tag;
/// Version of Roughenough
-pub const VERSION: &str = "1.1.2";
+pub const VERSION: &str = "1.1.3";
/// Roughenough version string enriched with any compile-time optional features
pub fn roughenough_version() -> String {