]> gitweb.ps.run Git - matrix_esp_thesis/blob - ext/olm/src/pk.cpp
add dependencies to repo
[matrix_esp_thesis] / ext / olm / src / pk.cpp
1 /* Copyright 2018, 2019 New Vector 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 #include "olm/pk.h"
16 #include "olm/cipher.h"
17 #include "olm/crypto.h"
18 #include "olm/ratchet.hh"
19 #include "olm/error.h"
20 #include "olm/memory.hh"
21 #include "olm/base64.hh"
22 #include "olm/pickle_encoding.h"
23 #include "olm/pickle.hh"
24
25 static const std::size_t MAC_LENGTH = 8;
26
27 const struct _olm_cipher_aes_sha_256 olm_pk_cipher_aes_sha256 =
28     OLM_CIPHER_INIT_AES_SHA_256("");
29 const struct _olm_cipher *olm_pk_cipher =
30     OLM_CIPHER_BASE(&olm_pk_cipher_aes_sha256);
31
32 extern "C" {
33
34 struct OlmPkEncryption {
35     OlmErrorCode last_error;
36     _olm_curve25519_public_key recipient_key;
37 };
38
39 const char * olm_pk_encryption_last_error(
40     const OlmPkEncryption * encryption
41 ) {
42     auto error = encryption->last_error;
43     return _olm_error_to_string(error);
44 }
45
46 OlmErrorCode olm_pk_encryption_last_error_code(
47     const OlmPkEncryption * encryption
48 ) {
49     return encryption->last_error;
50 }
51
52 size_t olm_pk_encryption_size(void) {
53     return sizeof(OlmPkEncryption);
54 }
55
56 OlmPkEncryption *olm_pk_encryption(
57     void * memory
58 ) {
59     olm::unset(memory, sizeof(OlmPkEncryption));
60     return new(memory) OlmPkEncryption;
61 }
62
63 size_t olm_clear_pk_encryption(
64     OlmPkEncryption *encryption
65 ) {
66     /* Clear the memory backing the encryption */
67     olm::unset(encryption, sizeof(OlmPkEncryption));
68     /* Initialise a fresh encryption object in case someone tries to use it */
69     new(encryption) OlmPkEncryption();
70     return sizeof(OlmPkEncryption);
71 }
72
73 size_t olm_pk_encryption_set_recipient_key (
74     OlmPkEncryption *encryption,
75     void const * key, size_t key_length
76 ) {
77     if (key_length < olm_pk_key_length()) {
78         encryption->last_error =
79             OlmErrorCode::OLM_INPUT_BUFFER_TOO_SMALL;
80         return std::size_t(-1);
81     }
82
83     olm::decode_base64(
84         (const uint8_t*)key,
85         olm_pk_key_length(),
86         (uint8_t *)encryption->recipient_key.public_key
87     );
88
89     return 0;
90 }
91
92 size_t olm_pk_ciphertext_length(
93     const OlmPkEncryption *encryption,
94     size_t plaintext_length
95 ) {
96     return olm::encode_base64_length(
97         _olm_cipher_aes_sha_256_ops.encrypt_ciphertext_length(olm_pk_cipher, plaintext_length)
98     );
99 }
100
101 size_t olm_pk_mac_length(
102     const OlmPkEncryption *encryption
103 ) {
104     return olm::encode_base64_length(_olm_cipher_aes_sha_256_ops.mac_length(olm_pk_cipher));
105 }
106
107 size_t olm_pk_encrypt_random_length(
108     const OlmPkEncryption *encryption
109 ) {
110     return CURVE25519_KEY_LENGTH;
111 }
112
113 size_t olm_pk_encrypt(
114     OlmPkEncryption *encryption,
115     void const * plaintext, size_t plaintext_length,
116     void * ciphertext, size_t ciphertext_length,
117     void * mac, size_t mac_length,
118     void * ephemeral_key, size_t ephemeral_key_size,
119     const void * random, size_t random_length
120 ) {
121     if (ciphertext_length
122             < olm_pk_ciphertext_length(encryption, plaintext_length)
123         || mac_length
124             < _olm_cipher_aes_sha_256_ops.mac_length(olm_pk_cipher)
125         || ephemeral_key_size
126             < olm_pk_key_length()) {
127         encryption->last_error =
128             OlmErrorCode::OLM_OUTPUT_BUFFER_TOO_SMALL;
129         return std::size_t(-1);
130     }
131     if (random_length < olm_pk_encrypt_random_length(encryption)) {
132         encryption->last_error =
133             OlmErrorCode::OLM_NOT_ENOUGH_RANDOM;
134         return std::size_t(-1);
135     }
136
137     _olm_curve25519_key_pair ephemeral_keypair;
138     _olm_crypto_curve25519_generate_key((const uint8_t *) random, &ephemeral_keypair);
139     olm::encode_base64(
140         (const uint8_t *)ephemeral_keypair.public_key.public_key,
141         CURVE25519_KEY_LENGTH,
142         (uint8_t *)ephemeral_key
143     );
144
145     olm::SharedKey secret;
146     _olm_crypto_curve25519_shared_secret(&ephemeral_keypair, &encryption->recipient_key, secret);
147     size_t raw_ciphertext_length =
148         _olm_cipher_aes_sha_256_ops.encrypt_ciphertext_length(olm_pk_cipher, plaintext_length);
149     uint8_t *ciphertext_pos = (uint8_t *) ciphertext + ciphertext_length - raw_ciphertext_length;
150     uint8_t raw_mac[MAC_LENGTH];
151     size_t result = _olm_cipher_aes_sha_256_ops.encrypt(
152         olm_pk_cipher,
153         secret, sizeof(secret),
154         (const uint8_t *) plaintext, plaintext_length,
155         (uint8_t *) ciphertext_pos, raw_ciphertext_length,
156         (uint8_t *) raw_mac, MAC_LENGTH
157     );
158     if (result != std::size_t(-1)) {
159         olm::encode_base64(raw_mac, MAC_LENGTH, (uint8_t *)mac);
160         olm::encode_base64(ciphertext_pos, raw_ciphertext_length, (uint8_t *)ciphertext);
161     }
162     return result;
163 }
164
165 struct OlmPkDecryption {
166     OlmErrorCode last_error;
167     _olm_curve25519_key_pair key_pair;
168 };
169
170 const char * olm_pk_decryption_last_error(
171     const OlmPkDecryption * decryption
172 ) {
173     auto error = decryption->last_error;
174     return _olm_error_to_string(error);
175 }
176
177 OlmErrorCode olm_pk_decryption_last_error_code(
178     const OlmPkDecryption * decryption
179 ) {
180     return decryption->last_error;
181 }
182
183 size_t olm_pk_decryption_size(void) {
184     return sizeof(OlmPkDecryption);
185 }
186
187 OlmPkDecryption *olm_pk_decryption(
188     void * memory
189 ) {
190     olm::unset(memory, sizeof(OlmPkDecryption));
191     return new(memory) OlmPkDecryption;
192 }
193
194 size_t olm_clear_pk_decryption(
195     OlmPkDecryption *decryption
196 ) {
197     /* Clear the memory backing the decryption */
198     olm::unset(decryption, sizeof(OlmPkDecryption));
199     /* Initialise a fresh decryption object in case someone tries to use it */
200     new(decryption) OlmPkDecryption();
201     return sizeof(OlmPkDecryption);
202 }
203
204 size_t olm_pk_private_key_length(void) {
205     return CURVE25519_KEY_LENGTH;
206 }
207
208 size_t olm_pk_generate_key_random_length(void) {
209     return olm_pk_private_key_length();
210 }
211
212 size_t olm_pk_key_length(void) {
213     return olm::encode_base64_length(CURVE25519_KEY_LENGTH);
214 }
215
216 size_t olm_pk_key_from_private(
217     OlmPkDecryption * decryption,
218     void * pubkey, size_t pubkey_length,
219     const void * privkey, size_t privkey_length
220 ) {
221     if (pubkey_length < olm_pk_key_length()) {
222         decryption->last_error =
223             OlmErrorCode::OLM_OUTPUT_BUFFER_TOO_SMALL;
224         return std::size_t(-1);
225     }
226     if (privkey_length < olm_pk_private_key_length()) {
227         decryption->last_error =
228             OlmErrorCode::OLM_INPUT_BUFFER_TOO_SMALL;
229         return std::size_t(-1);
230     }
231
232     _olm_crypto_curve25519_generate_key((const uint8_t *) privkey, &decryption->key_pair);
233     olm::encode_base64(
234         (const uint8_t *)decryption->key_pair.public_key.public_key,
235         CURVE25519_KEY_LENGTH,
236         (uint8_t *)pubkey
237     );
238     return 0;
239 }
240
241 size_t olm_pk_generate_key(
242     OlmPkDecryption * decryption,
243     void * pubkey, size_t pubkey_length,
244     const void * privkey, size_t privkey_length
245 ) {
246     return olm_pk_key_from_private(decryption, pubkey, pubkey_length, privkey, privkey_length);
247 }
248
249 namespace {
250     static const std::uint32_t PK_DECRYPTION_PICKLE_VERSION = 1;
251
252     static std::size_t pickle_length(
253         OlmPkDecryption const & value
254     ) {
255         std::size_t length = 0;
256         length += olm::pickle_length(PK_DECRYPTION_PICKLE_VERSION);
257         length += olm::pickle_length(value.key_pair);
258         return length;
259     }
260
261
262     static std::uint8_t * pickle(
263         std::uint8_t * pos,
264         OlmPkDecryption const & value
265     ) {
266         pos = olm::pickle(pos, PK_DECRYPTION_PICKLE_VERSION);
267         pos = olm::pickle(pos, value.key_pair);
268         return pos;
269     }
270
271
272     static std::uint8_t const * unpickle(
273         std::uint8_t const * pos, std::uint8_t const * end,
274         OlmPkDecryption & value
275     ) {
276         uint32_t pickle_version;
277         pos = olm::unpickle(pos, end, pickle_version); UNPICKLE_OK(pos);
278
279         switch (pickle_version) {
280         case 1:
281             break;
282
283         default:
284             value.last_error = OlmErrorCode::OLM_UNKNOWN_PICKLE_VERSION;
285             return nullptr;
286         }
287
288         pos = olm::unpickle(pos, end, value.key_pair); UNPICKLE_OK(pos);
289
290         return pos;
291     }
292 }
293
294 size_t olm_pickle_pk_decryption_length(
295     const OlmPkDecryption * decryption
296 ) {
297     return _olm_enc_output_length(pickle_length(*decryption));
298 }
299
300 size_t olm_pickle_pk_decryption(
301     OlmPkDecryption * decryption,
302     void const * key, size_t key_length,
303     void *pickled, size_t pickled_length
304 ) {
305     OlmPkDecryption & object = *decryption;
306     std::size_t raw_length = pickle_length(object);
307     if (pickled_length < _olm_enc_output_length(raw_length)) {
308         object.last_error = OlmErrorCode::OLM_OUTPUT_BUFFER_TOO_SMALL;
309         return std::size_t(-1);
310     }
311     pickle(_olm_enc_output_pos(reinterpret_cast<std::uint8_t *>(pickled), raw_length), object);
312     return _olm_enc_output(
313         reinterpret_cast<std::uint8_t const *>(key), key_length,
314         reinterpret_cast<std::uint8_t *>(pickled), raw_length
315     );
316 }
317
318 size_t olm_unpickle_pk_decryption(
319     OlmPkDecryption * decryption,
320     void const * key, size_t key_length,
321     void *pickled, size_t pickled_length,
322     void *pubkey, size_t pubkey_length
323 ) {
324     OlmPkDecryption & object = *decryption;
325     if (pubkey != NULL && pubkey_length < olm_pk_key_length()) {
326         object.last_error = OlmErrorCode::OLM_OUTPUT_BUFFER_TOO_SMALL;
327         return std::size_t(-1);
328     }
329     std::uint8_t * const input = reinterpret_cast<std::uint8_t *>(pickled);
330     std::size_t raw_length = _olm_enc_input(
331         reinterpret_cast<std::uint8_t const *>(key), key_length,
332         input, pickled_length, &object.last_error
333     );
334     if (raw_length == std::size_t(-1)) {
335         return std::size_t(-1);
336     }
337
338     std::uint8_t const * pos = input;
339     std::uint8_t const * end = pos + raw_length;
340
341     pos = unpickle(pos, end, object);
342
343     if (!pos) {
344         /* Input was corrupted. */
345         if (object.last_error == OlmErrorCode::OLM_SUCCESS) {
346             object.last_error = OlmErrorCode::OLM_CORRUPTED_PICKLE;
347         }
348         return std::size_t(-1);
349     } else if (pos != end) {
350         /* Input was longer than expected. */
351         object.last_error = OlmErrorCode::OLM_PICKLE_EXTRA_DATA;
352         return std::size_t(-1);
353     }
354
355     if (pubkey != NULL) {
356         olm::encode_base64(
357             (const uint8_t *)object.key_pair.public_key.public_key,
358             CURVE25519_KEY_LENGTH,
359             (uint8_t *)pubkey
360         );
361     }
362
363     return pickled_length;
364 }
365
366 size_t olm_pk_max_plaintext_length(
367     const OlmPkDecryption * decryption,
368     size_t ciphertext_length
369 ) {
370     return _olm_cipher_aes_sha_256_ops.decrypt_max_plaintext_length(
371         olm_pk_cipher, olm::decode_base64_length(ciphertext_length)
372     );
373 }
374
375 size_t olm_pk_decrypt(
376     OlmPkDecryption * decryption,
377     void const * ephemeral_key, size_t ephemeral_key_length,
378     void const * mac, size_t mac_length,
379     void * ciphertext, size_t ciphertext_length,
380     void * plaintext, size_t max_plaintext_length
381 ) {
382     if (max_plaintext_length
383             < olm_pk_max_plaintext_length(decryption, ciphertext_length)) {
384         decryption->last_error =
385             OlmErrorCode::OLM_OUTPUT_BUFFER_TOO_SMALL;
386         return std::size_t(-1);
387     }
388
389     size_t raw_ciphertext_length = olm::decode_base64_length(ciphertext_length);
390
391     if (ephemeral_key_length != olm::encode_base64_length(CURVE25519_KEY_LENGTH)
392         || mac_length != olm::encode_base64_length(MAC_LENGTH)
393         || raw_ciphertext_length == std::size_t(-1)) {
394         decryption->last_error = OlmErrorCode::OLM_INVALID_BASE64;
395         return std::size_t(-1);
396     }
397
398     struct _olm_curve25519_public_key ephemeral;
399     olm::decode_base64(
400         (const uint8_t*)ephemeral_key,
401         olm::encode_base64_length(CURVE25519_KEY_LENGTH),
402         (uint8_t *)ephemeral.public_key
403     );
404
405     olm::SharedKey secret;
406     _olm_crypto_curve25519_shared_secret(&decryption->key_pair, &ephemeral, secret);
407
408     uint8_t raw_mac[MAC_LENGTH];
409     olm::decode_base64(
410         (const uint8_t *)mac,
411         olm::encode_base64_length(MAC_LENGTH),
412         raw_mac
413     );
414
415     olm::decode_base64(
416         (const uint8_t *)ciphertext,
417         ciphertext_length,
418         (uint8_t *)ciphertext
419     );
420
421     size_t result = _olm_cipher_aes_sha_256_ops.decrypt(
422         olm_pk_cipher,
423         secret, sizeof(secret),
424         (uint8_t *) raw_mac, MAC_LENGTH,
425         (const uint8_t *) ciphertext, raw_ciphertext_length,
426         (uint8_t *) plaintext, max_plaintext_length
427     );
428     if (result == std::size_t(-1)) {
429         // we already checked the buffer sizes, so the only error that decrypt
430         // will return is if the MAC is incorrect
431         decryption->last_error =
432             OlmErrorCode::OLM_BAD_MESSAGE_MAC;
433         return std::size_t(-1);
434     } else {
435         return result;
436     }
437 }
438
439 size_t olm_pk_get_private_key(
440     OlmPkDecryption * decryption,
441     void *private_key, size_t private_key_length
442 ) {
443     if (private_key_length < olm_pk_private_key_length()) {
444         decryption->last_error =
445             OlmErrorCode::OLM_OUTPUT_BUFFER_TOO_SMALL;
446         return std::size_t(-1);
447     }
448     std::memcpy(
449         private_key,
450         decryption->key_pair.private_key.private_key,
451         olm_pk_private_key_length()
452     );
453     return olm_pk_private_key_length();
454 }
455
456 struct OlmPkSigning {
457     OlmErrorCode last_error;
458     _olm_ed25519_key_pair key_pair;
459 };
460
461 size_t olm_pk_signing_size(void) {
462     return sizeof(OlmPkSigning);
463 }
464
465 OlmPkSigning *olm_pk_signing(void * memory) {
466     olm::unset(memory, sizeof(OlmPkSigning));
467     return new(memory) OlmPkSigning;
468 }
469
470 const char * olm_pk_signing_last_error(const OlmPkSigning * sign) {
471     auto error = sign->last_error;
472     return _olm_error_to_string(error);
473 }
474
475 OlmErrorCode olm_pk_signing_last_error_code(const OlmPkSigning * sign) {
476     return sign->last_error;
477 }
478
479 size_t olm_clear_pk_signing(OlmPkSigning *sign) {
480     /* Clear the memory backing the signing */
481     olm::unset(sign, sizeof(OlmPkSigning));
482     /* Initialise a fresh signing object in case someone tries to use it */
483     new(sign) OlmPkSigning();
484     return sizeof(OlmPkSigning);
485 }
486
487 size_t olm_pk_signing_seed_length(void) {
488     return ED25519_RANDOM_LENGTH;
489 }
490
491 size_t olm_pk_signing_public_key_length(void) {
492     return olm::encode_base64_length(ED25519_PUBLIC_KEY_LENGTH);
493 }
494
495 size_t olm_pk_signing_key_from_seed(
496     OlmPkSigning * signing,
497     void * pubkey, size_t pubkey_length,
498     const void * seed, size_t seed_length
499 ) {
500     if (pubkey_length < olm_pk_signing_public_key_length()) {
501         signing->last_error =
502             OlmErrorCode::OLM_OUTPUT_BUFFER_TOO_SMALL;
503         return std::size_t(-1);
504     }
505     if (seed_length < olm_pk_signing_seed_length()) {
506         signing->last_error =
507             OlmErrorCode::OLM_INPUT_BUFFER_TOO_SMALL;
508         return std::size_t(-1);
509     }
510
511     _olm_crypto_ed25519_generate_key((const uint8_t *) seed, &signing->key_pair);
512     olm::encode_base64(
513         (const uint8_t *)signing->key_pair.public_key.public_key,
514         ED25519_PUBLIC_KEY_LENGTH,
515         (uint8_t *)pubkey
516     );
517     return 0;
518 }
519
520 size_t olm_pk_signature_length(void) {
521     return olm::encode_base64_length(ED25519_SIGNATURE_LENGTH);
522 }
523
524 size_t olm_pk_sign(
525     OlmPkSigning *signing,
526     uint8_t const * message, size_t message_length,
527     uint8_t * signature, size_t signature_length
528 ) {
529     if (signature_length < olm_pk_signature_length()) {
530         signing->last_error = OlmErrorCode::OLM_OUTPUT_BUFFER_TOO_SMALL;
531         return std::size_t(-1);
532     }
533     uint8_t *raw_sig = signature + olm_pk_signature_length() - ED25519_SIGNATURE_LENGTH;
534     _olm_crypto_ed25519_sign(
535         &signing->key_pair,
536         message, message_length, raw_sig
537     );
538     olm::encode_base64(raw_sig, ED25519_SIGNATURE_LENGTH, signature);
539     return olm_pk_signature_length();
540 }
541
542 }