1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
use crate::{encoder::Encode, Error, HashAlg, PublicKey, Result};
use base64ct::{Base64Unpadded, Encoding};
use core::{fmt, str};
use sha2::{Digest, Sha256};
const ENCODING_ERR_MSG: &str = "Base64 encoding error";
const SHA256_BASE64_LEN: usize = 43;
const SHA256_BIN_LEN: usize = 32;
const SHA256_PREFIX: &str = "SHA256:";
#[cfg_attr(docsrs, doc(cfg(feature = "fingerprint")))]
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub enum Fingerprint {
Sha256(Sha256Fingerprint),
}
impl Fingerprint {
pub fn algorithm(self) -> HashAlg {
match self {
Self::Sha256(_) => HashAlg::Sha256,
}
}
pub fn sha256(self) -> Option<Sha256Fingerprint> {
match self {
Self::Sha256(fingerprint) => Some(fingerprint),
}
}
pub fn is_sha256(self) -> bool {
self.sha256().is_some()
}
}
impl From<Sha256Fingerprint> for Fingerprint {
fn from(fingerprint: Sha256Fingerprint) -> Fingerprint {
Fingerprint::Sha256(fingerprint)
}
}
impl str::FromStr for Fingerprint {
type Err = Error;
fn from_str(id: &str) -> Result<Self> {
if id.starts_with(SHA256_PREFIX) {
Sha256Fingerprint::from_str(id).map(Into::into)
} else {
Err(Error::Algorithm)
}
}
}
impl fmt::Display for Fingerprint {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Sha256(fingerprint) => write!(f, "{}", fingerprint),
}
}
}
#[cfg_attr(docsrs, doc(cfg(feature = "fingerprint")))]
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct Sha256Fingerprint([u8; SHA256_BASE64_LEN]);
impl Sha256Fingerprint {
pub fn new(digest_bytes: &[u8; SHA256_BIN_LEN]) -> Self {
let mut base64 = [0u8; SHA256_BASE64_LEN];
Base64Unpadded::encode(digest_bytes, &mut base64).expect(ENCODING_ERR_MSG);
Self(base64)
}
pub fn as_base64(&self) -> &str {
str::from_utf8(&self.0).expect("invalid Base64 encoding")
}
pub fn to_bytes(&self) -> [u8; SHA256_BIN_LEN] {
let mut decoded_bytes = [0u8; SHA256_BIN_LEN];
let decoded_len = Base64Unpadded::decode(&self.0, &mut decoded_bytes)
.expect(ENCODING_ERR_MSG)
.len();
assert_eq!(SHA256_BIN_LEN, decoded_len);
decoded_bytes
}
}
impl TryFrom<PublicKey> for Sha256Fingerprint {
type Error = Error;
fn try_from(public_key: PublicKey) -> Result<Sha256Fingerprint> {
Sha256Fingerprint::try_from(&public_key)
}
}
impl TryFrom<&PublicKey> for Sha256Fingerprint {
type Error = Error;
fn try_from(public_key: &PublicKey) -> Result<Sha256Fingerprint> {
let mut digest = Sha256::new();
public_key.key_data().encode(&mut digest)?;
Ok(Self::new(&digest.finalize().into()))
}
}
impl fmt::Display for Sha256Fingerprint {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}{}", SHA256_PREFIX, self.as_base64())
}
}
impl str::FromStr for Sha256Fingerprint {
type Err = Error;
fn from_str(id: &str) -> Result<Self> {
let id = id.strip_prefix(SHA256_PREFIX).ok_or(Error::Algorithm)?;
let mut decoded_bytes = [0u8; SHA256_BIN_LEN];
match Base64Unpadded::decode(id, &mut decoded_bytes)?.len() {
SHA256_BIN_LEN => id
.as_bytes()
.try_into()
.map(Self)
.map_err(|_| Error::Length),
_ => Err(Error::Length),
}
}
}