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",
|
"qcheck-macros",
|
||||||
"radicle-ssh",
|
"radicle-ssh",
|
||||||
"serde",
|
"serde",
|
||||||
"sha2 0.10.6",
|
|
||||||
"sqlite",
|
"sqlite",
|
||||||
"ssh-key",
|
"ssh-key",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ $ rad self
|
||||||
ID did:key:z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
|
ID did:key:z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
|
||||||
Node ID z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
|
Node ID z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
|
||||||
Key (hash) SHA256:UIedaL6Cxm6OUErh9GQUzzglSk7VpQlVTI1TAFB/HWA
|
Key (hash) SHA256:UIedaL6Cxm6OUErh9GQUzzglSk7VpQlVTI1TAFB/HWA
|
||||||
Key (full) AAAAC3NzaC1lZDI1NTE5AAAAIHahWSBEpuT1ESZbynOmBNkLBSnR32Ar4woZqSV2YNH1
|
Key (full) ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHahWSBEpuT1ESZbynOmBNkLBSnR32Ar4woZqSV2YNH1
|
||||||
Storage (git) [..]/storage
|
Storage (git) [..]/storage
|
||||||
Storage (keys) [..]/keys
|
Storage (keys) [..]/keys
|
||||||
Node (socket) [..]/node/radicle.sock
|
Node (socket) [..]/node/radicle.sock
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@ cyphernet = { version = "0.2.0", optional = true }
|
||||||
multibase = { version = "0.9.1" }
|
multibase = { version = "0.9.1" }
|
||||||
ec25519 = { version = "0.1.0", features = [] }
|
ec25519 = { version = "0.1.0", features = [] }
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
sha2 = { version = "0.10.2" }
|
|
||||||
sqlite = { version = "0.30.3", optional = true }
|
sqlite = { version = "0.30.3", optional = true }
|
||||||
thiserror = { version = "1" }
|
thiserror = { version = "1" }
|
||||||
zeroize = { version = "1.5.7" }
|
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 use ed25519::{edwards25519, Error, KeyPair, Seed};
|
||||||
|
|
||||||
pub mod hash;
|
|
||||||
#[cfg(feature = "ssh")]
|
#[cfg(feature = "ssh")]
|
||||||
pub mod ssh;
|
pub mod ssh;
|
||||||
#[cfg(any(test, feature = "test"))]
|
#[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")]
|
#[cfg(feature = "cyphernet")]
|
||||||
impl cyphernet::EcPk for PublicKey {
|
impl cyphernet::EcPk for PublicKey {
|
||||||
const COMPRESSED_LEN: usize = 32;
|
const COMPRESSED_LEN: usize = 32;
|
||||||
|
|
|
||||||
|
|
@ -16,35 +16,20 @@ use crate::PublicKey;
|
||||||
pub use keystore::{Keystore, Passphrase};
|
pub use keystore::{Keystore, Passphrase};
|
||||||
|
|
||||||
pub mod fmt {
|
pub mod fmt {
|
||||||
use radicle_ssh::encoding::Encoding as _;
|
|
||||||
|
|
||||||
use crate::PublicKey;
|
use crate::PublicKey;
|
||||||
|
|
||||||
/// Get the SSH long key from a public key.
|
/// Get the SSH long key from a public key.
|
||||||
/// This is the output of `ssh-add -L`.
|
/// This is the output of `ssh-add -L`.
|
||||||
pub fn key(key: &PublicKey) -> String {
|
pub fn key(key: &PublicKey) -> String {
|
||||||
let mut buf = Vec::new();
|
ssh_key::PublicKey::from(*key).to_string()
|
||||||
|
|
||||||
buf.extend_ssh_string(b"ssh-ed25519");
|
|
||||||
buf.extend_ssh_string(key.as_ref());
|
|
||||||
|
|
||||||
base64::encode_config(buf, base64::STANDARD_NO_PAD)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the SSH key fingerprint from a public key.
|
/// Get the SSH key fingerprint from a public key.
|
||||||
/// This is the output of `ssh-add -l`.
|
/// This is the output of `ssh-add -l`.
|
||||||
pub fn fingerprint(key: &PublicKey) -> String {
|
pub fn fingerprint(key: &PublicKey) -> String {
|
||||||
use sha2::Digest;
|
ssh_key::PublicKey::from(*key)
|
||||||
|
.fingerprint(Default::default())
|
||||||
let mut buf = Vec::new();
|
.to_string()
|
||||||
|
|
||||||
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}")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
@ -61,7 +46,7 @@ pub mod fmt {
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
key(&pk),
|
key(&pk),
|
||||||
"AAAAC3NzaC1lZDI1NTE5AAAAINDoXIrhcnRjnLGUXUFdxhkuy08lkTOwrj2IoGsEX6+Q"
|
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINDoXIrhcnRjnLGUXUFdxhkuy08lkTOwrj2IoGsEX6+Q"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -431,7 +416,8 @@ AAAAQI84aPZsXxlQigpy1/Y/iJSmHSS//CIgvqvUMQIb/TM2vhCKruduH0cK02k9G8wOI+
|
||||||
EUMf2bSDyxbJyZThOEiAs=
|
EUMf2bSDyxbJyZThOEiAs=
|
||||||
-----END SSH SIGNATURE-----";
|
-----END SSH SIGNATURE-----";
|
||||||
|
|
||||||
let public_key = "AAAAC3NzaC1lZDI1NTE5AAAAIL460KIEccS4881p7PPpiiQBsxF+H5tgC6De6crw9rbU";
|
let public_key =
|
||||||
|
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL460KIEccS4881p7PPpiiQBsxF+H5tgC6De6crw9rbU";
|
||||||
let signature = ExtendedSignature::from_armored(armored).unwrap();
|
let signature = ExtendedSignature::from_armored(armored).unwrap();
|
||||||
|
|
||||||
assert_eq!(signature.version, 1);
|
assert_eq!(signature.version, 1);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use qcheck::Arbitrary;
|
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 {
|
impl Arbitrary for MockSigner {
|
||||||
fn arbitrary(g: &mut qcheck::Gen) -> Self {
|
fn arbitrary(g: &mut qcheck::Gen) -> Self {
|
||||||
|
|
@ -21,10 +21,3 @@ impl Arbitrary for PublicKey {
|
||||||
PublicKey(keypair.pk)
|
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 mod prelude {
|
||||||
pub use crate::bounded::BoundedVec;
|
pub use crate::bounded::BoundedVec;
|
||||||
pub use crate::clock::Timestamp;
|
pub use crate::clock::Timestamp;
|
||||||
pub use crate::crypto::hash::Digest;
|
|
||||||
pub use crate::crypto::{PublicKey, Signature, Signer};
|
pub use crate::crypto::{PublicKey, Signature, Signer};
|
||||||
pub use crate::deserializer::Deserializer;
|
pub use crate::deserializer::Deserializer;
|
||||||
pub use crate::identity::{Did, Id};
|
pub use crate::identity::{Did, Id};
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,6 @@ use std::{io, mem};
|
||||||
|
|
||||||
use byteorder::{NetworkEndian, ReadBytesExt, WriteBytesExt};
|
use byteorder::{NetworkEndian, ReadBytesExt, WriteBytesExt};
|
||||||
|
|
||||||
use crate::crypto::hash::Digest;
|
|
||||||
use crate::crypto::{PublicKey, Signature, Unverified};
|
use crate::crypto::{PublicKey, Signature, Unverified};
|
||||||
use crate::git;
|
use crate::git;
|
||||||
use crate::git::fmt;
|
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 {
|
impl Encode for Id {
|
||||||
fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
|
fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
|
||||||
self.deref().encode(writer)
|
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 {
|
impl Encode for filter::Filter {
|
||||||
fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
|
fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
|
||||||
let mut n = 0;
|
let mut n = 0;
|
||||||
|
|
@ -531,11 +516,6 @@ mod tests {
|
||||||
assert_eq!(deserialize::<Id>(&serialize(&input)).unwrap(), input);
|
assert_eq!(deserialize::<Id>(&serialize(&input)).unwrap(), input);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[quickcheck]
|
|
||||||
fn prop_digest(input: Digest) {
|
|
||||||
assert_eq!(deserialize::<Digest>(&serialize(&input)).unwrap(), input);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[quickcheck]
|
#[quickcheck]
|
||||||
fn prop_refs(input: Refs) {
|
fn prop_refs(input: Refs) {
|
||||||
assert_eq!(deserialize::<Refs>(&serialize(&input)).unwrap(), input);
|
assert_eq!(deserialize::<Refs>(&serialize(&input)).unwrap(), input);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue