]> gitweb.ps.run Git - matrix_esp_thesis/blob - ext/olm/src/olm.cpp
add dependencies to repo
[matrix_esp_thesis] / ext / olm / src / olm.cpp
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 #include "olm/olm.h"
16 #include "olm/session.hh"
17 #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 #include <new>
25 #include <cstring>
26
27 namespace {
28
29 static OlmAccount * to_c(olm::Account * account) {
30     return reinterpret_cast<OlmAccount *>(account);
31 }
32
33 static OlmSession * to_c(olm::Session * session) {
34     return reinterpret_cast<OlmSession *>(session);
35 }
36
37 static OlmUtility * to_c(olm::Utility * utility) {
38     return reinterpret_cast<OlmUtility *>(utility);
39 }
40
41 static olm::Account * from_c(OlmAccount * account) {
42     return reinterpret_cast<olm::Account *>(account);
43 }
44
45 static const olm::Account * from_c(OlmAccount const * account) {
46     return reinterpret_cast<olm::Account const *>(account);
47 }
48
49 static olm::Session * from_c(OlmSession * session) {
50     return reinterpret_cast<olm::Session *>(session);
51 }
52
53 static const olm::Session * from_c(OlmSession const * session) {
54     return reinterpret_cast<const olm::Session *>(session);
55 }
56
57 static olm::Utility * from_c(OlmUtility * utility) {
58     return reinterpret_cast<olm::Utility *>(utility);
59 }
60
61 static const olm::Utility * from_c(OlmUtility const * utility) {
62     return reinterpret_cast<const olm::Utility *>(utility);
63 }
64
65 static std::uint8_t * from_c(void * bytes) {
66     return reinterpret_cast<std::uint8_t *>(bytes);
67 }
68
69 static std::uint8_t const * from_c(void const * bytes) {
70     return reinterpret_cast<std::uint8_t const *>(bytes);
71 }
72
73 std::size_t b64_output_length(
74     size_t raw_length
75 ) {
76     return olm::encode_base64_length(raw_length);
77 }
78
79 std::uint8_t * b64_output_pos(
80     std::uint8_t * output,
81     size_t raw_length
82 ) {
83     return output + olm::encode_base64_length(raw_length) - raw_length;
84 }
85
86 std::size_t b64_output(
87     std::uint8_t * output, size_t raw_length
88 ) {
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     return base64_length;
93 }
94
95 std::size_t b64_input(
96     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         return std::size_t(-1);
103     }
104     olm::decode_base64(input, b64_length, input);
105     return raw_length;
106 }
107
108 } // namespace
109
110
111 extern "C" {
112
113 void olm_get_library_version(uint8_t *major, uint8_t *minor, uint8_t *patch) {
114     if (major != NULL) *major = OLMLIB_VERSION_MAJOR;
115     if (minor != NULL) *minor = OLMLIB_VERSION_MINOR;
116     if (patch != NULL) *patch = OLMLIB_VERSION_PATCH;
117 }
118
119 size_t olm_error(void) {
120     return std::size_t(-1);
121 }
122
123
124 const char * olm_account_last_error(
125     const OlmAccount * account
126 ) {
127     auto error = from_c(account)->last_error;
128     return _olm_error_to_string(error);
129 }
130
131 enum OlmErrorCode olm_account_last_error_code(
132     const OlmAccount * account
133 ) {
134     return from_c(account)->last_error;
135 }
136
137 const char * olm_session_last_error(
138     const OlmSession * session
139 ) {
140     auto error = from_c(session)->last_error;
141     return _olm_error_to_string(error);
142 }
143
144 enum OlmErrorCode olm_session_last_error_code(
145     OlmSession const * session
146 ) {
147     return from_c(session)->last_error;
148 }
149
150 const char * olm_utility_last_error(
151     OlmUtility const * utility
152 ) {
153     auto error = from_c(utility)->last_error;
154     return _olm_error_to_string(error);
155 }
156
157 enum OlmErrorCode olm_utility_last_error_code(
158     OlmUtility const * utility
159 ) {
160     return from_c(utility)->last_error;
161 }
162
163 size_t olm_account_size(void) {
164     return sizeof(olm::Account);
165 }
166
167
168 size_t olm_session_size(void) {
169     return sizeof(olm::Session);
170 }
171
172 size_t olm_utility_size(void) {
173     return sizeof(olm::Utility);
174 }
175
176 OlmAccount * olm_account(
177     void * memory
178 ) {
179     olm::unset(memory, sizeof(olm::Account));
180     return to_c(new(memory) olm::Account());
181 }
182
183
184 OlmSession * olm_session(
185     void * memory
186 ) {
187     olm::unset(memory, sizeof(olm::Session));
188     return to_c(new(memory) olm::Session());
189 }
190
191
192 OlmUtility * olm_utility(
193     void * memory
194 ) {
195     olm::unset(memory, sizeof(olm::Utility));
196     return to_c(new(memory) olm::Utility());
197 }
198
199
200 size_t olm_clear_account(
201     OlmAccount * account
202 ) {
203     /* Clear the memory backing the account  */
204     olm::unset(account, sizeof(olm::Account));
205     /* Initialise a fresh account object in case someone tries to use it */
206     new(account) olm::Account();
207     return sizeof(olm::Account);
208 }
209
210
211 size_t olm_clear_session(
212     OlmSession * session
213 ) {
214     /* Clear the memory backing the session */
215     olm::unset(session, sizeof(olm::Session));
216     /* Initialise a fresh session object in case someone tries to use it */
217     new(session) olm::Session();
218     return sizeof(olm::Session);
219 }
220
221
222 size_t olm_clear_utility(
223     OlmUtility * utility
224 ) {
225     /* Clear the memory backing the session */
226     olm::unset(utility, sizeof(olm::Utility));
227     /* Initialise a fresh session object in case someone tries to use it */
228     new(utility) olm::Utility();
229     return sizeof(olm::Utility);
230 }
231
232
233 size_t olm_pickle_account_length(
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(
241     OlmSession const * session
242 ) {
243     return _olm_enc_output_length(pickle_length(*from_c(session)));
244 }
245
246
247 size_t olm_pickle_account(
248     OlmAccount * account,
249     void const * key, size_t key_length,
250     void * pickled, size_t pickled_length
251 ) {
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         return size_t(-1);
257     }
258     pickle(_olm_enc_output_pos(from_c(pickled), raw_length), object);
259     return _olm_enc_output(from_c(key), key_length, from_c(pickled), raw_length);
260 }
261
262
263 size_t olm_pickle_session(
264     OlmSession * session,
265     void const * key, size_t key_length,
266     void * pickled, size_t pickled_length
267 ) {
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         return size_t(-1);
273     }
274     pickle(_olm_enc_output_pos(from_c(pickled), raw_length), object);
275     return _olm_enc_output(from_c(key), key_length, from_c(pickled), raw_length);
276 }
277
278
279 size_t olm_unpickle_account(
280     OlmAccount * account,
281     void const * key, size_t key_length,
282     void * pickled, size_t pickled_length
283 ) {
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     if (raw_length == std::size_t(-1)) {
290         return std::size_t(-1);
291     }
292
293     std::uint8_t const * pos = input;
294     std::uint8_t const * end = pos + raw_length;
295
296     pos = unpickle(pos, end, object);
297
298     if (!pos) {
299         /* Input was corrupted. */
300         if (object.last_error == OlmErrorCode::OLM_SUCCESS) {
301             object.last_error = OlmErrorCode::OLM_CORRUPTED_PICKLE;
302         }
303         return std::size_t(-1);
304     } else if (pos != end) {
305         /* Input was longer than expected. */
306         object.last_error = OlmErrorCode::OLM_PICKLE_EXTRA_DATA;
307         return std::size_t(-1);
308     }
309
310     return pickled_length;
311 }
312
313
314 size_t olm_unpickle_session(
315     OlmSession * session,
316     void const * key, size_t key_length,
317     void * pickled, size_t pickled_length
318 ) {
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     if (raw_length == std::size_t(-1)) {
325         return std::size_t(-1);
326     }
327
328     std::uint8_t const * pos = input;
329     std::uint8_t const * end = pos + raw_length;
330
331     pos = unpickle(pos, end, object);
332
333     if (!pos) {
334         /* Input was corrupted. */
335         if (object.last_error == OlmErrorCode::OLM_SUCCESS) {
336             object.last_error = OlmErrorCode::OLM_CORRUPTED_PICKLE;
337         }
338         return std::size_t(-1);
339     } else if (pos != end) {
340         /* Input was longer than expected. */
341         object.last_error = OlmErrorCode::OLM_PICKLE_EXTRA_DATA;
342         return std::size_t(-1);
343     }
344
345     return pickled_length;
346 }
347
348
349 size_t olm_create_account_random_length(
350     OlmAccount const * account
351 ) {
352     return from_c(account)->new_account_random_length();
353 }
354
355
356 size_t olm_create_account(
357     OlmAccount * account,
358     void * random, size_t random_length
359 ) {
360     size_t result = from_c(account)->new_account(from_c(random), random_length);
361     olm::unset(random, random_length);
362     return result;
363 }
364
365
366 size_t olm_account_identity_keys_length(
367     OlmAccount const * account
368 ) {
369     return from_c(account)->get_identity_json_length();
370 }
371
372
373 size_t olm_account_identity_keys(
374     OlmAccount * account,
375     void * identity_keys, size_t identity_key_length
376 ) {
377     return from_c(account)->get_identity_json(
378         from_c(identity_keys), identity_key_length
379     );
380 }
381
382
383 size_t olm_account_signature_length(
384     OlmAccount const * account
385 ) {
386     return b64_output_length(from_c(account)->signature_length());
387 }
388
389
390 size_t olm_account_sign(
391     OlmAccount * account,
392     void const * message, size_t message_length,
393     void * signature, size_t signature_length
394 ) {
395     std::size_t raw_length = from_c(account)->signature_length();
396     if (signature_length < b64_output_length(raw_length)) {
397         from_c(account)->last_error =
398             OlmErrorCode::OLM_OUTPUT_BUFFER_TOO_SMALL;
399         return std::size_t(-1);
400     }
401     from_c(account)->sign(
402          from_c(message), message_length,
403          b64_output_pos(from_c(signature), raw_length), raw_length
404     );
405     return b64_output(from_c(signature), raw_length);
406 }
407
408
409 size_t olm_account_one_time_keys_length(
410     OlmAccount const * account
411 ) {
412     return from_c(account)->get_one_time_keys_json_length();
413 }
414
415
416 size_t olm_account_one_time_keys(
417     OlmAccount * account,
418     void * one_time_keys_json, size_t one_time_key_json_length
419 ) {
420     return from_c(account)->get_one_time_keys_json(
421         from_c(one_time_keys_json), one_time_key_json_length
422     );
423 }
424
425
426 size_t olm_account_mark_keys_as_published(
427     OlmAccount * account
428 ) {
429     return from_c(account)->mark_keys_as_published();
430 }
431
432
433 size_t olm_account_max_number_of_one_time_keys(
434     OlmAccount const * account
435 ) {
436     return from_c(account)->max_number_of_one_time_keys();
437 }
438
439
440 size_t olm_account_generate_one_time_keys_random_length(
441     OlmAccount const * account,
442     size_t number_of_keys
443 ) {
444     return from_c(account)->generate_one_time_keys_random_length(number_of_keys);
445 }
446
447
448 size_t olm_account_generate_one_time_keys(
449     OlmAccount * account,
450     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         number_of_keys,
455         from_c(random), random_length
456     );
457     olm::unset(random, random_length);
458     return result;
459 }
460
461
462 size_t olm_account_generate_fallback_key_random_length(
463     OlmAccount const * account
464 ) {
465     return from_c(account)->generate_fallback_key_random_length();
466 }
467
468
469 size_t olm_account_generate_fallback_key(
470     OlmAccount * account,
471     void * random, size_t random_length
472 ) {
473     size_t result = from_c(account)->generate_fallback_key(
474         from_c(random), random_length
475     );
476     olm::unset(random, random_length);
477     return result;
478 }
479
480
481 size_t olm_account_fallback_key_length(
482     OlmAccount const * account
483 ) {
484     return from_c(account)->get_fallback_key_json_length();
485 }
486
487
488 size_t olm_account_fallback_key(
489     OlmAccount * account,
490     void * fallback_key_json, size_t fallback_key_json_length
491 ) {
492     return from_c(account)->get_fallback_key_json(
493         from_c(fallback_key_json), fallback_key_json_length
494     );
495 }
496
497
498 size_t olm_account_unpublished_fallback_key_length(
499     OlmAccount const * account
500 ) {
501     return from_c(account)->get_unpublished_fallback_key_json_length();
502 }
503
504
505 size_t olm_account_unpublished_fallback_key(
506     OlmAccount * account,
507     void * fallback_key_json, size_t fallback_key_json_length
508 ) {
509     return from_c(account)->get_unpublished_fallback_key_json(
510         from_c(fallback_key_json), fallback_key_json_length
511     );
512 }
513
514
515 void olm_account_forget_old_fallback_key(
516     OlmAccount * account
517 ) {
518     return from_c(account)->forget_old_fallback_key();
519 }
520
521
522 size_t olm_create_outbound_session_random_length(
523     OlmSession const * session
524 ) {
525     return from_c(session)->new_outbound_session_random_length();
526 }
527
528
529 size_t olm_create_outbound_session(
530     OlmSession * session,
531     OlmAccount const * account,
532     void const * their_identity_key, size_t their_identity_key_length,
533     void const * their_one_time_key, size_t their_one_time_key_length,
534     void * random, size_t random_length
535 ) {
536     std::uint8_t const * id_key = from_c(their_identity_key);
537     std::uint8_t const * ot_key = from_c(their_one_time_key);
538     std::size_t id_key_length = their_identity_key_length;
539     std::size_t ot_key_length = their_one_time_key_length;
540
541     if (olm::decode_base64_length(id_key_length) != CURVE25519_KEY_LENGTH
542             || olm::decode_base64_length(ot_key_length) != CURVE25519_KEY_LENGTH
543     ) {
544         from_c(session)->last_error = OlmErrorCode::OLM_INVALID_BASE64;
545         return std::size_t(-1);
546     }
547     _olm_curve25519_public_key identity_key;
548     _olm_curve25519_public_key one_time_key;
549
550     olm::decode_base64(id_key, id_key_length, identity_key.public_key);
551     olm::decode_base64(ot_key, ot_key_length, one_time_key.public_key);
552
553     size_t result = from_c(session)->new_outbound_session(
554         *from_c(account), identity_key, one_time_key,
555         from_c(random), random_length
556     );
557     olm::unset(random, random_length);
558     return result;
559 }
560
561
562 size_t olm_create_inbound_session(
563     OlmSession * session,
564     OlmAccount * account,
565     void * one_time_key_message, size_t message_length
566 ) {
567     std::size_t raw_length = b64_input(
568         from_c(one_time_key_message), message_length, from_c(session)->last_error
569     );
570     if (raw_length == std::size_t(-1)) {
571         return std::size_t(-1);
572     }
573     return from_c(session)->new_inbound_session(
574         *from_c(account), nullptr, from_c(one_time_key_message), raw_length
575     );
576 }
577
578
579 size_t olm_create_inbound_session_from(
580     OlmSession * session,
581     OlmAccount * account,
582     void const * their_identity_key, size_t their_identity_key_length,
583     void * one_time_key_message, size_t message_length
584 ) {
585     std::uint8_t const * id_key = from_c(their_identity_key);
586     std::size_t id_key_length = their_identity_key_length;
587
588     if (olm::decode_base64_length(id_key_length) != CURVE25519_KEY_LENGTH) {
589         from_c(session)->last_error = OlmErrorCode::OLM_INVALID_BASE64;
590         return std::size_t(-1);
591     }
592     _olm_curve25519_public_key identity_key;
593     olm::decode_base64(id_key, id_key_length, identity_key.public_key);
594
595     std::size_t raw_length = b64_input(
596         from_c(one_time_key_message), message_length, from_c(session)->last_error
597     );
598     if (raw_length == std::size_t(-1)) {
599         return std::size_t(-1);
600     }
601     return from_c(session)->new_inbound_session(
602         *from_c(account), &identity_key,
603         from_c(one_time_key_message), raw_length
604     );
605 }
606
607
608 size_t olm_session_id_length(
609     OlmSession const * session
610 ) {
611     return b64_output_length(from_c(session)->session_id_length());
612 }
613
614 size_t olm_session_id(
615     OlmSession * session,
616     void * id, size_t id_length
617 ) {
618     std::size_t raw_length = from_c(session)->session_id_length();
619     if (id_length < b64_output_length(raw_length)) {
620         from_c(session)->last_error =
621                 OlmErrorCode::OLM_OUTPUT_BUFFER_TOO_SMALL;
622         return std::size_t(-1);
623     }
624     std::size_t result = from_c(session)->session_id(
625        b64_output_pos(from_c(id), raw_length), raw_length
626     );
627     if (result == std::size_t(-1)) {
628         return result;
629     }
630     return b64_output(from_c(id), raw_length);
631 }
632
633
634 int olm_session_has_received_message(
635     OlmSession const * session
636 ) {
637     return from_c(session)->received_message;
638 }
639
640 void olm_session_describe(
641     OlmSession * session, char *buf, size_t buflen
642 ) {
643     from_c(session)->describe(buf, buflen);
644 }
645
646 size_t olm_matches_inbound_session(
647     OlmSession * session,
648     void * one_time_key_message, size_t message_length
649 ) {
650     std::size_t raw_length = b64_input(
651         from_c(one_time_key_message), message_length, from_c(session)->last_error
652     );
653     if (raw_length == std::size_t(-1)) {
654         return std::size_t(-1);
655     }
656     bool matches = from_c(session)->matches_inbound_session(
657         nullptr, from_c(one_time_key_message), raw_length
658     );
659     return matches ? 1 : 0;
660 }
661
662
663 size_t olm_matches_inbound_session_from(
664     OlmSession * session,
665     void const * their_identity_key, size_t their_identity_key_length,
666     void * one_time_key_message, size_t message_length
667 ) {
668     std::uint8_t const * id_key = from_c(their_identity_key);
669     std::size_t id_key_length = their_identity_key_length;
670
671     if (olm::decode_base64_length(id_key_length) != CURVE25519_KEY_LENGTH) {
672         from_c(session)->last_error = OlmErrorCode::OLM_INVALID_BASE64;
673         return std::size_t(-1);
674     }
675     _olm_curve25519_public_key identity_key;
676     olm::decode_base64(id_key, id_key_length, identity_key.public_key);
677
678     std::size_t raw_length = b64_input(
679         from_c(one_time_key_message), message_length, from_c(session)->last_error
680     );
681     if (raw_length == std::size_t(-1)) {
682         return std::size_t(-1);
683     }
684     bool matches = from_c(session)->matches_inbound_session(
685         &identity_key, from_c(one_time_key_message), raw_length
686     );
687     return matches ? 1 : 0;
688 }
689
690
691 size_t olm_remove_one_time_keys(
692     OlmAccount * account,
693     OlmSession * session
694 ) {
695     size_t result = from_c(account)->remove_key(
696         from_c(session)->bob_one_time_key
697     );
698     if (result == std::size_t(-1)) {
699         from_c(account)->last_error = OlmErrorCode::OLM_BAD_MESSAGE_KEY_ID;
700     }
701     return result;
702 }
703
704
705 size_t olm_encrypt_message_type(
706     OlmSession const * session
707 ) {
708     return size_t(from_c(session)->encrypt_message_type());
709 }
710
711
712 size_t olm_encrypt_random_length(
713     OlmSession const * session
714 ) {
715     return from_c(session)->encrypt_random_length();
716 }
717
718
719 size_t olm_encrypt_message_length(
720     OlmSession const * session,
721     size_t plaintext_length
722 ) {
723     return b64_output_length(
724         from_c(session)->encrypt_message_length(plaintext_length)
725     );
726 }
727
728
729 size_t olm_encrypt(
730     OlmSession * session,
731     void const * plaintext, size_t plaintext_length,
732     void * random, size_t random_length,
733     void * message, size_t message_length
734 ) {
735     std::size_t raw_length = from_c(session)->encrypt_message_length(
736         plaintext_length
737     );
738     if (message_length < b64_output_length(raw_length)) {
739         from_c(session)->last_error =
740             OlmErrorCode::OLM_OUTPUT_BUFFER_TOO_SMALL;
741         return std::size_t(-1);
742     }
743     std::size_t result = from_c(session)->encrypt(
744         from_c(plaintext), plaintext_length,
745         from_c(random), random_length,
746         b64_output_pos(from_c(message), raw_length), raw_length
747     );
748     olm::unset(random, random_length);
749     if (result == std::size_t(-1)) {
750         return result;
751     }
752     return b64_output(from_c(message), raw_length);
753 }
754
755
756 size_t olm_decrypt_max_plaintext_length(
757     OlmSession * session,
758     size_t message_type,
759     void * message, size_t message_length
760 ) {
761     std::size_t raw_length = b64_input(
762         from_c(message), message_length, from_c(session)->last_error
763     );
764     if (raw_length == std::size_t(-1)) {
765         return std::size_t(-1);
766     }
767     return from_c(session)->decrypt_max_plaintext_length(
768         olm::MessageType(message_type), from_c(message), raw_length
769     );
770 }
771
772
773 size_t olm_decrypt(
774     OlmSession * session,
775     size_t message_type,
776     void * message, size_t message_length,
777     void * plaintext, size_t max_plaintext_length
778 ) {
779     std::size_t raw_length = b64_input(
780         from_c(message), message_length, from_c(session)->last_error
781     );
782     if (raw_length == std::size_t(-1)) {
783         return std::size_t(-1);
784     }
785     return from_c(session)->decrypt(
786         olm::MessageType(message_type), from_c(message), raw_length,
787         from_c(plaintext), max_plaintext_length
788     );
789 }
790
791
792 size_t olm_sha256_length(
793    OlmUtility const * utility
794 ) {
795     return b64_output_length(from_c(utility)->sha256_length());
796 }
797
798
799 size_t olm_sha256(
800     OlmUtility * utility,
801     void const * input, size_t input_length,
802     void * output, size_t output_length
803 ) {
804     std::size_t raw_length = from_c(utility)->sha256_length();
805     if (output_length < b64_output_length(raw_length)) {
806         from_c(utility)->last_error =
807             OlmErrorCode::OLM_OUTPUT_BUFFER_TOO_SMALL;
808         return std::size_t(-1);
809     }
810     std::size_t result = from_c(utility)->sha256(
811        from_c(input), input_length,
812        b64_output_pos(from_c(output), raw_length), raw_length
813     );
814     if (result == std::size_t(-1)) {
815         return result;
816     }
817     return b64_output(from_c(output), raw_length);
818 }
819
820
821 size_t olm_ed25519_verify(
822     OlmUtility * utility,
823     void const * key, size_t key_length,
824     void const * message, size_t message_length,
825     void * signature, size_t signature_length
826 ) {
827     if (olm::decode_base64_length(key_length) != CURVE25519_KEY_LENGTH) {
828         from_c(utility)->last_error = OlmErrorCode::OLM_INVALID_BASE64;
829         return std::size_t(-1);
830     }
831     _olm_ed25519_public_key verify_key;
832     olm::decode_base64(from_c(key), key_length, verify_key.public_key);
833     std::size_t raw_signature_length = b64_input(
834         from_c(signature), signature_length, from_c(utility)->last_error
835     );
836     if (raw_signature_length == std::size_t(-1)) {
837         return std::size_t(-1);
838     }
839     return from_c(utility)->ed25519_verify(
840         verify_key,
841         from_c(message), message_length,
842         from_c(signature), raw_signature_length
843     );
844 }
845
846 }