olm.cpp 21.8 KB
Newer Older
Mark Haines's avatar
Mark Haines committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
/* Copyright 2015 OpenMarket Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
Richard van der Hoff's avatar
Richard van der Hoff committed
15
#include "olm/olm.h"
16
17
#include "olm/session.hh"
#include "olm/account.hh"
18
#include "olm/cipher.h"
19
#include "olm/pickle_encoding.h"
20
#include "olm/utility.hh"
21
#include "olm/base64.hh"
22
#include "olm/memory.hh"
23
24
25
26
27
28

#include <new>
#include <cstring>

namespace {

29
30
static OlmAccount * to_c(olm::Account * account) {
    return reinterpret_cast<OlmAccount *>(account);
31
32
}

33
34
35
36
37
38
static OlmSession * to_c(olm::Session * session) {
    return reinterpret_cast<OlmSession *>(session);
}

static OlmUtility * to_c(olm::Utility * utility) {
    return reinterpret_cast<OlmUtility *>(utility);
39
40
}

41
42
static olm::Account * from_c(OlmAccount * account) {
    return reinterpret_cast<olm::Account *>(account);
43
44
}

Hubert Chathi's avatar
Hubert Chathi committed
45
46
static const olm::Account * from_c(OlmAccount const * account) {
    return reinterpret_cast<olm::Account const *>(account);
47
48
}

49
50
51
52
static olm::Session * from_c(OlmSession * session) {
    return reinterpret_cast<olm::Session *>(session);
}

Hubert Chathi's avatar
Hubert Chathi committed
53
static const olm::Session * from_c(OlmSession const * session) {
54
55
56
    return reinterpret_cast<const olm::Session *>(session);
}

57
58
static olm::Utility * from_c(OlmUtility * utility) {
    return reinterpret_cast<olm::Utility *>(utility);
59
60
}

Hubert Chathi's avatar
Hubert Chathi committed
61
static const olm::Utility * from_c(OlmUtility const * utility) {
62
63
64
    return reinterpret_cast<const olm::Utility *>(utility);
}

65
66
67
68
69
70
71
72
73
74
75
static std::uint8_t * from_c(void * bytes) {
    return reinterpret_cast<std::uint8_t *>(bytes);
}

static std::uint8_t const * from_c(void const * bytes) {
    return reinterpret_cast<std::uint8_t const *>(bytes);
}

std::size_t b64_output_length(
    size_t raw_length
) {
76
    return olm::encode_base64_length(raw_length);
77
78
79
80
81
82
}

std::uint8_t * b64_output_pos(
    std::uint8_t * output,
    size_t raw_length
) {
83
    return output + olm::encode_base64_length(raw_length) - raw_length;
84
85
86
87
88
}

std::size_t b64_output(
    std::uint8_t * output, size_t raw_length
) {
89
    std::size_t base64_length = olm::encode_base64_length(raw_length);
90
    std::uint8_t * raw_output = output + base64_length - raw_length;
91
    olm::encode_base64(raw_output, raw_length, output);
92
93
94
95
96
    return base64_length;
}

std::size_t b64_input(
    std::uint8_t * input, size_t b64_length,
97
    OlmErrorCode & last_error
98
) {
99
    std::size_t raw_length = olm::decode_base64_length(b64_length);
100
    if (raw_length == std::size_t(-1)) {
101
        last_error = OlmErrorCode::OLM_INVALID_BASE64;
102
103
        return std::size_t(-1);
    }
104
    olm::decode_base64(input, b64_length, input);
105
106
107
108
109
110
111
112
    return raw_length;
}

} // namespace


extern "C" {

113
114
115
116
117
void olm_get_library_version(uint8_t *major, uint8_t *minor, uint8_t *patch) {
    if (major != NULL) *major = OLMLIB_VERSION_MAJOR;
    if (minor != NULL) *minor = OLMLIB_VERSION_MINOR;
    if (patch != NULL) *patch = OLMLIB_VERSION_PATCH;
}
118

manuroe's avatar
manuroe committed
119
size_t olm_error(void) {
120
121
122
123
    return std::size_t(-1);
}


124
const char * olm_account_last_error(
125
    const OlmAccount * account
126
) {
127
128
    auto error = from_c(account)->last_error;
    return _olm_error_to_string(error);
129
130
}

131
132
133
134
135
enum OlmErrorCode olm_account_last_error_code(
    const OlmAccount * account
) {
    return from_c(account)->last_error;
}
136

137
const char * olm_session_last_error(
138
    const OlmSession * session
139
) {
140
141
    auto error = from_c(session)->last_error;
    return _olm_error_to_string(error);
142
143
}

144
enum OlmErrorCode olm_session_last_error_code(
Hubert Chathi's avatar
Hubert Chathi committed
145
    OlmSession const * session
146
147
148
149
) {
    return from_c(session)->last_error;
}

150
const char * olm_utility_last_error(
Hubert Chathi's avatar
Hubert Chathi committed
151
    OlmUtility const * utility
152
) {
153
154
    auto error = from_c(utility)->last_error;
    return _olm_error_to_string(error);
155
}
156

157
enum OlmErrorCode olm_utility_last_error_code(
Hubert Chathi's avatar
Hubert Chathi committed
158
    OlmUtility const * utility
159
160
161
162
) {
    return from_c(utility)->last_error;
}

manuroe's avatar
manuroe committed
163
size_t olm_account_size(void) {
164
    return sizeof(olm::Account);
165
166
167
}


manuroe's avatar
manuroe committed
168
size_t olm_session_size(void) {
169
    return sizeof(olm::Session);
170
171
}

manuroe's avatar
manuroe committed
172
size_t olm_utility_size(void) {
173
174
    return sizeof(olm::Utility);
}
175

176
OlmAccount * olm_account(
177
178
    void * memory
) {
179
    olm::unset(memory, sizeof(olm::Account));
180
    return to_c(new(memory) olm::Account());
181
182
183
}


184
OlmSession * olm_session(
185
186
    void * memory
) {
187
    olm::unset(memory, sizeof(olm::Session));
188
    return to_c(new(memory) olm::Session());
189
190
191
}


192
193
194
195
196
197
198
199
OlmUtility * olm_utility(
    void * memory
) {
    olm::unset(memory, sizeof(olm::Utility));
    return to_c(new(memory) olm::Utility());
}


200
size_t olm_clear_account(
201
    OlmAccount * account
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
) {
    /* Clear the memory backing the account  */
    olm::unset(account, sizeof(olm::Account));
    /* Initialise a fresh account object in case someone tries to use it */
    new(account) olm::Account();
    return sizeof(olm::Account);
}


size_t olm_clear_session(
    OlmSession * session
) {
    /* Clear the memory backing the session */
    olm::unset(session, sizeof(olm::Session));
    /* Initialise a fresh session object in case someone tries to use it */
    new(session) olm::Session();
    return sizeof(olm::Session);
}


222
223
224
225
226
227
228
229
230
231
232
size_t olm_clear_utility(
    OlmUtility * utility
) {
    /* Clear the memory backing the session */
    olm::unset(utility, sizeof(olm::Utility));
    /* Initialise a fresh session object in case someone tries to use it */
    new(utility) olm::Utility();
    return sizeof(olm::Utility);
}


233
size_t olm_pickle_account_length(
Hubert Chathi's avatar
Hubert Chathi committed
234
    OlmAccount const * account
235
) {
236
    return _olm_enc_output_length(pickle_length(*from_c(account)));
237
238
239
}


240
size_t olm_pickle_session_length(
Hubert Chathi's avatar
Hubert Chathi committed
241
    OlmSession const * session
242
) {
243
    return _olm_enc_output_length(pickle_length(*from_c(session)));
244
245
246
}


247
248
size_t olm_pickle_account(
    OlmAccount * account,
249
250
251
    void const * key, size_t key_length,
    void * pickled, size_t pickled_length
) {
252
    olm::Account & object = *from_c(account);
253
    std::size_t raw_length = pickle_length(object);
254
    if (pickled_length < _olm_enc_output_length(raw_length)) {
255
        object.last_error = OlmErrorCode::OLM_OUTPUT_BUFFER_TOO_SMALL;
256
257
        return size_t(-1);
    }
258
259
    pickle(_olm_enc_output_pos(from_c(pickled), raw_length), object);
    return _olm_enc_output(from_c(key), key_length, from_c(pickled), raw_length);
260
261
262
}


263
264
size_t olm_pickle_session(
    OlmSession * session,
265
266
267
    void const * key, size_t key_length,
    void * pickled, size_t pickled_length
) {
268
    olm::Session & object = *from_c(session);
269
    std::size_t raw_length = pickle_length(object);
270
    if (pickled_length < _olm_enc_output_length(raw_length)) {
271
        object.last_error = OlmErrorCode::OLM_OUTPUT_BUFFER_TOO_SMALL;
272
273
        return size_t(-1);
    }
274
275
    pickle(_olm_enc_output_pos(from_c(pickled), raw_length), object);
    return _olm_enc_output(from_c(key), key_length, from_c(pickled), raw_length);
276
277
278
}


279
280
size_t olm_unpickle_account(
    OlmAccount * account,
281
282
283
    void const * key, size_t key_length,
    void * pickled, size_t pickled_length
) {
284
    olm::Account & object = *from_c(account);
285
    std::uint8_t * input = from_c(pickled);
286
    std::size_t raw_length = _olm_enc_input(
287
        from_c(key), key_length, input, pickled_length, &object.last_error
288
289
290
291
    );
    if (raw_length == std::size_t(-1)) {
        return std::size_t(-1);
    }
292
293
294
295
296
297
298
299

    std::uint8_t const * pos = input;
    std::uint8_t const * end = pos + raw_length;

    pos = unpickle(pos, end, object);

    if (!pos) {
        /* Input was corrupted. */
300
301
        if (object.last_error == OlmErrorCode::OLM_SUCCESS) {
            object.last_error = OlmErrorCode::OLM_CORRUPTED_PICKLE;
302
303
        }
        return std::size_t(-1);
304
305
    } else if (pos != end) {
        /* Input was longer than expected. */
306
        object.last_error = OlmErrorCode::OLM_PICKLE_EXTRA_DATA;
307
        return std::size_t(-1);
308
    }
309

310
311
312
313
    return pickled_length;
}


314
315
size_t olm_unpickle_session(
    OlmSession * session,
316
317
318
    void const * key, size_t key_length,
    void * pickled, size_t pickled_length
) {
319
    olm::Session & object = *from_c(session);
320
    std::uint8_t * input = from_c(pickled);
321
    std::size_t raw_length = _olm_enc_input(
322
        from_c(key), key_length, input, pickled_length, &object.last_error
323
324
325
326
    );
    if (raw_length == std::size_t(-1)) {
        return std::size_t(-1);
    }
327

328
329
330
331
332
333
334
    std::uint8_t const * pos = input;
    std::uint8_t const * end = pos + raw_length;

    pos = unpickle(pos, end, object);

    if (!pos) {
        /* Input was corrupted. */
335
336
        if (object.last_error == OlmErrorCode::OLM_SUCCESS) {
            object.last_error = OlmErrorCode::OLM_CORRUPTED_PICKLE;
337
338
        }
        return std::size_t(-1);
339
340
    } else if (pos != end) {
        /* Input was longer than expected. */
341
        object.last_error = OlmErrorCode::OLM_PICKLE_EXTRA_DATA;
342
        return std::size_t(-1);
343
    }
344

345
346
347
348
    return pickled_length;
}


349
size_t olm_create_account_random_length(
Hubert Chathi's avatar
Hubert Chathi committed
350
    OlmAccount const * account
351
352
353
354
355
) {
    return from_c(account)->new_account_random_length();
}


356
357
size_t olm_create_account(
    OlmAccount * account,
358
    void * random, size_t random_length
359
) {
360
361
362
    size_t result = from_c(account)->new_account(from_c(random), random_length);
    olm::unset(random, random_length);
    return result;
363
364
}

365

366
size_t olm_account_identity_keys_length(
Hubert Chathi's avatar
Hubert Chathi committed
367
    OlmAccount const * account
368
369
) {
    return from_c(account)->get_identity_json_length();
370
371
}

372

373
374
size_t olm_account_identity_keys(
    OlmAccount * account,
375
376
    void * identity_keys, size_t identity_key_length
) {
377
378
379
    return from_c(account)->get_identity_json(
        from_c(identity_keys), identity_key_length
    );
380
381
382
}


383
size_t olm_account_signature_length(
Hubert Chathi's avatar
Hubert Chathi committed
384
    OlmAccount const * account
385
386
387
388
389
390
391
392
393
394
395
396
397
) {
    return b64_output_length(from_c(account)->signature_length());
}


size_t olm_account_sign(
    OlmAccount * account,
    void const * message, size_t message_length,
    void * signature, size_t signature_length
) {
    std::size_t raw_length = from_c(account)->signature_length();
    if (signature_length < b64_output_length(raw_length)) {
        from_c(account)->last_error =
398
            OlmErrorCode::OLM_OUTPUT_BUFFER_TOO_SMALL;
399
400
401
402
403
404
405
406
407
408
        return std::size_t(-1);
    }
    from_c(account)->sign(
         from_c(message), message_length,
         b64_output_pos(from_c(signature), raw_length), raw_length
    );
    return b64_output(from_c(signature), raw_length);
}


409
size_t olm_account_one_time_keys_length(
Hubert Chathi's avatar
Hubert Chathi committed
410
    OlmAccount const * account
411
) {
412
    return from_c(account)->get_one_time_keys_json_length();
413
414
415
}


416
417
size_t olm_account_one_time_keys(
    OlmAccount * account,
418
    void * one_time_keys_json, size_t one_time_key_json_length
419
) {
420
421
422
    return from_c(account)->get_one_time_keys_json(
        from_c(one_time_keys_json), one_time_key_json_length
    );
423
424
425
}


426
427
428
429
430
431
432
433
size_t olm_account_mark_keys_as_published(
    OlmAccount * account
) {
    return from_c(account)->mark_keys_as_published();
}


size_t olm_account_max_number_of_one_time_keys(
Hubert Chathi's avatar
Hubert Chathi committed
434
    OlmAccount const * account
435
436
437
438
439
440
) {
    return from_c(account)->max_number_of_one_time_keys();
}


size_t olm_account_generate_one_time_keys_random_length(
Hubert Chathi's avatar
Hubert Chathi committed
441
    OlmAccount const * account,
442
443
444
445
446
447
448
449
450
    size_t number_of_keys
) {
    return from_c(account)->generate_one_time_keys_random_length(number_of_keys);
}


size_t olm_account_generate_one_time_keys(
    OlmAccount * account,
    size_t number_of_keys,
451
    void * random, size_t random_length
452
) {
453
    size_t result = from_c(account)->generate_one_time_keys(
454
455
456
        number_of_keys,
        from_c(random), random_length
    );
457
458
    olm::unset(random, random_length);
    return result;
459
460
461
}


Hubert Chathi's avatar
Hubert Chathi committed
462
size_t olm_account_generate_fallback_key_random_length(
Hubert Chathi's avatar
Hubert Chathi committed
463
    OlmAccount const * account
Hubert Chathi's avatar
Hubert Chathi committed
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
) {
    return from_c(account)->generate_fallback_key_random_length();
}


size_t olm_account_generate_fallback_key(
    OlmAccount * account,
    void * random, size_t random_length
) {
    size_t result = from_c(account)->generate_fallback_key(
        from_c(random), random_length
    );
    olm::unset(random, random_length);
    return result;
}


size_t olm_account_fallback_key_length(
Hubert Chathi's avatar
Hubert Chathi committed
482
    OlmAccount const * account
Hubert Chathi's avatar
Hubert Chathi committed
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
) {
    return from_c(account)->get_fallback_key_json_length();
}


size_t olm_account_fallback_key(
    OlmAccount * account,
    void * fallback_key_json, size_t fallback_key_json_length
) {
    return from_c(account)->get_fallback_key_json(
        from_c(fallback_key_json), fallback_key_json_length
    );
}


498
size_t olm_create_outbound_session_random_length(
Hubert Chathi's avatar
Hubert Chathi committed
499
    OlmSession const * session
Mark Haines's avatar
Mark Haines committed
500
501
502
503
) {
    return from_c(session)->new_outbound_session_random_length();
}

504

505
506
size_t olm_create_outbound_session(
    OlmSession * session,
507
    OlmAccount const * account,
508
509
    void const * their_identity_key, size_t their_identity_key_length,
    void const * their_one_time_key, size_t their_one_time_key_length,
510
    void * random, size_t random_length
511
) {
512
513
514
515
516
    std::uint8_t const * id_key = from_c(their_identity_key);
    std::uint8_t const * ot_key = from_c(their_one_time_key);
    std::size_t id_key_length = their_identity_key_length;
    std::size_t ot_key_length = their_one_time_key_length;

517
518
    if (olm::decode_base64_length(id_key_length) != CURVE25519_KEY_LENGTH
            || olm::decode_base64_length(ot_key_length) != CURVE25519_KEY_LENGTH
519
    ) {
520
        from_c(session)->last_error = OlmErrorCode::OLM_INVALID_BASE64;
521
522
        return std::size_t(-1);
    }
523
524
    _olm_curve25519_public_key identity_key;
    _olm_curve25519_public_key one_time_key;
525

526
527
    olm::decode_base64(id_key, id_key_length, identity_key.public_key);
    olm::decode_base64(ot_key, ot_key_length, one_time_key.public_key);
528

529
    size_t result = from_c(session)->new_outbound_session(
530
531
532
        *from_c(account), identity_key, one_time_key,
        from_c(random), random_length
    );
533
534
    olm::unset(random, random_length);
    return result;
535
536
537
}


538
539
540
size_t olm_create_inbound_session(
    OlmSession * session,
    OlmAccount * account,
541
542
543
544
545
546
547
548
549
    void * one_time_key_message, size_t message_length
) {
    std::size_t raw_length = b64_input(
        from_c(one_time_key_message), message_length, from_c(session)->last_error
    );
    if (raw_length == std::size_t(-1)) {
        return std::size_t(-1);
    }
    return from_c(session)->new_inbound_session(
550
551
552
553
554
555
556
557
558
559
560
        *from_c(account), nullptr, from_c(one_time_key_message), raw_length
    );
}


size_t olm_create_inbound_session_from(
    OlmSession * session,
    OlmAccount * account,
    void const * their_identity_key, size_t their_identity_key_length,
    void * one_time_key_message, size_t message_length
) {
561
562
563
    std::uint8_t const * id_key = from_c(their_identity_key);
    std::size_t id_key_length = their_identity_key_length;

564
    if (olm::decode_base64_length(id_key_length) != CURVE25519_KEY_LENGTH) {
565
        from_c(session)->last_error = OlmErrorCode::OLM_INVALID_BASE64;
566
567
        return std::size_t(-1);
    }
568
    _olm_curve25519_public_key identity_key;
569
    olm::decode_base64(id_key, id_key_length, identity_key.public_key);
570
571
572
573
574
575
576
577
578
579

    std::size_t raw_length = b64_input(
        from_c(one_time_key_message), message_length, from_c(session)->last_error
    );
    if (raw_length == std::size_t(-1)) {
        return std::size_t(-1);
    }
    return from_c(session)->new_inbound_session(
        *from_c(account), &identity_key,
        from_c(one_time_key_message), raw_length
580
581
582
583
    );
}


584
size_t olm_session_id_length(
Hubert Chathi's avatar
Hubert Chathi committed
585
    OlmSession const * session
586
587
588
589
590
591
592
593
594
595
596
) {
    return b64_output_length(from_c(session)->session_id_length());
}

size_t olm_session_id(
    OlmSession * session,
    void * id, size_t id_length
) {
    std::size_t raw_length = from_c(session)->session_id_length();
    if (id_length < b64_output_length(raw_length)) {
        from_c(session)->last_error =
597
                OlmErrorCode::OLM_OUTPUT_BUFFER_TOO_SMALL;
598
599
600
601
602
603
604
605
606
607
608
609
        return std::size_t(-1);
    }
    std::size_t result = from_c(session)->session_id(
       b64_output_pos(from_c(id), raw_length), raw_length
    );
    if (result == std::size_t(-1)) {
        return result;
    }
    return b64_output(from_c(id), raw_length);
}


610
int olm_session_has_received_message(
Hubert Chathi's avatar
Hubert Chathi committed
611
    OlmSession const * session
612
613
614
615
) {
    return from_c(session)->received_message;
}

616
617
void olm_session_describe(
    OlmSession * session, char *buf, size_t buflen
David Baker's avatar
David Baker committed
618
) {
619
    from_c(session)->describe(buf, buflen);
David Baker's avatar
David Baker committed
620
621
}

622
623
size_t olm_matches_inbound_session(
    OlmSession * session,
624
625
626
627
628
629
630
631
632
    void * one_time_key_message, size_t message_length
) {
    std::size_t raw_length = b64_input(
        from_c(one_time_key_message), message_length, from_c(session)->last_error
    );
    if (raw_length == std::size_t(-1)) {
        return std::size_t(-1);
    }
    bool matches = from_c(session)->matches_inbound_session(
633
634
635
636
637
638
639
640
641
642
643
        nullptr, from_c(one_time_key_message), raw_length
    );
    return matches ? 1 : 0;
}


size_t olm_matches_inbound_session_from(
    OlmSession * session,
    void const * their_identity_key, size_t their_identity_key_length,
    void * one_time_key_message, size_t message_length
) {
644
645
646
    std::uint8_t const * id_key = from_c(their_identity_key);
    std::size_t id_key_length = their_identity_key_length;

647
    if (olm::decode_base64_length(id_key_length) != CURVE25519_KEY_LENGTH) {
648
        from_c(session)->last_error = OlmErrorCode::OLM_INVALID_BASE64;
649
650
        return std::size_t(-1);
    }
651
    _olm_curve25519_public_key identity_key;
652
    olm::decode_base64(id_key, id_key_length, identity_key.public_key);
653
654
655
656
657
658
659
660
661

    std::size_t raw_length = b64_input(
        from_c(one_time_key_message), message_length, from_c(session)->last_error
    );
    if (raw_length == std::size_t(-1)) {
        return std::size_t(-1);
    }
    bool matches = from_c(session)->matches_inbound_session(
        &identity_key, from_c(one_time_key_message), raw_length
662
663
664
665
666
    );
    return matches ? 1 : 0;
}


667
668
669
size_t olm_remove_one_time_keys(
    OlmAccount * account,
    OlmSession * session
670
671
) {
    size_t result = from_c(account)->remove_key(
672
        from_c(session)->bob_one_time_key
673
674
    );
    if (result == std::size_t(-1)) {
675
        from_c(account)->last_error = OlmErrorCode::OLM_BAD_MESSAGE_KEY_ID;
676
677
678
679
680
    }
    return result;
}


681
size_t olm_encrypt_message_type(
Hubert Chathi's avatar
Hubert Chathi committed
682
    OlmSession const * session
683
684
685
686
687
) {
    return size_t(from_c(session)->encrypt_message_type());
}


688
size_t olm_encrypt_random_length(
Hubert Chathi's avatar
Hubert Chathi committed
689
    OlmSession const * session
690
691
692
693
694
) {
    return from_c(session)->encrypt_random_length();
}


695
size_t olm_encrypt_message_length(
Hubert Chathi's avatar
Hubert Chathi committed
696
    OlmSession const * session,
697
698
699
700
701
702
703
704
    size_t plaintext_length
) {
    return b64_output_length(
        from_c(session)->encrypt_message_length(plaintext_length)
    );
}


705
706
size_t olm_encrypt(
    OlmSession * session,
707
    void const * plaintext, size_t plaintext_length,
708
    void * random, size_t random_length,
709
710
711
712
713
    void * message, size_t message_length
) {
    std::size_t raw_length = from_c(session)->encrypt_message_length(
        plaintext_length
    );
714
    if (message_length < b64_output_length(raw_length)) {
715
        from_c(session)->last_error =
716
            OlmErrorCode::OLM_OUTPUT_BUFFER_TOO_SMALL;
717
718
        return std::size_t(-1);
    }
719
    std::size_t result = from_c(session)->encrypt(
720
721
722
723
        from_c(plaintext), plaintext_length,
        from_c(random), random_length,
        b64_output_pos(from_c(message), raw_length), raw_length
    );
724
    olm::unset(random, random_length);
725
726
727
    if (result == std::size_t(-1)) {
        return result;
    }
728
729
730
731
    return b64_output(from_c(message), raw_length);
}


732
733
size_t olm_decrypt_max_plaintext_length(
    OlmSession * session,
734
735
736
737
738
739
740
741
742
743
    size_t message_type,
    void * message, size_t message_length
) {
    std::size_t raw_length = b64_input(
        from_c(message), message_length, from_c(session)->last_error
    );
    if (raw_length == std::size_t(-1)) {
        return std::size_t(-1);
    }
    return from_c(session)->decrypt_max_plaintext_length(
744
        olm::MessageType(message_type), from_c(message), raw_length
745
746
747
748
    );
}


749
750
size_t olm_decrypt(
    OlmSession * session,
751
752
753
754
755
756
757
758
759
760
761
    size_t message_type,
    void * message, size_t message_length,
    void * plaintext, size_t max_plaintext_length
) {
    std::size_t raw_length = b64_input(
        from_c(message), message_length, from_c(session)->last_error
    );
    if (raw_length == std::size_t(-1)) {
        return std::size_t(-1);
    }
    return from_c(session)->decrypt(
762
        olm::MessageType(message_type), from_c(message), raw_length,
763
764
765
766
        from_c(plaintext), max_plaintext_length
    );
}

767
768

size_t olm_sha256_length(
Hubert Chathi's avatar
Hubert Chathi committed
769
   OlmUtility const * utility
770
771
772
773
774
775
776
777
778
779
780
781
782
) {
    return b64_output_length(from_c(utility)->sha256_length());
}


size_t olm_sha256(
    OlmUtility * utility,
    void const * input, size_t input_length,
    void * output, size_t output_length
) {
    std::size_t raw_length = from_c(utility)->sha256_length();
    if (output_length < b64_output_length(raw_length)) {
        from_c(utility)->last_error =
783
            OlmErrorCode::OLM_OUTPUT_BUFFER_TOO_SMALL;
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
        return std::size_t(-1);
    }
    std::size_t result = from_c(utility)->sha256(
       from_c(input), input_length,
       b64_output_pos(from_c(output), raw_length), raw_length
    );
    if (result == std::size_t(-1)) {
        return result;
    }
    return b64_output(from_c(output), raw_length);
}


size_t olm_ed25519_verify(
    OlmUtility * utility,
    void const * key, size_t key_length,
    void const * message, size_t message_length,
    void * signature, size_t signature_length
) {
803
    if (olm::decode_base64_length(key_length) != CURVE25519_KEY_LENGTH) {
804
        from_c(utility)->last_error = OlmErrorCode::OLM_INVALID_BASE64;
805
806
        return std::size_t(-1);
    }
807
    _olm_ed25519_public_key verify_key;
808
    olm::decode_base64(from_c(key), key_length, verify_key.public_key);
809
810
811
812
813
814
815
816
817
818
819
820
821
    std::size_t raw_signature_length = b64_input(
        from_c(signature), signature_length, from_c(utility)->last_error
    );
    if (raw_signature_length == std::size_t(-1)) {
        return std::size_t(-1);
    }
    return from_c(utility)->ed25519_verify(
        verify_key,
        from_c(message), message_length,
        from_c(signature), raw_signature_length
    );
}

822
}