159 lines
4.6 KiB
Rust
159 lines
4.6 KiB
Rust
//! Helpers to use cryptographic data types in nettext
|
|
|
|
pub use dryoc;
|
|
|
|
use dryoc::types::Bytes;
|
|
use dryoc::*;
|
|
|
|
use crate::dec;
|
|
use crate::enc;
|
|
|
|
const BM_HASH: &str = "h.b2";
|
|
|
|
const BM_SIGNATURE: &str = "sig.ed25519";
|
|
const BM_SIGN_KEYPAIR: &str = "sk.ed25519";
|
|
const BM_SIGN_PUBKEY: &str = "pk.ed25519";
|
|
|
|
// ---- types ----
|
|
|
|
#[derive(Eq, PartialEq, Clone, Debug)]
|
|
pub struct Hash(pub generichash::Hash);
|
|
|
|
#[derive(Eq, PartialEq, Clone, Debug)]
|
|
pub struct Signature(pub sign::Signature);
|
|
#[derive(Eq, PartialEq, Clone, Debug)]
|
|
pub struct SigningPublicKey(pub sign::PublicKey);
|
|
#[derive(PartialEq, Clone, Debug)]
|
|
pub struct SigningKeyPair(pub sign::SigningKeyPair<sign::PublicKey, sign::SecretKey>);
|
|
|
|
impl SigningKeyPair {
|
|
/// Return the public key of this keypair
|
|
pub fn public_key(&self) -> SigningPublicKey {
|
|
SigningPublicKey(self.0.public_key.clone())
|
|
}
|
|
}
|
|
|
|
// ---- encoding ----
|
|
|
|
impl enc::Encode for Hash {
|
|
fn term(&self) -> enc::Result<'_> {
|
|
enc::marked_bytes(BM_HASH, self.0.as_slice())
|
|
}
|
|
}
|
|
|
|
impl enc::Encode for Signature {
|
|
fn term(&self) -> enc::Result<'_> {
|
|
enc::marked_bytes(BM_SIGNATURE, self.0.as_slice())
|
|
}
|
|
}
|
|
|
|
impl enc::Encode for SigningPublicKey {
|
|
fn term(&self) -> enc::Result<'_> {
|
|
enc::marked_bytes(BM_SIGN_PUBKEY, self.0.as_slice())
|
|
}
|
|
}
|
|
|
|
impl enc::Encode for SigningKeyPair {
|
|
fn term(&self) -> enc::Result<'_> {
|
|
enc::marked_bytes(BM_SIGN_KEYPAIR, self.0.secret_key.as_slice())
|
|
}
|
|
}
|
|
|
|
// ---- calculating hashes, signatures, etc ----
|
|
|
|
/// Compute the hash of a payload with default dryoc parameters and optionnal key
|
|
pub fn compute_hash(bytes: &[u8], key: Option<&[u8; 32]>) -> Hash {
|
|
Hash(generichash::GenericHash::hash_with_defaults(bytes, key).unwrap())
|
|
}
|
|
|
|
/// Generate a new signing keypair
|
|
pub fn gen_signing_keypair() -> SigningKeyPair {
|
|
SigningKeyPair(sign::SigningKeyPair::gen_with_defaults())
|
|
}
|
|
|
|
/// Compute the ed25519 signature of a message using a secret key
|
|
pub fn compute_signature(message: &[u8], keypair: &SigningKeyPair) -> Signature {
|
|
Signature(
|
|
keypair
|
|
.0
|
|
.sign_with_defaults(message)
|
|
.unwrap()
|
|
.into_parts()
|
|
.0,
|
|
)
|
|
}
|
|
|
|
/// Verify the ed25519 signature of a message using a public key
|
|
pub fn verify_signature(
|
|
signature: &Signature,
|
|
message: &[u8],
|
|
public_key: &SigningPublicKey,
|
|
) -> bool {
|
|
sign::SignedMessage::from_parts(signature.0.clone(), message.to_vec())
|
|
.verify(&public_key.0)
|
|
.is_ok()
|
|
}
|
|
|
|
// ---- decode helpers ----
|
|
|
|
pub trait CryptoDec {
|
|
/// Try to interpret this string as a Blake2b512 digest
|
|
/// (32-bytes base64 encoded, prefixed by `h.b2:`)
|
|
///
|
|
/// Example:
|
|
///
|
|
/// ```
|
|
/// use nettext::dec::decode;
|
|
/// use nettext::crypto::{compute_hash, CryptoDec};
|
|
///
|
|
/// let term = decode(b"{
|
|
/// message = hello;
|
|
/// hash = h.b2:Mk3PAn3UowqTLEQfNlol6GsXPe-kuOWJSCU0cbgbcs8;
|
|
/// }").unwrap();
|
|
/// let [msg, hash] = term.dict_of(["message", "hash"], false).unwrap();
|
|
/// let expected_hash = compute_hash(msg.raw(), None);
|
|
/// assert_eq!(hash.hash().unwrap(), expected_hash);
|
|
/// ```
|
|
fn hash(&self) -> Result<Hash, dec::TypeError>;
|
|
|
|
/// Try to interpret this string as an ed25519 signature
|
|
/// (64 bytes base64 encoded, prefixed by `sig.ed25519:`)
|
|
fn signature(&self) -> Result<Signature, dec::TypeError>;
|
|
|
|
/// Try to interpret this string as an ed25519 keypair
|
|
/// (64 bytes base64 encoded, prefixed by `sk.ed25519:`)
|
|
fn keypair(&self) -> Result<SigningKeyPair, dec::TypeError>;
|
|
|
|
/// Try to interpret this string as an ed25519 public key
|
|
/// (32 bytes base64 encoded, prefixed by `pk.ed25519:`)
|
|
fn public_key(&self) -> Result<SigningPublicKey, dec::TypeError>;
|
|
}
|
|
|
|
impl<'a, 'b> CryptoDec for dec::Term<'a, 'b> {
|
|
fn hash(&self) -> Result<Hash, dec::TypeError> {
|
|
Ok(Hash(generichash::Hash::from(
|
|
self.marked_bytes_exact(BM_HASH)?,
|
|
)))
|
|
}
|
|
|
|
/// Try to interpret this string as an ed25519 signature (64 bytes base64 encoded)
|
|
fn signature(&self) -> Result<Signature, dec::TypeError> {
|
|
Ok(Signature(sign::Signature::from(
|
|
self.marked_bytes_exact(BM_SIGNATURE)?,
|
|
)))
|
|
}
|
|
|
|
fn keypair(&self) -> Result<SigningKeyPair, dec::TypeError> {
|
|
let secret_key = sign::SecretKey::from(self.marked_bytes_exact(BM_SIGN_KEYPAIR)?);
|
|
Ok(SigningKeyPair(sign::SigningKeyPair::from_secret_key(
|
|
secret_key,
|
|
)))
|
|
}
|
|
|
|
fn public_key(&self) -> Result<SigningPublicKey, dec::TypeError> {
|
|
Ok(SigningPublicKey(sign::PublicKey::from(
|
|
self.marked_bytes_exact(BM_SIGN_PUBKEY)?,
|
|
)))
|
|
}
|
|
}
|