-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: ♻️ Add docs and move keygen functions to module
key_pair
.
- Loading branch information
1 parent
733f975
commit e07085f
Showing
6 changed files
with
105 additions
and
62 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
{ | ||
"cSpell.words": [ | ||
"smallvec", | ||
"Subpacket", | ||
"subpackets", | ||
"thiserror", | ||
"unhashed", | ||
"zeroize", | ||
"Zeroizing" | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,21 @@ | ||
//! Error types wrapper | ||
use std::io; | ||
|
||
use thiserror::Error; | ||
|
||
/// Error type | ||
#[derive(Debug, Error)] | ||
#[non_exhaustive] | ||
pub enum Error { | ||
/// Error propagated from [`io::Error`] | ||
#[error("IO error: {0}")] | ||
Io(#[from] io::Error), | ||
|
||
/// Error propagated from [`pgp::errors::Error`] | ||
#[error("PGP error: {0}")] | ||
Pgp(#[from] pgp::errors::Error), | ||
} | ||
|
||
/// Result type for use in the crate. | ||
pub type Result<T> = std::result::Result<T, Error>; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,90 +1,52 @@ | ||
//! Utilities for key generation. | ||
use std::path::Path; | ||
|
||
use pgp::{ | ||
crypto::{hash::HashAlgorithm, sym::SymmetricKeyAlgorithm}, | ||
types::{CompressionAlgorithm, KeyTrait, SecretKeyTrait as _}, | ||
KeyType, SecretKeyParamsBuilder, | ||
}; | ||
use smallvec::smallvec; | ||
use pgp::types::KeyTrait; | ||
use tokio::{ | ||
fs::{self, DirBuilder}, | ||
try_join, | ||
}; | ||
use zeroize::Zeroizing; | ||
|
||
use crate::{error::Result, key_pair::KeyPair, secret_file::write_secret_file}; | ||
use crate::{key_pair::KeyPair, secret_file::write_secret_file, Result}; | ||
|
||
/// Write a key pair generated from `name` and `email` to a given path, in armored form as RFC 4880. | ||
pub async fn write_key_pair(name: &str, email: &str, path: impl AsRef<Path>) -> Result<()> { | ||
let path = path.as_ref(); | ||
|
||
// Create output directory if not exist. | ||
DirBuilder::new().recursive(true).create(path).await?; | ||
|
||
let key_pair = gen_key_pair(name, email)?; | ||
let key_pair = KeyPair::generate(name, email)?; | ||
let signed_secret_key = key_pair.secret_key(); | ||
let signed_public_key = key_pair.public_key(); | ||
let keyid = &hex::encode_upper(&signed_secret_key.key_id().as_ref()[4..]); | ||
let key_id = &hex::encode_upper(&signed_secret_key.key_id().as_ref()[4..]); | ||
|
||
let secret_key = path.join(format!("{}_0x{}_SECRET.asc", name, keyid)); | ||
let public_key = path.join(format!("{}_0x{}_public.asc", name, keyid)); | ||
let secret_key = path.join(format!("{}_0x{}_SECRET.asc", name, key_id)); | ||
let public_key = path.join(format!("{}_0x{}_public.asc", name, key_id)); | ||
|
||
let secret_key_pem = Zeroizing::new(signed_secret_key.to_armored_bytes(None)?); | ||
let pub_key_pem = signed_public_key.to_armored_bytes(None)?; | ||
let secret_key_armored = Zeroizing::new(signed_secret_key.to_armored_bytes(None)?); | ||
let public_key_armored = signed_public_key.to_armored_bytes(None)?; | ||
|
||
try_join!( | ||
write_secret_file(&secret_key, &secret_key_pem), | ||
fs::write(&public_key, &pub_key_pem) | ||
write_secret_file(&secret_key, &secret_key_armored), | ||
fs::write(&public_key, &public_key_armored) | ||
)?; | ||
|
||
Ok(()) | ||
} | ||
|
||
pub(crate) fn gen_key_pair(name: &str, email: &str) -> Result<KeyPair> { | ||
let secret_key = SecretKeyParamsBuilder::default() | ||
// Set keygen params. | ||
.key_type(KeyType::EdDSA) | ||
.primary_user_id(format!("{} <{}>", name, email)) | ||
.preferred_symmetric_algorithms(smallvec![ | ||
SymmetricKeyAlgorithm::AES256, | ||
SymmetricKeyAlgorithm::AES192, | ||
SymmetricKeyAlgorithm::AES128, | ||
SymmetricKeyAlgorithm::TripleDES, | ||
]) | ||
.preferred_hash_algorithms(smallvec![ | ||
HashAlgorithm::SHA2_512, | ||
HashAlgorithm::SHA2_384, | ||
HashAlgorithm::SHA2_256, | ||
HashAlgorithm::SHA2_224, | ||
HashAlgorithm::SHA1 | ||
]) | ||
.preferred_compression_algorithms(smallvec![ | ||
CompressionAlgorithm::ZLIB, | ||
CompressionAlgorithm::BZip2, | ||
CompressionAlgorithm::ZIP | ||
]) | ||
.can_sign(true) | ||
.build() | ||
.expect("msg") | ||
.generate() | ||
.expect("Failed to generate a plain key."); | ||
let passwd_fn = String::new; | ||
let signed_secret_key = secret_key.sign(passwd_fn)?; | ||
let public_key = signed_secret_key.public_key(); | ||
let signed_public_key = public_key.sign(&signed_secret_key, passwd_fn)?; | ||
|
||
Ok(KeyPair::from_keys(signed_secret_key, signed_public_key)) | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use pgp::{types::KeyTrait, Deserializable, SignedSecretKey}; | ||
|
||
use super::{gen_key_pair, Result}; | ||
use crate::{key_pair::KeyPair, Result}; | ||
|
||
#[tokio::test] | ||
#[ignore = "Manual testing for file generation."] | ||
async fn test() -> Result<()> { | ||
let key_pair = gen_key_pair("DS", "[email protected]")?; | ||
let key_pair = KeyPair::generate("DS", "[email protected]")?; | ||
let (secret_key, public_key) = (key_pair.secret_key(), key_pair.public_key()); | ||
println!("{}", secret_key.to_armored_string(None)?); | ||
println!("{}", public_key.to_armored_string(None)?); | ||
|
@@ -95,18 +57,15 @@ mod tests { | |
#[tokio::test] | ||
#[ignore = "Manual testing for file parsing."] | ||
async fn extract_key_info() -> Result<()> { | ||
let secret_key_str = gen_key_pair("DS", "[email protected]")? | ||
let secret_key_str = KeyPair::generate("DS", "[email protected]")? | ||
.secret_key() | ||
.to_armored_string(None)?; | ||
|
||
let secret_key = SignedSecretKey::from_string(&secret_key_str)?.0; | ||
dbg!(&secret_key); | ||
let key_id = secret_key.key_id(); | ||
|
||
dbg!(&key_id); | ||
|
||
dbg!(&hex::encode_upper(&key_id.as_ref()[4..])); | ||
|
||
Ok(()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,10 @@ | ||
#![warn(missing_docs)] | ||
//! Cryptographic functions for the digital signature app. | ||
pub mod error; | ||
mod key_pair; | ||
pub mod keygen; | ||
mod secret_file; | ||
pub mod signing; | ||
|
||
pub use error::Result; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,15 @@ | ||
//! Utilities for signing files. | ||
use chrono::Utc; | ||
use pgp::{ | ||
packet::{SignatureConfigBuilder, SignatureType, Subpacket, SubpacketData}, | ||
types::{PublicKeyTrait, SecretKeyTrait}, | ||
Signature, | ||
}; | ||
|
||
use crate::error::Result; | ||
use crate::Result; | ||
|
||
/// Generate a signature of the given data. | ||
pub fn sign(data: &[u8], secret_key: &impl SecretKeyTrait) -> Result<Signature> { | ||
let now = Utc::now(); | ||
let sig_conf = SignatureConfigBuilder::default() | ||
|
@@ -23,18 +26,19 @@ pub fn sign(data: &[u8], secret_key: &impl SecretKeyTrait) -> Result<Signature> | |
Ok(sig_conf.sign(secret_key, String::new, data)?) | ||
} | ||
|
||
/// Verify a signature of the given data. | ||
pub fn verify(data: &[u8], public_key: &impl PublicKeyTrait, signature: &Signature) -> Result<()> { | ||
Ok(signature.verify(public_key, data)?) | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::{sign, verify, Result}; | ||
use crate::keygen::gen_key_pair; | ||
use crate::key_pair::KeyPair; | ||
|
||
#[test] | ||
fn test_sign() -> Result<()> { | ||
let key_pair = gen_key_pair("DS", "[email protected]")?; | ||
let key_pair = KeyPair::generate("DS", "[email protected]")?; | ||
let (secret_key, public_key) = (key_pair.secret_key(), key_pair.public_key()); | ||
let signature = sign(b"Hello", &secret_key)?; | ||
verify(b"Hello", &public_key, &signature)?; | ||
|
@@ -43,7 +47,7 @@ mod tests { | |
|
||
#[test] | ||
fn test_sign_error() -> Result<()> { | ||
let key_pair = gen_key_pair("DS", "[email protected]")?; | ||
let key_pair = KeyPair::generate("DS", "[email protected]")?; | ||
let (secret_key, public_key) = (key_pair.secret_key(), key_pair.public_key()); | ||
let signature = sign(b"Hello", &secret_key)?; | ||
eprintln!( | ||
|