| 1 | /* Copyright 2015 OpenMarket Ltd |
| 2 | * |
| 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 |
| 6 | * |
| 7 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | * |
| 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. |
| 14 | */ |
| 15 | |
| 16 | #include <cstdint> |
| 17 | |
| 18 | #include "olm/crypto.h" |
| 19 | #include "olm/list.hh" |
| 20 | #include "olm/error.h" |
| 21 | |
| 22 | // Note: exports in this file are only for unit tests. Nobody else should be |
| 23 | // using this externally |
| 24 | #include "olm/olm_export.h" |
| 25 | |
| 26 | struct _olm_cipher; |
| 27 | |
| 28 | namespace olm { |
| 29 | |
| 30 | /** length of a shared key: the root key R(i), chain key C(i,j), and message key |
| 31 | * M(i,j)). They are all only used to stuff into HMACs, so could be any length |
| 32 | * for that. The chain key and message key are both derived from SHA256 |
| 33 | * operations, so their length is determined by that. */ |
| 34 | const std::size_t OLM_SHARED_KEY_LENGTH = SHA256_OUTPUT_LENGTH; |
| 35 | |
| 36 | typedef std::uint8_t SharedKey[OLM_SHARED_KEY_LENGTH]; |
| 37 | |
| 38 | struct ChainKey { |
| 39 | std::uint32_t index; |
| 40 | SharedKey key; |
| 41 | }; |
| 42 | |
| 43 | struct MessageKey { |
| 44 | std::uint32_t index; |
| 45 | SharedKey key; |
| 46 | }; |
| 47 | |
| 48 | |
| 49 | struct SenderChain { |
| 50 | _olm_curve25519_key_pair ratchet_key; |
| 51 | ChainKey chain_key; |
| 52 | }; |
| 53 | |
| 54 | |
| 55 | struct ReceiverChain { |
| 56 | _olm_curve25519_public_key ratchet_key; |
| 57 | ChainKey chain_key; |
| 58 | }; |
| 59 | |
| 60 | |
| 61 | struct SkippedMessageKey { |
| 62 | _olm_curve25519_public_key ratchet_key; |
| 63 | MessageKey message_key; |
| 64 | }; |
| 65 | |
| 66 | |
| 67 | static std::size_t const MAX_RECEIVER_CHAINS = 5; |
| 68 | static std::size_t const MAX_SKIPPED_MESSAGE_KEYS = 40; |
| 69 | |
| 70 | |
| 71 | struct KdfInfo { |
| 72 | std::uint8_t const * root_info; |
| 73 | std::size_t root_info_length; |
| 74 | std::uint8_t const * ratchet_info; |
| 75 | std::size_t ratchet_info_length; |
| 76 | }; |
| 77 | |
| 78 | |
| 79 | struct OLM_EXPORT Ratchet { |
| 80 | |
| 81 | Ratchet( |
| 82 | KdfInfo const & kdf_info, |
| 83 | _olm_cipher const *ratchet_cipher |
| 84 | ); |
| 85 | |
| 86 | /** A some strings identifying the application to feed into the KDF. */ |
| 87 | KdfInfo const & kdf_info; |
| 88 | |
| 89 | /** The AEAD cipher to use for encrypting messages. */ |
| 90 | _olm_cipher const *ratchet_cipher; |
| 91 | |
| 92 | /** The last error that happened encrypting or decrypting a message. */ |
| 93 | OlmErrorCode last_error; |
| 94 | |
| 95 | /** The root key is used to generate chain keys from the ephemeral keys. |
| 96 | * A new root_key derived each time a new chain is started. */ |
| 97 | SharedKey root_key; |
| 98 | |
| 99 | /** The sender chain is used to send messages. Each time a new ephemeral |
| 100 | * key is received from the remote server we generate a new sender chain |
| 101 | * with a new ephemeral key when we next send a message. */ |
| 102 | List<SenderChain, 1> sender_chain; |
| 103 | |
| 104 | /** The receiver chain is used to decrypt received messages. We store the |
| 105 | * last few chains so we can decrypt any out of order messages we haven't |
| 106 | * received yet. */ |
| 107 | List<ReceiverChain, MAX_RECEIVER_CHAINS> receiver_chains; |
| 108 | |
| 109 | /** List of message keys we've skipped over when advancing the receiver |
| 110 | * chain. */ |
| 111 | List<SkippedMessageKey, MAX_SKIPPED_MESSAGE_KEYS> skipped_message_keys; |
| 112 | |
| 113 | /** Initialise the session using a shared secret and the public part of the |
| 114 | * remote's first ratchet key */ |
| 115 | void initialise_as_bob( |
| 116 | std::uint8_t const * shared_secret, std::size_t shared_secret_length, |
| 117 | _olm_curve25519_public_key const & their_ratchet_key |
| 118 | ); |
| 119 | |
| 120 | /** Initialise the session using a shared secret and the public/private key |
| 121 | * pair for the first ratchet key */ |
| 122 | void initialise_as_alice( |
| 123 | std::uint8_t const * shared_secret, std::size_t shared_secret_length, |
| 124 | _olm_curve25519_key_pair const & our_ratchet_key |
| 125 | ); |
| 126 | |
| 127 | /** The number of bytes of output the encrypt method will write for |
| 128 | * a given message length. */ |
| 129 | std::size_t encrypt_output_length( |
| 130 | std::size_t plaintext_length |
| 131 | ) const; |
| 132 | |
| 133 | /** The number of bytes of random data the encrypt method will need to |
| 134 | * encrypt a message. This will be 32 bytes if the session needs to |
| 135 | * generate a new ephemeral key, or will be 0 bytes otherwise.*/ |
| 136 | std::size_t encrypt_random_length() const; |
| 137 | |
| 138 | /** Encrypt some plain-text. Returns the length of the encrypted message |
| 139 | * or std::size_t(-1) on failure. On failure last_error will be set with |
| 140 | * an error code. The last_error will be NOT_ENOUGH_RANDOM if the number |
| 141 | * of random bytes is too small. The last_error will be |
| 142 | * OUTPUT_BUFFER_TOO_SMALL if the output buffer is too small. */ |
| 143 | std::size_t encrypt( |
| 144 | std::uint8_t const * plaintext, std::size_t plaintext_length, |
| 145 | std::uint8_t const * random, std::size_t random_length, |
| 146 | std::uint8_t * output, std::size_t max_output_length |
| 147 | ); |
| 148 | |
| 149 | /** An upper bound on the number of bytes of plain-text the decrypt method |
| 150 | * will write for a given input message length. */ |
| 151 | std::size_t decrypt_max_plaintext_length( |
| 152 | std::uint8_t const * input, std::size_t input_length |
| 153 | ); |
| 154 | |
| 155 | /** Decrypt a message. Returns the length of the decrypted plain-text or |
| 156 | * std::size_t(-1) on failure. On failure last_error will be set with an |
| 157 | * error code. The last_error will be OUTPUT_BUFFER_TOO_SMALL if the |
| 158 | * plain-text buffer is too small. The last_error will be |
| 159 | * BAD_MESSAGE_VERSION if the message was encrypted with an unsupported |
| 160 | * version of the protocol. The last_error will be BAD_MESSAGE_FORMAT if |
| 161 | * the message headers could not be decoded. The last_error will be |
| 162 | * BAD_MESSAGE_MAC if the message could not be verified */ |
| 163 | std::size_t decrypt( |
| 164 | std::uint8_t const * input, std::size_t input_length, |
| 165 | std::uint8_t * plaintext, std::size_t max_plaintext_length |
| 166 | ); |
| 167 | }; |
| 168 | |
| 169 | |
| 170 | std::size_t pickle_length( |
| 171 | Ratchet const & value |
| 172 | ); |
| 173 | |
| 174 | |
| 175 | std::uint8_t * pickle( |
| 176 | std::uint8_t * pos, |
| 177 | Ratchet const & value |
| 178 | ); |
| 179 | |
| 180 | |
| 181 | std::uint8_t const * unpickle( |
| 182 | std::uint8_t const * pos, std::uint8_t const * end, |
| 183 | Ratchet & value, |
| 184 | bool includes_chain_index |
| 185 | ); |
| 186 | |
| 187 | |
| 188 | } // namespace olm |
| 189 | |