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