crypto: Cleanup `hash` module
Remove `Digest` type and use `ssh-key` for formatting public ssh key.
This commit is contained in:
parent
ef0628c48e
commit
7e1b2b6222
|
|
@ -1929,7 +1929,6 @@ dependencies = [
|
|||
"qcheck-macros",
|
||||
"radicle-ssh",
|
||||
"serde",
|
||||
"sha2 0.10.6",
|
||||
"sqlite",
|
||||
"ssh-key",
|
||||
"tempfile",
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ $ rad self
|
|||
ID did:key:z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
|
||||
Node ID z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
|
||||
Key (hash) SHA256:UIedaL6Cxm6OUErh9GQUzzglSk7VpQlVTI1TAFB/HWA
|
||||
Key (full) AAAAC3NzaC1lZDI1NTE5AAAAIHahWSBEpuT1ESZbynOmBNkLBSnR32Ar4woZqSV2YNH1
|
||||
Key (full) ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHahWSBEpuT1ESZbynOmBNkLBSnR32Ar4woZqSV2YNH1
|
||||
Storage (git) [..]/storage
|
||||
Storage (keys) [..]/keys
|
||||
Node (socket) [..]/node/radicle.sock
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ cyphernet = { version = "0.2.0", optional = true }
|
|||
multibase = { version = "0.9.1" }
|
||||
ec25519 = { version = "0.1.0", features = [] }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
sha2 = { version = "0.10.2" }
|
||||
sqlite = { version = "0.30.3", optional = true }
|
||||
thiserror = { version = "1" }
|
||||
zeroize = { version = "1.5.7" }
|
||||
|
|
|
|||
|
|
@ -1,69 +0,0 @@
|
|||
use std::{convert::TryInto, fmt};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sha2::{
|
||||
digest::{generic_array::GenericArray, OutputSizeUser},
|
||||
Digest as _, Sha256,
|
||||
};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Error)]
|
||||
pub enum DecodeError {
|
||||
#[error("invalid digest length {0}")]
|
||||
InvalidLength(usize),
|
||||
}
|
||||
|
||||
/// A SHA-256 hash.
|
||||
#[derive(Serialize, Deserialize, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct Digest([u8; 32]);
|
||||
|
||||
impl Digest {
|
||||
pub fn new(bytes: impl AsRef<[u8]>) -> Self {
|
||||
Self::from(Sha256::digest(bytes))
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8; 32]> for Digest {
|
||||
fn as_ref(&self) -> &[u8; 32] {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Digest {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "Hash({self})")
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Digest {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
for byte in &self.0 {
|
||||
write!(f, "{byte:02x}")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<[u8; 32]> for Digest {
|
||||
fn from(bytes: [u8; 32]) -> Self {
|
||||
Self(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&[u8]> for Digest {
|
||||
type Error = DecodeError;
|
||||
|
||||
fn try_from(bytes: &[u8]) -> Result<Self, DecodeError> {
|
||||
let bytes: [u8; 32] = bytes
|
||||
.try_into()
|
||||
.map_err(|_| DecodeError::InvalidLength(bytes.len()))?;
|
||||
|
||||
Ok(bytes.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<GenericArray<u8, <Sha256 as OutputSizeUser>::OutputSize>> for Digest {
|
||||
fn from(array: GenericArray<u8, <Sha256 as OutputSizeUser>::OutputSize>) -> Self {
|
||||
Self(array.into())
|
||||
}
|
||||
}
|
||||
|
|
@ -8,7 +8,6 @@ use thiserror::Error;
|
|||
|
||||
pub use ed25519::{edwards25519, Error, KeyPair, Seed};
|
||||
|
||||
pub mod hash;
|
||||
#[cfg(feature = "ssh")]
|
||||
pub mod ssh;
|
||||
#[cfg(any(test, feature = "test"))]
|
||||
|
|
@ -166,6 +165,13 @@ impl cyphernet::display::MultiDisplay<cyphernet::display::Encoding> for PublicKe
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "ssh")]
|
||||
impl From<PublicKey> for ssh_key::PublicKey {
|
||||
fn from(key: PublicKey) -> Self {
|
||||
ssh_key::PublicKey::from(ssh_key::public::Ed25519PublicKey(**key))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "cyphernet")]
|
||||
impl cyphernet::EcPk for PublicKey {
|
||||
const COMPRESSED_LEN: usize = 32;
|
||||
|
|
|
|||
|
|
@ -16,35 +16,20 @@ use crate::PublicKey;
|
|||
pub use keystore::{Keystore, Passphrase};
|
||||
|
||||
pub mod fmt {
|
||||
use radicle_ssh::encoding::Encoding as _;
|
||||
|
||||
use crate::PublicKey;
|
||||
|
||||
/// Get the SSH long key from a public key.
|
||||
/// This is the output of `ssh-add -L`.
|
||||
pub fn key(key: &PublicKey) -> String {
|
||||
let mut buf = Vec::new();
|
||||
|
||||
buf.extend_ssh_string(b"ssh-ed25519");
|
||||
buf.extend_ssh_string(key.as_ref());
|
||||
|
||||
base64::encode_config(buf, base64::STANDARD_NO_PAD)
|
||||
ssh_key::PublicKey::from(*key).to_string()
|
||||
}
|
||||
|
||||
/// Get the SSH key fingerprint from a public key.
|
||||
/// This is the output of `ssh-add -l`.
|
||||
pub fn fingerprint(key: &PublicKey) -> String {
|
||||
use sha2::Digest;
|
||||
|
||||
let mut buf = Vec::new();
|
||||
|
||||
buf.extend_ssh_string(b"ssh-ed25519");
|
||||
buf.extend_ssh_string(key.as_ref());
|
||||
|
||||
let sha = sha2::Sha256::digest(&buf).to_vec();
|
||||
let encoded = base64::encode_config(sha, base64::STANDARD_NO_PAD);
|
||||
|
||||
format!("SHA256:{encoded}")
|
||||
ssh_key::PublicKey::from(*key)
|
||||
.fingerprint(Default::default())
|
||||
.to_string()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
@ -61,7 +46,7 @@ pub mod fmt {
|
|||
|
||||
assert_eq!(
|
||||
key(&pk),
|
||||
"AAAAC3NzaC1lZDI1NTE5AAAAINDoXIrhcnRjnLGUXUFdxhkuy08lkTOwrj2IoGsEX6+Q"
|
||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINDoXIrhcnRjnLGUXUFdxhkuy08lkTOwrj2IoGsEX6+Q"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -431,7 +416,8 @@ AAAAQI84aPZsXxlQigpy1/Y/iJSmHSS//CIgvqvUMQIb/TM2vhCKruduH0cK02k9G8wOI+
|
|||
EUMf2bSDyxbJyZThOEiAs=
|
||||
-----END SSH SIGNATURE-----";
|
||||
|
||||
let public_key = "AAAAC3NzaC1lZDI1NTE5AAAAIL460KIEccS4881p7PPpiiQBsxF+H5tgC6De6crw9rbU";
|
||||
let public_key =
|
||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL460KIEccS4881p7PPpiiQBsxF+H5tgC6De6crw9rbU";
|
||||
let signature = ExtendedSignature::from_armored(armored).unwrap();
|
||||
|
||||
assert_eq!(signature.version, 1);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use qcheck::Arbitrary;
|
||||
|
||||
use crate::{hash, test::signer::MockSigner, KeyPair, PublicKey, SecretKey, Seed};
|
||||
use crate::{test::signer::MockSigner, KeyPair, PublicKey, SecretKey, Seed};
|
||||
|
||||
impl Arbitrary for MockSigner {
|
||||
fn arbitrary(g: &mut qcheck::Gen) -> Self {
|
||||
|
|
@ -21,10 +21,3 @@ impl Arbitrary for PublicKey {
|
|||
PublicKey(keypair.pk)
|
||||
}
|
||||
}
|
||||
|
||||
impl Arbitrary for hash::Digest {
|
||||
fn arbitrary(g: &mut qcheck::Gen) -> Self {
|
||||
let bytes: Vec<u8> = Arbitrary::arbitrary(g);
|
||||
hash::Digest::new(bytes)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ pub use runtime::Runtime;
|
|||
pub mod prelude {
|
||||
pub use crate::bounded::BoundedVec;
|
||||
pub use crate::clock::Timestamp;
|
||||
pub use crate::crypto::hash::Digest;
|
||||
pub use crate::crypto::{PublicKey, Signature, Signer};
|
||||
pub use crate::deserializer::Deserializer;
|
||||
pub use crate::identity::{Did, Id};
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ use std::{io, mem};
|
|||
|
||||
use byteorder::{NetworkEndian, ReadBytesExt, WriteBytesExt};
|
||||
|
||||
use crate::crypto::hash::Digest;
|
||||
use crate::crypto::{PublicKey, Signature, Unverified};
|
||||
use crate::git;
|
||||
use crate::git::fmt;
|
||||
|
|
@ -189,12 +188,6 @@ impl Encode for git::Url {
|
|||
}
|
||||
}
|
||||
|
||||
impl Encode for Digest {
|
||||
fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
|
||||
self.as_ref().encode(writer)
|
||||
}
|
||||
}
|
||||
|
||||
impl Encode for Id {
|
||||
fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
|
||||
self.deref().encode(writer)
|
||||
|
|
@ -396,14 +389,6 @@ impl Decode for Id {
|
|||
}
|
||||
}
|
||||
|
||||
impl Decode for Digest {
|
||||
fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
|
||||
let bytes: [u8; 32] = Decode::decode(reader)?;
|
||||
|
||||
Ok(Self::from(bytes))
|
||||
}
|
||||
}
|
||||
|
||||
impl Encode for filter::Filter {
|
||||
fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
|
||||
let mut n = 0;
|
||||
|
|
@ -531,11 +516,6 @@ mod tests {
|
|||
assert_eq!(deserialize::<Id>(&serialize(&input)).unwrap(), input);
|
||||
}
|
||||
|
||||
#[quickcheck]
|
||||
fn prop_digest(input: Digest) {
|
||||
assert_eq!(deserialize::<Digest>(&serialize(&input)).unwrap(), input);
|
||||
}
|
||||
|
||||
#[quickcheck]
|
||||
fn prop_refs(input: Refs) {
|
||||
assert_eq!(deserialize::<Refs>(&serialize(&input)).unwrap(), input);
|
||||
|
|
|
|||
Loading…
Reference in New Issue