...
This commit is contained in:
@@ -1,14 +1,100 @@
|
||||
pub fn add(left: u64, right: u64) -> u64 {
|
||||
left + right
|
||||
// In crates/libcryptoa/src/lib.rs
|
||||
use std::str::FromStr;
|
||||
use age::{Decryptor, Encryptor, x25519};
|
||||
use base64::{engine::general_purpose::STANDARD as B64, Engine as _};
|
||||
use ed25519_dalek::{Signature, Signer, SigningKey, Verifier, VerifyingKey};
|
||||
use secrecy::ExposeSecret;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum AsymmetricCryptoError {
|
||||
#[error("key parsing failed")]
|
||||
ParseKey,
|
||||
#[error("age crypto error: {0}")]
|
||||
Age(String),
|
||||
#[error("invalid utf-8 in plaintext")]
|
||||
Utf8,
|
||||
#[error("invalid signature length")]
|
||||
SignatureLen,
|
||||
#[error("signature verification failed")]
|
||||
Verify,
|
||||
#[error("base64 decoding failed: {0}")]
|
||||
Base64(#[from] base64::DecodeError),
|
||||
#[error("io error: {0}")]
|
||||
Io(#[from] std::io::Error),
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
fn parse_recipient(s: &str) -> Result<x25519::Recipient, AsymmetricCryptoError> {
|
||||
x25519::Recipient::from_str(s).map_err(|_| AsymmetricCryptoError::ParseKey)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_works() {
|
||||
let result = add(2, 2);
|
||||
assert_eq!(result, 4);
|
||||
fn parse_identity(s: &str) -> Result<x25519::Identity, AsymmetricCryptoError> {
|
||||
x25519::Identity::from_str(s).map_err(|_| AsymmetricCryptoError::ParseKey)
|
||||
}
|
||||
|
||||
fn parse_ed25519_signing_key(s: &str) -> Result<SigningKey, AsymmetricCryptoError> {
|
||||
let bytes = B64.decode(s)?;
|
||||
let key_bytes: [u8; 32] = bytes.try_into().map_err(|_| AsymmetricCryptoError::ParseKey)?;
|
||||
Ok(SigningKey::from_bytes(&key_bytes))
|
||||
}
|
||||
|
||||
fn parse_ed25519_verifying_key(s: &str) -> Result<VerifyingKey, AsymmetricCryptoError> {
|
||||
let bytes = B64.decode(s)?;
|
||||
let key_bytes: [u8; 32] = bytes.try_into().map_err(|_| AsymmetricCryptoError::ParseKey)?;
|
||||
VerifyingKey::from_bytes(&key_bytes).map_err(|_| AsymmetricCryptoError::ParseKey)
|
||||
}
|
||||
|
||||
pub fn gen_enc_keypair() -> (String, String) {
|
||||
let id = x25519::Identity::generate();
|
||||
let pk = id.to_public();
|
||||
(pk.to_string(), id.to_string().expose_secret().to_string())
|
||||
}
|
||||
|
||||
pub fn gen_sign_keypair() -> (String, String) {
|
||||
let signing_key = SigningKey::generate(&mut rand::rngs::OsRng);
|
||||
let verifying_key = signing_key.verifying_key();
|
||||
(B64.encode(verifying_key.to_bytes()), B64.encode(signing_key.to_bytes()))
|
||||
}
|
||||
|
||||
pub fn encrypt_b64(recipient_str: &str, msg: &str) -> Result<String, AsymmetricCryptoError> {
|
||||
let recipient = parse_recipient(recipient_str)?;
|
||||
let encryptor = Encryptor::with_recipients(vec![Box::new(recipient)])
|
||||
.ok_or_else(|| AsymmetricCryptoError::Age("Failed to create encryptor".into()))?;
|
||||
|
||||
let mut encrypted = vec![];
|
||||
let mut writer = encryptor.wrap_output(&mut encrypted)?;
|
||||
std::io::Write::write_all(&mut writer, msg.as_bytes())?;
|
||||
writer.finish()?;
|
||||
|
||||
Ok(B64.encode(encrypted))
|
||||
}
|
||||
|
||||
pub fn decrypt_b64(identity_str: &str, ct_b64: &str) -> Result<String, AsymmetricCryptoError> {
|
||||
let identity = parse_identity(identity_str)?;
|
||||
let ct = B64.decode(ct_b64)?;
|
||||
|
||||
let decryptor = Decryptor::new(&ct[..]).map_err(|e| AsymmetricCryptoError::Age(e.to_string()))?;
|
||||
|
||||
let mut decrypted = vec![];
|
||||
if let Decryptor::Recipients(d) = decryptor {
|
||||
let mut reader = d.decrypt(std::iter::once(&identity as &dyn age::Identity))
|
||||
.map_err(|e| AsymmetricCryptoError::Age(e.to_string()))?;
|
||||
std::io::Read::read_to_end(&mut reader, &mut decrypted)?;
|
||||
String::from_utf8(decrypted).map_err(|_| AsymmetricCryptoError::Utf8)
|
||||
} else {
|
||||
Err(AsymmetricCryptoError::Age("Passphrase decryption not supported".into()))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sign_b64(signing_secret_str: &str, msg: &str) -> Result<String, AsymmetricCryptoError> {
|
||||
let signing_key = parse_ed25519_signing_key(signing_secret_str)?;
|
||||
let signature = signing_key.sign(msg.as_bytes());
|
||||
Ok(B64.encode(signature.to_bytes()))
|
||||
}
|
||||
|
||||
pub fn verify_b64(verify_pub_str: &str, msg: &str, sig_b64: &str) -> Result<bool, AsymmetricCryptoError> {
|
||||
let verifying_key = parse_ed25519_verifying_key(verify_pub_str)?;
|
||||
let sig_bytes = B64.decode(sig_b64)?;
|
||||
let signature = Signature::from_slice(&sig_bytes).map_err(|_| AsymmetricCryptoError::SignatureLen)?;
|
||||
Ok(verifying_key.verify(msg.as_bytes(), &signature).is_ok())
|
||||
}
|
Reference in New Issue
Block a user