Skip to main content

libsignal_protocol/
identity_key.rs

1//
2// Copyright 2020-2022 Signal Messenger, LLC.
3// SPDX-License-Identifier: AGPL-3.0-only
4//
5
6//! Wrappers over cryptographic primitives from [`libsignal_core::curve`] to represent a user.
7
8#![warn(missing_docs)]
9
10use libsignal_core::{ProtocolAddress, ServiceId};
11use prost::Message;
12use rand::{CryptoRng, Rng};
13
14use crate::{KeyPair, PrivateKey, PublicKey, Result, SignalProtocolError, proto};
15
16// Used for domain separation between alternate-identity signatures and other key-to-key signatures.
17const ALTERNATE_IDENTITY_SIGNATURE_PREFIX_1: &[u8] = &[0xFF; 32];
18const ALTERNATE_IDENTITY_SIGNATURE_PREFIX_2: &[u8] = b"Signal_PNI_Signature";
19
20/// A public key that represents the identity of a user.
21///
22/// Wrapper for [`PublicKey`].
23#[derive(Debug, PartialEq, Eq, Clone, Copy, derive_more::From, derive_more::Into)]
24pub struct IdentityKey {
25    public_key: PublicKey,
26}
27
28impl IdentityKey {
29    /// Initialize a public-facing identity from a public key.
30    pub fn new(public_key: PublicKey) -> Self {
31        Self { public_key }
32    }
33
34    /// Return the public key representing this identity.
35    #[inline]
36    pub fn public_key(&self) -> &PublicKey {
37        &self.public_key
38    }
39
40    /// Return the public key representing this identity
41    pub fn into_public_key(self) -> PublicKey {
42        self.public_key
43    }
44
45    /// Return an owned byte slice which can be deserialized with [`Self::decode`].
46    #[inline]
47    pub fn serialize(&self) -> Box<[u8]> {
48        self.public_key.serialize()
49    }
50
51    /// Deserialize a public identity from a byte slice.
52    pub fn decode(value: &[u8]) -> Result<Self> {
53        let pk = PublicKey::try_from(value)?;
54        Ok(Self { public_key: pk })
55    }
56
57    /// Given a trusted identity `self`, verify that `other` represents an alternate identity for
58    /// this user.
59    ///
60    /// `signature` must be calculated from [`IdentityKeyPair::sign_alternate_identity`].
61    pub fn verify_alternate_identity(&self, other: &IdentityKey, signature: &[u8]) -> Result<bool> {
62        Ok(self.public_key.verify_signature_for_multipart_message(
63            &[
64                ALTERNATE_IDENTITY_SIGNATURE_PREFIX_1,
65                ALTERNATE_IDENTITY_SIGNATURE_PREFIX_2,
66                &other.serialize(),
67            ],
68            signature,
69        ))
70    }
71
72    /// Do two (identity key, protocol address) pairs map to the same account
73    ///
74    /// This function will always return false if the names in the protocol addresses aren't valid
75    /// service IDs.
76    pub fn is_same_account(
77        &self,
78        self_protocol_address: &ProtocolAddress,
79        other_key: &IdentityKey,
80        other_protocol_address: &ProtocolAddress,
81    ) -> bool {
82        if self.public_key() != other_key.public_key() {
83            return false;
84        }
85        let Some(self_service_id) =
86            ServiceId::parse_from_service_id_string(self_protocol_address.name())
87        else {
88            return false;
89        };
90        let Some(other_service_id) =
91            ServiceId::parse_from_service_id_string(other_protocol_address.name())
92        else {
93            return false;
94        };
95        self_service_id == other_service_id
96    }
97}
98
99impl TryFrom<&[u8]> for IdentityKey {
100    type Error = SignalProtocolError;
101
102    fn try_from(value: &[u8]) -> Result<Self> {
103        IdentityKey::decode(value)
104    }
105}
106
107/// The private identity of a user.
108///
109/// Can be converted to and from [`KeyPair`].
110#[derive(Copy, Clone)]
111pub struct IdentityKeyPair {
112    identity_key: IdentityKey,
113    private_key: PrivateKey,
114}
115
116impl IdentityKeyPair {
117    /// Create a key pair from a public `identity_key` and a private `private_key`.
118    pub fn new(identity_key: IdentityKey, private_key: PrivateKey) -> Self {
119        Self {
120            identity_key,
121            private_key,
122        }
123    }
124
125    /// Generate a random new identity from randomness in `csprng`.
126    pub fn generate<R: CryptoRng + Rng>(csprng: &mut R) -> Self {
127        let keypair = KeyPair::generate(csprng);
128
129        Self {
130            identity_key: keypair.public_key.into(),
131            private_key: keypair.private_key,
132        }
133    }
134
135    /// Return the public identity of this user.
136    #[inline]
137    pub fn identity_key(&self) -> &IdentityKey {
138        &self.identity_key
139    }
140
141    /// Return the public key that defines this identity.
142    #[inline]
143    pub fn public_key(&self) -> &PublicKey {
144        self.identity_key.public_key()
145    }
146
147    /// Return the private key that defines this identity.
148    #[inline]
149    pub fn private_key(&self) -> &PrivateKey {
150        &self.private_key
151    }
152
153    /// Return a byte slice which can later be deserialized with [`Self::try_from`].
154    pub fn serialize(&self) -> Box<[u8]> {
155        let structure = proto::storage::IdentityKeyPairStructure {
156            public_key: self.identity_key.serialize().to_vec(),
157            private_key: self.private_key.serialize().to_vec(),
158        };
159
160        let result = structure.encode_to_vec();
161        result.into_boxed_slice()
162    }
163
164    /// Generate a signature claiming that `other` represents the same user as `self`.
165    pub fn sign_alternate_identity<R: Rng + CryptoRng>(
166        &self,
167        other: &IdentityKey,
168        rng: &mut R,
169    ) -> Result<Box<[u8]>> {
170        Ok(self.private_key.calculate_signature_for_multipart_message(
171            &[
172                ALTERNATE_IDENTITY_SIGNATURE_PREFIX_1,
173                ALTERNATE_IDENTITY_SIGNATURE_PREFIX_2,
174                &other.serialize(),
175            ],
176            rng,
177        )?)
178    }
179}
180
181impl TryFrom<&[u8]> for IdentityKeyPair {
182    type Error = SignalProtocolError;
183
184    fn try_from(value: &[u8]) -> Result<Self> {
185        let structure = proto::storage::IdentityKeyPairStructure::decode(value)
186            .map_err(|_| SignalProtocolError::InvalidProtobufEncoding)?;
187        Ok(Self {
188            identity_key: IdentityKey::try_from(&structure.public_key[..])?,
189            private_key: PrivateKey::deserialize(&structure.private_key)?,
190        })
191    }
192}
193
194impl TryFrom<PrivateKey> for IdentityKeyPair {
195    type Error = SignalProtocolError;
196
197    fn try_from(private_key: PrivateKey) -> Result<Self> {
198        let identity_key = IdentityKey::new(private_key.public_key()?);
199        Ok(Self::new(identity_key, private_key))
200    }
201}
202
203impl From<KeyPair> for IdentityKeyPair {
204    fn from(value: KeyPair) -> Self {
205        Self {
206            identity_key: value.public_key.into(),
207            private_key: value.private_key,
208        }
209    }
210}
211
212impl From<IdentityKeyPair> for KeyPair {
213    fn from(value: IdentityKeyPair) -> Self {
214        Self::new(value.identity_key.into(), value.private_key)
215    }
216}
217
218#[cfg(test)]
219mod tests {
220    use rand::TryRngCore as _;
221    use rand::rngs::OsRng;
222
223    use super::*;
224
225    #[test]
226    fn test_identity_key_from() {
227        let key_pair = KeyPair::generate(&mut OsRng.unwrap_err());
228        let key_pair_public_serialized = key_pair.public_key.serialize();
229        let identity_key = IdentityKey::from(key_pair.public_key);
230        assert_eq!(key_pair_public_serialized, identity_key.serialize());
231    }
232
233    #[test]
234    fn test_serialize_identity_key_pair() -> Result<()> {
235        let identity_key_pair = IdentityKeyPair::generate(&mut OsRng.unwrap_err());
236        let serialized = identity_key_pair.serialize();
237        let deserialized_identity_key_pair = IdentityKeyPair::try_from(&serialized[..])?;
238        assert_eq!(
239            identity_key_pair.identity_key(),
240            deserialized_identity_key_pair.identity_key()
241        );
242        assert_eq!(
243            identity_key_pair.private_key().key_type(),
244            deserialized_identity_key_pair.private_key().key_type()
245        );
246        assert_eq!(
247            identity_key_pair.private_key().serialize(),
248            deserialized_identity_key_pair.private_key().serialize()
249        );
250
251        Ok(())
252    }
253
254    #[test]
255    fn test_alternate_identity_signing() -> Result<()> {
256        let mut rng = OsRng.unwrap_err();
257        let primary = IdentityKeyPair::generate(&mut rng);
258        let secondary = IdentityKeyPair::generate(&mut rng);
259
260        let signature = secondary.sign_alternate_identity(primary.identity_key(), &mut rng)?;
261        assert!(
262            secondary
263                .identity_key()
264                .verify_alternate_identity(primary.identity_key(), &signature)?
265        );
266        // Not symmetric.
267        assert!(
268            !primary
269                .identity_key()
270                .verify_alternate_identity(secondary.identity_key(), &signature)?
271        );
272
273        let another_signature =
274            secondary.sign_alternate_identity(primary.identity_key(), &mut rng)?;
275        assert_ne!(signature, another_signature);
276        assert!(
277            secondary
278                .identity_key()
279                .verify_alternate_identity(primary.identity_key(), &another_signature)?
280        );
281
282        let unrelated = IdentityKeyPair::generate(&mut rng);
283        assert!(
284            !secondary
285                .identity_key()
286                .verify_alternate_identity(unrelated.identity_key(), &signature)?
287        );
288        assert!(
289            !unrelated
290                .identity_key()
291                .verify_alternate_identity(primary.identity_key(), &signature)?
292        );
293
294        Ok(())
295    }
296}