verse_session_id/
session_id_pair.rs1use crate::errors;
2use crate::SessionId;
3use anyhow::Result;
4use ed25519_dalek::Digest;
5use serde::{Deserialize, Deserializer, Serialize, Serializer};
6use std::fmt;
7
8pub type SessionIdPair = ed25519_dalek::Keypair;
10
11pub const SIGNATURE_SALT_SIZE: usize = 8;
13pub const SIGNATURE_SIZE: usize = ed25519_dalek::Signature::BYTE_SIZE;
15
16pub trait SessionIdPublic {
18 fn verify(&self, payload: Vec<&[u8]>, sigset: &SignatureSet) -> Result<()>;
20}
21
22impl SessionIdPublic for SessionId {
23 fn verify(&self, payload: Vec<&[u8]>, sigset: &SignatureSet) -> Result<()> {
24 let pk =
25 ed25519_dalek::PublicKey::from_bytes(self.as_ref()).map_err(errors::signature!())?;
26 let mut hasher = ed25519_dalek::Sha512::new();
27 hasher.update(sigset.salt);
28 for p in payload {
29 hasher.update(p);
30 }
31 let signature = ed25519_dalek::Signature::from_bytes(&sigset.signature)
32 .map_err(errors::signature!())?;
33 Ok(pk
34 .verify_prehashed(hasher, None, &signature)
35 .map_err(errors::signature!())?)
36 }
37}
38
39pub trait ISessionIdPair {
40 fn get_id(&self) -> SessionId;
42 fn sign(&self, payload: Vec<&[u8]>) -> Result<SignatureSet>;
44}
45
46pub fn new_session_id_pair() -> Result<SessionIdPair> {
48 let sk = &mut [0u8; ed25519_dalek::SECRET_KEY_LENGTH];
49 getrandom::getrandom(sk)?;
50 let sk = ed25519_dalek::SecretKey::from_bytes(sk).map_err(errors::signature!())?;
51
52 Ok(ed25519_dalek::Keypair {
53 public: ed25519_dalek::PublicKey::from(&sk),
54 secret: sk,
55 })
56}
57
58impl ISessionIdPair for SessionIdPair {
59 fn get_id(&self) -> SessionId {
60 self.public.to_bytes().into()
61 }
62 fn sign(&self, payload: Vec<&[u8]>) -> Result<SignatureSet> {
63 let mut salt = [0u8; SIGNATURE_SALT_SIZE];
64 getrandom::getrandom(&mut salt)?;
65 let mut hasher = ed25519_dalek::Sha512::new();
66 hasher.update(salt);
67 for p in payload {
68 hasher.update(p);
69 }
70 let signature = self
71 .sign_prehashed(hasher, None)
72 .map_err(errors::signature!())?;
73
74 Ok(SignatureSet {
75 signature: signature.to_bytes(),
76 salt,
77 })
78 }
79}
80
81#[derive(Deserialize, Serialize, Eq, PartialEq, Debug)]
83pub struct SignatureSet {
84 #[serde(serialize_with = "as_base64", deserialize_with = "from_base64")]
85 pub signature: [u8; SIGNATURE_SIZE],
86 #[serde(serialize_with = "as_base64", deserialize_with = "from_base64")]
87 pub salt: [u8; SIGNATURE_SALT_SIZE],
88}
89
90impl fmt::Display for SignatureSet {
91 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
92 let mut buf = Vec::<u8>::with_capacity(SIGNATURE_SIZE + SIGNATURE_SALT_SIZE);
93 buf.extend_from_slice(&self.signature);
94 buf.extend_from_slice(&self.salt);
95 write!(f, "{}", base64::encode(buf))
96 }
97}
98impl std::str::FromStr for SignatureSet {
99 type Err = anyhow::Error;
100 fn from_str(s: &str) -> Result<Self, Self::Err> {
101 base64::decode(s)?.try_into()
102 }
103}
104impl TryFrom<Vec<u8>> for SignatureSet {
105 type Error = anyhow::Error;
106 fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
107 if value.len() != SIGNATURE_SIZE + SIGNATURE_SALT_SIZE {
108 return Err(errors::convert!(format!(
109 "{:?} != {:?}",
110 value.len(),
111 SIGNATURE_SIZE + SIGNATURE_SALT_SIZE
112 )));
113 }
114 let ss = SignatureSet {
115 signature: value[0..SIGNATURE_SIZE]
116 .try_into()
117 .map_err(|_v| errors::convert!())?,
118 salt: value[SIGNATURE_SIZE..]
119 .try_into()
120 .map_err(|_v| errors::convert!())?,
121 };
122 Ok(ss)
123 }
124}
125
126fn as_base64<const N: usize, S: Serializer>(
127 val: &[u8; N],
128 serializer: S,
129) -> Result<S::Ok, S::Error> {
130 serializer.serialize_str(&base64::encode(val))
131}
132
133fn from_base64<'de, const N: usize, D: Deserializer<'de>>(
134 deserializer: D,
135) -> Result<[u8; N], D::Error> {
136 use serde::de;
137
138 let res = <&str>::deserialize(deserializer).and_then(|s| {
139 base64::decode(s)
140 .map_err(|e| de::Error::custom(format!("invalid base64 string: {}, {}", s, e)))
141 })?;
142 res.try_into()
143 .map_err(|_| de::Error::custom(format!("invalid array size: {}", N)))
144}
145
146#[cfg(test)]
147mod tests {
148 use super::*;
149 #[test]
150 fn test_keypair() {
151 let kp = new_session_id_pair();
152 assert!(kp.is_ok());
154 }
155
156 #[test]
157 fn test_sign_verify() {
158 let kp = new_session_id_pair().unwrap();
159 let ss = kp
160 .sign(vec!["1234".as_bytes(), "testdata".as_bytes()])
161 .unwrap();
162 let session_id = kp.get_id();
165 let res = session_id.verify(vec!["1234".as_bytes(), "testdata".as_bytes()], &ss);
166 assert!(res.is_ok());
167
168 let res = session_id.verify(vec!["0234".as_bytes(), "testdata".as_bytes()], &ss);
169 assert!(res.is_err());
170
171 let kp = new_session_id_pair().unwrap();
172 let session_id = kp.get_id();
173 let res = session_id.verify(vec!["1234".as_bytes(), "testdata".as_bytes()], &ss);
174 assert!(res.is_err());
175
176 let ss1 = SignatureSet {
177 signature: ss.signature.clone(),
178 salt: Default::default(),
179 };
180 let res = session_id.verify(vec!["1234".as_bytes(), "testdata".as_bytes()], &ss1);
181 assert!(res.is_err());
182
183 let ss1 = SignatureSet {
184 signature: [0; SIGNATURE_SIZE],
185 salt: ss.salt.clone(),
186 };
187 let res = session_id.verify(vec!["1234".as_bytes(), "testdata".as_bytes()], &ss1);
188 assert!(res.is_err());
189 }
190 #[test]
191 fn test_ss_serialize() {
192 let ss = SignatureSet {
193 signature: [1; SIGNATURE_SIZE],
194 salt: [2; SIGNATURE_SALT_SIZE],
195 };
196 let serialized = serde_json::to_string(&ss).unwrap();
197 let deserialized: SignatureSet = serde_json::from_str(&serialized).unwrap();
198 assert_eq!(ss, deserialized);
199 }
200 #[test]
201 fn test_ss_serialize_str() {
202 let ss = SignatureSet {
203 signature: [1; SIGNATURE_SIZE],
204 salt: [2; SIGNATURE_SALT_SIZE],
205 };
206 let serialized = ss.to_string();
207 let deserialized: SignatureSet = serialized.parse().unwrap();
208 assert_eq!(ss, deserialized);
209 }
210}