1use crate::agent_key::{
7 AgentKey, DecryptionKey, EncryptionKey, JweAlgorithm, JweEncryption, JwsAlgorithm, SigningKey,
8 VerificationKey,
9};
10use crate::did::{KeyType, VerificationMaterial};
11use crate::error::{Error, Result};
12use crate::key_manager::{Secret, SecretMaterial};
13use crate::message::{EphemeralPublicKey, Jwe, JweProtected, Jws, JwsProtected, JwsSignature};
14#[cfg(feature = "crypto-p256")]
15use crate::message::{JweHeader, JweRecipient};
16use aes_gcm::{AeadInPlace, Aes256Gcm, KeyInit, Nonce};
17use async_trait::async_trait;
18use base64::Engine;
19#[cfg(feature = "crypto-ed25519")]
20use ed25519_dalek::{Signer as Ed25519Signer, Verifier, VerifyingKey};
21#[cfg(feature = "crypto-secp256k1")]
22use k256::{ecdsa::Signature as Secp256k1Signature, ecdsa::SigningKey as Secp256k1SigningKey};
23#[cfg(feature = "crypto-p256")]
24use p256::ecdh::EphemeralSecret as P256EphemeralSecret;
25#[cfg(feature = "crypto-p256")]
26use p256::elliptic_curve::sec1::{FromEncodedPoint, ToEncodedPoint};
27#[cfg(feature = "crypto-p256")]
28use p256::EncodedPoint as P256EncodedPoint;
29#[cfg(feature = "crypto-p256")]
30use p256::PublicKey as P256PublicKey;
31#[cfg(feature = "crypto-p256")]
32use p256::{ecdsa::Signature as P256Signature, ecdsa::SigningKey as P256SigningKey};
33#[cfg(any(
34 feature = "crypto-ed25519",
35 feature = "crypto-p256",
36 feature = "crypto-secp256k1"
37))]
38use rand::{rngs::OsRng, RngCore};
39use serde_json::Value;
40use std::convert::TryFrom;
41use std::sync::Arc;
42use uuid::Uuid;
43
44#[derive(Debug, Clone)]
46pub struct LocalAgentKey {
47 kid: String,
49 did: String,
51 pub secret: Secret,
53 key_type: KeyType,
55}
56
57impl LocalAgentKey {
58 pub async fn verify_jws(&self, jws: &crate::message::Jws) -> Result<Vec<u8>> {
60 let our_kid = crate::agent_key::AgentKey::key_id(self).to_string();
62 let signature = jws
63 .signatures
64 .iter()
65 .find(|s| s.get_kid() == Some(our_kid.clone()))
66 .ok_or_else(|| {
67 Error::Cryptography(format!("No signature found with kid: {}", our_kid))
68 })?;
69
70 let protected = signature.get_protected_header().map_err(|e| {
72 Error::Cryptography(format!("Failed to decode protected header: {}", e))
73 })?;
74
75 let signature_bytes = crate::message::base64_decode_flexible(&signature.signature)
77 .map_err(|e| Error::Cryptography(format!("Failed to decode signature: {}", e)))?;
78
79 let signing_input = format!("{}.{}", signature.protected, jws.payload);
81
82 let verified = self
84 .verify_signature(signing_input.as_bytes(), &signature_bytes, &protected)
85 .await?;
86
87 if !verified {
88 return Err(Error::Cryptography(
89 "Signature verification failed".to_string(),
90 ));
91 }
92
93 let payload_bytes = crate::message::base64_decode_flexible(&jws.payload)
95 .map_err(|e| Error::Cryptography(format!("Failed to decode payload: {}", e)))?;
96
97 Ok(payload_bytes)
98 }
99
100 pub async fn decrypt_jwe(&self, jwe: &crate::message::Jwe) -> Result<Vec<u8>> {
102 DecryptionKey::unwrap_jwe(self, jwe).await
104 }
105
106 pub async fn verify(&self, payload: &[u8], signature: &[u8]) -> Result<()> {
108 let protected = JwsProtected {
110 typ: "JWT".to_string(),
111 alg: self.recommended_jws_alg().as_str().to_string(),
112 kid: crate::agent_key::AgentKey::key_id(self).to_string(),
113 };
114
115 let result = self
117 .verify_signature(payload, signature, &protected)
118 .await?;
119 if result {
120 Ok(())
121 } else {
122 Err(Error::Cryptography(
123 "Signature verification failed".to_string(),
124 ))
125 }
126 }
127
128 pub async fn encrypt_to_jwk(
130 &self,
131 plaintext: &[u8],
132 recipient_jwk: &Value,
133 protected_header: Option<JweProtected>,
134 ) -> Result<Jwe> {
135 #[cfg(feature = "crypto-p256")]
136 {
137 let mut cek = [0u8; 32];
139 OsRng.fill_bytes(&mut cek);
140
141 let mut iv_bytes = [0u8; 12];
143 OsRng.fill_bytes(&mut iv_bytes);
144
145 let ephemeral_secret = P256EphemeralSecret::random(&mut OsRng);
147 let ephemeral_public_key = ephemeral_secret.public_key();
148
149 let point = ephemeral_public_key.to_encoded_point(false);
151 let x_bytes = point.x().unwrap().to_vec();
152 let y_bytes = point.y().unwrap().to_vec();
153 let x_b64 = base64::engine::general_purpose::STANDARD.encode(&x_bytes);
154 let y_b64 = base64::engine::general_purpose::STANDARD.encode(&y_bytes);
155
156 let ephemeral_key = crate::message::EphemeralPublicKey::Ec {
157 crv: "P-256".to_string(),
158 x: x_b64,
159 y: y_b64,
160 };
161
162 let recipient_x_b64 =
164 recipient_jwk
165 .get("x")
166 .and_then(|v| v.as_str())
167 .ok_or_else(|| {
168 Error::Cryptography("Missing x coordinate in recipient JWK".to_string())
169 })?;
170 let recipient_y_b64 =
171 recipient_jwk
172 .get("y")
173 .and_then(|v| v.as_str())
174 .ok_or_else(|| {
175 Error::Cryptography("Missing y coordinate in recipient JWK".to_string())
176 })?;
177
178 let recipient_x = base64::engine::general_purpose::STANDARD
179 .decode(recipient_x_b64)
180 .map_err(|e| Error::Cryptography(format!("Failed to decode x: {}", e)))?;
181 let recipient_y = base64::engine::general_purpose::STANDARD
182 .decode(recipient_y_b64)
183 .map_err(|e| Error::Cryptography(format!("Failed to decode y: {}", e)))?;
184
185 let mut recipient_point_bytes = vec![0x04]; recipient_point_bytes.extend_from_slice(&recipient_x);
188 recipient_point_bytes.extend_from_slice(&recipient_y);
189
190 let recipient_encoded_point = P256EncodedPoint::from_bytes(&recipient_point_bytes)
191 .map_err(|e| Error::Cryptography(format!("Invalid recipient point: {}", e)))?;
192
193 let recipient_pk = P256PublicKey::from_encoded_point(&recipient_encoded_point);
194 if recipient_pk.is_none().into() {
195 return Err(Error::Cryptography(
196 "Invalid recipient public key".to_string(),
197 ));
198 }
199 let recipient_pk = recipient_pk.unwrap();
200
201 let shared_secret = ephemeral_secret.diffie_hellman(&recipient_pk);
203 let shared_bytes = shared_secret.raw_secret_bytes();
204
205 let apv_raw = Uuid::new_v4();
207 let apv_b64 = base64::engine::general_purpose::STANDARD.encode(apv_raw.as_bytes());
208
209 let protected = protected_header.unwrap_or_else(|| crate::message::JweProtected {
210 epk: ephemeral_key,
211 apv: apv_b64.clone(),
212 apu: String::new(),
213 typ: crate::message::DIDCOMM_ENCRYPTED.to_string(),
214 enc: "A256GCM".to_string(),
215 alg: "ECDH-ES+A256KW".to_string(),
216 });
217
218 let apv_bytes = base64::engine::general_purpose::STANDARD
220 .decode(&protected.apv)
221 .unwrap_or_default();
222 let kek =
223 crate::crypto::derive_key_ecdh_es(shared_bytes.as_slice(), b"", &apv_bytes, 256)?;
224
225 let mut kek_array = [0u8; 32];
227 kek_array.copy_from_slice(&kek);
228 let wrapped_cek = crate::crypto::wrap_key_aes_kw(&kek_array, &cek)?;
229
230 let cipher = Aes256Gcm::new_from_slice(&cek)
232 .map_err(|e| Error::Cryptography(format!("Failed to create cipher: {}", e)))?;
233
234 let nonce = Nonce::from_slice(&iv_bytes);
235 let mut buffer = plaintext.to_vec();
236 let tag = cipher
237 .encrypt_in_place_detached(nonce, b"", &mut buffer)
238 .map_err(|e| Error::Cryptography(format!("Encryption failed: {:?}", e)))?;
239
240 let protected_json = serde_json::to_string(&protected).map_err(|e| {
242 Error::Serialization(format!("Failed to serialize protected header: {}", e))
243 })?;
244 let protected_b64 = base64::engine::general_purpose::STANDARD.encode(protected_json);
245
246 let recipient_kid = recipient_jwk
248 .get("kid")
249 .and_then(|v| v.as_str())
250 .unwrap_or("recipient-key")
251 .to_string();
252
253 let jwe = crate::message::Jwe {
255 ciphertext: base64::engine::general_purpose::STANDARD.encode(&buffer),
256 protected: protected_b64,
257 recipients: vec![crate::message::JweRecipient {
258 encrypted_key: base64::engine::general_purpose::STANDARD.encode(&wrapped_cek),
259 header: crate::message::JweHeader {
260 kid: recipient_kid,
261 sender_kid: Some(AgentKey::key_id(self).to_string()),
262 },
263 }],
264 tag: base64::engine::general_purpose::STANDARD.encode(tag),
265 iv: base64::engine::general_purpose::STANDARD.encode(iv_bytes),
266 };
267
268 Ok(jwe)
269 }
270
271 #[cfg(not(feature = "crypto-p256"))]
272 {
273 let _ = (plaintext, recipient_jwk, protected_header);
274 Err(Error::Cryptography(
275 "P-256 encryption not available - enable crypto-p256 feature".to_string(),
276 ))
277 }
278 }
279
280 pub fn new(secret: Secret, key_type: KeyType) -> Self {
282 let did = secret.id.clone();
283 let kid = match &secret.secret_material {
284 SecretMaterial::JWK { private_key_jwk } => {
285 if let Some(kid) = private_key_jwk.get("kid").and_then(|k| k.as_str()) {
286 kid.to_string()
287 } else {
288 if let Some(key_part) = did.strip_prefix("did:key:") {
290 format!("{}#{}", did, key_part)
293 } else if did.starts_with("did:web:") {
294 format!("{}#keys-1", did)
295 } else {
296 format!("{}#key-1", did)
297 }
298 }
299 }
300 };
301
302 Self {
303 kid,
304 did,
305 secret,
306 key_type,
307 }
308 }
309
310 #[cfg(feature = "crypto-ed25519")]
312 pub fn generate_ed25519(_kid: &str) -> Result<Self> {
313 let mut csprng = OsRng;
315 let signing_key = ed25519_dalek::SigningKey::generate(&mut csprng);
316 let verifying_key = VerifyingKey::from(&signing_key);
317
318 let public_key = verifying_key.to_bytes();
320 let private_key = signing_key.to_bytes();
321
322 let mut prefixed_key = vec![0xed, 0x01];
325 prefixed_key.extend_from_slice(&public_key);
326
327 let multibase_encoded = multibase::encode(multibase::Base::Base58Btc, &prefixed_key);
329 let did = format!("did:key:{}", multibase_encoded);
330
331 let kid = format!("{}#{}", did, multibase_encoded);
333
334 let secret = Secret {
336 id: did.clone(),
337 type_: crate::key_manager::SecretType::JsonWebKey2020,
338 secret_material: SecretMaterial::JWK {
339 private_key_jwk: serde_json::json!({
340 "kty": "OKP",
341 "kid": kid.clone(),
342 "crv": "Ed25519",
343 "x": base64::engine::general_purpose::STANDARD.encode(public_key),
344 "d": base64::engine::general_purpose::STANDARD.encode(private_key)
345 }),
346 },
347 };
348
349 Ok(Self {
350 kid,
351 did,
352 secret,
353 key_type: KeyType::Ed25519,
354 })
355 }
356
357 #[cfg(feature = "crypto-p256")]
359 pub fn generate_p256(_kid: &str) -> Result<Self> {
360 let mut rng = OsRng;
362 let signing_key = p256::ecdsa::SigningKey::random(&mut rng);
363
364 let private_key = signing_key.to_bytes().to_vec();
366 let public_key = signing_key
367 .verifying_key()
368 .to_encoded_point(false)
369 .to_bytes();
370
371 let mut prefixed_key = vec![0x12, 0x00];
374 prefixed_key.extend_from_slice(&public_key);
375
376 let multibase_encoded = multibase::encode(multibase::Base::Base58Btc, &prefixed_key);
378 let did = format!("did:key:{}", multibase_encoded);
379
380 let kid = format!("{}#{}", did, multibase_encoded);
382
383 let x = &public_key[1..33]; let y = &public_key[33..65];
386
387 let secret = Secret {
389 id: did.clone(),
390 type_: crate::key_manager::SecretType::JsonWebKey2020,
391 secret_material: SecretMaterial::JWK {
392 private_key_jwk: serde_json::json!({
393 "kty": "EC",
394 "kid": kid.clone(),
395 "crv": "P-256",
396 "x": base64::engine::general_purpose::STANDARD.encode(x),
397 "y": base64::engine::general_purpose::STANDARD.encode(y),
398 "d": base64::engine::general_purpose::STANDARD.encode(&private_key)
399 }),
400 },
401 };
402
403 Ok(Self {
404 kid,
405 did,
406 secret,
407 key_type: KeyType::P256,
408 })
409 }
410
411 #[cfg(feature = "crypto-secp256k1")]
413 pub fn generate_secp256k1(_kid: &str) -> Result<Self> {
414 let mut rng = OsRng;
416 let signing_key = k256::ecdsa::SigningKey::random(&mut rng);
417
418 let private_key = signing_key.to_bytes().to_vec();
420 let public_key = signing_key
421 .verifying_key()
422 .to_encoded_point(false)
423 .to_bytes();
424
425 let mut prefixed_key = vec![0xe7, 0x01];
428 prefixed_key.extend_from_slice(&public_key);
429
430 let multibase_encoded = multibase::encode(multibase::Base::Base58Btc, &prefixed_key);
432 let did = format!("did:key:{}", multibase_encoded);
433
434 let kid = format!("{}#{}", did, multibase_encoded);
436
437 let x = &public_key[1..33]; let y = &public_key[33..65];
440
441 let secret = Secret {
443 id: did.clone(),
444 type_: crate::key_manager::SecretType::JsonWebKey2020,
445 secret_material: SecretMaterial::JWK {
446 private_key_jwk: serde_json::json!({
447 "kty": "EC",
448 "kid": kid.clone(),
449 "crv": "secp256k1",
450 "x": base64::engine::general_purpose::STANDARD.encode(x),
451 "y": base64::engine::general_purpose::STANDARD.encode(y),
452 "d": base64::engine::general_purpose::STANDARD.encode(&private_key)
453 }),
454 },
455 };
456
457 Ok(Self {
458 kid,
459 did,
460 secret,
461 key_type: KeyType::Secp256k1,
462 })
463 }
464
465 fn private_key_jwk(&self) -> Result<&Value> {
467 match &self.secret.secret_material {
468 SecretMaterial::JWK { private_key_jwk } => Ok(private_key_jwk),
469 }
470 }
471
472 fn key_type_and_curve(&self) -> Result<(Option<&str>, Option<&str>)> {
474 let jwk = self.private_key_jwk()?;
475 let kty = jwk.get("kty").and_then(|v| v.as_str());
476 let crv = jwk.get("crv").and_then(|v| v.as_str());
477 Ok((kty, crv))
478 }
479
480 pub fn to_jwk(&self) -> Result<Value> {
482 Ok(self.private_key_jwk()?.clone())
483 }
484}
485
486#[async_trait]
487impl AgentKey for LocalAgentKey {
488 fn key_id(&self) -> &str {
489 &self.kid
490 }
491
492 fn public_key_jwk(&self) -> Result<Value> {
493 let jwk = self.private_key_jwk()?;
494
495 let mut public_jwk = serde_json::Map::new();
497
498 for (key, value) in jwk
500 .as_object()
501 .ok_or_else(|| Error::Cryptography("Invalid JWK format: not an object".to_string()))?
502 {
503 if key != "d" {
504 public_jwk.insert(key.clone(), value.clone());
505 }
506 }
507
508 Ok(Value::Object(public_jwk))
509 }
510
511 fn did(&self) -> &str {
512 &self.did
513 }
514
515 fn key_type(&self) -> &str {
516 match self.key_type {
517 #[cfg(feature = "crypto-ed25519")]
518 KeyType::Ed25519 => "Ed25519",
519 #[cfg(feature = "crypto-p256")]
520 KeyType::P256 => "P-256",
521 #[cfg(feature = "crypto-secp256k1")]
522 KeyType::Secp256k1 => "secp256k1",
523 }
524 }
525}
526
527#[async_trait]
528impl SigningKey for LocalAgentKey {
529 async fn sign(&self, data: &[u8]) -> Result<Vec<u8>> {
530 let (kty, crv) = self.key_type_and_curve()?;
531 let jwk = self.private_key_jwk()?;
532
533 match (kty, crv) {
534 #[cfg(feature = "crypto-ed25519")]
535 (Some("OKP"), Some("Ed25519")) => {
536 let private_key_base64 = jwk
538 .get("d")
539 .and_then(|v| v.as_str())
540 .ok_or_else(|| Error::Cryptography("Missing private key in JWK".to_string()))?;
541
542 let private_key_bytes = base64::engine::general_purpose::STANDARD
544 .decode(private_key_base64)
545 .map_err(|e| {
546 Error::Cryptography(format!("Failed to decode private key: {}", e))
547 })?;
548
549 if private_key_bytes.len() != 32 {
551 return Err(Error::Cryptography(format!(
552 "Invalid Ed25519 private key length: {}, expected 32 bytes",
553 private_key_bytes.len()
554 )));
555 }
556
557 let signing_key =
559 match ed25519_dalek::SigningKey::try_from(private_key_bytes.as_slice()) {
560 Ok(key) => key,
561 Err(e) => {
562 return Err(Error::Cryptography(format!(
563 "Failed to create Ed25519 signing key: {:?}",
564 e
565 )))
566 }
567 };
568
569 let signature = signing_key.sign(data);
571
572 Ok(signature.to_vec())
574 }
575 #[cfg(feature = "crypto-p256")]
576 (Some("EC"), Some("P-256")) => {
577 let private_key_base64 =
579 jwk.get("d").and_then(|v| v.as_str()).ok_or_else(|| {
580 Error::Cryptography("Missing private key (d) in JWK".to_string())
581 })?;
582
583 let private_key_bytes = base64::engine::general_purpose::STANDARD
585 .decode(private_key_base64)
586 .map_err(|e| {
587 Error::Cryptography(format!("Failed to decode P-256 private key: {}", e))
588 })?;
589
590 let signing_key = P256SigningKey::from_slice(&private_key_bytes).map_err(|e| {
592 Error::Cryptography(format!("Failed to create P-256 signing key: {:?}", e))
593 })?;
594
595 let signature: P256Signature = signing_key.sign(data);
597
598 let signature_bytes = signature.to_bytes();
600 Ok(signature_bytes.to_vec())
601 }
602 #[cfg(feature = "crypto-secp256k1")]
603 (Some("EC"), Some("secp256k1")) => {
604 let private_key_base64 =
606 jwk.get("d").and_then(|v| v.as_str()).ok_or_else(|| {
607 Error::Cryptography("Missing private key (d) in JWK".to_string())
608 })?;
609
610 let private_key_bytes = base64::engine::general_purpose::STANDARD
612 .decode(private_key_base64)
613 .map_err(|e| {
614 Error::Cryptography(format!(
615 "Failed to decode secp256k1 private key: {}",
616 e
617 ))
618 })?;
619
620 let signing_key =
622 Secp256k1SigningKey::from_slice(&private_key_bytes).map_err(|e| {
623 Error::Cryptography(format!(
624 "Failed to create secp256k1 signing key: {:?}",
625 e
626 ))
627 })?;
628
629 let signature: Secp256k1Signature = signing_key.sign(data);
631
632 let signature_bytes = signature.to_bytes();
634 Ok(signature_bytes.to_vec())
635 }
636 _ => Err(Error::Cryptography(format!(
638 "Unsupported key type for signing: kty={:?}, crv={:?}",
639 kty, crv
640 ))),
641 }
642 }
643
644 fn recommended_jws_alg(&self) -> JwsAlgorithm {
645 match self.key_type {
646 #[cfg(feature = "crypto-ed25519")]
647 KeyType::Ed25519 => JwsAlgorithm::EdDSA,
648 #[cfg(feature = "crypto-p256")]
649 KeyType::P256 => JwsAlgorithm::ES256,
650 #[cfg(feature = "crypto-secp256k1")]
651 KeyType::Secp256k1 => JwsAlgorithm::ES256K,
652 }
653 }
654
655 async fn create_jws(
656 &self,
657 payload: &[u8],
658 protected_header: Option<JwsProtected>,
659 ) -> Result<Jws> {
660 let payload_b64 = base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(payload);
662
663 let protected = if let Some(mut header) = protected_header {
665 header.alg = self.recommended_jws_alg().as_str().to_string();
667 if header.kid.is_empty() {
669 header.kid = crate::agent_key::AgentKey::key_id(self).to_string();
670 }
671 header
672 } else {
673 JwsProtected {
674 typ: crate::message::DIDCOMM_SIGNED.to_string(),
675 alg: self.recommended_jws_alg().as_str().to_string(),
676 kid: crate::agent_key::AgentKey::key_id(self).to_string(),
677 }
678 };
679
680 let protected_json = serde_json::to_string(&protected).map_err(|e| {
682 Error::Serialization(format!("Failed to serialize protected header: {}", e))
683 })?;
684
685 let protected_b64 = base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(protected_json);
686
687 let signing_input = format!("{}.{}", protected_b64, payload_b64);
689
690 let signature = self.sign(signing_input.as_bytes()).await?;
692
693 let signature_value = base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(&signature);
695
696 let jws = Jws {
698 payload: payload_b64,
699 signatures: vec![JwsSignature {
700 protected: protected_b64,
701 signature: signature_value,
702 }],
703 };
704
705 Ok(jws)
706 }
707}
708
709#[async_trait]
710impl VerificationKey for LocalAgentKey {
711 fn key_id(&self) -> &str {
712 &self.kid
713 }
714
715 fn public_key_jwk(&self) -> Result<Value> {
716 AgentKey::public_key_jwk(self)
717 }
718
719 async fn verify_signature(
720 &self,
721 payload: &[u8],
722 signature: &[u8],
723 protected_header: &JwsProtected,
724 ) -> Result<bool> {
725 let (kty, crv) = self.key_type_and_curve()?;
726 let jwk = self.private_key_jwk()?;
727
728 match (kty, crv, protected_header.alg.as_str()) {
729 #[cfg(feature = "crypto-ed25519")]
730 (Some("OKP"), Some("Ed25519"), "EdDSA") => {
731 let public_key_base64 = jwk.get("x").and_then(|v| v.as_str()).ok_or_else(|| {
733 Error::Cryptography("Missing public key (x) in JWK".to_string())
734 })?;
735
736 let public_key_bytes = base64::engine::general_purpose::STANDARD
738 .decode(public_key_base64)
739 .map_err(|e| {
740 Error::Cryptography(format!("Failed to decode public key: {}", e))
741 })?;
742
743 if public_key_bytes.len() != 32 {
745 return Err(Error::Cryptography(format!(
746 "Invalid Ed25519 public key length: {}, expected 32 bytes",
747 public_key_bytes.len()
748 )));
749 }
750
751 let verifying_key = match VerifyingKey::try_from(public_key_bytes.as_slice()) {
753 Ok(key) => key,
754 Err(e) => {
755 return Err(Error::Cryptography(format!(
756 "Failed to create Ed25519 verifying key: {:?}",
757 e
758 )))
759 }
760 };
761
762 if signature.len() != 64 {
764 return Err(Error::Cryptography(format!(
765 "Invalid Ed25519 signature length: {}, expected 64 bytes",
766 signature.len()
767 )));
768 }
769
770 let mut sig_bytes = [0u8; 64];
771 sig_bytes.copy_from_slice(signature);
772 let ed_signature = ed25519_dalek::Signature::from_bytes(&sig_bytes);
773
774 match verifying_key.verify(payload, &ed_signature) {
775 Ok(()) => Ok(true),
776 Err(_) => Ok(false),
777 }
778 }
779 #[cfg(feature = "crypto-p256")]
780 (Some("EC"), Some("P-256"), "ES256") => {
781 let x_b64 = jwk.get("x").and_then(|v| v.as_str()).ok_or_else(|| {
783 Error::Cryptography("Missing x coordinate in JWK".to_string())
784 })?;
785 let y_b64 = jwk.get("y").and_then(|v| v.as_str()).ok_or_else(|| {
786 Error::Cryptography("Missing y coordinate in JWK".to_string())
787 })?;
788
789 let x_bytes = base64::engine::general_purpose::STANDARD
791 .decode(x_b64)
792 .map_err(|e| {
793 Error::Cryptography(format!("Failed to decode x coordinate: {}", e))
794 })?;
795 let y_bytes = base64::engine::general_purpose::STANDARD
796 .decode(y_b64)
797 .map_err(|e| {
798 Error::Cryptography(format!("Failed to decode y coordinate: {}", e))
799 })?;
800
801 let mut point_bytes = vec![0x04]; point_bytes.extend_from_slice(&x_bytes);
804 point_bytes.extend_from_slice(&y_bytes);
805
806 let encoded_point = P256EncodedPoint::from_bytes(&point_bytes).map_err(|e| {
807 Error::Cryptography(format!("Failed to create P-256 encoded point: {}", e))
808 })?;
809
810 let public_key_opt = P256PublicKey::from_encoded_point(&encoded_point);
812 if public_key_opt.is_none().into() {
813 return Err(Error::Cryptography("Invalid P-256 public key".to_string()));
814 }
815 let public_key = public_key_opt.unwrap();
816
817 let p256_signature = P256Signature::from_slice(signature).map_err(|e| {
819 Error::Cryptography(format!("Failed to parse P-256 signature: {:?}", e))
820 })?;
821
822 let verifier = p256::ecdsa::VerifyingKey::from(public_key);
824 match verifier.verify(payload, &p256_signature) {
825 Ok(()) => Ok(true),
826 Err(_) => Ok(false),
827 }
828 }
829 #[cfg(feature = "crypto-secp256k1")]
830 (Some("EC"), Some("secp256k1"), "ES256K") => {
831 let x_b64 = jwk.get("x").and_then(|v| v.as_str()).ok_or_else(|| {
833 Error::Cryptography("Missing x coordinate in JWK".to_string())
834 })?;
835 let y_b64 = jwk.get("y").and_then(|v| v.as_str()).ok_or_else(|| {
836 Error::Cryptography("Missing y coordinate in JWK".to_string())
837 })?;
838
839 let x_bytes = base64::engine::general_purpose::STANDARD
841 .decode(x_b64)
842 .map_err(|e| {
843 Error::Cryptography(format!("Failed to decode x coordinate: {}", e))
844 })?;
845 let y_bytes = base64::engine::general_purpose::STANDARD
846 .decode(y_b64)
847 .map_err(|e| {
848 Error::Cryptography(format!("Failed to decode y coordinate: {}", e))
849 })?;
850
851 let mut point_bytes = vec![0x04]; point_bytes.extend_from_slice(&x_bytes);
854 point_bytes.extend_from_slice(&y_bytes);
855
856 let verifier =
858 k256::ecdsa::VerifyingKey::from_sec1_bytes(&point_bytes).map_err(|e| {
859 Error::Cryptography(format!(
860 "Failed to create secp256k1 verifying key: {:?}",
861 e
862 ))
863 })?;
864
865 let k256_signature = Secp256k1Signature::from_slice(signature).map_err(|e| {
867 Error::Cryptography(format!("Failed to parse secp256k1 signature: {:?}", e))
868 })?;
869
870 match verifier.verify(payload, &k256_signature) {
872 Ok(()) => Ok(true),
873 Err(_) => Ok(false),
874 }
875 }
876 _ => Err(Error::Cryptography(format!(
878 "Unsupported key type/algorithm combination for verification: kty={:?}, crv={:?}, alg={}",
879 kty, crv, protected_header.alg
880 ))),
881 }
882 }
883}
884
885#[async_trait]
886impl EncryptionKey for LocalAgentKey {
887 async fn encrypt(
888 &self,
889 plaintext: &[u8],
890 aad: Option<&[u8]>,
891 _recipient_public_key: &dyn VerificationKey,
892 ) -> Result<(Vec<u8>, Vec<u8>, Vec<u8>)> {
893 let mut cek = [0u8; 32]; OsRng.fill_bytes(&mut cek);
898
899 let mut iv_bytes = [0u8; 12]; OsRng.fill_bytes(&mut iv_bytes);
902
903 let cipher = Aes256Gcm::new_from_slice(&cek)
905 .map_err(|e| Error::Cryptography(format!("Failed to create AES-GCM cipher: {}", e)))?;
906
907 let nonce = Nonce::from_slice(&iv_bytes);
909
910 let mut buffer = plaintext.to_vec();
912 let aad_bytes = aad.unwrap_or(b"");
913 let tag = cipher
914 .encrypt_in_place_detached(nonce, aad_bytes, &mut buffer)
915 .map_err(|e| Error::Cryptography(format!("AES-GCM encryption failed: {}", e)))?;
916
917 Ok((buffer, iv_bytes.to_vec(), tag.to_vec()))
919 }
920
921 fn recommended_jwe_alg_enc(&self) -> (JweAlgorithm, JweEncryption) {
922 (JweAlgorithm::EcdhEsA256kw, JweEncryption::A256GCM)
925 }
926
927 async fn create_jwe(
928 &self,
929 plaintext: &[u8],
930 recipients: &[Arc<dyn VerificationKey>],
931 protected_header: Option<JweProtected>,
932 ) -> Result<Jwe> {
933 if recipients.is_empty() {
934 return Err(Error::Validation(
935 "No recipients specified for JWE".to_string(),
936 ));
937 }
938
939 let mut cek = [0u8; 32]; OsRng.fill_bytes(&mut cek);
942
943 let mut iv_bytes = [0u8; 12]; OsRng.fill_bytes(&mut iv_bytes);
946
947 #[cfg(feature = "crypto-p256")]
949 let ephemeral_secret = P256EphemeralSecret::random(&mut OsRng);
950 #[cfg(feature = "crypto-p256")]
951 let ephemeral_public_key = ephemeral_secret.public_key();
952
953 #[cfg(feature = "crypto-p256")]
955 let point = ephemeral_public_key.to_encoded_point(false); #[cfg(feature = "crypto-p256")]
957 let x_bytes = point.x().unwrap().to_vec();
958 #[cfg(feature = "crypto-p256")]
959 let y_bytes = point.y().unwrap().to_vec();
960
961 #[cfg(feature = "crypto-p256")]
963 let x_b64 = base64::engine::general_purpose::STANDARD.encode(&x_bytes);
964 #[cfg(feature = "crypto-p256")]
965 let y_b64 = base64::engine::general_purpose::STANDARD.encode(&y_bytes);
966
967 #[cfg(feature = "crypto-p256")]
969 let ephemeral_key = EphemeralPublicKey::Ec {
970 crv: "P-256".to_string(),
971 x: x_b64,
972 y: y_b64,
973 };
974 #[cfg(not(feature = "crypto-p256"))]
975 let ephemeral_key = EphemeralPublicKey::Ec {
976 crv: "P-256".to_string(),
977 x: "".to_string(),
978 y: "".to_string(),
979 };
980
981 let protected = protected_header.unwrap_or_else(|| {
983 let (alg, enc) = self.recommended_jwe_alg_enc();
984 JweProtected {
985 epk: ephemeral_key,
986 apv: base64::engine::general_purpose::STANDARD.encode(Uuid::new_v4().as_bytes()),
987 apu: String::new(),
988 typ: crate::message::DIDCOMM_ENCRYPTED.to_string(),
989 enc: enc.as_str().to_string(),
990 alg: alg.as_str().to_string(),
991 }
992 });
993
994 let cipher = Aes256Gcm::new_from_slice(&cek)
996 .map_err(|e| Error::Cryptography(format!("Failed to create AES-GCM cipher: {}", e)))?;
997
998 let nonce = Nonce::from_slice(&iv_bytes);
1000
1001 let mut buffer = plaintext.to_vec();
1003 let tag = cipher
1004 .encrypt_in_place_detached(nonce, b"", &mut buffer)
1005 .map_err(|e| Error::Cryptography(format!("AES-GCM encryption failed: {}", e)))?;
1006
1007 #[cfg(not(feature = "crypto-p256"))]
1009 {
1010 let _ = (recipients, protected, buffer, tag, iv_bytes); return Err(Error::Cryptography(
1012 "P-256 encryption not available - enable crypto-p256 feature".to_string(),
1013 ));
1014 }
1015
1016 #[cfg(feature = "crypto-p256")]
1017 {
1018 let mut jwe_recipients = Vec::with_capacity(recipients.len());
1019
1020 for recipient in recipients {
1021 let recipient_jwk = recipient.public_key_jwk()?;
1023
1024 let kty = recipient_jwk.get("kty").and_then(|v| v.as_str());
1026 let crv = recipient_jwk.get("crv").and_then(|v| v.as_str());
1027
1028 let encrypted_key = match (kty, crv) {
1029 (Some("EC"), Some("P-256")) => {
1030 let x_b64 =
1032 recipient_jwk
1033 .get("x")
1034 .and_then(|v| v.as_str())
1035 .ok_or_else(|| {
1036 Error::Cryptography(
1037 "Missing x coordinate in recipient JWK".to_string(),
1038 )
1039 })?;
1040 let y_b64 =
1041 recipient_jwk
1042 .get("y")
1043 .and_then(|v| v.as_str())
1044 .ok_or_else(|| {
1045 Error::Cryptography(
1046 "Missing y coordinate in recipient JWK".to_string(),
1047 )
1048 })?;
1049
1050 let x_bytes = base64::engine::general_purpose::STANDARD
1051 .decode(x_b64)
1052 .map_err(|e| {
1053 Error::Cryptography(format!("Failed to decode x coordinate: {}", e))
1054 })?;
1055 let y_bytes = base64::engine::general_purpose::STANDARD
1056 .decode(y_b64)
1057 .map_err(|e| {
1058 Error::Cryptography(format!("Failed to decode y coordinate: {}", e))
1059 })?;
1060
1061 let mut point_bytes = vec![0x04]; point_bytes.extend_from_slice(&x_bytes);
1064 point_bytes.extend_from_slice(&y_bytes);
1065
1066 let encoded_point =
1067 P256EncodedPoint::from_bytes(&point_bytes).map_err(|e| {
1068 Error::Cryptography(format!(
1069 "Failed to create P-256 encoded point: {}",
1070 e
1071 ))
1072 })?;
1073
1074 let recipient_pk_opt = P256PublicKey::from_encoded_point(&encoded_point);
1076 if recipient_pk_opt.is_none().into() {
1077 return Err(Error::Cryptography(
1078 "Invalid P-256 public key".to_string(),
1079 ));
1080 }
1081 let recipient_pk = recipient_pk_opt.unwrap();
1082
1083 let shared_secret = ephemeral_secret.diffie_hellman(&recipient_pk);
1085 let shared_bytes = shared_secret.raw_secret_bytes();
1086
1087 let apv_bytes = base64::engine::general_purpose::STANDARD
1090 .decode(&protected.apv)
1091 .unwrap_or_default();
1092 let kek = crate::crypto::derive_key_ecdh_es(
1093 shared_bytes.as_slice(),
1094 b"", &apv_bytes,
1096 256, )?;
1098
1099 let mut kek_array = [0u8; 32];
1101 kek_array.copy_from_slice(&kek);
1102
1103 crate::crypto::wrap_key_aes_kw(&kek_array, &cek)?
1104 }
1105 _ => {
1107 return Err(Error::Cryptography(format!(
1108 "Unsupported recipient key type for encryption: kty={:?}, crv={:?}",
1109 kty, crv
1110 )));
1111 }
1112 };
1113
1114 jwe_recipients.push(JweRecipient {
1116 encrypted_key: base64::engine::general_purpose::STANDARD.encode(encrypted_key),
1117 header: JweHeader {
1118 kid: (**recipient).key_id().to_string(),
1119 sender_kid: Some(crate::agent_key::AgentKey::key_id(self).to_string()),
1120 },
1121 });
1122 }
1123
1124 let protected_json = serde_json::to_string(&protected).map_err(|e| {
1126 Error::Serialization(format!("Failed to serialize protected header: {}", e))
1127 })?;
1128
1129 let protected_b64 = base64::engine::general_purpose::STANDARD.encode(protected_json);
1130
1131 let jwe = Jwe {
1133 ciphertext: base64::engine::general_purpose::STANDARD.encode(buffer),
1134 protected: protected_b64,
1135 recipients: jwe_recipients,
1136 tag: base64::engine::general_purpose::STANDARD.encode(tag),
1137 iv: base64::engine::general_purpose::STANDARD.encode(iv_bytes),
1138 };
1139
1140 Ok(jwe)
1141 }
1142 }
1143}
1144
1145#[async_trait]
1146impl DecryptionKey for LocalAgentKey {
1147 async fn decrypt(
1148 &self,
1149 ciphertext: &[u8],
1150 encrypted_key: &[u8],
1151 iv: &[u8],
1152 tag: &[u8],
1153 aad: Option<&[u8]>,
1154 _sender_key: Option<&dyn VerificationKey>,
1155 ) -> Result<Vec<u8>> {
1156 let _ = (ciphertext, encrypted_key, iv, tag, aad);
1160 Err(Error::Cryptography(
1161 "decrypt() is not supported for ECDH-ES+A256KW keys; use unwrap_jwe() instead"
1162 .to_string(),
1163 ))
1164 }
1165
1166 async fn unwrap_jwe(&self, jwe: &Jwe) -> Result<Vec<u8>> {
1167 let our_kid = crate::agent_key::AgentKey::key_id(self);
1168
1169 let our_did = our_kid.split('#').next().unwrap_or(our_kid);
1171 let recipient = jwe
1172 .recipients
1173 .iter()
1174 .find(|r| r.header.kid == our_kid || r.header.kid.starts_with(&format!("{}#", our_did)))
1175 .ok_or_else(|| {
1176 Error::Cryptography(format!(
1177 "No matching recipient found for key ID: {}",
1178 our_kid
1179 ))
1180 })?;
1181
1182 let protected_bytes =
1184 crate::message::base64_decode_flexible(&jwe.protected).map_err(|e| {
1185 Error::Cryptography(format!("Failed to decode protected header: {}", e))
1186 })?;
1187
1188 let protected: JweProtected = serde_json::from_slice(&protected_bytes)
1189 .map_err(|e| Error::Cryptography(format!("Failed to parse protected header: {}", e)))?;
1190
1191 let ciphertext = crate::message::base64_decode_flexible(&jwe.ciphertext)
1193 .map_err(|e| Error::Cryptography(format!("Failed to decode ciphertext: {}", e)))?;
1194
1195 let wrapped_cek = crate::message::base64_decode_flexible(&recipient.encrypted_key)
1196 .map_err(|e| Error::Cryptography(format!("Failed to decode encrypted key: {}", e)))?;
1197
1198 let iv = crate::message::base64_decode_flexible(&jwe.iv)
1199 .map_err(|e| Error::Cryptography(format!("Failed to decode IV: {}", e)))?;
1200
1201 let tag = crate::message::base64_decode_flexible(&jwe.tag)
1202 .map_err(|e| Error::Cryptography(format!("Failed to decode tag: {}", e)))?;
1203
1204 let shared_bytes: Vec<u8> = match &protected.epk {
1206 #[cfg(feature = "crypto-ed25519")]
1207 EphemeralPublicKey::Okp { crv, x } if crv == "X25519" => {
1208 let epk_bytes = crate::message::base64_decode_flexible(x).map_err(|e| {
1210 Error::Cryptography(format!("Failed to decode X25519 EPK: {}", e))
1211 })?;
1212 if epk_bytes.len() != 32 {
1213 return Err(Error::Cryptography("Invalid X25519 EPK length".to_string()));
1214 }
1215
1216 let jwk = self.private_key_jwk()?;
1218 let d_b64 = jwk.get("d").and_then(|v| v.as_str()).ok_or_else(|| {
1219 Error::Cryptography("Missing private key (d) in JWK".to_string())
1220 })?;
1221 let d_bytes = crate::message::base64_decode_flexible(d_b64).map_err(|e| {
1222 Error::Cryptography(format!("Failed to decode private key: {}", e))
1223 })?;
1224
1225 use sha2::Digest;
1228 let hash = sha2::Sha512::digest(&d_bytes);
1229 let mut x25519_key_bytes = [0u8; 32];
1230 x25519_key_bytes.copy_from_slice(&hash[..32]);
1231
1232 let secret = x25519_dalek::StaticSecret::from(x25519_key_bytes);
1233 let epk_array: [u8; 32] = epk_bytes[..32].try_into().unwrap();
1234 let public = x25519_dalek::PublicKey::from(epk_array);
1235 let shared = secret.diffie_hellman(&public);
1236 shared.as_bytes().to_vec()
1237 }
1238 #[cfg(feature = "crypto-p256")]
1239 EphemeralPublicKey::Ec { x, y, .. } => {
1240 let epk_x = crate::message::base64_decode_flexible(x)
1242 .map_err(|e| Error::Cryptography(format!("Failed to decode EPK x: {}", e)))?;
1243 let epk_y = crate::message::base64_decode_flexible(y)
1244 .map_err(|e| Error::Cryptography(format!("Failed to decode EPK y: {}", e)))?;
1245
1246 let mut epk_point_bytes = vec![0x04];
1247 epk_point_bytes.extend_from_slice(&epk_x);
1248 epk_point_bytes.extend_from_slice(&epk_y);
1249
1250 let epk_encoded_point = P256EncodedPoint::from_bytes(&epk_point_bytes)
1251 .map_err(|e| Error::Cryptography(format!("Invalid EPK point: {}", e)))?;
1252
1253 let epk_public_key = P256PublicKey::from_encoded_point(&epk_encoded_point);
1254 if epk_public_key.is_none().into() {
1255 return Err(Error::Cryptography("Invalid EPK public key".to_string()));
1256 }
1257 let epk_public_key = epk_public_key.unwrap();
1258
1259 let jwk = self.private_key_jwk()?;
1260 let d_b64 = jwk.get("d").and_then(|v| v.as_str()).ok_or_else(|| {
1261 Error::Cryptography("Missing private key (d) in JWK".to_string())
1262 })?;
1263 let d_bytes = base64::engine::general_purpose::STANDARD
1264 .decode(d_b64)
1265 .map_err(|e| {
1266 Error::Cryptography(format!("Failed to decode private key: {}", e))
1267 })?;
1268
1269 let secret_key = p256::SecretKey::from_bytes((&d_bytes[..]).into())
1270 .map_err(|e| Error::Cryptography(format!("Invalid private key: {}", e)))?;
1271
1272 let shared_secret = p256::ecdh::diffie_hellman(
1273 secret_key.to_nonzero_scalar(),
1274 epk_public_key.as_affine(),
1275 );
1276 shared_secret.raw_secret_bytes().to_vec()
1277 }
1278 _ => {
1279 return Err(Error::Cryptography(
1280 "Unsupported EPK type for JWE decryption".to_string(),
1281 ))
1282 }
1283 };
1284
1285 let apu = if protected.apu.is_empty() {
1288 Vec::new()
1289 } else {
1290 crate::message::base64_decode_flexible(&protected.apu).unwrap_or_default()
1291 };
1292 let apv = if protected.apv.is_empty() {
1293 Vec::new()
1294 } else {
1295 crate::message::base64_decode_flexible(&protected.apv).unwrap_or_default()
1296 };
1297
1298 let kek = crate::crypto::derive_key_ecdh_es(&shared_bytes, &apu, &apv, 256)?;
1299
1300 let mut kek_array = [0u8; 32];
1302 kek_array.copy_from_slice(&kek);
1303 let cek = crate::crypto::unwrap_key_aes_kw(&kek_array, &wrapped_cek)?;
1304
1305 let cipher = Aes256Gcm::new_from_slice(&cek)
1307 .map_err(|e| Error::Cryptography(format!("Failed to create AES-GCM cipher: {}", e)))?;
1308
1309 let nonce = Nonce::from_slice(&iv);
1310
1311 let mut padded_tag = [0u8; 16];
1312 let copy_len = std::cmp::min(tag.len(), 16);
1313 padded_tag[..copy_len].copy_from_slice(&tag[..copy_len]);
1314 let tag_array = aes_gcm::Tag::from_slice(&padded_tag);
1315
1316 let mut buffer = ciphertext.to_vec();
1317 cipher
1318 .decrypt_in_place_detached(nonce, jwe.protected.as_bytes(), &mut buffer, tag_array)
1319 .or_else(|_| {
1320 buffer = ciphertext.to_vec();
1322 cipher.decrypt_in_place_detached(nonce, b"", &mut buffer, tag_array)
1323 })
1324 .map_err(|e| Error::Cryptography(format!("AES-GCM decryption failed: {:?}", e)))?;
1325
1326 Ok(buffer)
1327 }
1328}
1329
1330#[derive(Debug, Clone)]
1332pub struct PublicVerificationKey {
1333 kid: String,
1335 public_jwk: Value,
1337}
1338
1339impl PublicVerificationKey {
1340 pub async fn verify_jws(&self, jws: &crate::message::Jws) -> Result<Vec<u8>> {
1342 let signature = jws
1344 .signatures
1345 .iter()
1346 .find(|s| s.get_kid().as_ref() == Some(&self.kid))
1347 .ok_or_else(|| {
1348 Error::Cryptography(format!("No signature found with kid: {}", self.kid))
1349 })?;
1350
1351 let protected = signature.get_protected_header().map_err(|e| {
1353 Error::Cryptography(format!("Failed to decode protected header: {}", e))
1354 })?;
1355
1356 let signature_bytes = crate::message::base64_decode_flexible(&signature.signature)
1358 .map_err(|e| Error::Cryptography(format!("Failed to decode signature: {}", e)))?;
1359
1360 let signing_input = format!("{}.{}", signature.protected, jws.payload);
1362
1363 let verified = self
1365 .verify_signature(signing_input.as_bytes(), &signature_bytes, &protected)
1366 .await
1367 .map_err(|e| Error::Cryptography(e.to_string()))?;
1368
1369 if !verified {
1370 return Err(Error::Cryptography(
1371 "Signature verification failed".to_string(),
1372 ));
1373 }
1374
1375 let payload_bytes = crate::message::base64_decode_flexible(&jws.payload)
1377 .map_err(|e| Error::Cryptography(format!("Failed to decode payload: {}", e)))?;
1378
1379 Ok(payload_bytes)
1380 }
1381
1382 pub async fn verify(&self, payload: &[u8], signature: &[u8]) -> Result<()> {
1384 let kty = self.public_jwk.get("kty").and_then(|v| v.as_str());
1386 let crv = self.public_jwk.get("crv").and_then(|v| v.as_str());
1387
1388 let alg = match (kty, crv) {
1390 (Some("OKP"), Some("Ed25519")) => "EdDSA",
1391 (Some("EC"), Some("P-256")) => "ES256",
1392 (Some("EC"), Some("secp256k1")) => "ES256K",
1393 _ => return Err(Error::Cryptography("Unsupported key type".to_string())),
1394 };
1395
1396 let protected = JwsProtected {
1397 typ: "JWT".to_string(),
1398 alg: alg.to_string(),
1399 kid: self.kid.clone(),
1400 };
1401
1402 let result = self
1404 .verify_signature(payload, signature, &protected)
1405 .await?;
1406 if result {
1407 Ok(())
1408 } else {
1409 Err(Error::Cryptography(
1410 "Signature verification failed".to_string(),
1411 ))
1412 }
1413 }
1414
1415 pub fn new(kid: String, public_jwk: Value) -> Self {
1417 Self { kid, public_jwk }
1418 }
1419
1420 pub fn from_jwk(jwk: &Value, kid: &str, _did: &str) -> Result<Self> {
1422 let mut public_jwk = serde_json::Map::new();
1424
1425 if let Some(obj) = jwk.as_object() {
1426 for (key, value) in obj {
1428 if key != "d" {
1429 public_jwk.insert(key.clone(), value.clone());
1430 }
1431 }
1432 } else {
1433 return Err(Error::Cryptography(
1434 "Invalid JWK format: not an object".to_string(),
1435 ));
1436 }
1437
1438 Ok(Self {
1439 kid: kid.to_string(),
1440 public_jwk: Value::Object(public_jwk),
1441 })
1442 }
1443
1444 pub fn from_verification_material(
1446 kid: String,
1447 material: &VerificationMaterial,
1448 ) -> Result<Self> {
1449 match material {
1450 VerificationMaterial::JWK { public_key_jwk } => {
1451 Ok(Self::new(kid, public_key_jwk.clone()))
1452 }
1453 VerificationMaterial::Base58 { public_key_base58 } => {
1454 let public_key_bytes = bs58::decode(public_key_base58).into_vec().map_err(|e| {
1456 Error::Cryptography(format!("Failed to decode Base58 key: {}", e))
1457 })?;
1458
1459 Ok(Self::new(
1461 kid,
1462 serde_json::json!({
1463 "kty": "OKP",
1464 "crv": "Ed25519",
1465 "x": base64::engine::general_purpose::STANDARD.encode(public_key_bytes),
1466 }),
1467 ))
1468 }
1469 VerificationMaterial::Multibase {
1470 public_key_multibase,
1471 } => {
1472 let (_, bytes) = multibase::decode(public_key_multibase).map_err(|e| {
1474 Error::Cryptography(format!("Failed to decode Multibase key: {}", e))
1475 })?;
1476
1477 if bytes.len() >= 2 && bytes[0] == 0xed && bytes[1] == 0x01 {
1479 let key_bytes = &bytes[2..];
1481 Ok(Self::new(
1482 kid,
1483 serde_json::json!({
1484 "kty": "OKP",
1485 "crv": "Ed25519",
1486 "x": base64::engine::general_purpose::STANDARD.encode(key_bytes),
1487 }),
1488 ))
1489 } else {
1490 Ok(Self::new(
1492 kid,
1493 serde_json::json!({
1494 "kty": "OKP",
1495 "crv": "Ed25519",
1496 "x": base64::engine::general_purpose::STANDARD.encode(bytes),
1497 }),
1498 ))
1499 }
1500 }
1501 }
1502 }
1503}
1504
1505#[async_trait]
1506impl VerificationKey for PublicVerificationKey {
1507 fn key_id(&self) -> &str {
1508 &self.kid
1509 }
1510
1511 fn public_key_jwk(&self) -> Result<Value> {
1512 Ok(self.public_jwk.clone())
1513 }
1514
1515 async fn verify_signature(
1516 &self,
1517 payload: &[u8],
1518 signature: &[u8],
1519 protected_header: &JwsProtected,
1520 ) -> Result<bool> {
1521 let kty = self.public_jwk.get("kty").and_then(|v| v.as_str());
1522 let crv = self.public_jwk.get("crv").and_then(|v| v.as_str());
1523
1524 match (kty, crv, protected_header.alg.as_str()) {
1525 #[cfg(feature = "crypto-ed25519")]
1526 (Some("OKP"), Some("Ed25519"), "EdDSA") => {
1527 let public_key_base64 = self
1529 .public_jwk
1530 .get("x")
1531 .and_then(|v| v.as_str())
1532 .ok_or_else(|| {
1533 Error::Cryptography("Missing public key (x) in JWK".to_string())
1534 })?;
1535
1536 let public_key_bytes = base64::engine::general_purpose::STANDARD
1538 .decode(public_key_base64)
1539 .map_err(|e| {
1540 Error::Cryptography(format!("Failed to decode public key: {}", e))
1541 })?;
1542
1543 if public_key_bytes.len() != 32 {
1545 return Err(Error::Cryptography(format!(
1546 "Invalid Ed25519 public key length: {}, expected 32 bytes",
1547 public_key_bytes.len()
1548 )));
1549 }
1550
1551 let verifying_key = match VerifyingKey::try_from(public_key_bytes.as_slice()) {
1553 Ok(key) => key,
1554 Err(e) => {
1555 return Err(Error::Cryptography(format!(
1556 "Failed to create Ed25519 verifying key: {:?}",
1557 e
1558 )))
1559 }
1560 };
1561
1562 if signature.len() != 64 {
1564 return Err(Error::Cryptography(format!(
1565 "Invalid Ed25519 signature length: {}, expected 64 bytes",
1566 signature.len()
1567 )));
1568 }
1569
1570 let mut sig_bytes = [0u8; 64];
1571 sig_bytes.copy_from_slice(signature);
1572 let ed_signature = ed25519_dalek::Signature::from_bytes(&sig_bytes);
1573
1574 match verifying_key.verify(payload, &ed_signature) {
1575 Ok(()) => Ok(true),
1576 Err(_) => Ok(false),
1577 }
1578 }
1579 #[cfg(feature = "crypto-p256")]
1580 (Some("EC"), Some("P-256"), "ES256") => {
1581 let x_b64 = self
1583 .public_jwk
1584 .get("x")
1585 .and_then(|v| v.as_str())
1586 .ok_or_else(|| {
1587 Error::Cryptography("Missing x coordinate in JWK".to_string())
1588 })?;
1589 let y_b64 = self
1590 .public_jwk
1591 .get("y")
1592 .and_then(|v| v.as_str())
1593 .ok_or_else(|| {
1594 Error::Cryptography("Missing y coordinate in JWK".to_string())
1595 })?;
1596
1597 let x_bytes = base64::engine::general_purpose::STANDARD
1599 .decode(x_b64)
1600 .map_err(|e| {
1601 Error::Cryptography(format!("Failed to decode x coordinate: {}", e))
1602 })?;
1603 let y_bytes = base64::engine::general_purpose::STANDARD
1604 .decode(y_b64)
1605 .map_err(|e| {
1606 Error::Cryptography(format!("Failed to decode y coordinate: {}", e))
1607 })?;
1608
1609 let mut point_bytes = vec![0x04]; point_bytes.extend_from_slice(&x_bytes);
1612 point_bytes.extend_from_slice(&y_bytes);
1613
1614 let encoded_point = P256EncodedPoint::from_bytes(&point_bytes).map_err(|e| {
1615 Error::Cryptography(format!("Failed to create P-256 encoded point: {}", e))
1616 })?;
1617
1618 let public_key_opt = P256PublicKey::from_encoded_point(&encoded_point);
1620 if public_key_opt.is_none().into() {
1621 return Err(Error::Cryptography("Invalid P-256 public key".to_string()));
1622 }
1623 let public_key = public_key_opt.unwrap();
1624
1625 let p256_signature = P256Signature::from_der(signature).map_err(|e| {
1627 Error::Cryptography(format!("Failed to parse P-256 signature: {:?}", e))
1628 })?;
1629
1630 let verifier = p256::ecdsa::VerifyingKey::from(public_key);
1632 match verifier.verify(payload, &p256_signature) {
1633 Ok(()) => Ok(true),
1634 Err(_) => Ok(false),
1635 }
1636 }
1637 #[cfg(feature = "crypto-secp256k1")]
1638 (Some("EC"), Some("secp256k1"), "ES256K") => {
1639 let x_b64 = self
1641 .public_jwk
1642 .get("x")
1643 .and_then(|v| v.as_str())
1644 .ok_or_else(|| {
1645 Error::Cryptography("Missing x coordinate in JWK".to_string())
1646 })?;
1647 let y_b64 = self
1648 .public_jwk
1649 .get("y")
1650 .and_then(|v| v.as_str())
1651 .ok_or_else(|| {
1652 Error::Cryptography("Missing y coordinate in JWK".to_string())
1653 })?;
1654
1655 let x_bytes = base64::engine::general_purpose::STANDARD
1657 .decode(x_b64)
1658 .map_err(|e| {
1659 Error::Cryptography(format!("Failed to decode x coordinate: {}", e))
1660 })?;
1661 let y_bytes = base64::engine::general_purpose::STANDARD
1662 .decode(y_b64)
1663 .map_err(|e| {
1664 Error::Cryptography(format!("Failed to decode y coordinate: {}", e))
1665 })?;
1666
1667 let mut point_bytes = vec![0x04]; point_bytes.extend_from_slice(&x_bytes);
1670 point_bytes.extend_from_slice(&y_bytes);
1671
1672 let verifier =
1674 k256::ecdsa::VerifyingKey::from_sec1_bytes(&point_bytes).map_err(|e| {
1675 Error::Cryptography(format!(
1676 "Failed to create secp256k1 verifying key: {:?}",
1677 e
1678 ))
1679 })?;
1680
1681 let k256_signature = Secp256k1Signature::from_der(signature).map_err(|e| {
1683 Error::Cryptography(format!("Failed to parse secp256k1 signature: {:?}", e))
1684 })?;
1685
1686 match verifier.verify(payload, &k256_signature) {
1688 Ok(()) => Ok(true),
1689 Err(_) => Ok(false),
1690 }
1691 }
1692 _ => Err(Error::Cryptography(format!(
1694 "Unsupported key type/algorithm combination for verification: kty={:?}, crv={:?}, alg={}",
1695 kty, crv, protected_header.alg
1696 ))),
1697 }
1698 }
1699}