Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Transaction IDs are onw a sha512 of the entry and allow multiple sigs.

Policies are used for all tranactions (unimplemented, but the structure
is there).

Names for keys are no longer unique...keys are handled by id, and
SecretKeys now have ids (their hmac).

all private containers are PrivateWithHmac now, meaning their content
can be verified AND their HMAC can be included in transactions.

adding names to claims (again, not unique). this allows them to take the
place of forward.

removed forwards. they are incredibly stupid, because they duplicate
claims in almost every way (except forwards had names, claims did not,
which i fixed). now you can have a "Mastodon" claim that points to your
mastodon account etc.

restructing many container types, but mainly claims/stamps:
ClaimContainer no longer exists, and claims/stamps no longer have signed
content. instead, all signing and verification is done at the
transaction level. this means a signed stamp is really just a
normal transaction (which can be included both in the stamper or
stampee's identity). similarly, publishing is no longer a separate
process, but rather a new transaction type (that cannot be saved to the
identity) which allows publishing to also be multisig.

there's a ton of supporting shit for all the above, but that's the main
stuff. a large amount of tests are broken, but the system compiles, and
its time to check things in before i go off on another whim and rewire a
bunch of stuff.
  • Loading branch information
orthecreedence committed Oct 23, 2022
1 parent 5620688 commit efadf74
Show file tree
Hide file tree
Showing 20 changed files with 3,639 additions and 4,353 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/target
Cargo.lock
/play
vars.mk
119 changes: 60 additions & 59 deletions src/crypto/key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,11 @@ use crate::{
sign::Signable,
},
};
use ed25519_dalek::{Signer};
use ed25519_dalek::{Digest as Ed25519Digest, Signer, generic_array::GenericArray};
use hmac::{
Mac,
digest::{
FixedOutput,
crypto_common::generic_array::GenericArray,
},
};
use rand::{RngCore, rngs::OsRng};
Expand Down Expand Up @@ -63,25 +62,23 @@ pub enum KeyID {
SignKeypair(SignKeypairPublic),
#[rasn(tag(explicit(1)))]
CryptoKeypair(CryptoKeypairPublic),
#[rasn(tag(explicit(2)))]
SecretKey(Hmac),
}

impl KeyID {
pub fn as_string(&self) -> String {
fn get_bytes(ty_prefix: u8, key_prefix: u8, bytes: &[u8]) -> Vec<u8> {
let mut res = vec![ty_prefix, key_prefix];
let mut bytes_vec = Vec::from(bytes);
res.append(&mut bytes_vec);
res
}
let bytes = match self {
match self {
Self::SignKeypair(SignKeypairPublic::Ed25519(pubkey)) => {
get_bytes(0, 0, pubkey.as_ref())
ser::base64_encode(pubkey.as_ref())
}
Self::CryptoKeypair(CryptoKeypairPublic::Curve25519XChaCha20Poly1305(pubkey)) => {
get_bytes(1, 0, pubkey.as_ref())
ser::base64_encode(pubkey.as_ref())
}
};
ser::base64_encode(&bytes)
Self::SecretKey(hmac) => {
ser::base64_encode(hmac.deref())
}
}
}

#[cfg(test)]
Expand All @@ -97,6 +94,18 @@ impl KeyID {
let master_key = SecretKey::new_xchacha20poly1305().unwrap();
Self::CryptoKeypair(CryptoKeypair::new_curve25519xchacha20poly1305(&master_key).unwrap().into())
}

#[cfg(test)]
#[allow(dead_code)]
pub(crate) fn random_secret() -> Self {
Self::SecretKey(Hmac::new_sha512(&HmacKey::new_sha512().unwrap(), b"get a job").unwrap())
}
}

impl std::fmt::Display for KeyID {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.as_string())
}
}

/// A symmetric encryption key nonce
Expand Down Expand Up @@ -284,68 +293,38 @@ impl SignKeypair {
/// Hash a value then sign it, returning the hash and the signature. This is
/// already how signing works, but we basically control the hash process
/// ourselves so we can return the hash.
pub fn sign_and_hash(&self, master_key: &SecretKey, data: &[u8]) -> Result<(Binary<64>, SignKeypairSignature)> {
pub fn sign(&self, master_key: &SecretKey, data: &[u8]) -> Result<SignKeypairSignature> {
match self {
Self::Ed25519 { secret: ref sec_locked_opt, .. } => {
let sec_locked = sec_locked_opt.as_ref().ok_or(Error::CryptoKeyMissing)?;
let seckey = ed25519_dalek::SecretKey::from_bytes(sec_locked.open(master_key)?.expose_secret().as_ref())
.map_err(|_| Error::CryptoSignatureFailed)?;
let pubkey: ed25519_dalek::PublicKey = (&seckey).into();
let keypair = ed25519_dalek::Keypair { public: pubkey, secret: seckey };
let mut prehashed = ed25519_dalek::Sha512::new();
prehashed.update(data);
// i don't like this clone but oh well...?
let sig_obj = keypair.sign_prehashed(prehashed.clone(), Some(b"stamp-protocol"));
let sig_obj = keypair.sign(data);
let sig = SignKeypairSignature::Ed25519(Binary::new(sig_obj.to_bytes()));
let hash_vec = Vec::from(prehashed.finalize().as_slice());
let hash_arr: [u8; 64] = hash_vec.as_slice().try_into()
.map_err(|_| Error::CryptoSignatureFailed)?;
let hash = Sha512(Binary(hash_arr));
Ok((hash, sig))
Ok(sig)
}
}
}

/// Sign a value with our secret signing key.
///
/// Must be unlocked via our master key.
pub fn sign(&self, master_key: &SecretKey, data: &[u8]) -> Result<SignKeypairSignature> {
// sign and hash but throw away the hash
self.sign_and_hash(master_key, data)
.map(|x| x.1)
}

/// Make sure a set of data has the appropriate hash and also verifies
/// against its signature.
pub fn verify_and_hash(&self, hash: Sha512, signature: &SignKeypairSignature, data: &[u8]) -> Result<Sha512> {
/// Verify a value with a detached signature given the public key of the
/// signer.
pub fn verify(&self, signature: &SignKeypairSignature, data: &[u8]) -> Result<()> {
match (self, signature) {
(Self::Ed25519 { public: ref pubkey_bytes, .. }, SignKeypairSignature::Ed25519(ref sig_bytes)) => {
let pubkey = ed25519_dalek::PublicKey::from_bytes(&pubkey_bytes[..])
.map_err(|_| Error::CryptoSignatureVerificationFailed)?;
let sig_arr: [u8; 64] = sig_bytes.deref().clone().try_into()
.map_err(|_| Error::CryptoSignatureVerificationFailed)?;
let prehashed = ed25519_dalek::Sha512::default().chain(data);
let body_hash_vec = Vec::from(prehashed.clone().finalize().as_slice());
let body_hash_arr: [u8; 64] = hash_vec.as_slice().try_into()
.map_err(|_| Error::CryptoSignatureFailed)?;
let body_hash = Sha512(Binary(body_hash_arr));

if hash != body_hash {
Err(Error::CryptoSignatureVerificationFailed)?;
}

let sig = ed25519_dalek::Signature::from(sig_arr);
pubkey.verify_prehashed_strict(data, &sig)
.map_err(|_| Error::CryptoSignatureVerificationFailed)
pubkey.verify_strict(data, &sig)
.map_err(|_| Error::CryptoSignatureVerificationFailed)?;
Ok(())
}
}
}

/// Verify a value with a detached signature given the public key of the
/// signer.
pub fn verify(&self, signature: &SignKeypairSignature, data: &[u8]) -> Result<()> {
}

/// Re-encrypt this signing keypair with a new master key.
pub fn reencrypt(self, previous_master_key: &SecretKey, new_master_key: &SecretKey) -> Result<Self> {
match self {
Expand Down Expand Up @@ -657,35 +636,57 @@ impl From<CryptoKeypair> for CryptoKeypairPublic {
}
}

pub const SHA512_LEN: usize = 64;

/// Holds a sha512 signature. We could just use Binary<64> directly but this
/// sets a more clear intention, and these days I'm all about clear intentions
/// and open communication (as long as it's securely encrypted between
/// participants, of course).
#[derive(Debug, PartialEq, AsnType, Encode, Decode, Serialize, Deserialize)]
pub struct Sha512(Binary<64>);
#[derive(Clone, Debug, PartialEq, AsnType, Encode, Decode, Serialize, Deserialize)]
pub struct Sha512(Binary<SHA512_LEN>);

impl Sha512 {
/// Create a new Sha512 from a byte array
pub fn new(bytes: [u8; 64]) -> Self {
Self(Binary::new(bytes))
/// How bany bytes are in this Sha512? HMMM I WONDER
pub fn len() -> usize {
SHA512_LEN
}

/// Create a new SHA512 hash from binary data
pub fn hash(input: &[u8]) -> Result<Self> {
let genarr = ed25519_dalek::Sha512::digest(input);
let hash_arr: [u8; 64] = genarr.as_slice().try_into()
.map_err(|_| Error::CryptoHashFailed)?;
Ok(Self(Binary::new(hash_arr)))
}

#[cfg(test)]
pub(crate) fn random() -> Self {
let mut randbuf = [0u8; 64];
OsRng.fill_bytes(&mut randbuf);
Self::new(randbuf)
Self(Binary::new(randbuf))
}
}

impl From<[u8; 64]> for Sha512 {
fn from(arr: [u8; 64]) -> Self {
Self(Binary::new(arr))
}
}

impl Deref for Sha512 {
type Target = [u8];
type Target = [u8; 64];

fn deref(&self) -> &Self::Target {
&self.0.deref()
}
}

impl std::fmt::Display for Sha512 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", ser::base64_encode(self.deref()))
}
}

/// A key for deriving an HMAC
#[derive(Debug, AsnType, Encode, Decode, Serialize, Deserialize)]
#[rasn(choice)]
Expand Down
14 changes: 7 additions & 7 deletions src/crypto/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,11 @@ impl ser::SerdeBinary for Message {}
/// because an identity could have many CryptoKeypairs).
pub fn send(sender_master_key: &SecretKey, sender_identity_id: &IdentityID, sender_key: &Subkey, recipient_key: &Subkey, message: &[u8]) -> Result<Message> {
let sender_crypto = sender_key.key().as_cryptokey()
.ok_or(Error::IdentitySubkeyWrongType)?;
.ok_or(Error::KeychainSubkeyWrongType)?;
let recipient_crypto = recipient_key.key().as_cryptokey()
.ok_or(Error::IdentitySubkeyWrongType)?;
.ok_or(Error::KeychainSubkeyWrongType)?;
let sealed = recipient_crypto.seal(sender_master_key, sender_crypto, message)?;
let key_id = sender_key.key_id().ok_or(Error::IdentitySubkeyWrongType)?;
let key_id = sender_key.key_id();
let signed_msg = SignedObject::new(sender_identity_id.clone(), key_id, sealed);
Ok(Message::Signed(signed_msg))
}
Expand All @@ -72,9 +72,9 @@ pub fn send(sender_master_key: &SecretKey, sender_identity_id: &IdentityID, send
/// message, which signs the *outside* of the message (not the inside).
pub fn open(recipient_master_key: &SecretKey, recipient_key: &Subkey, sender_key: &Subkey, sealed: &Message) -> Result<Vec<u8>> {
let sender_crypto = sender_key.key().as_cryptokey()
.ok_or(Error::IdentitySubkeyWrongType)?;
.ok_or(Error::KeychainSubkeyWrongType)?;
let recipient_crypto = recipient_key.key().as_cryptokey()
.ok_or(Error::IdentitySubkeyWrongType)?;
.ok_or(Error::KeychainSubkeyWrongType)?;
let signed_message = match sealed {
Message::Signed(SignedObject { ref body, .. }) => body,
_ => Err(Error::CryptoWrongMessageType)?,
Expand All @@ -88,15 +88,15 @@ pub fn open(recipient_master_key: &SecretKey, recipient_key: &Subkey, sender_key
/// cryptographically verified.
pub fn send_anonymous(recipient_key: &Subkey, message: &[u8]) -> Result<Message> {
let recipient_crypto = recipient_key.key().as_cryptokey()
.ok_or(Error::IdentitySubkeyWrongType)?;
.ok_or(Error::KeychainSubkeyWrongType)?;
let sealed = recipient_crypto.seal_anonymous(message)?;
Ok(Message::Anonymous(sealed))
}

/// Open an anonymous message send with [send_anonymous].
pub fn open_anonymous(recipient_master_key: &SecretKey, recipient_key: &Subkey, sealed: &Message) -> Result<Vec<u8>> {
let recipient_crypto = recipient_key.key().as_cryptokey()
.ok_or(Error::IdentitySubkeyWrongType)?;
.ok_or(Error::KeychainSubkeyWrongType)?;
let anon_message = match sealed {
Message::Anonymous(ref data) => data,
_ => Err(Error::CryptoWrongMessageType)?,
Expand Down
12 changes: 6 additions & 6 deletions src/crypto/sign.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,9 @@ impl ser::SerdeBinary for Signature {}
/// Sign a message with a private key, returning the detached signature.
pub fn sign(master_key: &SecretKey, signing_identity_id: &IdentityID, signing_key: &Subkey, message: &[u8]) -> Result<Signature> {
let sign_key = signing_key.key().as_signkey()
.ok_or(Error::IdentitySubkeyWrongType)?;
.ok_or(Error::KeychainSubkeyWrongType)?;
let signature = sign_key.sign(master_key, message)?;
let key_id = signing_key.key_id().ok_or(Error::IdentitySubkeyWrongType)?;
let key_id = signing_key.key_id();
Ok(Signature::Detached {
sig: SignedObject::new(signing_identity_id.clone(), key_id, signature)
})
Expand All @@ -74,16 +74,16 @@ pub fn verify(signing_key: &Subkey, signature: &Signature, message: &[u8]) -> Re
.map(|x| x.body())
.ok_or(Error::CryptoWrongSignatureType)?;
let sign_key = signing_key.key().as_signkey()
.ok_or(Error::IdentitySubkeyWrongType)?;
.ok_or(Error::KeychainSubkeyWrongType)?;
sign_key.verify(detached, message)
}

/// Sign a message with a private key, returning the detached signature.
pub fn sign_attached(master_key: &SecretKey, signing_identity_id: &IdentityID, signing_key: &Subkey, message: &[u8]) -> Result<Signature> {
let sign_key = signing_key.key().as_signkey()
.ok_or(Error::IdentitySubkeyWrongType)?;
.ok_or(Error::KeychainSubkeyWrongType)?;
let signature = sign_key.sign(master_key, message)?;
let key_id = signing_key.key_id().ok_or(Error::IdentitySubkeyWrongType)?;
let key_id = signing_key.key_id();
Ok(Signature::Attached {
sig: SignedObject::new(signing_identity_id.clone(), key_id, signature),
data: message.to_vec().into(),
Expand All @@ -96,7 +96,7 @@ pub fn verify_attached(signing_key: &Subkey, signature: &Signature) -> Result<()
.map(|x| (x.0.body(), x.1))
.ok_or(Error::CryptoWrongSignatureType)?;
let sign_key = signing_key.key().as_signkey()
.ok_or(Error::IdentitySubkeyWrongType)?;
.ok_or(Error::KeychainSubkeyWrongType)?;
sign_key.verify(attached.0, attached.1)
}

Expand Down
Loading

0 comments on commit efadf74

Please sign in to comment.