Previously, we ran our first iteration of the cli application by setting up the project and adding commands.
In this post, we will cover our first command, generate,
that generates a secret containing the key and the IV (initial-value) to the output file given as a flag for this command.
Implementing Generate Command Logic
Create a new file generate.rs
and start adding logic to generate a key and an IV (initial-value).
Install a new dependency for generating random values by running the below command.
cargo add rand
Import newly added dependency to main.rs
file. And import generate.rs
in main.rs
.
Let us add logic to the generate.rs
file:
Here, we are using a crate called serde for serialization and deserialization.
Add serde dependencies to Cargo.toml
file.
serde_json = "1.0.85"
serde = "1.0.85"
serde_derive = "1.0.85"
More on serde
Define a struct Secret with two members key and initial-value both are of type String.
Now implement a function new for Secret struct. This function is used to generate a Secret by encoding the key and initial-value to base64.
Using rand crate a key and an initial value are generated from random values. Both key and initial-value are of length 16. Then the secret is written to the output file path which is received as user input.
use super::*;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Secret {
key: String,
inital_value: String,
}
impl Secret {
pub fn new(out_path: String) {
let mut key = [0u8; 16];
thread_rng().fill_bytes(&mut key[..]);
let mut inital_value = [0u8; 16];
thread_rng().fill_bytes(&mut inital_value[..]);
let secret = Secret {
key: base64::encode(key),
inital_value: base64::encode(inital_value),
};
let secret = to_vec(&secret).unwrap();
let mut file = File::create(out_path).unwrap();
file.write_all(&secret).unwrap();
println!("Secret Generated Successfully")
}
Fixing up main.rs
file to generate the secret Keystore.
use clap::{Parser, Subcommand};
use generate::Secret;
use rand::*;
mod commands;
use commands::Cryptifer;
mod generate;
use serde_derive::{Deserialize, Serialize};
use serde_json::to_vec;
use std::fs::File;
use std::io::Write;
fn main() {
let cryptifer = Cryptifer::parse();
match cryptifer.command {
commands::Commands::Generate { output_path } => {
Secret::new(output_path);
}
commands::Commands::Encrypt {
file_path: _,
key_path: _,
} => todo!(),
commands::Commands::Decrypt {
encrypted_file: _,
key_path: _,
} => todo!(),
}
}
Running Your First Command
cargo run generate -o Keystore.secret
That generates the secret file with the key and Initial-value.
Wrapping Things Up
In this post, we achieved our milestone by completing the first command of our CLI application. This command generates key and initial-value from the random values. Then we encoded those values into base64 and stored them in a file. If you run into any issues with any part of this tutorial, please leave a comment so that I can update the content to be more clear. If you like this post, please follow me on Hashnode and subscribe to my newsletter for future updates.