co_didcomm/messages/
jwe.rs1use base64_url::{decode, encode};
2use rand::{prelude::SliceRandom, Rng};
3
4use crate::{
5 messages::helpers::{create_fallback_getter, serialization_base64_jwm_header},
6 Jwk, JwmHeader,
7};
8
9#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
14pub struct Recipient {
15 pub header: Jwk,
16
17 pub encrypted_key: String,
18}
19
20impl Recipient {
21 pub fn new(header: Jwk, encrypted_key: String) -> Self {
22 Recipient {
23 header,
24 encrypted_key,
25 }
26 }
27}
28
29#[derive(Serialize, Deserialize, Clone, Default)]
32pub struct Jwe {
33 #[serde(default)]
35 #[serde(skip_serializing_if = "Option::is_none")]
36 #[serde(with = "serialization_base64_jwm_header")]
37 pub protected: Option<JwmHeader>,
38
39 #[serde(skip_serializing_if = "Option::is_none")]
41 pub unprotected: Option<JwmHeader>,
42
43 #[serde(flatten)]
46 #[serde(skip_serializing_if = "Option::is_none")]
47 pub recipient: Option<Recipient>,
48
49 #[serde(skip_serializing_if = "Option::is_none")]
52 pub recipients: Option<Vec<Recipient>>,
53
54 ciphertext: String,
56
57 iv: String,
59
60 #[serde(skip_serializing_if = "Option::is_none")]
62 pub tag: Option<String>,
63}
64
65impl Jwe {
66 pub fn new(
68 unprotected: Option<JwmHeader>,
69 recipients: Option<Vec<Recipient>>,
70 ciphertext: impl AsRef<[u8]>,
71 protected: Option<JwmHeader>,
72 tag: Option<impl AsRef<[u8]>>,
73 iv_input: Option<String>,
74 ) -> Self {
75 Jwe {
76 unprotected,
77 recipients,
78 ciphertext: encode(ciphertext.as_ref()),
79 protected,
80 iv: Self::ensure_iv(iv_input),
81 tag: tag.map(|tag_unencoded| encode(tag_unencoded.as_ref())),
82 recipient: None,
83 }
84 }
85
86 pub fn new_flat(
88 unprotected: Option<JwmHeader>,
89 recipient: Recipient,
90 ciphertext: impl AsRef<[u8]>,
91 protected: Option<JwmHeader>,
92 tag: Option<impl AsRef<[u8]>>,
93 iv_input: Option<String>,
94 ) -> Self {
95 Jwe {
96 unprotected,
97 recipients: None,
98 ciphertext: encode(ciphertext.as_ref()),
99 protected,
100 iv: Self::ensure_iv(iv_input),
101 tag: tag.map(|tag_unencoded| encode(tag_unencoded.as_ref())),
102 recipient: Some(recipient),
103 }
104 }
105
106 pub fn generate_iv() -> String {
108 let mut rng = rand::thread_rng();
109 let mut a = rng.gen::<[u8; 24]>().to_vec();
110 a.shuffle(&mut rng);
111 encode(&a)
112 }
113
114 pub fn get_iv(&self) -> impl AsRef<[u8]> {
116 decode(&self.iv).unwrap()
117 }
118
119 pub fn get_payload(&self) -> Vec<u8> {
121 decode(&self.ciphertext).unwrap()
122 }
123
124 create_fallback_getter!(protected, unprotected, alg, String);
125
126 create_fallback_getter!(protected, unprotected, cty, String);
127
128 create_fallback_getter!(protected, unprotected, enc, String);
129
130 create_fallback_getter!(protected, unprotected, epk, Jwk);
131
132 create_fallback_getter!(protected, unprotected, jku, String);
133
134 create_fallback_getter!(protected, unprotected, jwk, Jwk);
135
136 create_fallback_getter!(protected, unprotected, kid, String);
137
138 create_fallback_getter!(protected, unprotected, skid, String);
139
140 fn ensure_iv(iv_input: Option<String>) -> String {
146 iv_input.unwrap_or_else(|| {
147 let mut rng = rand::thread_rng();
148 let mut a = rng.gen::<[u8; 24]>().to_vec();
149 a.shuffle(&mut rng);
150 encode(&a)
151 })
152 }
153}
154
155#[test]
156fn default_jwe_with_random_iv() {
157 let not_expected: Vec<u8> = vec![0; 24];
159 let jwe = Jwe::new(None, None, vec![], None, Some(vec![]), None);
161 assert_ne!(not_expected, decode(&jwe.iv).unwrap());
163}