Skip to content

Cryptography

Benny Neugebauer edited this page Oct 11, 2019 · 14 revisions

Decryption errors

Code generation

(z.util.murmurhash3('Field too long',42)+'').substr(0,4); // 1738
Error Code Type/Error Reason
2 (1778) RangeError
Offset is outside the bounds of the DataView
Remote side failed to decrypt our message and sends 💣
200 DecryptError
Unknown message type
Remote side does not follow proteus specification
201 (2237) DecryptError.InvalidMessage
Can't initialise a session from a CipherMessage.
Occurs when the remote party thinks we have an initialised session, but it does not/no longer exist locally. We must have confirmed the session with the remote party by sending them a message. Until then then they continue to send us PreKeyMessages instead of CipherMessages. We prematurely deleted the session before decrypting all events.
202 DecryptError.InvalidMessage
Unknown message format: The message is neither a "CipherMessage" nor a "PreKeyMessage".
Remote side does not follow proteus specification
203 DecryptError.PrekeyNotFound
Could not delete PreKey
204 (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)
205 (1976) DecryptError.InvalidMessage
No matching session tag.
Usually happens when we receive a message intended for another client.
206 DecryptError.InvalidSignature
Decryption of a message in sync failed
Envelope mac key verification failed
207 (8550) DecryptError.InvalidSignature
Decryption of a newer message failed
Envelope mac key verification failed. Session broken or out of sync. Reset the session and decryption is likely to work again!
208 (2521) DecryptError.OutdatedMessage
Message is out of sync
Opposite of "Too distant future" error
209 (1701) DecryptError.DuplicateMessage
Duplicate message
Happens if an encrypted message is decrypted twice
210 DecryptError.InvalidSignature
Decryption of a previous (older) message failed
Envelope mac key verification
211 (1300) DecryptError.TooDistantFuture
Message is from too distant in the future
More than 1000 messages on the receive chain were skipped
213 DecryptError.InvalidMessage
Sender failed to encrypt a message.
Error on receiver side when remote side sends a 💣
300 DecryptError.InvalidMessage
The received message was too big.

Cause decryption errors

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 = {};

Detecting if conversation has degraded

  1. conv is verified
  2. backend rejects message because of missing client id
  3. 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

  1. req to /conversation/xxxxxxx/otr
  2. BE returns { missed: deleted: redundant: }
  3. take the missed json object, and put in a request to: /users/prekeys
  4. pass missed keys to: public func sessionWithId(sessionId: String, fromStringPreKey base64StringKey: String) throws -> CBSession to create a session
  5. resent to same /conversation/xxxx/otr
  6. 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

Objects

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()

Proteus.keys.PreKey

Serialized format

serialized_format =
  id: 456
  payload: 'base64encodedstring'
  type: 'Proteus.keys.PreKey'
  version: 1
Clone this wiki locally