libsignal_protocol/
identity_key.rs1#![warn(missing_docs)]
9
10use prost::Message;
11use rand::{CryptoRng, Rng};
12
13use crate::{proto, KeyPair, PrivateKey, PublicKey, Result, SignalProtocolError};
14
15const ALTERNATE_IDENTITY_SIGNATURE_PREFIX_1: &[u8] = &[0xFF; 32];
17const ALTERNATE_IDENTITY_SIGNATURE_PREFIX_2: &[u8] = b"Signal_PNI_Signature";
18
19#[derive(
23 Debug, PartialOrd, Ord, PartialEq, Eq, Clone, Copy, derive_more::From, derive_more::Into,
24)]
25pub struct IdentityKey {
26 public_key: PublicKey,
27}
28
29impl IdentityKey {
30 pub fn new(public_key: PublicKey) -> Self {
32 Self { public_key }
33 }
34
35 #[inline]
37 pub fn public_key(&self) -> &PublicKey {
38 &self.public_key
39 }
40
41 #[inline]
43 pub fn serialize(&self) -> Box<[u8]> {
44 self.public_key.serialize()
45 }
46
47 pub fn decode(value: &[u8]) -> Result<Self> {
49 let pk = PublicKey::try_from(value)?;
50 Ok(Self { public_key: pk })
51 }
52
53 pub fn verify_alternate_identity(&self, other: &IdentityKey, signature: &[u8]) -> Result<bool> {
58 Ok(self.public_key.verify_signature_for_multipart_message(
59 &[
60 ALTERNATE_IDENTITY_SIGNATURE_PREFIX_1,
61 ALTERNATE_IDENTITY_SIGNATURE_PREFIX_2,
62 &other.serialize(),
63 ],
64 signature,
65 ))
66 }
67}
68
69impl TryFrom<&[u8]> for IdentityKey {
70 type Error = SignalProtocolError;
71
72 fn try_from(value: &[u8]) -> Result<Self> {
73 IdentityKey::decode(value)
74 }
75}
76
77#[derive(Copy, Clone)]
81pub struct IdentityKeyPair {
82 identity_key: IdentityKey,
83 private_key: PrivateKey,
84}
85
86impl IdentityKeyPair {
87 pub fn new(identity_key: IdentityKey, private_key: PrivateKey) -> Self {
89 Self {
90 identity_key,
91 private_key,
92 }
93 }
94
95 pub fn generate<R: CryptoRng + Rng>(csprng: &mut R) -> Self {
97 let keypair = KeyPair::generate(csprng);
98
99 Self {
100 identity_key: keypair.public_key.into(),
101 private_key: keypair.private_key,
102 }
103 }
104
105 #[inline]
107 pub fn identity_key(&self) -> &IdentityKey {
108 &self.identity_key
109 }
110
111 #[inline]
113 pub fn public_key(&self) -> &PublicKey {
114 self.identity_key.public_key()
115 }
116
117 #[inline]
119 pub fn private_key(&self) -> &PrivateKey {
120 &self.private_key
121 }
122
123 pub fn serialize(&self) -> Box<[u8]> {
125 let structure = proto::storage::IdentityKeyPairStructure {
126 public_key: self.identity_key.serialize().to_vec(),
127 private_key: self.private_key.serialize().to_vec(),
128 };
129
130 let result = structure.encode_to_vec();
131 result.into_boxed_slice()
132 }
133
134 pub fn sign_alternate_identity<R: Rng + CryptoRng>(
136 &self,
137 other: &IdentityKey,
138 rng: &mut R,
139 ) -> Result<Box<[u8]>> {
140 Ok(self.private_key.calculate_signature_for_multipart_message(
141 &[
142 ALTERNATE_IDENTITY_SIGNATURE_PREFIX_1,
143 ALTERNATE_IDENTITY_SIGNATURE_PREFIX_2,
144 &other.serialize(),
145 ],
146 rng,
147 )?)
148 }
149}
150
151impl TryFrom<&[u8]> for IdentityKeyPair {
152 type Error = SignalProtocolError;
153
154 fn try_from(value: &[u8]) -> Result<Self> {
155 let structure = proto::storage::IdentityKeyPairStructure::decode(value)
156 .map_err(|_| SignalProtocolError::InvalidProtobufEncoding)?;
157 Ok(Self {
158 identity_key: IdentityKey::try_from(&structure.public_key[..])?,
159 private_key: PrivateKey::deserialize(&structure.private_key)?,
160 })
161 }
162}
163
164impl TryFrom<PrivateKey> for IdentityKeyPair {
165 type Error = SignalProtocolError;
166
167 fn try_from(private_key: PrivateKey) -> Result<Self> {
168 let identity_key = IdentityKey::new(private_key.public_key()?);
169 Ok(Self::new(identity_key, private_key))
170 }
171}
172
173impl From<KeyPair> for IdentityKeyPair {
174 fn from(value: KeyPair) -> Self {
175 Self {
176 identity_key: value.public_key.into(),
177 private_key: value.private_key,
178 }
179 }
180}
181
182impl From<IdentityKeyPair> for KeyPair {
183 fn from(value: IdentityKeyPair) -> Self {
184 Self::new(value.identity_key.into(), value.private_key)
185 }
186}
187
188#[cfg(test)]
189mod tests {
190 use rand::rngs::OsRng;
191 use rand::TryRngCore as _;
192
193 use super::*;
194
195 #[test]
196 fn test_identity_key_from() {
197 let key_pair = KeyPair::generate(&mut OsRng.unwrap_err());
198 let key_pair_public_serialized = key_pair.public_key.serialize();
199 let identity_key = IdentityKey::from(key_pair.public_key);
200 assert_eq!(key_pair_public_serialized, identity_key.serialize());
201 }
202
203 #[test]
204 fn test_serialize_identity_key_pair() -> Result<()> {
205 let identity_key_pair = IdentityKeyPair::generate(&mut OsRng.unwrap_err());
206 let serialized = identity_key_pair.serialize();
207 let deserialized_identity_key_pair = IdentityKeyPair::try_from(&serialized[..])?;
208 assert_eq!(
209 identity_key_pair.identity_key(),
210 deserialized_identity_key_pair.identity_key()
211 );
212 assert_eq!(
213 identity_key_pair.private_key().key_type(),
214 deserialized_identity_key_pair.private_key().key_type()
215 );
216 assert_eq!(
217 identity_key_pair.private_key().serialize(),
218 deserialized_identity_key_pair.private_key().serialize()
219 );
220
221 Ok(())
222 }
223
224 #[test]
225 fn test_alternate_identity_signing() -> Result<()> {
226 let mut rng = OsRng.unwrap_err();
227 let primary = IdentityKeyPair::generate(&mut rng);
228 let secondary = IdentityKeyPair::generate(&mut rng);
229
230 let signature = secondary.sign_alternate_identity(primary.identity_key(), &mut rng)?;
231 assert!(secondary
232 .identity_key()
233 .verify_alternate_identity(primary.identity_key(), &signature)?);
234 assert!(!primary
236 .identity_key()
237 .verify_alternate_identity(secondary.identity_key(), &signature)?);
238
239 let another_signature =
240 secondary.sign_alternate_identity(primary.identity_key(), &mut rng)?;
241 assert_ne!(signature, another_signature);
242 assert!(secondary
243 .identity_key()
244 .verify_alternate_identity(primary.identity_key(), &another_signature)?);
245
246 let unrelated = IdentityKeyPair::generate(&mut rng);
247 assert!(!secondary
248 .identity_key()
249 .verify_alternate_identity(unrelated.identity_key(), &signature)?);
250 assert!(!unrelated
251 .identity_key()
252 .verify_alternate_identity(primary.identity_key(), &signature)?);
253
254 Ok(())
255 }
256}