1 /* Copyright 2015, 2016 OpenMarket Ltd
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
15 #include "olm/ratchet.hh"
16 #include "olm/message.hh"
17 #include "olm/memory.hh"
18 #include "olm/cipher.h"
19 #include "olm/pickle.hh"
25 static const std::uint8_t PROTOCOL_VERSION = 3;
26 static const std::uint8_t MESSAGE_KEY_SEED[1] = {0x01};
27 static const std::uint8_t CHAIN_KEY_SEED[1] = {0x02};
28 static const std::size_t MAX_MESSAGE_GAP = 2000;
32 * Advance the root key, creating a new message chain.
34 * @param root_key previous root key R(n-1)
35 * @param our_key our new ratchet key T(n)
36 * @param their_key their most recent ratchet key T(n-1)
37 * @param info table of constants for the ratchet function
38 * @param new_root_key[out] returns the new root key R(n)
39 * @param new_chain_key[out] returns the first chain key in the new chain
42 static void create_chain_key(
43 olm::SharedKey const & root_key,
44 _olm_curve25519_key_pair const & our_key,
45 _olm_curve25519_public_key const & their_key,
46 olm::KdfInfo const & info,
47 olm::SharedKey & new_root_key,
48 olm::ChainKey & new_chain_key
50 olm::SharedKey secret;
51 _olm_crypto_curve25519_shared_secret(&our_key, &their_key, secret);
52 std::uint8_t derived_secrets[2 * olm::OLM_SHARED_KEY_LENGTH];
53 _olm_crypto_hkdf_sha256(
54 secret, sizeof(secret),
55 root_key, sizeof(root_key),
56 info.ratchet_info, info.ratchet_info_length,
57 derived_secrets, sizeof(derived_secrets)
59 std::uint8_t const * pos = derived_secrets;
60 pos = olm::load_array(new_root_key, pos);
61 pos = olm::load_array(new_chain_key.key, pos);
62 new_chain_key.index = 0;
63 olm::unset(derived_secrets);
68 static void advance_chain_key(
69 olm::ChainKey const & chain_key,
70 olm::ChainKey & new_chain_key
72 _olm_crypto_hmac_sha256(
73 chain_key.key, sizeof(chain_key.key),
74 CHAIN_KEY_SEED, sizeof(CHAIN_KEY_SEED),
77 new_chain_key.index = chain_key.index + 1;
81 static void create_message_keys(
82 olm::ChainKey const & chain_key,
83 olm::KdfInfo const & info,
84 olm::MessageKey & message_key) {
85 _olm_crypto_hmac_sha256(
86 chain_key.key, sizeof(chain_key.key),
87 MESSAGE_KEY_SEED, sizeof(MESSAGE_KEY_SEED),
90 message_key.index = chain_key.index;
94 static std::size_t verify_mac_and_decrypt(
95 _olm_cipher const *cipher,
96 olm::MessageKey const & message_key,
97 olm::MessageReader const & reader,
98 std::uint8_t * plaintext, std::size_t max_plaintext_length
100 return cipher->ops->decrypt(
102 message_key.key, sizeof(message_key.key),
103 reader.input, reader.input_length,
104 reader.ciphertext, reader.ciphertext_length,
105 plaintext, max_plaintext_length
110 static std::size_t verify_mac_and_decrypt_for_existing_chain(
111 olm::Ratchet const & session,
112 olm::ChainKey const & chain,
113 olm::MessageReader const & reader,
114 std::uint8_t * plaintext, std::size_t max_plaintext_length
116 if (reader.counter < chain.index) {
117 return std::size_t(-1);
120 /* Limit the number of hashes we're prepared to compute */
121 if (reader.counter - chain.index > MAX_MESSAGE_GAP) {
122 return std::size_t(-1);
125 olm::ChainKey new_chain = chain;
127 while (new_chain.index < reader.counter) {
128 advance_chain_key(new_chain, new_chain);
131 olm::MessageKey message_key;
132 create_message_keys(new_chain, session.kdf_info, message_key);
134 std::size_t result = verify_mac_and_decrypt(
135 session.ratchet_cipher, message_key, reader,
136 plaintext, max_plaintext_length
139 olm::unset(new_chain);
144 static std::size_t verify_mac_and_decrypt_for_new_chain(
145 olm::Ratchet const & session,
146 olm::MessageReader const & reader,
147 std::uint8_t * plaintext, std::size_t max_plaintext_length
149 olm::SharedKey new_root_key;
150 olm::ReceiverChain new_chain;
152 /* They shouldn't move to a new chain until we've sent them a message
153 * acknowledging the last one */
154 if (session.sender_chain.empty()) {
155 return std::size_t(-1);
158 /* Limit the number of hashes we're prepared to compute */
159 if (reader.counter > MAX_MESSAGE_GAP) {
160 return std::size_t(-1);
162 olm::load_array(new_chain.ratchet_key.public_key, reader.ratchet_key);
165 session.root_key, session.sender_chain[0].ratchet_key,
166 new_chain.ratchet_key, session.kdf_info,
167 new_root_key, new_chain.chain_key
169 std::size_t result = verify_mac_and_decrypt_for_existing_chain(
170 session, new_chain.chain_key, reader,
171 plaintext, max_plaintext_length
173 olm::unset(new_root_key);
174 olm::unset(new_chain);
181 olm::Ratchet::Ratchet(
182 olm::KdfInfo const & kdf_info,
183 _olm_cipher const * ratchet_cipher
184 ) : kdf_info(kdf_info),
185 ratchet_cipher(ratchet_cipher),
186 last_error(OlmErrorCode::OLM_SUCCESS) {
190 void olm::Ratchet::initialise_as_bob(
191 std::uint8_t const * shared_secret, std::size_t shared_secret_length,
192 _olm_curve25519_public_key const & their_ratchet_key
194 std::uint8_t derived_secrets[2 * olm::OLM_SHARED_KEY_LENGTH];
195 _olm_crypto_hkdf_sha256(
196 shared_secret, shared_secret_length,
198 kdf_info.root_info, kdf_info.root_info_length,
199 derived_secrets, sizeof(derived_secrets)
201 receiver_chains.insert();
202 receiver_chains[0].chain_key.index = 0;
203 std::uint8_t const * pos = derived_secrets;
204 pos = olm::load_array(root_key, pos);
205 pos = olm::load_array(receiver_chains[0].chain_key.key, pos);
206 receiver_chains[0].ratchet_key = their_ratchet_key;
207 olm::unset(derived_secrets);
211 void olm::Ratchet::initialise_as_alice(
212 std::uint8_t const * shared_secret, std::size_t shared_secret_length,
213 _olm_curve25519_key_pair const & our_ratchet_key
215 std::uint8_t derived_secrets[2 * olm::OLM_SHARED_KEY_LENGTH];
216 _olm_crypto_hkdf_sha256(
217 shared_secret, shared_secret_length,
219 kdf_info.root_info, kdf_info.root_info_length,
220 derived_secrets, sizeof(derived_secrets)
222 sender_chain.insert();
223 sender_chain[0].chain_key.index = 0;
224 std::uint8_t const * pos = derived_secrets;
225 pos = olm::load_array(root_key, pos);
226 pos = olm::load_array(sender_chain[0].chain_key.key, pos);
227 sender_chain[0].ratchet_key = our_ratchet_key;
228 olm::unset(derived_secrets);
234 static std::size_t pickle_length(
235 const olm::SharedKey & value
237 return olm::OLM_SHARED_KEY_LENGTH;
241 static std::uint8_t * pickle(
243 const olm::SharedKey & value
245 return olm::pickle_bytes(pos, value, olm::OLM_SHARED_KEY_LENGTH);
249 static std::uint8_t const * unpickle(
250 std::uint8_t const * pos, std::uint8_t const * end,
251 olm::SharedKey & value
253 return olm::unpickle_bytes(pos, end, value, olm::OLM_SHARED_KEY_LENGTH);
257 static std::size_t pickle_length(
258 const olm::SenderChain & value
260 std::size_t length = 0;
261 length += olm::pickle_length(value.ratchet_key);
262 length += olm::pickle_length(value.chain_key.key);
263 length += olm::pickle_length(value.chain_key.index);
268 static std::uint8_t * pickle(
270 const olm::SenderChain & value
272 pos = olm::pickle(pos, value.ratchet_key);
273 pos = olm::pickle(pos, value.chain_key.key);
274 pos = olm::pickle(pos, value.chain_key.index);
279 static std::uint8_t const * unpickle(
280 std::uint8_t const * pos, std::uint8_t const * end,
281 olm::SenderChain & value
283 pos = olm::unpickle(pos, end, value.ratchet_key); UNPICKLE_OK(pos);
284 pos = olm::unpickle(pos, end, value.chain_key.key); UNPICKLE_OK(pos);
285 pos = olm::unpickle(pos, end, value.chain_key.index); UNPICKLE_OK(pos);
289 static std::size_t pickle_length(
290 const olm::ReceiverChain & value
292 std::size_t length = 0;
293 length += olm::pickle_length(value.ratchet_key);
294 length += olm::pickle_length(value.chain_key.key);
295 length += olm::pickle_length(value.chain_key.index);
300 static std::uint8_t * pickle(
302 const olm::ReceiverChain & value
304 pos = olm::pickle(pos, value.ratchet_key);
305 pos = olm::pickle(pos, value.chain_key.key);
306 pos = olm::pickle(pos, value.chain_key.index);
311 static std::uint8_t const * unpickle(
312 std::uint8_t const * pos, std::uint8_t const * end,
313 olm::ReceiverChain & value
315 pos = olm::unpickle(pos, end, value.ratchet_key); UNPICKLE_OK(pos);
316 pos = olm::unpickle(pos, end, value.chain_key.key); UNPICKLE_OK(pos);
317 pos = olm::unpickle(pos, end, value.chain_key.index); UNPICKLE_OK(pos);
322 static std::size_t pickle_length(
323 const olm::SkippedMessageKey & value
325 std::size_t length = 0;
326 length += olm::pickle_length(value.ratchet_key);
327 length += olm::pickle_length(value.message_key.key);
328 length += olm::pickle_length(value.message_key.index);
333 static std::uint8_t * pickle(
335 const olm::SkippedMessageKey & value
337 pos = olm::pickle(pos, value.ratchet_key);
338 pos = olm::pickle(pos, value.message_key.key);
339 pos = olm::pickle(pos, value.message_key.index);
344 static std::uint8_t const * unpickle(
345 std::uint8_t const * pos, std::uint8_t const * end,
346 olm::SkippedMessageKey & value
348 pos = olm::unpickle(pos, end, value.ratchet_key); UNPICKLE_OK(pos);
349 pos = olm::unpickle(pos, end, value.message_key.key); UNPICKLE_OK(pos);
350 pos = olm::unpickle(pos, end, value.message_key.index); UNPICKLE_OK(pos);
358 std::size_t olm::pickle_length(
359 olm::Ratchet const & value
361 std::size_t length = 0;
362 length += olm::OLM_SHARED_KEY_LENGTH;
363 length += olm::pickle_length(value.sender_chain);
364 length += olm::pickle_length(value.receiver_chains);
365 length += olm::pickle_length(value.skipped_message_keys);
369 std::uint8_t * olm::pickle(
371 olm::Ratchet const & value
373 pos = pickle(pos, value.root_key);
374 pos = pickle(pos, value.sender_chain);
375 pos = pickle(pos, value.receiver_chains);
376 pos = pickle(pos, value.skipped_message_keys);
381 std::uint8_t const * olm::unpickle(
382 std::uint8_t const * pos, std::uint8_t const * end,
383 olm::Ratchet & value,
384 bool includes_chain_index
386 pos = unpickle(pos, end, value.root_key); UNPICKLE_OK(pos);
387 pos = unpickle(pos, end, value.sender_chain); UNPICKLE_OK(pos);
388 pos = unpickle(pos, end, value.receiver_chains); UNPICKLE_OK(pos);
389 pos = unpickle(pos, end, value.skipped_message_keys); UNPICKLE_OK(pos);
391 // pickle v 0x80000001 includes a chain index; pickle v1 does not.
392 if (includes_chain_index) {
394 pos = unpickle(pos, end, dummy); UNPICKLE_OK(pos);
400 std::size_t olm::Ratchet::encrypt_output_length(
401 std::size_t plaintext_length
403 std::size_t counter = 0;
404 if (!sender_chain.empty()) {
405 counter = sender_chain[0].chain_key.index;
407 std::size_t padded = ratchet_cipher->ops->encrypt_ciphertext_length(
411 return olm::encode_message_length(
412 counter, CURVE25519_KEY_LENGTH, padded, ratchet_cipher->ops->mac_length(ratchet_cipher)
417 std::size_t olm::Ratchet::encrypt_random_length() const {
418 return sender_chain.empty() ? CURVE25519_RANDOM_LENGTH : 0;
422 std::size_t olm::Ratchet::encrypt(
423 std::uint8_t const * plaintext, std::size_t plaintext_length,
424 std::uint8_t const * random, std::size_t random_length,
425 std::uint8_t * output, std::size_t max_output_length
427 std::size_t output_length = encrypt_output_length(plaintext_length);
429 if (random_length < encrypt_random_length()) {
430 last_error = OlmErrorCode::OLM_NOT_ENOUGH_RANDOM;
431 return std::size_t(-1);
433 if (max_output_length < output_length) {
434 last_error = OlmErrorCode::OLM_OUTPUT_BUFFER_TOO_SMALL;
435 return std::size_t(-1);
438 if (sender_chain.empty()) {
439 sender_chain.insert();
440 _olm_crypto_curve25519_generate_key(random, &sender_chain[0].ratchet_key);
443 sender_chain[0].ratchet_key,
444 receiver_chains[0].ratchet_key,
446 root_key, sender_chain[0].chain_key
451 create_message_keys(sender_chain[0].chain_key, kdf_info, keys);
452 advance_chain_key(sender_chain[0].chain_key, sender_chain[0].chain_key);
454 std::size_t ciphertext_length = ratchet_cipher->ops->encrypt_ciphertext_length(
458 std::uint32_t counter = keys.index;
459 _olm_curve25519_public_key const & ratchet_key =
460 sender_chain[0].ratchet_key.public_key;
462 olm::MessageWriter writer;
465 writer, PROTOCOL_VERSION, counter, CURVE25519_KEY_LENGTH,
470 olm::store_array(writer.ratchet_key, ratchet_key.public_key);
472 ratchet_cipher->ops->encrypt(
474 keys.key, sizeof(keys.key),
475 plaintext, plaintext_length,
476 writer.ciphertext, ciphertext_length,
477 output, output_length
481 return output_length;
485 std::size_t olm::Ratchet::decrypt_max_plaintext_length(
486 std::uint8_t const * input, std::size_t input_length
488 olm::MessageReader reader;
490 reader, input, input_length,
491 ratchet_cipher->ops->mac_length(ratchet_cipher)
494 if (!reader.ciphertext) {
495 last_error = OlmErrorCode::OLM_BAD_MESSAGE_FORMAT;
496 return std::size_t(-1);
499 return ratchet_cipher->ops->decrypt_max_plaintext_length(
500 ratchet_cipher, reader.ciphertext_length);
504 std::size_t olm::Ratchet::decrypt(
505 std::uint8_t const * input, std::size_t input_length,
506 std::uint8_t * plaintext, std::size_t max_plaintext_length
508 olm::MessageReader reader;
510 reader, input, input_length,
511 ratchet_cipher->ops->mac_length(ratchet_cipher)
514 if (reader.version != PROTOCOL_VERSION) {
515 last_error = OlmErrorCode::OLM_BAD_MESSAGE_VERSION;
516 return std::size_t(-1);
519 if (!reader.has_counter || !reader.ratchet_key || !reader.ciphertext) {
520 last_error = OlmErrorCode::OLM_BAD_MESSAGE_FORMAT;
521 return std::size_t(-1);
524 std::size_t max_length = ratchet_cipher->ops->decrypt_max_plaintext_length(
526 reader.ciphertext_length
529 if (max_plaintext_length < max_length) {
530 last_error = OlmErrorCode::OLM_OUTPUT_BUFFER_TOO_SMALL;
531 return std::size_t(-1);
534 if (reader.ratchet_key_length != CURVE25519_KEY_LENGTH) {
535 last_error = OlmErrorCode::OLM_BAD_MESSAGE_FORMAT;
536 return std::size_t(-1);
539 ReceiverChain * chain = nullptr;
541 for (olm::ReceiverChain & receiver_chain : receiver_chains) {
542 if (0 == std::memcmp(
543 receiver_chain.ratchet_key.public_key, reader.ratchet_key,
544 CURVE25519_KEY_LENGTH
546 chain = &receiver_chain;
551 std::size_t result = std::size_t(-1);
554 result = verify_mac_and_decrypt_for_new_chain(
555 *this, reader, plaintext, max_plaintext_length
557 } else if (chain->chain_key.index > reader.counter) {
558 /* Chain already advanced beyond the key for this message
559 * Check if the message keys are in the skipped key list. */
560 for (olm::SkippedMessageKey & skipped : skipped_message_keys) {
561 if (reader.counter == skipped.message_key.index
563 skipped.ratchet_key.public_key, reader.ratchet_key,
564 CURVE25519_KEY_LENGTH
567 /* Found the key for this message. Check the MAC. */
569 result = verify_mac_and_decrypt(
570 ratchet_cipher, skipped.message_key, reader,
571 plaintext, max_plaintext_length
574 if (result != std::size_t(-1)) {
575 /* Remove the key from the skipped keys now that we've
576 * decoded the message it corresponds to. */
578 skipped_message_keys.erase(&skipped);
584 result = verify_mac_and_decrypt_for_existing_chain(
585 *this, chain->chain_key,
586 reader, plaintext, max_plaintext_length
590 if (result == std::size_t(-1)) {
591 last_error = OlmErrorCode::OLM_BAD_MESSAGE_MAC;
592 return std::size_t(-1);
596 /* They have started using a new ephemeral ratchet key.
597 * We need to derive a new set of chain keys.
598 * We can discard our previous ephemeral ratchet key.
599 * We will generate a new key when we send the next message. */
601 chain = receiver_chains.insert();
602 olm::load_array(chain->ratchet_key.public_key, reader.ratchet_key);
604 // TODO: we've already done this once, in
605 // verify_mac_and_decrypt_for_new_chain(). we could reuse the result.
607 root_key, sender_chain[0].ratchet_key, chain->ratchet_key,
608 kdf_info, root_key, chain->chain_key
611 olm::unset(sender_chain[0]);
612 sender_chain.erase(sender_chain.begin());
615 while (chain->chain_key.index < reader.counter) {
616 olm::SkippedMessageKey & key = *skipped_message_keys.insert();
617 create_message_keys(chain->chain_key, kdf_info, key.message_key);
618 key.ratchet_key = chain->ratchet_key;
619 advance_chain_key(chain->chain_key, chain->chain_key);
622 advance_chain_key(chain->chain_key, chain->chain_key);