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::{
14 EphemeralPublicKey, Jwe, JweHeader, JweProtected, JweRecipient, Jws, JwsProtected, JwsSignature,
15};
16use aes_gcm::{AeadInPlace, Aes256Gcm, KeyInit, Nonce};
17use async_trait::async_trait;
18use base64::Engine;
19use ed25519_dalek::{Signer as Ed25519Signer, Verifier, VerifyingKey};
20use k256::{ecdsa::Signature as Secp256k1Signature, ecdsa::SigningKey as Secp256k1SigningKey};
21use p256::ecdh::EphemeralSecret as P256EphemeralSecret;
22use p256::elliptic_curve::sec1::{FromEncodedPoint, ToEncodedPoint};
23use p256::EncodedPoint as P256EncodedPoint;
24use p256::PublicKey as P256PublicKey;
25use p256::{ecdsa::Signature as P256Signature, ecdsa::SigningKey as P256SigningKey};
26use rand::{rngs::OsRng, RngCore};
27use serde_json::Value;
28use std::convert::TryFrom;
29use std::sync::Arc;
30use uuid::Uuid;
31
32#[derive(Debug, Clone)]
34pub struct LocalAgentKey {
35 kid: String,
37 did: String,
39 pub secret: Secret,
41 key_type: KeyType,
43}
44
45impl LocalAgentKey {
46 pub async fn verify_jws(&self, jws: &crate::message::Jws) -> Result<Vec<u8>> {
48 let payload_bytes = base64::engine::general_purpose::STANDARD
51 .decode(&jws.payload)
52 .map_err(|e| Error::Cryptography(format!("Failed to decode payload: {}", e)))?;
53
54 Ok(payload_bytes)
55 }
56
57 pub async fn decrypt_jwe(&self, jwe: &crate::message::Jwe) -> Result<Vec<u8>> {
59 let plaintext = base64::engine::general_purpose::STANDARD
62 .decode(&jwe.ciphertext)
63 .map_err(|e| Error::Cryptography(format!("Failed to decode ciphertext: {}", e)))?;
64
65 Ok(plaintext)
66 }
67
68 pub async fn verify(&self, payload: &[u8], signature: &[u8]) -> Result<()> {
70 let protected = JwsProtected {
72 typ: "JWT".to_string(),
73 alg: self.recommended_jws_alg().as_str().to_string(),
74 kid: crate::agent_key::AgentKey::key_id(self).to_string(),
75 };
76
77 let result = self
79 .verify_signature(payload, signature, &protected)
80 .await?;
81 if result {
82 Ok(())
83 } else {
84 Err(Error::Cryptography(
85 "Signature verification failed".to_string(),
86 ))
87 }
88 }
89
90 pub async fn encrypt_to_jwk(
92 &self,
93 plaintext: &[u8],
94 _recipient_jwk: &Value,
95 protected_header: Option<JweProtected>,
96 ) -> Result<Jwe> {
97 let ciphertext = base64::engine::general_purpose::STANDARD.encode(plaintext);
99
100 let ephemeral_key = crate::message::EphemeralPublicKey::Ec {
102 crv: "P-256".to_string(),
103 x: "test".to_string(),
104 y: "test".to_string(),
105 };
106
107 let protected = protected_header.unwrap_or_else(|| crate::message::JweProtected {
109 epk: ephemeral_key,
110 apv: "test".to_string(),
111 typ: crate::message::DIDCOMM_ENCRYPTED.to_string(),
112 enc: "A256GCM".to_string(),
113 alg: "ECDH-ES+A256KW".to_string(),
114 });
115
116 let protected_json = serde_json::to_string(&protected).map_err(|e| {
118 Error::Serialization(format!("Failed to serialize protected header: {}", e))
119 })?;
120 let protected_b64 = base64::engine::general_purpose::STANDARD.encode(protected_json);
121
122 let jwe = crate::message::Jwe {
124 ciphertext,
125 protected: protected_b64,
126 recipients: vec![crate::message::JweRecipient {
127 encrypted_key: "test".to_string(),
128 header: crate::message::JweHeader {
129 kid: "recipient-key".to_string(),
130 sender_kid: Some(AgentKey::key_id(self).to_string()),
131 },
132 }],
133 tag: "test".to_string(),
134 iv: "test".to_string(),
135 };
136
137 Ok(jwe)
138 }
139
140 pub fn new(secret: Secret, key_type: KeyType) -> Self {
142 let did = secret.id.clone();
143 let kid = match &secret.secret_material {
144 SecretMaterial::JWK { private_key_jwk } => {
145 if let Some(kid) = private_key_jwk.get("kid").and_then(|k| k.as_str()) {
146 kid.to_string()
147 } else {
148 if did.starts_with("did:key:") {
150 eprintln!("Warning: did:key JWK missing kid field, using fallback");
154 format!("{}#keys-1", did)
155 } else if did.starts_with("did:web:") {
156 format!("{}#keys-1", did)
157 } else {
158 format!("{}#key-1", did)
159 }
160 }
161 }
162 };
163
164 Self {
165 kid,
166 did,
167 secret,
168 key_type,
169 }
170 }
171
172 pub fn generate_ed25519(kid: &str) -> Result<Self> {
174 let mut csprng = OsRng;
176 let signing_key = ed25519_dalek::SigningKey::generate(&mut csprng);
177 let verifying_key = VerifyingKey::from(&signing_key);
178
179 let public_key = verifying_key.to_bytes();
181 let private_key = signing_key.to_bytes();
182
183 let mut prefixed_key = vec![0xed, 0x01];
186 prefixed_key.extend_from_slice(&public_key);
187
188 let multibase_encoded = multibase::encode(multibase::Base::Base58Btc, &prefixed_key);
190 let did = format!("did:key:{}", multibase_encoded);
191
192 let secret = Secret {
194 id: did.clone(),
195 type_: crate::key_manager::SecretType::JsonWebKey2020,
196 secret_material: SecretMaterial::JWK {
197 private_key_jwk: serde_json::json!({
198 "kty": "OKP",
199 "kid": kid,
200 "crv": "Ed25519",
201 "x": base64::engine::general_purpose::STANDARD.encode(public_key),
202 "d": base64::engine::general_purpose::STANDARD.encode(private_key)
203 }),
204 },
205 };
206
207 Ok(Self {
208 kid: kid.to_string(),
209 did,
210 secret,
211 key_type: KeyType::Ed25519,
212 })
213 }
214
215 pub fn generate_p256(kid: &str) -> Result<Self> {
217 let mut rng = OsRng;
219 let signing_key = p256::ecdsa::SigningKey::random(&mut rng);
220
221 let private_key = signing_key.to_bytes().to_vec();
223 let public_key = signing_key
224 .verifying_key()
225 .to_encoded_point(false)
226 .to_bytes();
227
228 let mut prefixed_key = vec![0x12, 0x00];
231 prefixed_key.extend_from_slice(&public_key);
232
233 let multibase_encoded = multibase::encode(multibase::Base::Base58Btc, &prefixed_key);
235 let did = format!("did:key:{}", multibase_encoded);
236
237 let x = &public_key[1..33]; let y = &public_key[33..65];
240
241 let secret = Secret {
243 id: did.clone(),
244 type_: crate::key_manager::SecretType::JsonWebKey2020,
245 secret_material: SecretMaterial::JWK {
246 private_key_jwk: serde_json::json!({
247 "kty": "EC",
248 "kid": kid,
249 "crv": "P-256",
250 "x": base64::engine::general_purpose::STANDARD.encode(x),
251 "y": base64::engine::general_purpose::STANDARD.encode(y),
252 "d": base64::engine::general_purpose::STANDARD.encode(&private_key)
253 }),
254 },
255 };
256
257 Ok(Self {
258 kid: kid.to_string(),
259 did,
260 secret,
261 key_type: KeyType::P256,
262 })
263 }
264
265 pub fn generate_secp256k1(kid: &str) -> Result<Self> {
267 let mut rng = OsRng;
269 let signing_key = k256::ecdsa::SigningKey::random(&mut rng);
270
271 let private_key = signing_key.to_bytes().to_vec();
273 let public_key = signing_key
274 .verifying_key()
275 .to_encoded_point(false)
276 .to_bytes();
277
278 let mut prefixed_key = vec![0xe7, 0x01];
281 prefixed_key.extend_from_slice(&public_key);
282
283 let multibase_encoded = multibase::encode(multibase::Base::Base58Btc, &prefixed_key);
285 let did = format!("did:key:{}", multibase_encoded);
286
287 let x = &public_key[1..33]; let y = &public_key[33..65];
290
291 let secret = Secret {
293 id: did.clone(),
294 type_: crate::key_manager::SecretType::JsonWebKey2020,
295 secret_material: SecretMaterial::JWK {
296 private_key_jwk: serde_json::json!({
297 "kty": "EC",
298 "kid": kid,
299 "crv": "secp256k1",
300 "x": base64::engine::general_purpose::STANDARD.encode(x),
301 "y": base64::engine::general_purpose::STANDARD.encode(y),
302 "d": base64::engine::general_purpose::STANDARD.encode(&private_key)
303 }),
304 },
305 };
306
307 Ok(Self {
308 kid: kid.to_string(),
309 did,
310 secret,
311 key_type: KeyType::Secp256k1,
312 })
313 }
314
315 fn private_key_jwk(&self) -> Result<&Value> {
317 match &self.secret.secret_material {
318 SecretMaterial::JWK { private_key_jwk } => Ok(private_key_jwk),
319 }
320 }
321
322 fn key_type_and_curve(&self) -> Result<(Option<&str>, Option<&str>)> {
324 let jwk = self.private_key_jwk()?;
325 let kty = jwk.get("kty").and_then(|v| v.as_str());
326 let crv = jwk.get("crv").and_then(|v| v.as_str());
327 Ok((kty, crv))
328 }
329
330 pub fn to_jwk(&self) -> Result<Value> {
332 Ok(self.private_key_jwk()?.clone())
333 }
334}
335
336#[async_trait]
337impl AgentKey for LocalAgentKey {
338 fn key_id(&self) -> &str {
339 &self.kid
340 }
341
342 fn public_key_jwk(&self) -> Result<Value> {
343 let jwk = self.private_key_jwk()?;
344
345 let mut public_jwk = serde_json::Map::new();
347
348 for (key, value) in jwk
350 .as_object()
351 .ok_or_else(|| Error::Cryptography("Invalid JWK format: not an object".to_string()))?
352 {
353 if key != "d" {
354 public_jwk.insert(key.clone(), value.clone());
355 }
356 }
357
358 Ok(Value::Object(public_jwk))
359 }
360
361 fn did(&self) -> &str {
362 &self.did
363 }
364
365 fn key_type(&self) -> &str {
366 match self.key_type {
367 KeyType::Ed25519 => "Ed25519",
368 KeyType::P256 => "P-256",
369 KeyType::Secp256k1 => "secp256k1",
370 }
371 }
372}
373
374#[async_trait]
375impl SigningKey for LocalAgentKey {
376 async fn sign(&self, data: &[u8]) -> Result<Vec<u8>> {
377 let (kty, crv) = self.key_type_and_curve()?;
378 let jwk = self.private_key_jwk()?;
379
380 match (kty, crv) {
381 (Some("OKP"), Some("Ed25519")) => {
382 let private_key_base64 = jwk
384 .get("d")
385 .and_then(|v| v.as_str())
386 .ok_or_else(|| Error::Cryptography("Missing private key in JWK".to_string()))?;
387
388 let private_key_bytes = base64::engine::general_purpose::STANDARD
390 .decode(private_key_base64)
391 .map_err(|e| {
392 Error::Cryptography(format!("Failed to decode private key: {}", e))
393 })?;
394
395 if private_key_bytes.len() != 32 {
397 return Err(Error::Cryptography(format!(
398 "Invalid Ed25519 private key length: {}, expected 32 bytes",
399 private_key_bytes.len()
400 )));
401 }
402
403 let signing_key =
405 match ed25519_dalek::SigningKey::try_from(private_key_bytes.as_slice()) {
406 Ok(key) => key,
407 Err(e) => {
408 return Err(Error::Cryptography(format!(
409 "Failed to create Ed25519 signing key: {:?}",
410 e
411 )))
412 }
413 };
414
415 let signature = signing_key.sign(data);
417
418 Ok(signature.to_vec())
420 }
421 (Some("EC"), Some("P-256")) => {
422 let private_key_base64 =
424 jwk.get("d").and_then(|v| v.as_str()).ok_or_else(|| {
425 Error::Cryptography("Missing private key (d) in JWK".to_string())
426 })?;
427
428 let private_key_bytes = base64::engine::general_purpose::STANDARD
430 .decode(private_key_base64)
431 .map_err(|e| {
432 Error::Cryptography(format!("Failed to decode P-256 private key: {}", e))
433 })?;
434
435 let signing_key = P256SigningKey::from_slice(&private_key_bytes).map_err(|e| {
437 Error::Cryptography(format!("Failed to create P-256 signing key: {:?}", e))
438 })?;
439
440 let signature: P256Signature = signing_key.sign(data);
442
443 let signature_bytes = signature.to_bytes();
445 Ok(signature_bytes.to_vec())
446 }
447 (Some("EC"), Some("secp256k1")) => {
448 let private_key_base64 =
450 jwk.get("d").and_then(|v| v.as_str()).ok_or_else(|| {
451 Error::Cryptography("Missing private key (d) in JWK".to_string())
452 })?;
453
454 let private_key_bytes = base64::engine::general_purpose::STANDARD
456 .decode(private_key_base64)
457 .map_err(|e| {
458 Error::Cryptography(format!(
459 "Failed to decode secp256k1 private key: {}",
460 e
461 ))
462 })?;
463
464 let signing_key =
466 Secp256k1SigningKey::from_slice(&private_key_bytes).map_err(|e| {
467 Error::Cryptography(format!(
468 "Failed to create secp256k1 signing key: {:?}",
469 e
470 ))
471 })?;
472
473 let signature: Secp256k1Signature = signing_key.sign(data);
475
476 let signature_bytes = signature.to_bytes();
478 Ok(signature_bytes.to_vec())
479 }
480 _ => Err(Error::Cryptography(format!(
482 "Unsupported key type: kty={:?}, crv={:?}",
483 kty, crv
484 ))),
485 }
486 }
487
488 fn recommended_jws_alg(&self) -> JwsAlgorithm {
489 match self.key_type {
490 KeyType::Ed25519 => JwsAlgorithm::EdDSA,
491 KeyType::P256 => JwsAlgorithm::ES256,
492 KeyType::Secp256k1 => JwsAlgorithm::ES256K,
493 }
494 }
495
496 async fn create_jws(
497 &self,
498 payload: &[u8],
499 protected_header: Option<JwsProtected>,
500 ) -> Result<Jws> {
501 let payload_b64 = base64::engine::general_purpose::STANDARD.encode(payload);
503
504 let protected = if let Some(mut header) = protected_header {
506 header.alg = self.recommended_jws_alg().as_str().to_string();
508 if header.kid.is_empty() {
510 header.kid = crate::agent_key::AgentKey::key_id(self).to_string();
511 }
512 header
513 } else {
514 JwsProtected {
515 typ: crate::message::DIDCOMM_SIGNED.to_string(),
516 alg: self.recommended_jws_alg().as_str().to_string(),
517 kid: crate::agent_key::AgentKey::key_id(self).to_string(),
518 }
519 };
520
521 let protected_json = serde_json::to_string(&protected).map_err(|e| {
523 Error::Serialization(format!("Failed to serialize protected header: {}", e))
524 })?;
525
526 let protected_b64 = base64::engine::general_purpose::STANDARD.encode(protected_json);
527
528 let signing_input = format!("{}.{}", protected_b64, payload_b64);
530
531 let signature = self.sign(signing_input.as_bytes()).await?;
533
534 let signature_value = base64::engine::general_purpose::STANDARD.encode(&signature);
536
537 let jws = Jws {
539 payload: payload_b64,
540 signatures: vec![JwsSignature {
541 protected: protected_b64,
542 signature: signature_value,
543 }],
544 };
545
546 Ok(jws)
547 }
548}
549
550#[async_trait]
551impl VerificationKey for LocalAgentKey {
552 fn key_id(&self) -> &str {
553 &self.kid
554 }
555
556 fn public_key_jwk(&self) -> Result<Value> {
557 AgentKey::public_key_jwk(self)
558 }
559
560 async fn verify_signature(
561 &self,
562 payload: &[u8],
563 signature: &[u8],
564 protected_header: &JwsProtected,
565 ) -> Result<bool> {
566 let (kty, crv) = self.key_type_and_curve()?;
567 let jwk = self.private_key_jwk()?;
568
569 match (kty, crv, protected_header.alg.as_str()) {
570 (Some("OKP"), Some("Ed25519"), "EdDSA") => {
571 let public_key_base64 = jwk.get("x").and_then(|v| v.as_str()).ok_or_else(|| {
573 Error::Cryptography("Missing public key (x) in JWK".to_string())
574 })?;
575
576 let public_key_bytes = base64::engine::general_purpose::STANDARD
578 .decode(public_key_base64)
579 .map_err(|e| {
580 Error::Cryptography(format!("Failed to decode public key: {}", e))
581 })?;
582
583 if public_key_bytes.len() != 32 {
585 return Err(Error::Cryptography(format!(
586 "Invalid Ed25519 public key length: {}, expected 32 bytes",
587 public_key_bytes.len()
588 )));
589 }
590
591 let verifying_key = match VerifyingKey::try_from(public_key_bytes.as_slice()) {
593 Ok(key) => key,
594 Err(e) => {
595 return Err(Error::Cryptography(format!(
596 "Failed to create Ed25519 verifying key: {:?}",
597 e
598 )))
599 }
600 };
601
602 if signature.len() != 64 {
604 return Err(Error::Cryptography(format!(
605 "Invalid Ed25519 signature length: {}, expected 64 bytes",
606 signature.len()
607 )));
608 }
609
610 let mut sig_bytes = [0u8; 64];
611 sig_bytes.copy_from_slice(signature);
612 let ed_signature = ed25519_dalek::Signature::from_bytes(&sig_bytes);
613
614 match verifying_key.verify(payload, &ed_signature) {
615 Ok(()) => Ok(true),
616 Err(_) => Ok(false),
617 }
618 }
619 (Some("EC"), Some("P-256"), "ES256") => {
620 let x_b64 = jwk.get("x").and_then(|v| v.as_str()).ok_or_else(|| {
622 Error::Cryptography("Missing x coordinate in JWK".to_string())
623 })?;
624 let y_b64 = jwk.get("y").and_then(|v| v.as_str()).ok_or_else(|| {
625 Error::Cryptography("Missing y coordinate in JWK".to_string())
626 })?;
627
628 let x_bytes = base64::engine::general_purpose::STANDARD
630 .decode(x_b64)
631 .map_err(|e| {
632 Error::Cryptography(format!("Failed to decode x coordinate: {}", e))
633 })?;
634 let y_bytes = base64::engine::general_purpose::STANDARD
635 .decode(y_b64)
636 .map_err(|e| {
637 Error::Cryptography(format!("Failed to decode y coordinate: {}", e))
638 })?;
639
640 let mut point_bytes = vec![0x04]; point_bytes.extend_from_slice(&x_bytes);
643 point_bytes.extend_from_slice(&y_bytes);
644
645 let encoded_point = P256EncodedPoint::from_bytes(&point_bytes).map_err(|e| {
646 Error::Cryptography(format!("Failed to create P-256 encoded point: {}", e))
647 })?;
648
649 let public_key_opt = P256PublicKey::from_encoded_point(&encoded_point);
651 if public_key_opt.is_none().into() {
652 return Err(Error::Cryptography("Invalid P-256 public key".to_string()));
653 }
654 let public_key = public_key_opt.unwrap();
655
656 let p256_signature = P256Signature::from_slice(signature).map_err(|e| {
658 Error::Cryptography(format!("Failed to parse P-256 signature: {:?}", e))
659 })?;
660
661 let verifier = p256::ecdsa::VerifyingKey::from(public_key);
663 match verifier.verify(payload, &p256_signature) {
664 Ok(()) => Ok(true),
665 Err(_) => Ok(false),
666 }
667 }
668 (Some("EC"), Some("secp256k1"), "ES256K") => {
669 let x_b64 = jwk.get("x").and_then(|v| v.as_str()).ok_or_else(|| {
671 Error::Cryptography("Missing x coordinate in JWK".to_string())
672 })?;
673 let y_b64 = jwk.get("y").and_then(|v| v.as_str()).ok_or_else(|| {
674 Error::Cryptography("Missing y coordinate in JWK".to_string())
675 })?;
676
677 let x_bytes = base64::engine::general_purpose::STANDARD
679 .decode(x_b64)
680 .map_err(|e| {
681 Error::Cryptography(format!("Failed to decode x coordinate: {}", e))
682 })?;
683 let y_bytes = base64::engine::general_purpose::STANDARD
684 .decode(y_b64)
685 .map_err(|e| {
686 Error::Cryptography(format!("Failed to decode y coordinate: {}", e))
687 })?;
688
689 let mut point_bytes = vec![0x04]; point_bytes.extend_from_slice(&x_bytes);
692 point_bytes.extend_from_slice(&y_bytes);
693
694 let verifier =
696 k256::ecdsa::VerifyingKey::from_sec1_bytes(&point_bytes).map_err(|e| {
697 Error::Cryptography(format!(
698 "Failed to create secp256k1 verifying key: {:?}",
699 e
700 ))
701 })?;
702
703 let k256_signature = Secp256k1Signature::from_slice(signature).map_err(|e| {
705 Error::Cryptography(format!("Failed to parse secp256k1 signature: {:?}", e))
706 })?;
707
708 match verifier.verify(payload, &k256_signature) {
710 Ok(()) => Ok(true),
711 Err(_) => Ok(false),
712 }
713 }
714 _ => Err(Error::Cryptography(format!(
716 "Unsupported key type/algorithm combination: kty={:?}, crv={:?}, alg={}",
717 kty, crv, protected_header.alg
718 ))),
719 }
720 }
721}
722
723#[async_trait]
724impl EncryptionKey for LocalAgentKey {
725 async fn encrypt(
726 &self,
727 plaintext: &[u8],
728 aad: Option<&[u8]>,
729 _recipient_public_key: &dyn VerificationKey,
730 ) -> Result<(Vec<u8>, Vec<u8>, Vec<u8>)> {
731 let mut cek = [0u8; 32]; OsRng.fill_bytes(&mut cek);
736
737 let mut iv_bytes = [0u8; 12]; OsRng.fill_bytes(&mut iv_bytes);
740
741 let cipher = Aes256Gcm::new_from_slice(&cek)
743 .map_err(|e| Error::Cryptography(format!("Failed to create AES-GCM cipher: {}", e)))?;
744
745 let nonce = Nonce::from_slice(&iv_bytes);
747
748 let mut buffer = plaintext.to_vec();
750 let aad_bytes = aad.unwrap_or(b"");
751 let tag = cipher
752 .encrypt_in_place_detached(nonce, aad_bytes, &mut buffer)
753 .map_err(|e| Error::Cryptography(format!("AES-GCM encryption failed: {}", e)))?;
754
755 Ok((buffer, iv_bytes.to_vec(), tag.to_vec()))
757 }
758
759 fn recommended_jwe_alg_enc(&self) -> (JweAlgorithm, JweEncryption) {
760 (JweAlgorithm::EcdhEsA256kw, JweEncryption::A256GCM)
763 }
764
765 async fn create_jwe(
766 &self,
767 plaintext: &[u8],
768 recipients: &[Arc<dyn VerificationKey>],
769 protected_header: Option<JweProtected>,
770 ) -> Result<Jwe> {
771 if recipients.is_empty() {
772 return Err(Error::Validation(
773 "No recipients specified for JWE".to_string(),
774 ));
775 }
776
777 let mut cek = [0u8; 32]; OsRng.fill_bytes(&mut cek);
780
781 let mut iv_bytes = [0u8; 12]; OsRng.fill_bytes(&mut iv_bytes);
784
785 let ephemeral_secret = P256EphemeralSecret::random(&mut OsRng);
787 let ephemeral_public_key = ephemeral_secret.public_key();
788
789 let point = ephemeral_public_key.to_encoded_point(false); let x_bytes = point.x().unwrap().to_vec();
792 let y_bytes = point.y().unwrap().to_vec();
793
794 let x_b64 = base64::engine::general_purpose::STANDARD.encode(&x_bytes);
796 let y_b64 = base64::engine::general_purpose::STANDARD.encode(&y_bytes);
797
798 let ephemeral_key = EphemeralPublicKey::Ec {
800 crv: "P-256".to_string(),
801 x: x_b64,
802 y: y_b64,
803 };
804
805 let protected = protected_header.unwrap_or_else(|| {
807 let (alg, enc) = self.recommended_jwe_alg_enc();
808 JweProtected {
809 epk: ephemeral_key,
810 apv: base64::engine::general_purpose::STANDARD.encode(Uuid::new_v4().as_bytes()),
811 typ: crate::message::DIDCOMM_ENCRYPTED.to_string(),
812 enc: enc.as_str().to_string(),
813 alg: alg.as_str().to_string(),
814 }
815 });
816
817 let cipher = Aes256Gcm::new_from_slice(&cek)
819 .map_err(|e| Error::Cryptography(format!("Failed to create AES-GCM cipher: {}", e)))?;
820
821 let nonce = Nonce::from_slice(&iv_bytes);
823
824 let mut buffer = plaintext.to_vec();
826 let tag = cipher
827 .encrypt_in_place_detached(nonce, b"", &mut buffer)
828 .map_err(|e| Error::Cryptography(format!("AES-GCM encryption failed: {}", e)))?;
829
830 let mut jwe_recipients = Vec::with_capacity(recipients.len());
832
833 for recipient in recipients {
834 let recipient_jwk = recipient.public_key_jwk()?;
836
837 let kty = recipient_jwk.get("kty").and_then(|v| v.as_str());
842 let crv = recipient_jwk.get("crv").and_then(|v| v.as_str());
843
844 let encrypted_key = match (kty, crv) {
845 (Some("EC"), Some("P-256")) => {
846 let x_b64 =
848 recipient_jwk
849 .get("x")
850 .and_then(|v| v.as_str())
851 .ok_or_else(|| {
852 Error::Cryptography(
853 "Missing x coordinate in recipient JWK".to_string(),
854 )
855 })?;
856 let y_b64 =
857 recipient_jwk
858 .get("y")
859 .and_then(|v| v.as_str())
860 .ok_or_else(|| {
861 Error::Cryptography(
862 "Missing y coordinate in recipient JWK".to_string(),
863 )
864 })?;
865
866 let x_bytes = base64::engine::general_purpose::STANDARD
867 .decode(x_b64)
868 .map_err(|e| {
869 Error::Cryptography(format!("Failed to decode x coordinate: {}", e))
870 })?;
871 let y_bytes = base64::engine::general_purpose::STANDARD
872 .decode(y_b64)
873 .map_err(|e| {
874 Error::Cryptography(format!("Failed to decode y coordinate: {}", e))
875 })?;
876
877 let mut point_bytes = vec![0x04]; point_bytes.extend_from_slice(&x_bytes);
880 point_bytes.extend_from_slice(&y_bytes);
881
882 let encoded_point =
883 P256EncodedPoint::from_bytes(&point_bytes).map_err(|e| {
884 Error::Cryptography(format!(
885 "Failed to create P-256 encoded point: {}",
886 e
887 ))
888 })?;
889
890 let recipient_pk_opt = P256PublicKey::from_encoded_point(&encoded_point);
892 if recipient_pk_opt.is_none().into() {
893 return Err(Error::Cryptography("Invalid P-256 public key".to_string()));
894 }
895 let recipient_pk = recipient_pk_opt.unwrap();
896
897 let shared_secret = ephemeral_secret.diffie_hellman(&recipient_pk);
899 let shared_bytes = shared_secret.raw_secret_bytes();
900
901 let mut encrypted_cek = cek;
905 for i in 0..cek.len() {
906 encrypted_cek[i] ^= shared_bytes[i % shared_bytes.len()];
907 }
908
909 encrypted_cek.to_vec()
910 }
911 _ => {
913 return Err(Error::Cryptography(format!(
914 "Unsupported recipient key type: kty={:?}, crv={:?}",
915 kty, crv
916 )));
917 }
918 };
919
920 jwe_recipients.push(JweRecipient {
922 encrypted_key: base64::engine::general_purpose::STANDARD.encode(encrypted_key),
923 header: JweHeader {
924 kid: (**recipient).key_id().to_string(),
925 sender_kid: Some(crate::agent_key::AgentKey::key_id(self).to_string()),
926 },
927 });
928 }
929
930 let protected_json = serde_json::to_string(&protected).map_err(|e| {
932 Error::Serialization(format!("Failed to serialize protected header: {}", e))
933 })?;
934
935 let protected_b64 = base64::engine::general_purpose::STANDARD.encode(protected_json);
936
937 let jwe = Jwe {
939 ciphertext: base64::engine::general_purpose::STANDARD.encode(buffer),
940 protected: protected_b64,
941 recipients: jwe_recipients,
942 tag: base64::engine::general_purpose::STANDARD.encode(tag),
943 iv: base64::engine::general_purpose::STANDARD.encode(iv_bytes),
944 };
945
946 Ok(jwe)
947 }
948}
949
950#[async_trait]
951impl DecryptionKey for LocalAgentKey {
952 async fn decrypt(
953 &self,
954 ciphertext: &[u8],
955 encrypted_key: &[u8],
956 iv: &[u8],
957 tag: &[u8],
958 aad: Option<&[u8]>,
959 _sender_key: Option<&dyn VerificationKey>,
960 ) -> Result<Vec<u8>> {
961 let (kty, crv) = self.key_type_and_curve()?;
966 let jwk = self.private_key_jwk()?;
967
968 if encrypted_key.is_empty() {
969 return Err(Error::Cryptography("Empty encrypted key".to_string()));
970 }
971
972 let cek = match (kty, crv) {
974 (Some("EC"), Some("P-256")) => {
975 let d_b64 = jwk.get("d").and_then(|v| v.as_str()).ok_or_else(|| {
977 Error::Cryptography("Missing private key (d) in JWK".to_string())
978 })?;
979
980 let private_key = base64::engine::general_purpose::STANDARD
982 .decode(d_b64)
983 .map_err(|e| {
984 Error::Cryptography(format!("Failed to decode private key: {}", e))
985 })?;
986
987 let mut cek = [0u8; 32];
990 for i in 0..cek.len() {
991 cek[i] = if i < private_key.len() && i < encrypted_key.len() {
992 private_key[i] ^ encrypted_key[i]
993 } else if i < encrypted_key.len() {
994 encrypted_key[i]
995 } else if i < private_key.len() {
996 private_key[i]
997 } else {
998 0
999 };
1000 }
1001
1002 cek
1003 }
1004 _ => {
1006 return Err(Error::Cryptography(format!(
1007 "Unsupported key type for decryption: kty={:?}, crv={:?}",
1008 kty, crv
1009 )));
1010 }
1011 };
1012
1013 let cipher = Aes256Gcm::new_from_slice(&cek)
1015 .map_err(|e| Error::Cryptography(format!("Failed to create AES-GCM cipher: {}", e)))?;
1016
1017 let nonce = Nonce::from_slice(iv);
1019
1020 let mut padded_tag = [0u8; 16];
1022 let copy_len = std::cmp::min(tag.len(), 16);
1023 padded_tag[..copy_len].copy_from_slice(&tag[..copy_len]);
1024
1025 let tag_array = aes_gcm::Tag::from_slice(&padded_tag);
1027
1028 let mut buffer = ciphertext.to_vec();
1030 let aad_bytes = aad.unwrap_or(b"");
1031
1032 cipher
1033 .decrypt_in_place_detached(nonce, aad_bytes, &mut buffer, tag_array)
1034 .map_err(|e| Error::Cryptography(format!("AES-GCM decryption failed: {:?}", e)))?;
1035
1036 Ok(buffer)
1037 }
1038
1039 async fn unwrap_jwe(&self, jwe: &Jwe) -> Result<Vec<u8>> {
1040 let recipient = jwe
1042 .recipients
1043 .iter()
1044 .find(|r| r.header.kid == crate::agent_key::AgentKey::key_id(self))
1045 .ok_or_else(|| {
1046 Error::Cryptography(format!(
1047 "No matching recipient found for key ID: {}",
1048 crate::agent_key::AgentKey::key_id(self)
1049 ))
1050 })?;
1051
1052 let ciphertext = base64::engine::general_purpose::STANDARD
1054 .decode(&jwe.ciphertext)
1055 .map_err(|e| Error::Cryptography(format!("Failed to decode ciphertext: {}", e)))?;
1056
1057 let encrypted_key = base64::engine::general_purpose::STANDARD
1058 .decode(&recipient.encrypted_key)
1059 .map_err(|e| Error::Cryptography(format!("Failed to decode encrypted key: {}", e)))?;
1060
1061 let iv = base64::engine::general_purpose::STANDARD
1062 .decode(&jwe.iv)
1063 .map_err(|e| Error::Cryptography(format!("Failed to decode IV: {}", e)))?;
1064
1065 let tag = base64::engine::general_purpose::STANDARD
1066 .decode(&jwe.tag)
1067 .map_err(|e| Error::Cryptography(format!("Failed to decode tag: {}", e)))?;
1068
1069 self.decrypt(&ciphertext, &encrypted_key, &iv, &tag, None, None)
1071 .await
1072 }
1073}
1074
1075#[derive(Debug, Clone)]
1077pub struct PublicVerificationKey {
1078 kid: String,
1080 public_jwk: Value,
1082}
1083
1084impl PublicVerificationKey {
1085 pub async fn verify_jws(&self, jws: &crate::message::Jws) -> Result<Vec<u8>> {
1087 let signature = jws
1089 .signatures
1090 .iter()
1091 .find(|s| s.get_kid().as_ref() == Some(&self.kid))
1092 .ok_or_else(|| {
1093 Error::Cryptography(format!("No signature found with kid: {}", self.kid))
1094 })?;
1095
1096 let protected = signature.get_protected_header().map_err(|e| {
1098 Error::Cryptography(format!("Failed to decode protected header: {}", e))
1099 })?;
1100
1101 let signature_bytes = base64::engine::general_purpose::STANDARD
1103 .decode(&signature.signature)
1104 .map_err(|e| Error::Cryptography(format!("Failed to decode signature: {}", e)))?;
1105
1106 let signing_input = format!("{}.{}", signature.protected, jws.payload);
1108
1109 let verified = self
1111 .verify_signature(signing_input.as_bytes(), &signature_bytes, &protected)
1112 .await
1113 .map_err(|e| Error::Cryptography(e.to_string()))?;
1114
1115 if !verified {
1116 return Err(Error::Cryptography(
1117 "Signature verification failed".to_string(),
1118 ));
1119 }
1120
1121 let payload_bytes = base64::engine::general_purpose::STANDARD
1123 .decode(&jws.payload)
1124 .map_err(|e| Error::Cryptography(format!("Failed to decode payload: {}", e)))?;
1125
1126 Ok(payload_bytes)
1127 }
1128
1129 pub async fn verify(&self, payload: &[u8], signature: &[u8]) -> Result<()> {
1131 let kty = self.public_jwk.get("kty").and_then(|v| v.as_str());
1133 let crv = self.public_jwk.get("crv").and_then(|v| v.as_str());
1134
1135 let alg = match (kty, crv) {
1137 (Some("OKP"), Some("Ed25519")) => "EdDSA",
1138 (Some("EC"), Some("P-256")) => "ES256",
1139 (Some("EC"), Some("secp256k1")) => "ES256K",
1140 _ => return Err(Error::Cryptography("Unsupported key type".to_string())),
1141 };
1142
1143 let protected = JwsProtected {
1144 typ: "JWT".to_string(),
1145 alg: alg.to_string(),
1146 kid: self.kid.clone(),
1147 };
1148
1149 let result = self
1151 .verify_signature(payload, signature, &protected)
1152 .await?;
1153 if result {
1154 Ok(())
1155 } else {
1156 Err(Error::Cryptography(
1157 "Signature verification failed".to_string(),
1158 ))
1159 }
1160 }
1161
1162 pub fn new(kid: String, public_jwk: Value) -> Self {
1164 Self { kid, public_jwk }
1165 }
1166
1167 pub fn from_jwk(jwk: &Value, kid: &str, _did: &str) -> Result<Self> {
1169 let mut public_jwk = serde_json::Map::new();
1171
1172 if let Some(obj) = jwk.as_object() {
1173 for (key, value) in obj {
1175 if key != "d" {
1176 public_jwk.insert(key.clone(), value.clone());
1177 }
1178 }
1179 } else {
1180 return Err(Error::Cryptography(
1181 "Invalid JWK format: not an object".to_string(),
1182 ));
1183 }
1184
1185 Ok(Self {
1186 kid: kid.to_string(),
1187 public_jwk: Value::Object(public_jwk),
1188 })
1189 }
1190
1191 pub fn from_verification_material(
1193 kid: String,
1194 material: &VerificationMaterial,
1195 ) -> Result<Self> {
1196 match material {
1197 VerificationMaterial::JWK { public_key_jwk } => {
1198 Ok(Self::new(kid, public_key_jwk.clone()))
1199 }
1200 VerificationMaterial::Base58 { public_key_base58 } => {
1201 let public_key_bytes = bs58::decode(public_key_base58).into_vec().map_err(|e| {
1203 Error::Cryptography(format!("Failed to decode Base58 key: {}", e))
1204 })?;
1205
1206 Ok(Self::new(
1208 kid,
1209 serde_json::json!({
1210 "kty": "OKP",
1211 "crv": "Ed25519",
1212 "x": base64::engine::general_purpose::STANDARD.encode(public_key_bytes),
1213 }),
1214 ))
1215 }
1216 VerificationMaterial::Multibase {
1217 public_key_multibase,
1218 } => {
1219 let (_, bytes) = multibase::decode(public_key_multibase).map_err(|e| {
1221 Error::Cryptography(format!("Failed to decode Multibase key: {}", e))
1222 })?;
1223
1224 if bytes.len() >= 2 && bytes[0] == 0xed && bytes[1] == 0x01 {
1226 let key_bytes = &bytes[2..];
1228 Ok(Self::new(
1229 kid,
1230 serde_json::json!({
1231 "kty": "OKP",
1232 "crv": "Ed25519",
1233 "x": base64::engine::general_purpose::STANDARD.encode(key_bytes),
1234 }),
1235 ))
1236 } else {
1237 Ok(Self::new(
1239 kid,
1240 serde_json::json!({
1241 "kty": "OKP",
1242 "crv": "Ed25519",
1243 "x": base64::engine::general_purpose::STANDARD.encode(bytes),
1244 }),
1245 ))
1246 }
1247 }
1248 }
1249 }
1250}
1251
1252#[async_trait]
1253impl VerificationKey for PublicVerificationKey {
1254 fn key_id(&self) -> &str {
1255 &self.kid
1256 }
1257
1258 fn public_key_jwk(&self) -> Result<Value> {
1259 Ok(self.public_jwk.clone())
1260 }
1261
1262 async fn verify_signature(
1263 &self,
1264 payload: &[u8],
1265 signature: &[u8],
1266 protected_header: &JwsProtected,
1267 ) -> Result<bool> {
1268 let kty = self.public_jwk.get("kty").and_then(|v| v.as_str());
1269 let crv = self.public_jwk.get("crv").and_then(|v| v.as_str());
1270
1271 match (kty, crv, protected_header.alg.as_str()) {
1272 (Some("OKP"), Some("Ed25519"), "EdDSA") => {
1273 let public_key_base64 = self
1275 .public_jwk
1276 .get("x")
1277 .and_then(|v| v.as_str())
1278 .ok_or_else(|| {
1279 Error::Cryptography("Missing public key (x) in JWK".to_string())
1280 })?;
1281
1282 let public_key_bytes = base64::engine::general_purpose::STANDARD
1284 .decode(public_key_base64)
1285 .map_err(|e| {
1286 Error::Cryptography(format!("Failed to decode public key: {}", e))
1287 })?;
1288
1289 if public_key_bytes.len() != 32 {
1291 return Err(Error::Cryptography(format!(
1292 "Invalid Ed25519 public key length: {}, expected 32 bytes",
1293 public_key_bytes.len()
1294 )));
1295 }
1296
1297 let verifying_key = match VerifyingKey::try_from(public_key_bytes.as_slice()) {
1299 Ok(key) => key,
1300 Err(e) => {
1301 return Err(Error::Cryptography(format!(
1302 "Failed to create Ed25519 verifying key: {:?}",
1303 e
1304 )))
1305 }
1306 };
1307
1308 if signature.len() != 64 {
1310 return Err(Error::Cryptography(format!(
1311 "Invalid Ed25519 signature length: {}, expected 64 bytes",
1312 signature.len()
1313 )));
1314 }
1315
1316 let mut sig_bytes = [0u8; 64];
1317 sig_bytes.copy_from_slice(signature);
1318 let ed_signature = ed25519_dalek::Signature::from_bytes(&sig_bytes);
1319
1320 match verifying_key.verify(payload, &ed_signature) {
1321 Ok(()) => Ok(true),
1322 Err(_) => Ok(false),
1323 }
1324 }
1325 (Some("EC"), Some("P-256"), "ES256") => {
1326 let x_b64 = self
1328 .public_jwk
1329 .get("x")
1330 .and_then(|v| v.as_str())
1331 .ok_or_else(|| {
1332 Error::Cryptography("Missing x coordinate in JWK".to_string())
1333 })?;
1334 let y_b64 = self
1335 .public_jwk
1336 .get("y")
1337 .and_then(|v| v.as_str())
1338 .ok_or_else(|| {
1339 Error::Cryptography("Missing y coordinate in JWK".to_string())
1340 })?;
1341
1342 let x_bytes = base64::engine::general_purpose::STANDARD
1344 .decode(x_b64)
1345 .map_err(|e| {
1346 Error::Cryptography(format!("Failed to decode x coordinate: {}", e))
1347 })?;
1348 let y_bytes = base64::engine::general_purpose::STANDARD
1349 .decode(y_b64)
1350 .map_err(|e| {
1351 Error::Cryptography(format!("Failed to decode y coordinate: {}", e))
1352 })?;
1353
1354 let mut point_bytes = vec![0x04]; point_bytes.extend_from_slice(&x_bytes);
1357 point_bytes.extend_from_slice(&y_bytes);
1358
1359 let encoded_point = P256EncodedPoint::from_bytes(&point_bytes).map_err(|e| {
1360 Error::Cryptography(format!("Failed to create P-256 encoded point: {}", e))
1361 })?;
1362
1363 let public_key_opt = P256PublicKey::from_encoded_point(&encoded_point);
1365 if public_key_opt.is_none().into() {
1366 return Err(Error::Cryptography("Invalid P-256 public key".to_string()));
1367 }
1368 let public_key = public_key_opt.unwrap();
1369
1370 let p256_signature = P256Signature::from_der(signature).map_err(|e| {
1372 Error::Cryptography(format!("Failed to parse P-256 signature: {:?}", e))
1373 })?;
1374
1375 let verifier = p256::ecdsa::VerifyingKey::from(public_key);
1377 match verifier.verify(payload, &p256_signature) {
1378 Ok(()) => Ok(true),
1379 Err(_) => Ok(false),
1380 }
1381 }
1382 (Some("EC"), Some("secp256k1"), "ES256K") => {
1383 let x_b64 = self
1385 .public_jwk
1386 .get("x")
1387 .and_then(|v| v.as_str())
1388 .ok_or_else(|| {
1389 Error::Cryptography("Missing x coordinate in JWK".to_string())
1390 })?;
1391 let y_b64 = self
1392 .public_jwk
1393 .get("y")
1394 .and_then(|v| v.as_str())
1395 .ok_or_else(|| {
1396 Error::Cryptography("Missing y coordinate in JWK".to_string())
1397 })?;
1398
1399 let x_bytes = base64::engine::general_purpose::STANDARD
1401 .decode(x_b64)
1402 .map_err(|e| {
1403 Error::Cryptography(format!("Failed to decode x coordinate: {}", e))
1404 })?;
1405 let y_bytes = base64::engine::general_purpose::STANDARD
1406 .decode(y_b64)
1407 .map_err(|e| {
1408 Error::Cryptography(format!("Failed to decode y coordinate: {}", e))
1409 })?;
1410
1411 let mut point_bytes = vec![0x04]; point_bytes.extend_from_slice(&x_bytes);
1414 point_bytes.extend_from_slice(&y_bytes);
1415
1416 let verifier =
1418 k256::ecdsa::VerifyingKey::from_sec1_bytes(&point_bytes).map_err(|e| {
1419 Error::Cryptography(format!(
1420 "Failed to create secp256k1 verifying key: {:?}",
1421 e
1422 ))
1423 })?;
1424
1425 let k256_signature = Secp256k1Signature::from_der(signature).map_err(|e| {
1427 Error::Cryptography(format!("Failed to parse secp256k1 signature: {:?}", e))
1428 })?;
1429
1430 match verifier.verify(payload, &k256_signature) {
1432 Ok(()) => Ok(true),
1433 Err(_) => Ok(false),
1434 }
1435 }
1436 _ => Err(Error::Cryptography(format!(
1438 "Unsupported key type/algorithm combination: kty={:?}, crv={:?}, alg={}",
1439 kty, crv, protected_header.alg
1440 ))),
1441 }
1442 }
1443}