1use crate::{Error, Result};
6use alloc::{string::String, vec::Vec};
7use serde::{Deserialize, Serialize};
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
11#[repr(u8)]
12pub enum SigningAlgorithm {
13 Ed25519 = 0x01,
15 EcdsaP256 = 0x02,
17 RsaPss2048 = 0x03,
19}
20
21impl SigningAlgorithm {
22 pub fn from_byte(byte: u8) -> Result<Self> {
24 match byte {
25 0x01 => Ok(SigningAlgorithm::Ed25519),
26 0x02 => Ok(SigningAlgorithm::EcdsaP256),
27 0x03 => Ok(SigningAlgorithm::RsaPss2048),
28 _ => Err(Error::UnsupportedAlgorithm(byte)),
29 }
30 }
31
32 pub fn name(&self) -> &'static str {
34 match self {
35 SigningAlgorithm::Ed25519 => "ed25519",
36 SigningAlgorithm::EcdsaP256 => "ecdsa-p256",
37 SigningAlgorithm::RsaPss2048 => "rsa-pss-2048",
38 }
39 }
40}
41
42#[derive(Debug, Clone)]
44pub struct KeyPair {
45 pub public_key_pem: String,
47 pub private_key_pem: String,
49}
50
51#[cfg(feature = "signing")]
53pub fn generate_key_pair(algorithm: SigningAlgorithm) -> Result<KeyPair> {
54 match algorithm {
55 SigningAlgorithm::Ed25519 => generate_ed25519_key_pair_pem(),
56 SigningAlgorithm::EcdsaP256 => generate_ecdsa_p256_key_pair(),
57 SigningAlgorithm::RsaPss2048 => generate_rsa_pss_key_pair(),
58 }
59}
60
61#[cfg(feature = "signing")]
62fn generate_ed25519_key_pair_pem() -> Result<KeyPair> {
63 use ed25519_dalek::SigningKey;
64 use rand::rngs::OsRng;
65
66 let signing_key = SigningKey::generate(&mut OsRng);
67 let verifying_key = signing_key.verifying_key();
68
69 let private_pem = format!(
71 "-----BEGIN PRIVATE KEY-----\n{}\n-----END PRIVATE KEY-----",
72 base64::Engine::encode(
73 &base64::engine::general_purpose::STANDARD,
74 signing_key.as_bytes()
75 )
76 );
77
78 let public_pem = format!(
79 "-----BEGIN PUBLIC KEY-----\n{}\n-----END PUBLIC KEY-----",
80 base64::Engine::encode(
81 &base64::engine::general_purpose::STANDARD,
82 verifying_key.as_bytes()
83 )
84 );
85
86 Ok(KeyPair {
87 public_key_pem: public_pem,
88 private_key_pem: private_pem,
89 })
90}
91
92#[cfg(feature = "signing")]
98pub fn generate_ed25519_key_pair() -> Result<(Vec<u8>, Vec<u8>)> {
99 use ed25519_dalek::SigningKey;
100 use rand::rngs::OsRng;
101
102 let signing_key = SigningKey::generate(&mut OsRng);
103 let verifying_key = signing_key.verifying_key();
104
105 Ok((
106 verifying_key.as_bytes().to_vec(),
107 signing_key.as_bytes().to_vec(),
108 ))
109}
110
111#[cfg(feature = "signing")]
112fn generate_ecdsa_p256_key_pair() -> Result<KeyPair> {
113 use p256::ecdsa::SigningKey;
114 use rand::rngs::OsRng;
115
116 let signing_key = SigningKey::random(&mut OsRng);
117 let verifying_key = signing_key.verifying_key();
118
119 let private_bytes = signing_key.to_bytes();
121 let public_bytes = verifying_key.to_encoded_point(false);
122
123 let private_pem = format!(
124 "-----BEGIN EC PRIVATE KEY-----\n{}\n-----END EC PRIVATE KEY-----",
125 base64::Engine::encode(&base64::engine::general_purpose::STANDARD, &private_bytes)
126 );
127
128 let public_pem = format!(
129 "-----BEGIN PUBLIC KEY-----\n{}\n-----END PUBLIC KEY-----",
130 base64::Engine::encode(
131 &base64::engine::general_purpose::STANDARD,
132 public_bytes.as_bytes()
133 )
134 );
135
136 Ok(KeyPair {
137 public_key_pem: public_pem,
138 private_key_pem: private_pem,
139 })
140}
141
142#[cfg(feature = "signing")]
143fn generate_rsa_pss_key_pair() -> Result<KeyPair> {
144 use rand::rngs::OsRng;
145 use rsa::{RsaPrivateKey, RsaPublicKey};
146
147 let bits = 2048;
148 let private_key = RsaPrivateKey::new(&mut OsRng, bits)
149 .map_err(|e| Error::KeyGenerationFailed(e.to_string()))?;
150 let _public_key = RsaPublicKey::from(&private_key);
151
152 let private_pem = format!(
154 "-----BEGIN RSA PRIVATE KEY-----\n{}\n-----END RSA PRIVATE KEY-----",
155 "... RSA PRIVATE KEY DATA ..."
156 );
157
158 let public_pem = format!(
159 "-----BEGIN RSA PUBLIC KEY-----\n{}\n-----END RSA PUBLIC KEY-----",
160 "... RSA PUBLIC KEY DATA ..."
161 );
162
163 Ok(KeyPair {
164 public_key_pem: public_pem,
165 private_key_pem: private_pem,
166 })
167}
168
169#[cfg(feature = "signing")]
171pub fn sign(data: &[u8], private_key_pem: &str, algorithm: SigningAlgorithm) -> Result<Vec<u8>> {
172 match algorithm {
173 SigningAlgorithm::Ed25519 => sign_ed25519_pem(data, private_key_pem),
174 SigningAlgorithm::EcdsaP256 => sign_ecdsa_p256(data, private_key_pem),
175 SigningAlgorithm::RsaPss2048 => sign_rsa_pss(data, private_key_pem),
176 }
177}
178
179#[cfg(feature = "signing")]
180fn sign_ed25519_pem(data: &[u8], private_key_pem: &str) -> Result<Vec<u8>> {
181 use ed25519_dalek::{Signer, SigningKey};
182
183 let pem_content = private_key_pem
185 .strip_prefix("-----BEGIN PRIVATE KEY-----\n")
186 .and_then(|s| s.strip_suffix("\n-----END PRIVATE KEY-----"))
187 .ok_or_else(|| Error::InvalidKeyFormat("Invalid PEM format".to_string()))?;
188
189 let key_bytes =
190 base64::Engine::decode(&base64::engine::general_purpose::STANDARD, pem_content)?;
191
192 if key_bytes.len() != 32 {
193 return Err(Error::InvalidKeyLength {
194 expected: 32,
195 actual: key_bytes.len(),
196 });
197 }
198
199 let signing_key = SigningKey::from_bytes(
200 &key_bytes
201 .try_into()
202 .map_err(|_| Error::InvalidKeyFormat("Failed to convert key bytes".to_string()))?,
203 );
204
205 let signature = signing_key.sign(data);
206 Ok(signature.to_bytes().to_vec())
207}
208
209#[cfg(feature = "signing")]
218pub fn sign_ed25519(data: &[u8], private_key: &[u8]) -> Result<Vec<u8>> {
219 use ed25519_dalek::{Signer, SigningKey};
220
221 if private_key.len() != 32 {
222 return Err(Error::InvalidKeyLength {
223 expected: 32,
224 actual: private_key.len(),
225 });
226 }
227
228 let signing_key = SigningKey::from_bytes(
229 &private_key
230 .try_into()
231 .map_err(|_| Error::InvalidKeyFormat("Failed to convert key bytes".to_string()))?,
232 );
233
234 let signature = signing_key.sign(data);
235 Ok(signature.to_bytes().to_vec())
236}
237
238#[cfg(feature = "signing")]
239fn sign_ecdsa_p256(_data: &[u8], _private_key_pem: &str) -> Result<Vec<u8>> {
240 Err(Error::SigningFailed("Not yet implemented".to_string()))
242}
243
244#[cfg(feature = "signing")]
245fn sign_rsa_pss(_data: &[u8], _private_key_pem: &str) -> Result<Vec<u8>> {
246 Err(Error::SigningFailed("Not yet implemented".to_string()))
248}
249
250#[cfg(feature = "signing")]
252pub fn verify(
253 data: &[u8],
254 signature: &[u8],
255 public_key_pem: &str,
256 algorithm: SigningAlgorithm,
257) -> Result<bool> {
258 match algorithm {
259 SigningAlgorithm::Ed25519 => verify_ed25519_pem(data, signature, public_key_pem),
260 SigningAlgorithm::EcdsaP256 => verify_ecdsa_p256(data, signature, public_key_pem),
261 SigningAlgorithm::RsaPss2048 => verify_rsa_pss(data, signature, public_key_pem),
262 }
263}
264
265#[cfg(feature = "signing")]
266fn verify_ed25519_pem(data: &[u8], signature: &[u8], public_key_pem: &str) -> Result<bool> {
267 use ed25519_dalek::{Signature, VerifyingKey};
268
269 let pem_content = public_key_pem
271 .strip_prefix("-----BEGIN PUBLIC KEY-----\n")
272 .and_then(|s| s.strip_suffix("\n-----END PUBLIC KEY-----"))
273 .ok_or_else(|| Error::InvalidKeyFormat("Invalid PEM format".to_string()))?;
274
275 let key_bytes =
276 base64::Engine::decode(&base64::engine::general_purpose::STANDARD, pem_content)?;
277
278 if key_bytes.len() != 32 {
279 return Err(Error::InvalidKeyLength {
280 expected: 32,
281 actual: key_bytes.len(),
282 });
283 }
284
285 if signature.len() != 64 {
286 return Err(Error::InvalidKeyLength {
287 expected: 64,
288 actual: signature.len(),
289 });
290 }
291
292 let verifying_key = VerifyingKey::from_bytes(
293 &key_bytes
294 .try_into()
295 .map_err(|_| Error::InvalidKeyFormat("Failed to convert key bytes".to_string()))?,
296 )
297 .map_err(|_| Error::InvalidKeyFormat("Invalid public key".to_string()))?;
298
299 let sig =
300 Signature::from_bytes(&signature.try_into().map_err(|_| {
301 Error::InvalidKeyFormat("Failed to convert signature bytes".to_string())
302 })?);
303
304 verifying_key
305 .verify_strict(data, &sig)
306 .map(|_| true)
307 .map_err(|_| Error::SignatureVerificationFailed)
308}
309
310#[cfg(feature = "signing")]
320pub fn verify_ed25519(data: &[u8], signature: &[u8], public_key: &[u8]) -> Result<bool> {
321 use ed25519_dalek::{Signature, VerifyingKey};
322
323 if public_key.len() != 32 {
324 return Err(Error::InvalidKeyLength {
325 expected: 32,
326 actual: public_key.len(),
327 });
328 }
329
330 if signature.len() != 64 {
331 return Err(Error::InvalidKeyLength {
332 expected: 64,
333 actual: signature.len(),
334 });
335 }
336
337 let verifying_key = VerifyingKey::from_bytes(
338 &public_key
339 .try_into()
340 .map_err(|_| Error::InvalidKeyFormat("Failed to convert key bytes".to_string()))?,
341 )
342 .map_err(|_| Error::InvalidKeyFormat("Invalid public key".to_string()))?;
343
344 let sig =
345 Signature::from_bytes(&signature.try_into().map_err(|_| {
346 Error::InvalidKeyFormat("Failed to convert signature bytes".to_string())
347 })?);
348
349 verifying_key
350 .verify_strict(data, &sig)
351 .map(|_| true)
352 .map_err(|_| Error::SignatureVerificationFailed)
353}
354
355#[cfg(feature = "signing")]
356fn verify_ecdsa_p256(_data: &[u8], _signature: &[u8], _public_key_pem: &str) -> Result<bool> {
357 Err(Error::SignatureVerificationFailed)
359}
360
361#[cfg(feature = "signing")]
362fn verify_rsa_pss(_data: &[u8], _signature: &[u8], _public_key_pem: &str) -> Result<bool> {
363 Err(Error::SignatureVerificationFailed)
365}
366
367#[cfg(test)]
368mod tests {
369 use super::*;
370
371 #[test]
372 fn test_algorithm_from_byte() {
373 assert_eq!(
374 SigningAlgorithm::from_byte(0x01).unwrap(),
375 SigningAlgorithm::Ed25519
376 );
377 assert_eq!(
378 SigningAlgorithm::from_byte(0x02).unwrap(),
379 SigningAlgorithm::EcdsaP256
380 );
381 assert_eq!(
382 SigningAlgorithm::from_byte(0x03).unwrap(),
383 SigningAlgorithm::RsaPss2048
384 );
385 assert!(SigningAlgorithm::from_byte(0xFF).is_err());
386 }
387
388 #[test]
389 fn test_algorithm_name() {
390 assert_eq!(SigningAlgorithm::Ed25519.name(), "ed25519");
391 assert_eq!(SigningAlgorithm::EcdsaP256.name(), "ecdsa-p256");
392 assert_eq!(SigningAlgorithm::RsaPss2048.name(), "rsa-pss-2048");
393 }
394}