2022-03-30 16:40:16 +00:00
// Copyright (c) 2022 Yureka Lilian <yuka@yuka.dev>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
2024-07-09 15:01:42 +00:00
use xso ::{ text ::Base64 , AsXml , FromXml } ;
2024-06-26 11:13:02 +00:00
2022-04-04 19:09:49 +00:00
use crate ::message ::MessagePayload ;
2024-06-26 11:13:02 +00:00
use crate ::ns ;
2022-03-30 16:40:16 +00:00
use crate ::pubsub ::PubSubPayload ;
2024-06-26 11:13:02 +00:00
/// Element of the device list
2024-07-09 15:01:42 +00:00
#[ derive(FromXml, AsXml, PartialEq, Debug, Clone) ]
2024-06-26 11:13:02 +00:00
#[ xml(namespace = ns::LEGACY_OMEMO, name = " device " ) ]
pub struct Device {
/// Device id
#[ xml(attribute) ]
pub id : u32 ,
}
2022-03-30 16:40:16 +00:00
generate_element! (
/// A user's device list contains the OMEMO device ids of all the user's
/// devicse. These can be used to look up bundles and build a session.
DeviceList , " list " , LEGACY_OMEMO ,
children : [
/// List of devices
devices : Vec < Device > = ( " device " , LEGACY_OMEMO ) = > Device
]
) ;
impl PubSubPayload for DeviceList { }
2024-06-26 17:35:56 +00:00
/// SignedPreKey public key
/// Part of a device's bundle
2024-07-09 15:01:42 +00:00
#[ derive(FromXml, AsXml, PartialEq, Debug, Clone) ]
2024-06-26 17:35:56 +00:00
#[ xml(namespace = ns::LEGACY_OMEMO, name = " signedPreKeyPublic " ) ]
pub struct SignedPreKeyPublic {
/// SignedPreKey id
#[ xml(attribute(default, name = " signedPreKeyId " )) ]
pub signed_pre_key_id : Option < u32 > ,
/// Serialized PublicKey
#[ xml(text = Base64) ]
pub data : Vec < u8 > ,
}
2022-03-30 16:40:16 +00:00
2024-06-26 17:35:56 +00:00
/// SignedPreKey signature
/// Part of a device's bundle
2024-07-09 15:01:42 +00:00
#[ derive(FromXml, AsXml, PartialEq, Debug, Clone) ]
2024-06-26 17:35:56 +00:00
#[ xml(namespace = ns::LEGACY_OMEMO, name = " signedPreKeySignature " ) ]
pub struct SignedPreKeySignature {
/// Signature bytes
#[ xml(text = Base64) ]
pub data : Vec < u8 > ,
}
2022-03-30 16:40:16 +00:00
2024-06-26 17:35:56 +00:00
/// Part of a device's bundle
2024-07-09 15:01:42 +00:00
#[ derive(FromXml, AsXml, PartialEq, Debug, Clone) ]
2024-06-26 17:35:56 +00:00
#[ xml(namespace = ns::LEGACY_OMEMO, name = " identityKey " ) ]
pub struct IdentityKey {
/// Serialized PublicKey
#[ xml(text = Base64) ]
pub data : Vec < u8 > ,
}
2022-03-30 16:40:16 +00:00
generate_element! (
/// List of (single use) PreKeys
/// Part of a device's bundle
Prekeys , " prekeys " , LEGACY_OMEMO ,
children : [
/// List of (single use) PreKeys
keys : Vec < PreKeyPublic > = ( " preKeyPublic " , LEGACY_OMEMO ) = > PreKeyPublic ,
]
) ;
2024-06-26 17:35:56 +00:00
/// PreKey public key
/// Part of a device's bundle
2024-07-09 15:01:42 +00:00
#[ derive(FromXml, AsXml, PartialEq, Debug, Clone) ]
2024-06-26 17:35:56 +00:00
#[ xml(namespace = ns::LEGACY_OMEMO, name = " preKeyPublic " ) ]
pub struct PreKeyPublic {
/// PreKey id
#[ xml(attribute = " preKeyId " ) ]
pub pre_key_id : u32 ,
/// Serialized PublicKey
#[ xml(text = Base64) ]
pub data : Vec < u8 > ,
}
2022-03-30 16:40:16 +00:00
generate_element! (
/// A collection of publicly accessible data that can be used to build a session with a device, namely its public IdentityKey, a signed PreKey with corresponding signature, and a list of (single use) PreKeys.
Bundle , " bundle " , LEGACY_OMEMO ,
children : [
/// SignedPreKey public key
signed_pre_key_public : Option < SignedPreKeyPublic > = ( " signedPreKeyPublic " , LEGACY_OMEMO ) = > SignedPreKeyPublic ,
/// SignedPreKey signature
signed_pre_key_signature : Option < SignedPreKeySignature > = ( " signedPreKeySignature " , LEGACY_OMEMO ) = > SignedPreKeySignature ,
/// IdentityKey public key
identity_key : Option < IdentityKey > = ( " identityKey " , LEGACY_OMEMO ) = > IdentityKey ,
/// List of (single use) PreKeys
prekeys : Option < Prekeys > = ( " prekeys " , LEGACY_OMEMO ) = > Prekeys ,
]
) ;
impl PubSubPayload for Bundle { }
generate_element! (
/// The header contains encrypted keys for a message
Header , " header " , LEGACY_OMEMO ,
attributes : [
/// The device id of the sender
sid : Required < u32 > = " sid " ,
] ,
children : [
/// The key that the payload message is encrypted with, separately
/// encrypted for each recipient device.
keys : Vec < Key > = ( " key " , LEGACY_OMEMO ) = > Key ,
/// IV used for payload encryption
iv : Required < IV > = ( " iv " , LEGACY_OMEMO ) = > IV
]
) ;
2024-06-26 17:35:56 +00:00
/// IV used for payload encryption
2024-07-09 15:01:42 +00:00
#[ derive(FromXml, AsXml, PartialEq, Debug, Clone) ]
2024-06-26 17:35:56 +00:00
#[ xml(namespace = ns::LEGACY_OMEMO, name = " iv " ) ]
pub struct IV {
/// IV bytes
#[ xml(text = Base64) ]
pub data : Vec < u8 > ,
}
2022-03-30 16:40:16 +00:00
generate_attribute! (
/// prekey attribute for the key element.
IsPreKey ,
" prekey " ,
bool
) ;
2024-06-26 17:35:56 +00:00
/// Part of the OMEMO element header
2024-07-09 15:01:42 +00:00
#[ derive(FromXml, AsXml, PartialEq, Debug, Clone) ]
2024-06-26 17:35:56 +00:00
#[ xml(namespace = ns::LEGACY_OMEMO, name = " key " ) ]
pub struct Key {
/// The device id this key is encrypted for.
#[ xml(attribute) ]
pub rid : u32 ,
/// The key element MUST be tagged with a prekey attribute set to true
/// if a PreKeySignalMessage is being used.
#[ xml(attribute(default)) ]
pub prekey : IsPreKey ,
/// The 16 bytes key and the GCM authentication tag concatenated together
/// and encrypted using the corresponding long-standing SignalProtocol
/// session
#[ xml(text = Base64) ]
pub data : Vec < u8 > ,
}
2022-03-30 16:40:16 +00:00
2024-06-26 17:35:56 +00:00
/// The encrypted message body
2024-07-09 15:01:42 +00:00
#[ derive(FromXml, AsXml, PartialEq, Debug, Clone) ]
2024-06-26 17:35:56 +00:00
#[ xml(namespace = ns::LEGACY_OMEMO, name = " payload " ) ]
pub struct Payload {
/// Encrypted with AES-128 in Galois/Counter Mode (GCM)
#[ xml(text = Base64) ]
pub data : Vec < u8 > ,
}
2022-03-30 16:40:16 +00:00
generate_element! (
/// An OMEMO element, which can be either a MessageElement (with payload),
/// or a KeyTransportElement (without payload).
Encrypted , " encrypted " , LEGACY_OMEMO ,
children : [
/// The header contains encrypted keys for a message
header : Required < Header > = ( " header " , LEGACY_OMEMO ) = > Header ,
/// Payload for MessageElement
payload : Option < Payload > = ( " payload " , LEGACY_OMEMO ) = > Payload
]
) ;
impl MessagePayload for Encrypted { }
#[ cfg(test) ]
mod tests {
use super ::* ;
use crate ::Element ;
#[ test ]
fn parse_bundle ( ) {
2022-03-22 22:29:25 +00:00
let elem : Element = r #" <bundle xmlns= " eu . siacs . conversations . axolotl " >
2022-03-30 16:40:16 +00:00
< signedPreKeyPublic signedPreKeyId = " 1 " > BYAbACA15bPn95p7RGC2XbgQyly8aRKS4BaJ + hD8Ybhe < / signedPreKeyPublic >
< signedPreKeySignature > sIJVNDZi / NgFsry4OBdM + adyGttLEXbUh / h / 5 dVOZveMgyVoIdgwBUzq8Wgd2xYTQMioNzwYebTX + 9 p0h9eujA = = < / signedPreKeySignature >
< identityKey > BQFd2p / Oq97vAAdLKA09DlcSg0x1xWn260p1jaeyIhAZ < / identityKey >
< prekeys >
< preKeyPublic preKeyId = " 1 " > BbjHsF5ndtNV8ToRcJTYSNGePgAWsFGkSL6OG7B7LXRe < / preKeyPublic >
< preKeyPublic preKeyId = " 2 " > BeWHsbBNx1uer1ia / nW / 6 tn / OlqHll9itjjUTIvV39x7 < / preKeyPublic >
< preKeyPublic preKeyId = " 3 " > BeVr5xPmNErkwK3ocPmv0Nohy3C4PKQBnxMuOqiXotJY < / preKeyPublic >
< / prekeys >
< / bundle >
" #.parse().unwrap();
let bundle : Bundle = elem . try_into ( ) . unwrap ( ) ;
let bundle2 = Bundle {
2022-04-04 19:09:49 +00:00
signed_pre_key_public : Some ( SignedPreKeyPublic {
signed_pre_key_id : Some ( 1 ) ,
data : vec ! [
5 , 128 , 27 , 0 , 32 , 53 , 229 , 179 , 231 , 247 , 154 , 123 , 68 , 96 , 182 , 93 , 184 , 16 ,
202 , 92 , 188 , 105 , 18 , 146 , 224 , 22 , 137 , 250 , 16 , 252 , 97 , 184 , 94 ,
] ,
} ) ,
signed_pre_key_signature : Some ( SignedPreKeySignature {
data : vec ! [
176 , 130 , 85 , 52 , 54 , 98 , 252 , 216 , 5 , 178 , 188 , 184 , 56 , 23 , 76 , 249 , 167 ,
114 , 26 , 219 , 75 , 17 , 118 , 212 , 135 , 248 , 127 , 229 , 213 , 78 , 102 , 247 , 140 ,
131 , 37 , 104 , 33 , 216 , 48 , 5 , 76 , 234 , 241 , 104 , 29 , 219 , 22 , 19 , 64 , 200 , 168 ,
55 , 60 , 24 , 121 , 180 , 215 , 251 , 218 , 116 , 135 , 215 , 174 , 140 ,
] ,
} ) ,
identity_key : Some ( IdentityKey {
data : vec ! [
5 , 1 , 93 , 218 , 159 , 206 , 171 , 222 , 239 , 0 , 7 , 75 , 40 , 13 , 61 , 14 , 87 , 18 , 131 ,
76 , 117 , 197 , 105 , 246 , 235 , 74 , 117 , 141 , 167 , 178 , 34 , 16 , 25 ,
] ,
} ) ,
prekeys : Some ( Prekeys {
keys : vec ! [
PreKeyPublic {
pre_key_id : 1 ,
data : vec ! [
5 , 184 , 199 , 176 , 94 , 103 , 118 , 211 , 85 , 241 , 58 , 17 , 112 , 148 , 216 ,
72 , 209 , 158 , 62 , 0 , 22 , 176 , 81 , 164 , 72 , 190 , 142 , 27 , 176 , 123 , 45 ,
116 , 94 ,
] ,
} ,
PreKeyPublic {
pre_key_id : 2 ,
data : vec ! [
5 , 229 , 135 , 177 , 176 , 77 , 199 , 91 , 158 , 175 , 88 , 154 , 254 , 117 , 191 ,
234 , 217 , 255 , 58 , 90 , 135 , 150 , 95 , 98 , 182 , 56 , 212 , 76 , 139 , 213 ,
223 , 220 , 123 ,
] ,
} ,
PreKeyPublic {
pre_key_id : 3 ,
data : vec ! [
5 , 229 , 107 , 231 , 19 , 230 , 52 , 74 , 228 , 192 , 173 , 232 , 112 , 249 , 175 ,
208 , 218 , 33 , 203 , 112 , 184 , 60 , 164 , 1 , 159 , 19 , 46 , 58 , 168 , 151 ,
162 , 210 , 88 ,
] ,
} ,
] ,
} ) ,
2022-03-30 16:40:16 +00:00
} ;
assert_eq! ( bundle , bundle2 ) ;
}
#[ test ]
fn parse_device_list ( ) {
2022-03-22 22:29:25 +00:00
let elem : Element = r #" <list xmlns= " eu . siacs . conversations . axolotl " >
2022-03-30 16:40:16 +00:00
< device id = " 1164059891 " / >
< device id = " 26052318 " / >
< device id = " 564866972 " / >
< / list >
2022-04-04 19:09:49 +00:00
" #
. parse ( )
. unwrap ( ) ;
2022-03-30 16:40:16 +00:00
let list : DeviceList = elem . try_into ( ) . unwrap ( ) ;
let list2 = DeviceList {
devices : vec ! [
2022-04-04 19:09:49 +00:00
Device { id : 1164059891 } ,
Device { id : 26052318 } ,
Device { id : 564866972 } ,
2022-03-30 16:40:16 +00:00
] ,
} ;
assert_eq! ( list , list2 ) ;
}
#[ test ]
fn parse_encrypted ( ) {
2022-03-22 22:29:25 +00:00
let elem : Element = r #" <encrypted xmlns= " eu . siacs . conversations . axolotl " >
2022-03-30 16:40:16 +00:00
< header sid = " 564866972 " >
< key prekey = " true " rid = " 1236 " > Mwjp9AESIQVylscLPpj / HlowaTiIsaBj73HCVEllXpVTtMG9EYwRexohBQFd2p / Oq97vAAdLKA09DlcSg0x1xWn260p1jaeyIhAZImIzCiEFhaQ4I + DuQgo6vCLCjHu4uewDZmWHuBl8uJw1IkyZxhUQABgAIjCoEVgVThWlaIlnN3V5Bg1hQX7OD1cvstLD5lH3zZMadL3KeONELESlBbeKmNgcYC / e3HZnbgWzBiic36yNAjAW < / key >
< key rid = " 26052318 " > MwohBTV6dpumL1OxA9MdIFmu2E19 + cIWDHWYfhdubvo0hmh6EAAYHCIwNc9 / 59 eeYi8pVZQhMJJMVkKUkFP / yrTfG3o1lfpHGseCqb / JTgtDytQPiYrTpHl2V / mdsM6IPig = < / key >
< key rid = " 1164059891 " > MwohBVnhz9pvEj1s1waEHuk5qpQqhUrpavycFz0hq / KYwI8oEAAYCSIwedEGN6MidxyvaPI8zorLcpG0Y7e7ecGkkd5vdDrL7Qt1tXaHb0iDyE / rZZHpFiNN38Izfp5vHv4 = < / key >
< iv > SY / SCGPt0CnA2odB < / iv >
< / header >
< payload > Vas = < / payload >
< / encrypted >
" #.parse().unwrap();
let encrypted : Encrypted = elem . try_into ( ) . unwrap ( ) ;
let encrypted2 = Encrypted {
header : Header {
sid : 564866972 ,
keys : vec ! [
Key {
rid : 1236 ,
prekey : IsPreKey ::True ,
2022-04-04 19:09:49 +00:00
data : vec ! [
51 , 8 , 233 , 244 , 1 , 18 , 33 , 5 , 114 , 150 , 199 , 11 , 62 , 152 , 255 , 30 , 90 ,
48 , 105 , 56 , 136 , 177 , 160 , 99 , 239 , 113 , 194 , 84 , 73 , 101 , 94 , 149 ,
83 , 180 , 193 , 189 , 17 , 140 , 17 , 123 , 26 , 33 , 5 , 1 , 93 , 218 , 159 , 206 ,
171 , 222 , 239 , 0 , 7 , 75 , 40 , 13 , 61 , 14 , 87 , 18 , 131 , 76 , 117 , 197 ,
105 , 246 , 235 , 74 , 117 , 141 , 167 , 178 , 34 , 16 , 25 , 34 , 98 , 51 , 10 , 33 ,
5 , 133 , 164 , 56 , 35 , 224 , 238 , 66 , 10 , 58 , 188 , 34 , 194 , 140 , 123 , 184 ,
185 , 236 , 3 , 102 , 101 , 135 , 184 , 25 , 124 , 184 , 156 , 53 , 34 , 76 , 153 ,
198 , 21 , 16 , 0 , 24 , 0 , 34 , 48 , 168 , 17 , 88 , 21 , 78 , 21 , 165 , 104 , 137 ,
103 , 55 , 117 , 121 , 6 , 13 , 97 , 65 , 126 , 206 , 15 , 87 , 47 , 178 , 210 , 195 ,
230 , 81 , 247 , 205 , 147 , 26 , 116 , 189 , 202 , 120 , 227 , 68 , 44 , 68 , 165 ,
5 , 183 , 138 , 152 , 216 , 28 , 96 , 47 , 222 , 220 , 118 , 103 , 110 , 5 , 179 , 6 ,
40 , 156 , 223 , 172 , 141 , 2 , 48 , 22 ,
] ,
2022-03-30 16:40:16 +00:00
} ,
Key {
rid : 26052318 ,
prekey : IsPreKey ::False ,
2022-04-04 19:09:49 +00:00
data : vec ! [
51 , 10 , 33 , 5 , 53 , 122 , 118 , 155 , 166 , 47 , 83 , 177 , 3 , 211 , 29 , 32 , 89 ,
174 , 216 , 77 , 125 , 249 , 194 , 22 , 12 , 117 , 152 , 126 , 23 , 110 , 110 , 250 ,
52 , 134 , 104 , 122 , 16 , 0 , 24 , 28 , 34 , 48 , 53 , 207 , 127 , 231 , 215 , 158 ,
98 , 47 , 41 , 85 , 148 , 33 , 48 , 146 , 76 , 86 , 66 , 148 , 144 , 83 , 255 , 202 ,
180 , 223 , 27 , 122 , 53 , 149 , 250 , 71 , 26 , 199 , 130 , 169 , 191 , 201 , 78 ,
11 , 67 , 202 , 212 , 15 , 137 , 138 , 211 , 164 , 121 , 118 , 87 , 249 , 157 , 176 ,
206 , 136 , 62 , 40 ,
] ,
2022-03-30 16:40:16 +00:00
} ,
Key {
rid : 1164059891 ,
prekey : IsPreKey ::False ,
2022-04-04 19:09:49 +00:00
data : vec ! [
51 , 10 , 33 , 5 , 89 , 225 , 207 , 218 , 111 , 18 , 61 , 108 , 215 , 6 , 132 , 30 ,
233 , 57 , 170 , 148 , 42 , 133 , 74 , 233 , 106 , 252 , 156 , 23 , 61 , 33 , 171 ,
242 , 152 , 192 , 143 , 40 , 16 , 0 , 24 , 9 , 34 , 48 , 121 , 209 , 6 , 55 , 163 , 34 ,
119 , 28 , 175 , 104 , 242 , 60 , 206 , 138 , 203 , 114 , 145 , 180 , 99 , 183 , 187 ,
121 , 193 , 164 , 145 , 222 , 111 , 116 , 58 , 203 , 237 , 11 , 117 , 181 , 118 ,
135 , 111 , 72 , 131 , 200 , 79 , 235 , 101 , 145 , 233 , 22 , 35 , 77 , 223 , 194 ,
51 , 126 , 158 , 111 , 30 , 254 ,
] ,
2022-03-30 16:40:16 +00:00
} ,
] ,
iv : IV {
2022-04-04 19:09:49 +00:00
data : vec ! [ 73 , 143 , 210 , 8 , 99 , 237 , 208 , 41 , 192 , 218 , 135 , 65 ] ,
2022-03-30 16:40:16 +00:00
} ,
} ,
payload : Some ( Payload {
2022-04-04 19:09:49 +00:00
data : vec ! [ 85 , 171 ] ,
2022-03-30 16:40:16 +00:00
} ) ,
} ;
assert_eq! ( encrypted , encrypted2 ) ;
}
}