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, JwsHeader, JwsProtected,
15 JwsSignature,
16};
17use aes_gcm::{AeadInPlace, Aes256Gcm, KeyInit, Nonce};
18use async_trait::async_trait;
19use base64::Engine;
20use ed25519_dalek::{Signer as Ed25519Signer, Verifier, VerifyingKey};
21use k256::{ecdsa::Signature as Secp256k1Signature, ecdsa::SigningKey as Secp256k1SigningKey};
22use p256::ecdh::EphemeralSecret as P256EphemeralSecret;
23use p256::elliptic_curve::sec1::{FromEncodedPoint, ToEncodedPoint};
24use p256::EncodedPoint as P256EncodedPoint;
25use p256::PublicKey as P256PublicKey;
26use p256::{ecdsa::Signature as P256Signature, ecdsa::SigningKey as P256SigningKey};
27use rand::{rngs::OsRng, RngCore};
28use serde_json::Value;
29use std::convert::TryFrom;
30use std::sync::Arc;
31use uuid::Uuid;
32
33#[derive(Debug, Clone)]
35pub struct LocalAgentKey {
36 kid: String,
38 did: String,
40 pub secret: Secret,
42 key_type: KeyType,
44}
45
46impl LocalAgentKey {
47 pub async fn verify_jws(&self, jws: &crate::message::Jws) -> Result<Vec<u8>> {
49 let payload_bytes = base64::engine::general_purpose::STANDARD
52 .decode(&jws.payload)
53 .map_err(|e| Error::Cryptography(format!("Failed to decode payload: {}", e)))?;
54
55 Ok(payload_bytes)
56 }
57
58 pub async fn decrypt_jwe(&self, jwe: &crate::message::Jwe) -> Result<Vec<u8>> {
60 let plaintext = base64::engine::general_purpose::STANDARD
63 .decode(&jwe.ciphertext)
64 .map_err(|e| Error::Cryptography(format!("Failed to decode ciphertext: {}", e)))?;
65
66 Ok(plaintext)
67 }
68
69 pub async fn verify(&self, payload: &[u8], signature: &[u8]) -> Result<()> {
71 let protected = JwsProtected {
73 typ: "JWT".to_string(),
74 alg: self.recommended_jws_alg().as_str().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 format!("{}#keys-1", did)
149 }
150 }
151 };
152
153 Self {
154 kid,
155 did,
156 secret,
157 key_type,
158 }
159 }
160
161 pub fn generate_ed25519(kid: &str) -> Result<Self> {
163 let mut csprng = OsRng;
165 let signing_key = ed25519_dalek::SigningKey::generate(&mut csprng);
166 let verifying_key = VerifyingKey::from(&signing_key);
167
168 let public_key = verifying_key.to_bytes();
170 let private_key = signing_key.to_bytes();
171
172 let mut prefixed_key = vec![0xed, 0x01];
175 prefixed_key.extend_from_slice(&public_key);
176
177 let multibase_encoded = multibase::encode(multibase::Base::Base58Btc, &prefixed_key);
179 let did = format!("did:key:{}", multibase_encoded);
180
181 let secret = Secret {
183 id: did.clone(),
184 type_: crate::key_manager::SecretType::JsonWebKey2020,
185 secret_material: SecretMaterial::JWK {
186 private_key_jwk: serde_json::json!({
187 "kty": "OKP",
188 "kid": kid,
189 "crv": "Ed25519",
190 "x": base64::engine::general_purpose::STANDARD.encode(public_key),
191 "d": base64::engine::general_purpose::STANDARD.encode(private_key)
192 }),
193 },
194 };
195
196 Ok(Self {
197 kid: kid.to_string(),
198 did,
199 secret,
200 key_type: KeyType::Ed25519,
201 })
202 }
203
204 pub fn generate_p256(kid: &str) -> Result<Self> {
206 let mut rng = OsRng;
208 let signing_key = p256::ecdsa::SigningKey::random(&mut rng);
209
210 let private_key = signing_key.to_bytes().to_vec();
212 let public_key = signing_key
213 .verifying_key()
214 .to_encoded_point(false)
215 .to_bytes();
216
217 let mut prefixed_key = vec![0x12, 0x00];
220 prefixed_key.extend_from_slice(&public_key);
221
222 let multibase_encoded = multibase::encode(multibase::Base::Base58Btc, &prefixed_key);
224 let did = format!("did:key:{}", multibase_encoded);
225
226 let x = &public_key[1..33]; let y = &public_key[33..65];
229
230 let secret = Secret {
232 id: did.clone(),
233 type_: crate::key_manager::SecretType::JsonWebKey2020,
234 secret_material: SecretMaterial::JWK {
235 private_key_jwk: serde_json::json!({
236 "kty": "EC",
237 "kid": kid,
238 "crv": "P-256",
239 "x": base64::engine::general_purpose::STANDARD.encode(x),
240 "y": base64::engine::general_purpose::STANDARD.encode(y),
241 "d": base64::engine::general_purpose::STANDARD.encode(&private_key)
242 }),
243 },
244 };
245
246 Ok(Self {
247 kid: kid.to_string(),
248 did,
249 secret,
250 key_type: KeyType::P256,
251 })
252 }
253
254 pub fn generate_secp256k1(kid: &str) -> Result<Self> {
256 let mut rng = OsRng;
258 let signing_key = k256::ecdsa::SigningKey::random(&mut rng);
259
260 let private_key = signing_key.to_bytes().to_vec();
262 let public_key = signing_key
263 .verifying_key()
264 .to_encoded_point(false)
265 .to_bytes();
266
267 let mut prefixed_key = vec![0xe7, 0x01];
270 prefixed_key.extend_from_slice(&public_key);
271
272 let multibase_encoded = multibase::encode(multibase::Base::Base58Btc, &prefixed_key);
274 let did = format!("did:key:{}", multibase_encoded);
275
276 let x = &public_key[1..33]; let y = &public_key[33..65];
279
280 let secret = Secret {
282 id: did.clone(),
283 type_: crate::key_manager::SecretType::JsonWebKey2020,
284 secret_material: SecretMaterial::JWK {
285 private_key_jwk: serde_json::json!({
286 "kty": "EC",
287 "kid": kid,
288 "crv": "secp256k1",
289 "x": base64::engine::general_purpose::STANDARD.encode(x),
290 "y": base64::engine::general_purpose::STANDARD.encode(y),
291 "d": base64::engine::general_purpose::STANDARD.encode(&private_key)
292 }),
293 },
294 };
295
296 Ok(Self {
297 kid: kid.to_string(),
298 did,
299 secret,
300 key_type: KeyType::Secp256k1,
301 })
302 }
303
304 fn private_key_jwk(&self) -> Result<&Value> {
306 match &self.secret.secret_material {
307 SecretMaterial::JWK { private_key_jwk } => Ok(private_key_jwk),
308 }
309 }
310
311 fn key_type_and_curve(&self) -> Result<(Option<&str>, Option<&str>)> {
313 let jwk = self.private_key_jwk()?;
314 let kty = jwk.get("kty").and_then(|v| v.as_str());
315 let crv = jwk.get("crv").and_then(|v| v.as_str());
316 Ok((kty, crv))
317 }
318
319 pub fn to_jwk(&self) -> Result<Value> {
321 Ok(self.private_key_jwk()?.clone())
322 }
323}
324
325#[async_trait]
326impl AgentKey for LocalAgentKey {
327 fn key_id(&self) -> &str {
328 &self.kid
329 }
330
331 fn public_key_jwk(&self) -> Result<Value> {
332 let jwk = self.private_key_jwk()?;
333
334 let mut public_jwk = serde_json::Map::new();
336
337 for (key, value) in jwk
339 .as_object()
340 .ok_or_else(|| Error::Cryptography("Invalid JWK format: not an object".to_string()))?
341 {
342 if key != "d" {
343 public_jwk.insert(key.clone(), value.clone());
344 }
345 }
346
347 Ok(Value::Object(public_jwk))
348 }
349
350 fn did(&self) -> &str {
351 &self.did
352 }
353
354 fn key_type(&self) -> &str {
355 match self.key_type {
356 KeyType::Ed25519 => "Ed25519",
357 KeyType::P256 => "P-256",
358 KeyType::Secp256k1 => "secp256k1",
359 }
360 }
361}
362
363#[async_trait]
364impl SigningKey for LocalAgentKey {
365 async fn sign(&self, data: &[u8]) -> Result<Vec<u8>> {
366 let (kty, crv) = self.key_type_and_curve()?;
367 let jwk = self.private_key_jwk()?;
368
369 match (kty, crv) {
370 (Some("OKP"), Some("Ed25519")) => {
371 let private_key_base64 = jwk
373 .get("d")
374 .and_then(|v| v.as_str())
375 .ok_or_else(|| Error::Cryptography("Missing private key in JWK".to_string()))?;
376
377 let private_key_bytes = base64::engine::general_purpose::STANDARD
379 .decode(private_key_base64)
380 .map_err(|e| {
381 Error::Cryptography(format!("Failed to decode private key: {}", e))
382 })?;
383
384 if private_key_bytes.len() != 32 {
386 return Err(Error::Cryptography(format!(
387 "Invalid Ed25519 private key length: {}, expected 32 bytes",
388 private_key_bytes.len()
389 )));
390 }
391
392 let signing_key =
394 match ed25519_dalek::SigningKey::try_from(private_key_bytes.as_slice()) {
395 Ok(key) => key,
396 Err(e) => {
397 return Err(Error::Cryptography(format!(
398 "Failed to create Ed25519 signing key: {:?}",
399 e
400 )))
401 }
402 };
403
404 let signature = signing_key.sign(data);
406
407 Ok(signature.to_vec())
409 }
410 (Some("EC"), Some("P-256")) => {
411 let private_key_base64 =
413 jwk.get("d").and_then(|v| v.as_str()).ok_or_else(|| {
414 Error::Cryptography("Missing private key (d) in JWK".to_string())
415 })?;
416
417 let private_key_bytes = base64::engine::general_purpose::STANDARD
419 .decode(private_key_base64)
420 .map_err(|e| {
421 Error::Cryptography(format!("Failed to decode P-256 private key: {}", e))
422 })?;
423
424 let signing_key = P256SigningKey::from_slice(&private_key_bytes).map_err(|e| {
426 Error::Cryptography(format!("Failed to create P-256 signing key: {:?}", e))
427 })?;
428
429 let signature: P256Signature = signing_key.sign(data);
431
432 let signature_bytes_der = signature.to_der();
434 Ok(signature_bytes_der.as_bytes().to_vec())
435 }
436 (Some("EC"), Some("secp256k1")) => {
437 let private_key_base64 =
439 jwk.get("d").and_then(|v| v.as_str()).ok_or_else(|| {
440 Error::Cryptography("Missing private key (d) in JWK".to_string())
441 })?;
442
443 let private_key_bytes = base64::engine::general_purpose::STANDARD
445 .decode(private_key_base64)
446 .map_err(|e| {
447 Error::Cryptography(format!(
448 "Failed to decode secp256k1 private key: {}",
449 e
450 ))
451 })?;
452
453 let signing_key =
455 Secp256k1SigningKey::from_slice(&private_key_bytes).map_err(|e| {
456 Error::Cryptography(format!(
457 "Failed to create secp256k1 signing key: {:?}",
458 e
459 ))
460 })?;
461
462 let signature: Secp256k1Signature = signing_key.sign(data);
464
465 let signature_bytes_der = signature.to_der();
467 Ok(signature_bytes_der.as_bytes().to_vec())
468 }
469 _ => Err(Error::Cryptography(format!(
471 "Unsupported key type: kty={:?}, crv={:?}",
472 kty, crv
473 ))),
474 }
475 }
476
477 fn recommended_jws_alg(&self) -> JwsAlgorithm {
478 match self.key_type {
479 KeyType::Ed25519 => JwsAlgorithm::EdDSA,
480 KeyType::P256 => JwsAlgorithm::ES256,
481 KeyType::Secp256k1 => JwsAlgorithm::ES256K,
482 }
483 }
484
485 async fn create_jws(
486 &self,
487 payload: &[u8],
488 protected_header: Option<JwsProtected>,
489 ) -> Result<Jws> {
490 let payload_b64 = base64::engine::general_purpose::STANDARD.encode(payload);
492
493 let protected = if let Some(mut header) = protected_header {
495 header.alg = self.recommended_jws_alg().as_str().to_string();
497 header
498 } else {
499 JwsProtected {
500 typ: crate::message::DIDCOMM_SIGNED.to_string(),
501 alg: self.recommended_jws_alg().as_str().to_string(),
502 }
503 };
504
505 let protected_json = serde_json::to_string(&protected).map_err(|e| {
507 Error::Serialization(format!("Failed to serialize protected header: {}", e))
508 })?;
509
510 let protected_b64 = base64::engine::general_purpose::STANDARD.encode(protected_json);
511
512 let signing_input = format!("{}.{}", protected_b64, payload_b64);
514
515 let signature = self.sign(signing_input.as_bytes()).await?;
517
518 let signature_value = base64::engine::general_purpose::STANDARD.encode(&signature);
520
521 let jws = Jws {
523 payload: payload_b64,
524 signatures: vec![JwsSignature {
525 protected: protected_b64,
526 signature: signature_value,
527 header: JwsHeader {
528 kid: crate::agent_key::AgentKey::key_id(self).to_string(),
529 },
530 }],
531 };
532
533 Ok(jws)
534 }
535}
536
537#[async_trait]
538impl VerificationKey for LocalAgentKey {
539 fn key_id(&self) -> &str {
540 &self.kid
541 }
542
543 fn public_key_jwk(&self) -> Result<Value> {
544 AgentKey::public_key_jwk(self)
545 }
546
547 async fn verify_signature(
548 &self,
549 payload: &[u8],
550 signature: &[u8],
551 protected_header: &JwsProtected,
552 ) -> Result<bool> {
553 let (kty, crv) = self.key_type_and_curve()?;
554 let jwk = self.private_key_jwk()?;
555
556 match (kty, crv, protected_header.alg.as_str()) {
557 (Some("OKP"), Some("Ed25519"), "EdDSA") => {
558 let public_key_base64 = jwk.get("x").and_then(|v| v.as_str()).ok_or_else(|| {
560 Error::Cryptography("Missing public key (x) in JWK".to_string())
561 })?;
562
563 let public_key_bytes = base64::engine::general_purpose::STANDARD
565 .decode(public_key_base64)
566 .map_err(|e| {
567 Error::Cryptography(format!("Failed to decode public key: {}", e))
568 })?;
569
570 if public_key_bytes.len() != 32 {
572 return Err(Error::Cryptography(format!(
573 "Invalid Ed25519 public key length: {}, expected 32 bytes",
574 public_key_bytes.len()
575 )));
576 }
577
578 let verifying_key = match VerifyingKey::try_from(public_key_bytes.as_slice()) {
580 Ok(key) => key,
581 Err(e) => {
582 return Err(Error::Cryptography(format!(
583 "Failed to create Ed25519 verifying key: {:?}",
584 e
585 )))
586 }
587 };
588
589 if signature.len() != 64 {
591 return Err(Error::Cryptography(format!(
592 "Invalid Ed25519 signature length: {}, expected 64 bytes",
593 signature.len()
594 )));
595 }
596
597 let mut sig_bytes = [0u8; 64];
598 sig_bytes.copy_from_slice(signature);
599 let ed_signature = ed25519_dalek::Signature::from_bytes(&sig_bytes);
600
601 match verifying_key.verify(payload, &ed_signature) {
602 Ok(()) => Ok(true),
603 Err(_) => Ok(false),
604 }
605 }
606 (Some("EC"), Some("P-256"), "ES256") => {
607 let x_b64 = jwk.get("x").and_then(|v| v.as_str()).ok_or_else(|| {
609 Error::Cryptography("Missing x coordinate in JWK".to_string())
610 })?;
611 let y_b64 = jwk.get("y").and_then(|v| v.as_str()).ok_or_else(|| {
612 Error::Cryptography("Missing y coordinate in JWK".to_string())
613 })?;
614
615 let x_bytes = base64::engine::general_purpose::STANDARD
617 .decode(x_b64)
618 .map_err(|e| {
619 Error::Cryptography(format!("Failed to decode x coordinate: {}", e))
620 })?;
621 let y_bytes = base64::engine::general_purpose::STANDARD
622 .decode(y_b64)
623 .map_err(|e| {
624 Error::Cryptography(format!("Failed to decode y coordinate: {}", e))
625 })?;
626
627 let mut point_bytes = vec![0x04]; point_bytes.extend_from_slice(&x_bytes);
630 point_bytes.extend_from_slice(&y_bytes);
631
632 let encoded_point = P256EncodedPoint::from_bytes(&point_bytes).map_err(|e| {
633 Error::Cryptography(format!("Failed to create P-256 encoded point: {}", e))
634 })?;
635
636 let public_key_opt = P256PublicKey::from_encoded_point(&encoded_point);
638 if public_key_opt.is_none().into() {
639 return Err(Error::Cryptography("Invalid P-256 public key".to_string()));
640 }
641 let public_key = public_key_opt.unwrap();
642
643 let p256_signature = P256Signature::from_der(signature).map_err(|e| {
645 Error::Cryptography(format!("Failed to parse P-256 signature: {:?}", e))
646 })?;
647
648 let verifier = p256::ecdsa::VerifyingKey::from(public_key);
650 match verifier.verify(payload, &p256_signature) {
651 Ok(()) => Ok(true),
652 Err(_) => Ok(false),
653 }
654 }
655 (Some("EC"), Some("secp256k1"), "ES256K") => {
656 let x_b64 = jwk.get("x").and_then(|v| v.as_str()).ok_or_else(|| {
658 Error::Cryptography("Missing x coordinate in JWK".to_string())
659 })?;
660 let y_b64 = jwk.get("y").and_then(|v| v.as_str()).ok_or_else(|| {
661 Error::Cryptography("Missing y coordinate in JWK".to_string())
662 })?;
663
664 let x_bytes = base64::engine::general_purpose::STANDARD
666 .decode(x_b64)
667 .map_err(|e| {
668 Error::Cryptography(format!("Failed to decode x coordinate: {}", e))
669 })?;
670 let y_bytes = base64::engine::general_purpose::STANDARD
671 .decode(y_b64)
672 .map_err(|e| {
673 Error::Cryptography(format!("Failed to decode y coordinate: {}", e))
674 })?;
675
676 let mut point_bytes = vec![0x04]; point_bytes.extend_from_slice(&x_bytes);
679 point_bytes.extend_from_slice(&y_bytes);
680
681 let verifier =
683 k256::ecdsa::VerifyingKey::from_sec1_bytes(&point_bytes).map_err(|e| {
684 Error::Cryptography(format!(
685 "Failed to create secp256k1 verifying key: {:?}",
686 e
687 ))
688 })?;
689
690 let k256_signature = Secp256k1Signature::from_der(signature).map_err(|e| {
692 Error::Cryptography(format!("Failed to parse secp256k1 signature: {:?}", e))
693 })?;
694
695 match verifier.verify(payload, &k256_signature) {
697 Ok(()) => Ok(true),
698 Err(_) => Ok(false),
699 }
700 }
701 _ => Err(Error::Cryptography(format!(
703 "Unsupported key type/algorithm combination: kty={:?}, crv={:?}, alg={}",
704 kty, crv, protected_header.alg
705 ))),
706 }
707 }
708}
709
710#[async_trait]
711impl EncryptionKey for LocalAgentKey {
712 async fn encrypt(
713 &self,
714 plaintext: &[u8],
715 aad: Option<&[u8]>,
716 _recipient_public_key: &dyn VerificationKey,
717 ) -> Result<(Vec<u8>, Vec<u8>, Vec<u8>)> {
718 let mut cek = [0u8; 32]; OsRng.fill_bytes(&mut cek);
723
724 let mut iv_bytes = [0u8; 12]; OsRng.fill_bytes(&mut iv_bytes);
727
728 let cipher = Aes256Gcm::new_from_slice(&cek)
730 .map_err(|e| Error::Cryptography(format!("Failed to create AES-GCM cipher: {}", e)))?;
731
732 let nonce = Nonce::from_slice(&iv_bytes);
734
735 let mut buffer = plaintext.to_vec();
737 let aad_bytes = aad.unwrap_or(b"");
738 let tag = cipher
739 .encrypt_in_place_detached(nonce, aad_bytes, &mut buffer)
740 .map_err(|e| Error::Cryptography(format!("AES-GCM encryption failed: {}", e)))?;
741
742 Ok((buffer, iv_bytes.to_vec(), tag.to_vec()))
744 }
745
746 fn recommended_jwe_alg_enc(&self) -> (JweAlgorithm, JweEncryption) {
747 (JweAlgorithm::EcdhEsA256kw, JweEncryption::A256GCM)
750 }
751
752 async fn create_jwe(
753 &self,
754 plaintext: &[u8],
755 recipients: &[Arc<dyn VerificationKey>],
756 protected_header: Option<JweProtected>,
757 ) -> Result<Jwe> {
758 if recipients.is_empty() {
759 return Err(Error::Validation(
760 "No recipients specified for JWE".to_string(),
761 ));
762 }
763
764 let mut cek = [0u8; 32]; OsRng.fill_bytes(&mut cek);
767
768 let mut iv_bytes = [0u8; 12]; OsRng.fill_bytes(&mut iv_bytes);
771
772 let ephemeral_secret = P256EphemeralSecret::random(&mut OsRng);
774 let ephemeral_public_key = ephemeral_secret.public_key();
775
776 let point = ephemeral_public_key.to_encoded_point(false); let x_bytes = point.x().unwrap().to_vec();
779 let y_bytes = point.y().unwrap().to_vec();
780
781 let x_b64 = base64::engine::general_purpose::STANDARD.encode(&x_bytes);
783 let y_b64 = base64::engine::general_purpose::STANDARD.encode(&y_bytes);
784
785 let ephemeral_key = EphemeralPublicKey::Ec {
787 crv: "P-256".to_string(),
788 x: x_b64,
789 y: y_b64,
790 };
791
792 let protected = protected_header.unwrap_or_else(|| {
794 let (alg, enc) = self.recommended_jwe_alg_enc();
795 JweProtected {
796 epk: ephemeral_key,
797 apv: base64::engine::general_purpose::STANDARD.encode(Uuid::new_v4().as_bytes()),
798 typ: crate::message::DIDCOMM_ENCRYPTED.to_string(),
799 enc: enc.as_str().to_string(),
800 alg: alg.as_str().to_string(),
801 }
802 });
803
804 let cipher = Aes256Gcm::new_from_slice(&cek)
806 .map_err(|e| Error::Cryptography(format!("Failed to create AES-GCM cipher: {}", e)))?;
807
808 let nonce = Nonce::from_slice(&iv_bytes);
810
811 let mut buffer = plaintext.to_vec();
813 let tag = cipher
814 .encrypt_in_place_detached(nonce, b"", &mut buffer)
815 .map_err(|e| Error::Cryptography(format!("AES-GCM encryption failed: {}", e)))?;
816
817 let mut jwe_recipients = Vec::with_capacity(recipients.len());
819
820 for recipient in recipients {
821 let recipient_jwk = recipient.public_key_jwk()?;
823
824 let kty = recipient_jwk.get("kty").and_then(|v| v.as_str());
829 let crv = recipient_jwk.get("crv").and_then(|v| v.as_str());
830
831 let encrypted_key = match (kty, crv) {
832 (Some("EC"), Some("P-256")) => {
833 let x_b64 =
835 recipient_jwk
836 .get("x")
837 .and_then(|v| v.as_str())
838 .ok_or_else(|| {
839 Error::Cryptography(
840 "Missing x coordinate in recipient JWK".to_string(),
841 )
842 })?;
843 let y_b64 =
844 recipient_jwk
845 .get("y")
846 .and_then(|v| v.as_str())
847 .ok_or_else(|| {
848 Error::Cryptography(
849 "Missing y coordinate in recipient JWK".to_string(),
850 )
851 })?;
852
853 let x_bytes = base64::engine::general_purpose::STANDARD
854 .decode(x_b64)
855 .map_err(|e| {
856 Error::Cryptography(format!("Failed to decode x coordinate: {}", e))
857 })?;
858 let y_bytes = base64::engine::general_purpose::STANDARD
859 .decode(y_b64)
860 .map_err(|e| {
861 Error::Cryptography(format!("Failed to decode y coordinate: {}", e))
862 })?;
863
864 let mut point_bytes = vec![0x04]; point_bytes.extend_from_slice(&x_bytes);
867 point_bytes.extend_from_slice(&y_bytes);
868
869 let encoded_point =
870 P256EncodedPoint::from_bytes(&point_bytes).map_err(|e| {
871 Error::Cryptography(format!(
872 "Failed to create P-256 encoded point: {}",
873 e
874 ))
875 })?;
876
877 let recipient_pk_opt = P256PublicKey::from_encoded_point(&encoded_point);
879 if recipient_pk_opt.is_none().into() {
880 return Err(Error::Cryptography("Invalid P-256 public key".to_string()));
881 }
882 let recipient_pk = recipient_pk_opt.unwrap();
883
884 let shared_secret = ephemeral_secret.diffie_hellman(&recipient_pk);
886 let shared_bytes = shared_secret.raw_secret_bytes();
887
888 let mut encrypted_cek = cek;
892 for i in 0..cek.len() {
893 encrypted_cek[i] ^= shared_bytes[i % shared_bytes.len()];
894 }
895
896 encrypted_cek.to_vec()
897 }
898 _ => {
900 return Err(Error::Cryptography(format!(
901 "Unsupported recipient key type: kty={:?}, crv={:?}",
902 kty, crv
903 )));
904 }
905 };
906
907 jwe_recipients.push(JweRecipient {
909 encrypted_key: base64::engine::general_purpose::STANDARD.encode(encrypted_key),
910 header: JweHeader {
911 kid: (**recipient).key_id().to_string(),
912 sender_kid: Some(crate::agent_key::AgentKey::key_id(self).to_string()),
913 },
914 });
915 }
916
917 let protected_json = serde_json::to_string(&protected).map_err(|e| {
919 Error::Serialization(format!("Failed to serialize protected header: {}", e))
920 })?;
921
922 let protected_b64 = base64::engine::general_purpose::STANDARD.encode(protected_json);
923
924 let jwe = Jwe {
926 ciphertext: base64::engine::general_purpose::STANDARD.encode(buffer),
927 protected: protected_b64,
928 recipients: jwe_recipients,
929 tag: base64::engine::general_purpose::STANDARD.encode(tag),
930 iv: base64::engine::general_purpose::STANDARD.encode(iv_bytes),
931 };
932
933 Ok(jwe)
934 }
935}
936
937#[async_trait]
938impl DecryptionKey for LocalAgentKey {
939 async fn decrypt(
940 &self,
941 ciphertext: &[u8],
942 encrypted_key: &[u8],
943 iv: &[u8],
944 tag: &[u8],
945 aad: Option<&[u8]>,
946 _sender_key: Option<&dyn VerificationKey>,
947 ) -> Result<Vec<u8>> {
948 let (kty, crv) = self.key_type_and_curve()?;
953 let jwk = self.private_key_jwk()?;
954
955 if encrypted_key.is_empty() {
956 return Err(Error::Cryptography("Empty encrypted key".to_string()));
957 }
958
959 let cek = match (kty, crv) {
961 (Some("EC"), Some("P-256")) => {
962 let d_b64 = jwk.get("d").and_then(|v| v.as_str()).ok_or_else(|| {
964 Error::Cryptography("Missing private key (d) in JWK".to_string())
965 })?;
966
967 let private_key = base64::engine::general_purpose::STANDARD
969 .decode(d_b64)
970 .map_err(|e| {
971 Error::Cryptography(format!("Failed to decode private key: {}", e))
972 })?;
973
974 let mut cek = [0u8; 32];
977 for i in 0..cek.len() {
978 cek[i] = if i < private_key.len() && i < encrypted_key.len() {
979 private_key[i] ^ encrypted_key[i]
980 } else if i < encrypted_key.len() {
981 encrypted_key[i]
982 } else if i < private_key.len() {
983 private_key[i]
984 } else {
985 0
986 };
987 }
988
989 cek
990 }
991 _ => {
993 return Err(Error::Cryptography(format!(
994 "Unsupported key type for decryption: kty={:?}, crv={:?}",
995 kty, crv
996 )));
997 }
998 };
999
1000 let cipher = Aes256Gcm::new_from_slice(&cek)
1002 .map_err(|e| Error::Cryptography(format!("Failed to create AES-GCM cipher: {}", e)))?;
1003
1004 let nonce = Nonce::from_slice(iv);
1006
1007 let mut padded_tag = [0u8; 16];
1009 let copy_len = std::cmp::min(tag.len(), 16);
1010 padded_tag[..copy_len].copy_from_slice(&tag[..copy_len]);
1011
1012 let tag_array = aes_gcm::Tag::from_slice(&padded_tag);
1014
1015 let mut buffer = ciphertext.to_vec();
1017 let aad_bytes = aad.unwrap_or(b"");
1018
1019 cipher
1020 .decrypt_in_place_detached(nonce, aad_bytes, &mut buffer, tag_array)
1021 .map_err(|e| Error::Cryptography(format!("AES-GCM decryption failed: {:?}", e)))?;
1022
1023 Ok(buffer)
1024 }
1025
1026 async fn unwrap_jwe(&self, jwe: &Jwe) -> Result<Vec<u8>> {
1027 let recipient = jwe
1029 .recipients
1030 .iter()
1031 .find(|r| r.header.kid == crate::agent_key::AgentKey::key_id(self))
1032 .ok_or_else(|| {
1033 Error::Cryptography(format!(
1034 "No matching recipient found for key ID: {}",
1035 crate::agent_key::AgentKey::key_id(self)
1036 ))
1037 })?;
1038
1039 let ciphertext = base64::engine::general_purpose::STANDARD
1041 .decode(&jwe.ciphertext)
1042 .map_err(|e| Error::Cryptography(format!("Failed to decode ciphertext: {}", e)))?;
1043
1044 let encrypted_key = base64::engine::general_purpose::STANDARD
1045 .decode(&recipient.encrypted_key)
1046 .map_err(|e| Error::Cryptography(format!("Failed to decode encrypted key: {}", e)))?;
1047
1048 let iv = base64::engine::general_purpose::STANDARD
1049 .decode(&jwe.iv)
1050 .map_err(|e| Error::Cryptography(format!("Failed to decode IV: {}", e)))?;
1051
1052 let tag = base64::engine::general_purpose::STANDARD
1053 .decode(&jwe.tag)
1054 .map_err(|e| Error::Cryptography(format!("Failed to decode tag: {}", e)))?;
1055
1056 self.decrypt(&ciphertext, &encrypted_key, &iv, &tag, None, None)
1058 .await
1059 }
1060}
1061
1062#[derive(Debug, Clone)]
1064pub struct PublicVerificationKey {
1065 kid: String,
1067 public_jwk: Value,
1069}
1070
1071impl PublicVerificationKey {
1072 pub async fn verify_jws(&self, jws: &crate::message::Jws) -> Result<Vec<u8>> {
1074 let signature = jws
1076 .signatures
1077 .iter()
1078 .find(|s| s.header.kid == self.kid)
1079 .ok_or_else(|| {
1080 Error::Cryptography(format!("No signature found with kid: {}", self.kid))
1081 })?;
1082
1083 let protected_bytes = base64::engine::general_purpose::STANDARD
1085 .decode(&signature.protected)
1086 .map_err(|e| {
1087 Error::Cryptography(format!("Failed to decode protected header: {}", e))
1088 })?;
1089
1090 let protected: JwsProtected = serde_json::from_slice(&protected_bytes).map_err(|e| {
1092 Error::Serialization(format!("Failed to parse protected header: {}", e))
1093 })?;
1094
1095 let signature_bytes = base64::engine::general_purpose::STANDARD
1097 .decode(&signature.signature)
1098 .map_err(|e| Error::Cryptography(format!("Failed to decode signature: {}", e)))?;
1099
1100 let signing_input = format!("{}.{}", signature.protected, jws.payload);
1102
1103 let verified = self
1105 .verify_signature(signing_input.as_bytes(), &signature_bytes, &protected)
1106 .await
1107 .map_err(|e| Error::Cryptography(e.to_string()))?;
1108
1109 if !verified {
1110 return Err(Error::Cryptography(
1111 "Signature verification failed".to_string(),
1112 ));
1113 }
1114
1115 let payload_bytes = base64::engine::general_purpose::STANDARD
1117 .decode(&jws.payload)
1118 .map_err(|e| Error::Cryptography(format!("Failed to decode payload: {}", e)))?;
1119
1120 Ok(payload_bytes)
1121 }
1122
1123 pub async fn verify(&self, payload: &[u8], signature: &[u8]) -> Result<()> {
1125 let kty = self.public_jwk.get("kty").and_then(|v| v.as_str());
1127 let crv = self.public_jwk.get("crv").and_then(|v| v.as_str());
1128
1129 let alg = match (kty, crv) {
1131 (Some("OKP"), Some("Ed25519")) => "EdDSA",
1132 (Some("EC"), Some("P-256")) => "ES256",
1133 (Some("EC"), Some("secp256k1")) => "ES256K",
1134 _ => return Err(Error::Cryptography("Unsupported key type".to_string())),
1135 };
1136
1137 let protected = JwsProtected {
1138 typ: "JWT".to_string(),
1139 alg: alg.to_string(),
1140 };
1141
1142 let result = self
1144 .verify_signature(payload, signature, &protected)
1145 .await?;
1146 if result {
1147 Ok(())
1148 } else {
1149 Err(Error::Cryptography(
1150 "Signature verification failed".to_string(),
1151 ))
1152 }
1153 }
1154
1155 pub fn new(kid: String, public_jwk: Value) -> Self {
1157 Self { kid, public_jwk }
1158 }
1159
1160 pub fn from_jwk(jwk: &Value, kid: &str, _did: &str) -> Result<Self> {
1162 let mut public_jwk = serde_json::Map::new();
1164
1165 if let Some(obj) = jwk.as_object() {
1166 for (key, value) in obj {
1168 if key != "d" {
1169 public_jwk.insert(key.clone(), value.clone());
1170 }
1171 }
1172 } else {
1173 return Err(Error::Cryptography(
1174 "Invalid JWK format: not an object".to_string(),
1175 ));
1176 }
1177
1178 Ok(Self {
1179 kid: kid.to_string(),
1180 public_jwk: Value::Object(public_jwk),
1181 })
1182 }
1183
1184 pub fn from_verification_material(
1186 kid: String,
1187 material: &VerificationMaterial,
1188 ) -> Result<Self> {
1189 match material {
1190 VerificationMaterial::JWK { public_key_jwk } => {
1191 Ok(Self::new(kid, public_key_jwk.clone()))
1192 }
1193 VerificationMaterial::Base58 { public_key_base58 } => {
1194 let public_key_bytes = bs58::decode(public_key_base58).into_vec().map_err(|e| {
1196 Error::Cryptography(format!("Failed to decode Base58 key: {}", e))
1197 })?;
1198
1199 Ok(Self::new(
1201 kid,
1202 serde_json::json!({
1203 "kty": "OKP",
1204 "crv": "Ed25519",
1205 "x": base64::engine::general_purpose::STANDARD.encode(public_key_bytes),
1206 }),
1207 ))
1208 }
1209 VerificationMaterial::Multibase {
1210 public_key_multibase,
1211 } => {
1212 let (_, bytes) = multibase::decode(public_key_multibase).map_err(|e| {
1214 Error::Cryptography(format!("Failed to decode Multibase key: {}", e))
1215 })?;
1216
1217 if bytes.len() >= 2 && bytes[0] == 0xed && bytes[1] == 0x01 {
1219 let key_bytes = &bytes[2..];
1221 Ok(Self::new(
1222 kid,
1223 serde_json::json!({
1224 "kty": "OKP",
1225 "crv": "Ed25519",
1226 "x": base64::engine::general_purpose::STANDARD.encode(key_bytes),
1227 }),
1228 ))
1229 } else {
1230 Ok(Self::new(
1232 kid,
1233 serde_json::json!({
1234 "kty": "OKP",
1235 "crv": "Ed25519",
1236 "x": base64::engine::general_purpose::STANDARD.encode(bytes),
1237 }),
1238 ))
1239 }
1240 }
1241 }
1242 }
1243}
1244
1245#[async_trait]
1246impl VerificationKey for PublicVerificationKey {
1247 fn key_id(&self) -> &str {
1248 &self.kid
1249 }
1250
1251 fn public_key_jwk(&self) -> Result<Value> {
1252 Ok(self.public_jwk.clone())
1253 }
1254
1255 async fn verify_signature(
1256 &self,
1257 payload: &[u8],
1258 signature: &[u8],
1259 protected_header: &JwsProtected,
1260 ) -> Result<bool> {
1261 let kty = self.public_jwk.get("kty").and_then(|v| v.as_str());
1262 let crv = self.public_jwk.get("crv").and_then(|v| v.as_str());
1263
1264 match (kty, crv, protected_header.alg.as_str()) {
1265 (Some("OKP"), Some("Ed25519"), "EdDSA") => {
1266 let public_key_base64 = self
1268 .public_jwk
1269 .get("x")
1270 .and_then(|v| v.as_str())
1271 .ok_or_else(|| {
1272 Error::Cryptography("Missing public key (x) in JWK".to_string())
1273 })?;
1274
1275 let public_key_bytes = base64::engine::general_purpose::STANDARD
1277 .decode(public_key_base64)
1278 .map_err(|e| {
1279 Error::Cryptography(format!("Failed to decode public key: {}", e))
1280 })?;
1281
1282 if public_key_bytes.len() != 32 {
1284 return Err(Error::Cryptography(format!(
1285 "Invalid Ed25519 public key length: {}, expected 32 bytes",
1286 public_key_bytes.len()
1287 )));
1288 }
1289
1290 let verifying_key = match VerifyingKey::try_from(public_key_bytes.as_slice()) {
1292 Ok(key) => key,
1293 Err(e) => {
1294 return Err(Error::Cryptography(format!(
1295 "Failed to create Ed25519 verifying key: {:?}",
1296 e
1297 )))
1298 }
1299 };
1300
1301 if signature.len() != 64 {
1303 return Err(Error::Cryptography(format!(
1304 "Invalid Ed25519 signature length: {}, expected 64 bytes",
1305 signature.len()
1306 )));
1307 }
1308
1309 let mut sig_bytes = [0u8; 64];
1310 sig_bytes.copy_from_slice(signature);
1311 let ed_signature = ed25519_dalek::Signature::from_bytes(&sig_bytes);
1312
1313 match verifying_key.verify(payload, &ed_signature) {
1314 Ok(()) => Ok(true),
1315 Err(_) => Ok(false),
1316 }
1317 }
1318 (Some("EC"), Some("P-256"), "ES256") => {
1319 let x_b64 = self
1321 .public_jwk
1322 .get("x")
1323 .and_then(|v| v.as_str())
1324 .ok_or_else(|| {
1325 Error::Cryptography("Missing x coordinate in JWK".to_string())
1326 })?;
1327 let y_b64 = self
1328 .public_jwk
1329 .get("y")
1330 .and_then(|v| v.as_str())
1331 .ok_or_else(|| {
1332 Error::Cryptography("Missing y coordinate in JWK".to_string())
1333 })?;
1334
1335 let x_bytes = base64::engine::general_purpose::STANDARD
1337 .decode(x_b64)
1338 .map_err(|e| {
1339 Error::Cryptography(format!("Failed to decode x coordinate: {}", e))
1340 })?;
1341 let y_bytes = base64::engine::general_purpose::STANDARD
1342 .decode(y_b64)
1343 .map_err(|e| {
1344 Error::Cryptography(format!("Failed to decode y coordinate: {}", e))
1345 })?;
1346
1347 let mut point_bytes = vec![0x04]; point_bytes.extend_from_slice(&x_bytes);
1350 point_bytes.extend_from_slice(&y_bytes);
1351
1352 let encoded_point = P256EncodedPoint::from_bytes(&point_bytes).map_err(|e| {
1353 Error::Cryptography(format!("Failed to create P-256 encoded point: {}", e))
1354 })?;
1355
1356 let public_key_opt = P256PublicKey::from_encoded_point(&encoded_point);
1358 if public_key_opt.is_none().into() {
1359 return Err(Error::Cryptography("Invalid P-256 public key".to_string()));
1360 }
1361 let public_key = public_key_opt.unwrap();
1362
1363 let p256_signature = P256Signature::from_der(signature).map_err(|e| {
1365 Error::Cryptography(format!("Failed to parse P-256 signature: {:?}", e))
1366 })?;
1367
1368 let verifier = p256::ecdsa::VerifyingKey::from(public_key);
1370 match verifier.verify(payload, &p256_signature) {
1371 Ok(()) => Ok(true),
1372 Err(_) => Ok(false),
1373 }
1374 }
1375 (Some("EC"), Some("secp256k1"), "ES256K") => {
1376 let x_b64 = self
1378 .public_jwk
1379 .get("x")
1380 .and_then(|v| v.as_str())
1381 .ok_or_else(|| {
1382 Error::Cryptography("Missing x coordinate in JWK".to_string())
1383 })?;
1384 let y_b64 = self
1385 .public_jwk
1386 .get("y")
1387 .and_then(|v| v.as_str())
1388 .ok_or_else(|| {
1389 Error::Cryptography("Missing y coordinate in JWK".to_string())
1390 })?;
1391
1392 let x_bytes = base64::engine::general_purpose::STANDARD
1394 .decode(x_b64)
1395 .map_err(|e| {
1396 Error::Cryptography(format!("Failed to decode x coordinate: {}", e))
1397 })?;
1398 let y_bytes = base64::engine::general_purpose::STANDARD
1399 .decode(y_b64)
1400 .map_err(|e| {
1401 Error::Cryptography(format!("Failed to decode y coordinate: {}", e))
1402 })?;
1403
1404 let mut point_bytes = vec![0x04]; point_bytes.extend_from_slice(&x_bytes);
1407 point_bytes.extend_from_slice(&y_bytes);
1408
1409 let verifier =
1411 k256::ecdsa::VerifyingKey::from_sec1_bytes(&point_bytes).map_err(|e| {
1412 Error::Cryptography(format!(
1413 "Failed to create secp256k1 verifying key: {:?}",
1414 e
1415 ))
1416 })?;
1417
1418 let k256_signature = Secp256k1Signature::from_der(signature).map_err(|e| {
1420 Error::Cryptography(format!("Failed to parse secp256k1 signature: {:?}", e))
1421 })?;
1422
1423 match verifier.verify(payload, &k256_signature) {
1425 Ok(()) => Ok(true),
1426 Err(_) => Ok(false),
1427 }
1428 }
1429 _ => Err(Error::Cryptography(format!(
1431 "Unsupported key type/algorithm combination: kty={:?}, crv={:?}, alg={}",
1432 kty, crv, protected_header.alg
1433 ))),
1434 }
1435 }
1436}