-
Notifications
You must be signed in to change notification settings - Fork 292
Cryptography
Gregor Herdmann edited this page Nov 2, 2016
·
14 revisions
Code generation
(z.util.murmurhash3('Field too long',42)+'').substr(0,4); // 1738
Code | Type/Error | Reason |
---|---|---|
1300 |
DecryptError.TooDistantFuture Message is from too distant in the future |
More than 1000 messages on the receive chain were skipped |
1701 |
DecryptError.DuplicateMessage Duplicate message |
Happens if an encrypted message is decrypted twice |
1976 |
DecryptError.InvalidMessage No matching session state. |
Usually happens when we receive a message intended for another client. |
2237 |
DecryptError.InvalidMessage Can't initialise a session from a CipherMessage. |
Relates to not persisting sessions correctly. Will happen when the remote party thinks we have an initialised session, but we can't load it from our local store. However, this will only happen when we have already confirmed the session with the remote party by sending them a message. If they just send us messages without any reply, they will continue to send us PreKeyMessages instead of raw CipherMessages. This bug is caused if we already had established a session and lost (null or undefined ) it. |
2521 |
DecryptError.OutdatedMessage Outdated message |
Opposite of "Too distant future" error |
3690 |
DecryptError.RemoteIdentityChanged Remote identity changed |
Client of the user has changed without informing us (Man in the middle attack? or database conflicts on the remote side: sessions get mixed with new client) |
8550 |
DecryptError.InvalidSignature Invalid signature |
Session broken or out of sync. Reset the session and decryption is likely to work again! |
Destroy session states
// This will enforce 'No matching session state.'
var client_id = "494C60375CC490E4".toLowerCase();
var sessions = wire.app.repository.cryptography.cryptobox.store.sessions;
var cryptobox_session = sessions[Object.keys(sessions).filter((session_key) => session_key.endsWith(client_id))[0]];
cryptobox_session.session_states = {};
- conv is verified
- backend rejects message because of missing client id
- we check for that device.... if it is unknown to us and not verified we show "conv degraded"
Retrieve the identity key pair
wire.app.repository.encryption.cryptobox
Payload after successful registration
Permanent device:
{
"cookie": "Wire - 569cff83-a338-487f-8f06-7a7c250664eb",
"time": "2015-12-17T16:06:09.097Z",
"location": {
"lat": 51.5,
"lon": -0.13
},
"address": "62.96.148.44",
"model": "Chrome 47.0.2526.80",
"id": "5791adc5672bf043",
"type": "permanent",
"class": "desktop",
"label": "Windows NT 10.0"
}
Temporary device:
{
"cookie": "Wire - 2507b1a5-1cf0-4144-b284-c349e6e8029e",
"time": "2015-12-17T16:08:56.293Z",
"location": {
"lat": 51.5,
"lon": -0.13
},
"address": "62.96.148.44",
"model": "Chrome 47.0.2526.80",
"id": "585d8f6b2a118d6f",
"type": "temporary",
"class": "desktop",
"label": "Windows NT 10.0"
}
iOS behaviour
Sending a message
- req to
/conversation/xxxxxxx/otr
- BE returns
{ missed: deleted: redundant: }
- take the missed json object, and put in a request to:
/users/prekeys
- pass missed keys to:
public func sessionWithId(sessionId: String, fromStringPreKey base64StringKey: String) throws -> CBSession
to create a session - resent to same /conversation/xxxx/otr
- repeat until there are no more
"missed"
Note:
When I want to send, I need to get the session of each client recipient, with: CBSession *session = [box sessionById:client.remoteIdentifier error:&error]
and encrypt for that client with: NSData *encryptedData = [session encrypt:dataToEncrypt error:&error];
Receiving a message
When receiving an event, the event has the "sender"
JSON field. That's the client ID of the sender.
CBSession *session = [self sessionById:sessionId error:&error];
if (session != nil) { // I already have a session
decryptedMessageData = [session decrypt:data error:&error];
if (createdNewSession) {
*createdNewSession = NO;
}
}
else {
CBSessionMessage *sessionMessage = [self sessionMessageWithId:sessionId fromMessage:data error:&error];
decryptedMessageData = sessionMessage.data;
}
Useful:
- When fetching
/notifications
, pass your client ID (not mandatory) - When opening web socket, same
Composition
cryptobox.CryptoboxSession = client_id, Store, Proteus.session.Session
Proteus.session.Session(local Proteus.keys.IdentityKeyPair, remote Proteus.keys.PreKeyBundle)
Proteus.keys.PreKeyBundle = Proteus.keys.IdentityKey & Proteus.keys.PreKey
Proteus.keys.PreKey = key_id & Proteus.keys.KeyPair
Proteus.keys.KeyPair = secret_key & public_key
Creation
pre_key = Proteus.keys.PreKey.new prekey_id
pre_key_bundle = Proteus.keys.PreKeyBundle.new(@identity.public_key, pk).serialise()
Serialized format
serialized_format =
id: 456
payload: 'base64encodedstring'
type: 'Proteus.keys.PreKey'
version: 1