Line data Source code
1 : // Copyright (c) 2020 Famedly GmbH
2 : // SPDX-License-Identifier: AGPL-3.0-or-later
3 :
4 : import 'dart:convert';
5 : import 'dart:ffi';
6 : import 'dart:math';
7 : import 'dart:typed_data';
8 :
9 : import 'package:ffi/ffi.dart';
10 :
11 : import 'common.dart';
12 : import 'ffi.dart';
13 :
14 : typedef _ObjectLengthFunc = int Function(Pointer<NativeType>);
15 : typedef _PickleUnpickleFunc = int Function(
16 : Pointer<NativeType>, Pointer<Uint8>, int, Pointer<Uint8>, int);
17 : typedef _CalculateMacFunc = int Function(Pointer<NativeType>, Pointer<Uint8>,
18 : int, Pointer<Uint8>, int, Pointer<Uint8>, int);
19 :
20 1 : String _readStr(
21 : _ObjectLengthFunc len,
22 : int Function(Pointer<NativeType>, Pointer<Uint8>, int) data,
23 : Pointer<NativeType> inst) {
24 1 : final l = len(inst);
25 : final mem = malloc.call<Uint8>(l);
26 : try {
27 1 : final dl = data(inst, mem, l);
28 2 : assert(dl <= l);
29 2 : return utf8.decode(mem.asTypedList(dl));
30 : } finally {
31 1 : malloc.free(mem);
32 : }
33 : }
34 :
35 1 : String _readStr2(
36 : _ObjectLengthFunc len,
37 : int Function(Pointer<NativeType>, Pointer<Uint8>, int) data,
38 : Pointer<NativeType> inst) {
39 1 : final l = len(inst);
40 : final mem = malloc.call<Uint8>(l);
41 : try {
42 1 : data(inst, mem, l);
43 2 : return utf8.decode(mem.asTypedList(l));
44 : } finally {
45 1 : malloc.free(mem);
46 : }
47 : }
48 :
49 1 : String _pickle(_ObjectLengthFunc len, _PickleUnpickleFunc data,
50 : Pointer<NativeType> inst, String key) {
51 1 : final units = utf8.encode(key);
52 1 : final outLen = len(inst);
53 2 : final mem = malloc.call<Uint8>(units.length + outLen);
54 1 : final outMem = mem.elementAt(units.length);
55 : try {
56 3 : mem.asTypedList(units.length).setAll(0, units);
57 2 : data(inst, mem, units.length, outMem, outLen);
58 2 : return utf8.decode(outMem.asTypedList(outLen));
59 : } finally {
60 1 : malloc.free(mem);
61 : }
62 : }
63 :
64 1 : void _unpickle(_PickleUnpickleFunc func, Pointer<NativeType> inst, String data,
65 : String key) {
66 1 : final dby = utf8.encode(data);
67 1 : final kby = utf8.encode(key);
68 3 : final mem = malloc.call<Uint8>(dby.length + kby.length);
69 1 : final keyMem = mem.elementAt(dby.length);
70 : try {
71 3 : mem.asTypedList(dby.length).setAll(0, dby);
72 3 : keyMem.asTypedList(kby.length).setAll(0, kby);
73 3 : func(inst, keyMem, kby.length, mem, dby.length);
74 : } finally {
75 1 : malloc.free(mem);
76 : }
77 : }
78 :
79 1 : String _calculateMac(_CalculateMacFunc func, Pointer<NativeType> inst,
80 : String input, String info) {
81 1 : final inputUnits = utf8.encode(input);
82 1 : final infoUnits = utf8.encode(info);
83 1 : final outMemLen = olm_sas_mac_length(inst);
84 : final mem =
85 4 : malloc.call<Uint8>(inputUnits.length + infoUnits.length + outMemLen);
86 1 : final infoMem = mem.elementAt(inputUnits.length);
87 1 : final outMem = infoMem.elementAt(infoUnits.length);
88 : try {
89 3 : mem.asTypedList(inputUnits.length).setAll(0, inputUnits);
90 3 : infoMem.asTypedList(infoUnits.length).setAll(0, infoUnits);
91 3 : func(inst, mem, inputUnits.length, infoMem, infoUnits.length, outMem,
92 : outMemLen);
93 2 : return utf8.decode(outMem.asTypedList(outMemLen));
94 : } finally {
95 1 : malloc.free(mem);
96 : }
97 : }
98 :
99 1 : void _fillRandom(Uint8List list) {
100 1 : final rng = Random.secure();
101 5 : list.setAll(0, Iterable.generate(list.length, (i) => rng.nextInt(256)));
102 : }
103 :
104 1 : void _createRandom(
105 : void Function(Pointer<NativeType>, Pointer<Uint8> random, int size) func,
106 : _ObjectLengthFunc len,
107 : Pointer<NativeType> inst) {
108 1 : final l = len(inst);
109 : final mem = malloc.call<Uint8>(l);
110 : try {
111 2 : _fillRandom(mem.asTypedList(l));
112 1 : func(inst, mem, l);
113 : } finally {
114 1 : malloc.free(mem);
115 : }
116 : }
117 :
118 : class _NativeObject {
119 : Pointer<Uint8> _mem;
120 : Pointer<NativeType>? _maybeInst;
121 2 : Pointer<NativeType> get _inst => _maybeInst ?? (throw UseAfterFreeError());
122 :
123 1 : _NativeObject(int Function() get_size,
124 : Pointer<NativeType> Function(Pointer<Uint8>) create)
125 1 : : _mem = malloc.call<Uint8>(get_size()) {
126 3 : _maybeInst = create(_mem);
127 : }
128 :
129 1 : void _freed() {
130 1 : _maybeInst = null;
131 2 : malloc.free(_mem);
132 : }
133 : }
134 :
135 1 : Future<void> init() async {
136 1 : olm_get_library_version; // just load the function, not calling it
137 : }
138 :
139 1 : List<int> get_library_version() {
140 : final mem = malloc.call<Uint8>(3);
141 : try {
142 2 : olm_get_library_version(
143 : mem.elementAt(0), mem.elementAt(1), mem.elementAt(2));
144 2 : return List<int>.from(mem.asTypedList(3));
145 : } finally {
146 1 : malloc.free(mem);
147 : }
148 : }
149 :
150 : class EncryptResult {
151 : int type;
152 : String body;
153 1 : EncryptResult._(this.type, this.body);
154 : }
155 :
156 : class DecryptResult {
157 : int message_index;
158 : String plaintext;
159 1 : DecryptResult._(this.message_index, this.plaintext);
160 : }
161 :
162 : class Account extends _NativeObject {
163 4 : Account() : super(olm_account_size, olm_account);
164 :
165 1 : void free() {
166 2 : olm_clear_account(_inst);
167 1 : _freed();
168 : }
169 :
170 1 : void create() {
171 2 : _createRandom(olm_create_account, olm_create_account_random_length, _inst);
172 : }
173 :
174 1 : String identity_keys() {
175 1 : return _readStr(
176 1 : olm_account_identity_keys_length, olm_account_identity_keys, _inst);
177 : }
178 :
179 1 : String one_time_keys() {
180 1 : return _readStr(
181 1 : olm_account_one_time_keys_length, olm_account_one_time_keys, _inst);
182 : }
183 :
184 1 : String fallback_key() {
185 1 : return _readStr(
186 1 : olm_account_fallback_key_length, olm_account_fallback_key, _inst);
187 : }
188 :
189 1 : String unpublished_fallback_key() {
190 1 : return _readStr(olm_account_unpublished_fallback_key_length,
191 1 : olm_account_unpublished_fallback_key, _inst);
192 : }
193 :
194 1 : String pickle(String key) {
195 2 : return _pickle(olm_pickle_account_length, olm_pickle_account, _inst, key);
196 : }
197 :
198 1 : void unpickle(String key, String data) {
199 2 : return _unpickle(olm_unpickle_account, _inst, data, key);
200 : }
201 :
202 1 : void generate_one_time_keys(int count) {
203 1 : _createRandom(
204 1 : (inst, random, size) =>
205 2 : olm_account_generate_one_time_keys(_inst, count, random, size),
206 2 : (inst) => olm_account_generate_one_time_keys_random_length(inst, count),
207 1 : _inst);
208 : }
209 :
210 1 : void generate_fallback_key() {
211 1 : _createRandom(olm_account_generate_fallback_key,
212 1 : olm_account_generate_fallback_key_random_length, _inst);
213 : }
214 :
215 1 : void remove_one_time_keys(Session session) {
216 3 : olm_remove_one_time_keys(_inst, session._inst);
217 : }
218 :
219 1 : void mark_keys_as_published() {
220 2 : olm_account_mark_keys_as_published(_inst);
221 : }
222 :
223 1 : int max_number_of_one_time_keys() {
224 2 : return olm_account_max_number_of_one_time_keys(_inst);
225 : }
226 :
227 1 : String sign(String message) {
228 1 : final units = utf8.encode(message);
229 2 : final outLen = olm_account_signature_length(_inst);
230 2 : final mem = malloc.call<Uint8>(units.length + outLen);
231 1 : final outMem = mem.elementAt(units.length);
232 : try {
233 3 : mem.asTypedList(units.length).setAll(0, units);
234 3 : olm_account_sign(_inst, mem, units.length, outMem, outLen);
235 2 : return utf8.decode(outMem.asTypedList(outLen));
236 : } finally {
237 1 : malloc.free(mem);
238 : }
239 : }
240 : }
241 :
242 : class Session extends _NativeObject {
243 4 : Session() : super(olm_session_size, olm_session);
244 :
245 1 : void free() {
246 2 : olm_clear_session(_inst);
247 1 : _freed();
248 : }
249 :
250 1 : String pickle(String key) {
251 2 : return _pickle(olm_pickle_session_length, olm_pickle_session, _inst, key);
252 : }
253 :
254 1 : void unpickle(String key, String data) {
255 2 : return _unpickle(olm_unpickle_session, _inst, data, key);
256 : }
257 :
258 1 : void create_outbound(
259 : Account account, String identity_key, String one_time_key) {
260 1 : final identity_key_units = utf8.encode(identity_key);
261 1 : final one_time_key_units = utf8.encode(one_time_key);
262 2 : final randomLen = olm_create_outbound_session_random_length(_inst);
263 : final mem = malloc.call<Uint8>(
264 4 : identity_key_units.length + one_time_key_units.length + randomLen);
265 1 : final otMem = mem.elementAt(identity_key_units.length);
266 1 : final rndMem = otMem.elementAt(one_time_key_units.length);
267 : try {
268 3 : mem.asTypedList(identity_key_units.length).setAll(0, identity_key_units);
269 : otMem
270 2 : .asTypedList(one_time_key_units.length)
271 1 : .setAll(0, one_time_key_units);
272 2 : _fillRandom(rndMem.asTypedList(randomLen));
273 1 : olm_create_outbound_session(
274 1 : _inst,
275 1 : account._inst,
276 : mem,
277 1 : identity_key_units.length,
278 : otMem,
279 1 : one_time_key_units.length,
280 : rndMem,
281 : randomLen);
282 : } finally {
283 1 : malloc.free(mem);
284 : }
285 : }
286 :
287 1 : void create_inbound(Account account, String message) {
288 1 : final message_units = utf8.encode(message);
289 1 : final mem = malloc.call<Uint8>(message_units.length);
290 : try {
291 3 : mem.asTypedList(message_units.length).setAll(0, message_units);
292 1 : olm_create_inbound_session(
293 3 : _inst, account._inst, mem, message_units.length);
294 : } finally {
295 1 : malloc.free(mem);
296 : }
297 : }
298 :
299 1 : void create_inbound_from(
300 : Account account, String identity_key, String one_time_key) {
301 1 : final identity_key_units = utf8.encode(identity_key);
302 1 : final one_time_key_units = utf8.encode(one_time_key);
303 : final mem = malloc
304 3 : .call<Uint8>(identity_key_units.length + one_time_key_units.length);
305 1 : final otMem = mem.elementAt(identity_key_units.length);
306 : try {
307 3 : mem.asTypedList(identity_key_units.length).setAll(0, identity_key_units);
308 : otMem
309 2 : .asTypedList(one_time_key_units.length)
310 1 : .setAll(0, one_time_key_units);
311 3 : olm_create_inbound_session_from(_inst, account._inst, mem,
312 2 : identity_key_units.length, otMem, one_time_key_units.length);
313 : } finally {
314 1 : malloc.free(mem);
315 : }
316 : }
317 :
318 1 : String session_id() {
319 2 : return _readStr(olm_session_id_length, olm_session_id, _inst);
320 : }
321 :
322 1 : bool has_received_message() {
323 4 : return olm_session_has_received_message(_inst) != 0;
324 : }
325 :
326 1 : int encrypt_message_type() {
327 2 : return olm_encrypt_message_type(_inst);
328 : }
329 :
330 1 : bool matches_inbound(String message) {
331 1 : final message_units = utf8.encode(message);
332 1 : final mem = malloc.call<Uint8>(message_units.length);
333 3 : mem.asTypedList(message_units.length).setAll(0, message_units);
334 : try {
335 4 : return olm_matches_inbound_session(_inst, mem, message_units.length) != 0;
336 : } finally {
337 1 : malloc.free(mem);
338 : }
339 : }
340 :
341 1 : bool matches_inbound_from(String identity_key, String message) {
342 1 : final identity_key_units = utf8.encode(identity_key);
343 1 : final message_units = utf8.encode(message);
344 : final mem =
345 3 : malloc.call<Uint8>(identity_key_units.length + message_units.length);
346 1 : final mem2 = mem.elementAt(identity_key_units.length);
347 3 : mem.asTypedList(identity_key_units.length).setAll(0, identity_key_units);
348 3 : mem2.asTypedList(message_units.length).setAll(0, message_units);
349 : try {
350 2 : return olm_matches_inbound_session_from(_inst, mem,
351 2 : identity_key_units.length, mem2, message_units.length) !=
352 : 0;
353 : } finally {
354 1 : malloc.free(mem);
355 : }
356 : }
357 :
358 1 : EncryptResult encrypt(String plaintext) {
359 1 : final units = utf8.encode(plaintext);
360 2 : final randomLen = olm_encrypt_random_length(_inst);
361 3 : final outLen = olm_encrypt_message_length(_inst, units.length);
362 3 : final mem = malloc.call<Uint8>(units.length + randomLen + outLen);
363 1 : final rndMem = mem.elementAt(units.length);
364 : final outMem = rndMem.elementAt(randomLen);
365 : try {
366 3 : mem.asTypedList(units.length).setAll(0, units);
367 2 : _fillRandom(rndMem.asTypedList(randomLen));
368 1 : final result1 = encrypt_message_type();
369 3 : olm_encrypt(_inst, mem, units.length, rndMem, randomLen, outMem, outLen);
370 2 : final result2 = utf8.decode(outMem.asTypedList(outLen));
371 1 : return EncryptResult._(result1, result2);
372 : } finally {
373 1 : malloc.free(mem);
374 : }
375 : }
376 :
377 1 : String decrypt(int message_type, String message) {
378 1 : final units = utf8.encode(message);
379 1 : final mem = malloc.call<Uint8>(units.length);
380 : try {
381 3 : mem.asTypedList(units.length).setAll(0, units);
382 1 : int outLen = olm_decrypt_max_plaintext_length(
383 2 : _inst, message_type, mem, units.length);
384 3 : mem.asTypedList(units.length).setAll(0, units);
385 : final outMem = malloc.call<Uint8>(outLen);
386 : try {
387 : outLen =
388 3 : olm_decrypt(_inst, message_type, mem, units.length, outMem, outLen);
389 2 : return utf8.decode(outMem.asTypedList(outLen));
390 : } finally {
391 1 : malloc.free(outMem);
392 : }
393 : } finally {
394 1 : malloc.free(mem);
395 : }
396 : }
397 : }
398 :
399 : class Utility extends _NativeObject {
400 4 : Utility() : super(olm_utility_size, olm_utility);
401 :
402 1 : void free() {
403 2 : olm_clear_utility(_inst);
404 1 : _freed();
405 : }
406 :
407 1 : String sha256(String input) {
408 3 : return sha256_bytes(utf8.encoder.convert(input));
409 : }
410 :
411 : /// Not implemented for Web in upstream olm.
412 1 : String sha256_bytes(Uint8List input) {
413 1 : final mem = malloc.call<Uint8>(input.length);
414 3 : mem.asTypedList(input.length).setAll(0, input);
415 : try {
416 2 : return sha256_pointer(mem, input.length);
417 : } finally {
418 1 : malloc.free(mem);
419 : }
420 : }
421 :
422 : /// Available for Native only.
423 1 : String sha256_pointer(Pointer<Uint8> input, int size) {
424 2 : final outLen = olm_sha256_length(_inst);
425 : final outMem = malloc.call<Uint8>(outLen);
426 : try {
427 2 : olm_sha256(_inst, input, size, outMem, outLen);
428 2 : return utf8.decode(outMem.asTypedList(outLen));
429 : } finally {
430 1 : malloc.free(outMem);
431 : }
432 : }
433 :
434 1 : void ed25519_verify(String key, String message, String signature) {
435 1 : final key_units = utf8.encode(key);
436 1 : final message_units = utf8.encode(message);
437 1 : final signature_units = utf8.encode(signature);
438 : final mem1 = malloc.call<Uint8>(
439 5 : key_units.length + message_units.length + signature_units.length);
440 1 : final mem2 = mem1.elementAt(key_units.length);
441 1 : final mem3 = mem2.elementAt(message_units.length);
442 : try {
443 3 : mem1.asTypedList(key_units.length).setAll(0, key_units);
444 3 : mem2.asTypedList(message_units.length).setAll(0, message_units);
445 3 : mem3.asTypedList(signature_units.length).setAll(0, signature_units);
446 3 : olm_ed25519_verify(_inst, mem1, key_units.length, mem2,
447 2 : message_units.length, mem3, signature_units.length);
448 : } finally {
449 1 : malloc.free(mem1);
450 : }
451 : }
452 : }
453 :
454 : class InboundGroupSession extends _NativeObject {
455 1 : InboundGroupSession()
456 3 : : super(olm_inbound_group_session_size, olm_inbound_group_session);
457 :
458 1 : void free() {
459 2 : olm_clear_inbound_group_session(_inst);
460 1 : _freed();
461 : }
462 :
463 1 : String pickle(String key) {
464 1 : return _pickle(olm_pickle_inbound_group_session_length,
465 1 : olm_pickle_inbound_group_session, _inst, key);
466 : }
467 :
468 1 : void unpickle(String key, String data) {
469 2 : return _unpickle(olm_unpickle_inbound_group_session, _inst, data, key);
470 : }
471 :
472 1 : void create(String session_key) {
473 1 : final units = utf8.encode(session_key);
474 1 : final mem = malloc.call<Uint8>(units.length);
475 : try {
476 3 : mem.asTypedList(units.length).setAll(0, units);
477 3 : olm_init_inbound_group_session(_inst, mem, units.length);
478 : } finally {
479 1 : malloc.free(mem);
480 : }
481 : }
482 :
483 1 : void import_session(String session_key) {
484 1 : final units = utf8.encode(session_key);
485 1 : final mem = malloc.call<Uint8>(units.length);
486 : try {
487 3 : mem.asTypedList(units.length).setAll(0, units);
488 3 : olm_import_inbound_group_session(_inst, mem, units.length);
489 : } finally {
490 1 : malloc.free(mem);
491 : }
492 : }
493 :
494 1 : DecryptResult decrypt(String message) {
495 1 : final units = utf8.encode(message);
496 1 : final mem = malloc.call<Uint8>(units.length);
497 : try {
498 3 : mem.asTypedList(units.length).setAll(0, units);
499 : int outLen =
500 3 : olm_group_decrypt_max_plaintext_length(_inst, mem, units.length);
501 3 : mem.asTypedList(units.length).setAll(0, units);
502 1 : final outMem = malloc.call<Uint8>(outLen + 4);
503 1 : final outMem2 = outMem.elementAt(outLen).cast<Uint32>();
504 : try {
505 1 : outLen = olm_group_decrypt(
506 2 : _inst, mem, units.length, outMem, outLen, outMem2);
507 1 : return DecryptResult._(
508 3 : outMem2.value, utf8.decode(outMem.asTypedList(outLen)));
509 : } finally {
510 1 : malloc.free(outMem);
511 : }
512 : } finally {
513 1 : malloc.free(mem);
514 : }
515 : }
516 :
517 1 : String session_id() {
518 1 : return _readStr(olm_inbound_group_session_id_length,
519 1 : olm_inbound_group_session_id, _inst);
520 : }
521 :
522 1 : int first_known_index() {
523 3 : return olm_inbound_group_session_first_known_index(_inst);
524 : }
525 :
526 1 : String export_session(int message_index) {
527 1 : return _readStr(
528 : olm_export_inbound_group_session_length,
529 1 : (inst, mem, len) =>
530 1 : olm_export_inbound_group_session(inst, mem, len, message_index),
531 1 : _inst);
532 : }
533 : }
534 :
535 : class OutboundGroupSession extends _NativeObject {
536 1 : OutboundGroupSession()
537 3 : : super(olm_outbound_group_session_size, olm_outbound_group_session);
538 :
539 1 : void free() {
540 2 : olm_clear_outbound_group_session(_inst);
541 1 : _freed();
542 : }
543 :
544 1 : String pickle(String key) {
545 1 : return _pickle(olm_pickle_outbound_group_session_length,
546 1 : olm_pickle_outbound_group_session, _inst, key);
547 : }
548 :
549 1 : void unpickle(String key, String data) {
550 2 : return _unpickle(olm_unpickle_outbound_group_session, _inst, data, key);
551 : }
552 :
553 1 : void create() {
554 1 : _createRandom(olm_init_outbound_group_session,
555 1 : olm_init_outbound_group_session_random_length, _inst);
556 : }
557 :
558 1 : String encrypt(String plaintext) {
559 1 : final units = utf8.encode(plaintext);
560 3 : final outLen = olm_group_encrypt_message_length(_inst, units.length);
561 2 : final mem = malloc.call<Uint8>(units.length + outLen);
562 1 : final outMem = mem.elementAt(units.length);
563 : try {
564 3 : mem.asTypedList(units.length).setAll(0, units);
565 3 : olm_group_encrypt(_inst, mem, units.length, outMem, outLen);
566 2 : return utf8.decode(outMem.asTypedList(outLen));
567 : } finally {
568 1 : malloc.free(mem);
569 : }
570 : }
571 :
572 1 : String session_id() {
573 1 : return _readStr(olm_outbound_group_session_id_length,
574 1 : olm_outbound_group_session_id, _inst);
575 : }
576 :
577 1 : int message_index() {
578 3 : return olm_outbound_group_session_message_index(_inst);
579 : }
580 :
581 1 : String session_key() {
582 1 : return _readStr(olm_outbound_group_session_key_length,
583 1 : olm_outbound_group_session_key, _inst);
584 : }
585 : }
586 :
587 : class SAS extends _NativeObject {
588 4 : SAS() : super(olm_sas_size, olm_sas) {
589 2 : _createRandom(olm_create_sas, olm_create_sas_random_length, _inst);
590 : }
591 :
592 1 : void free() {
593 2 : olm_clear_sas(_inst);
594 1 : _freed();
595 : }
596 :
597 1 : String get_pubkey() {
598 2 : return _readStr2(olm_sas_pubkey_length, olm_sas_get_pubkey, _inst);
599 : }
600 :
601 1 : void set_their_key(String their_key) {
602 1 : final units = utf8.encode(their_key);
603 1 : final mem = malloc.call<Uint8>(units.length);
604 : try {
605 3 : mem.asTypedList(units.length).setAll(0, units);
606 3 : olm_sas_set_their_key(_inst, mem, units.length);
607 : } finally {
608 1 : malloc.free(mem);
609 : }
610 : }
611 :
612 1 : Uint8List generate_bytes(String info, int length) {
613 1 : final units = utf8.encode(info);
614 2 : final mem = malloc.call<Uint8>(units.length + length);
615 1 : final outMem = mem.elementAt(units.length);
616 : try {
617 3 : mem.asTypedList(units.length).setAll(0, units);
618 3 : olm_sas_generate_bytes(_inst, mem, units.length, outMem, length);
619 2 : return Uint8List.fromList(outMem.asTypedList(length));
620 : } finally {
621 1 : malloc.free(mem);
622 : }
623 : }
624 :
625 1 : String calculate_mac(String input, String info) {
626 2 : return _calculateMac(olm_sas_calculate_mac, _inst, input, info);
627 : }
628 :
629 1 : String calculate_mac_long_kdf(String input, String info) {
630 2 : return _calculateMac(olm_sas_calculate_mac_long_kdf, _inst, input, info);
631 : }
632 : }
633 :
634 : class PkEncryptResult {
635 : String ciphertext;
636 : String mac;
637 : String ephemeral;
638 1 : PkEncryptResult._(this.ciphertext, this.mac, this.ephemeral);
639 : }
640 :
641 : class PkEncryption extends _NativeObject {
642 4 : PkEncryption() : super(olm_pk_encryption_size, olm_pk_encryption);
643 :
644 1 : void free() {
645 2 : olm_clear_pk_encryption(_inst);
646 1 : _freed();
647 : }
648 :
649 1 : void set_recipient_key(String key) {
650 1 : final units = utf8.encode(key);
651 1 : final mem = malloc.call<Uint8>(units.length);
652 : try {
653 3 : mem.asTypedList(units.length).setAll(0, units);
654 3 : olm_pk_encryption_set_recipient_key(_inst, mem, units.length);
655 : } finally {
656 1 : malloc.free(mem);
657 : }
658 : }
659 :
660 1 : PkEncryptResult encrypt(String plaintext) {
661 1 : final units = utf8.encode(plaintext);
662 2 : final rndLen = olm_pk_encrypt_random_length(_inst);
663 3 : final outLen = olm_pk_ciphertext_length(_inst, units.length);
664 2 : final macLen = olm_pk_mac_length(_inst);
665 2 : final ephLen = olm_pk_key_length();
666 : final mem =
667 5 : malloc.call<Uint8>(units.length + rndLen + outLen + macLen + ephLen);
668 1 : final rndMem = mem.elementAt(units.length);
669 : final outMem = rndMem.elementAt(rndLen);
670 : final macMem = outMem.elementAt(outLen);
671 : final ephMem = macMem.elementAt(macLen);
672 : try {
673 3 : mem.asTypedList(units.length).setAll(0, units);
674 2 : _fillRandom(rndMem.asTypedList(rndLen));
675 3 : olm_pk_encrypt(_inst, mem, units.length, outMem, outLen, macMem, macLen,
676 : ephMem, ephLen, rndMem, rndLen);
677 1 : return PkEncryptResult._(
678 2 : utf8.decode(outMem.asTypedList(outLen)),
679 2 : utf8.decode(macMem.asTypedList(macLen)),
680 2 : utf8.decode(ephMem.asTypedList(ephLen)));
681 : } finally {
682 1 : malloc.free(mem);
683 : }
684 : }
685 : }
686 :
687 : class PkDecryption extends _NativeObject {
688 4 : PkDecryption() : super(olm_pk_decryption_size, olm_pk_decryption);
689 :
690 1 : void free() {
691 2 : olm_clear_pk_decryption(_inst);
692 1 : _freed();
693 : }
694 :
695 1 : String init_with_private_key(Uint8List private_key) {
696 2 : final outLen = olm_pk_key_length();
697 2 : final mem = malloc.call<Uint8>(private_key.length + outLen);
698 1 : final outMem = mem.elementAt(private_key.length);
699 : try {
700 3 : mem.asTypedList(private_key.length).setAll(0, private_key);
701 3 : olm_pk_key_from_private(_inst, outMem, outLen, mem, private_key.length);
702 2 : return utf8.decode(outMem.asTypedList(outLen));
703 : } finally {
704 1 : malloc.free(mem);
705 : }
706 : }
707 :
708 1 : String generate_key() {
709 2 : final len = olm_pk_private_key_length();
710 2 : final outLen = olm_pk_key_length();
711 1 : final mem = malloc.call<Uint8>(len + outLen);
712 : final outMem = mem.elementAt(len);
713 : try {
714 2 : _fillRandom(mem.asTypedList(len));
715 2 : olm_pk_key_from_private(_inst, outMem, outLen, mem, len);
716 2 : return utf8.decode(outMem.asTypedList(outLen));
717 : } finally {
718 1 : malloc.free(mem);
719 : }
720 : }
721 :
722 1 : Uint8List get_private_key() {
723 2 : final len = olm_pk_private_key_length();
724 : final mem = malloc.call<Uint8>(len);
725 : try {
726 2 : olm_pk_get_private_key(_inst, mem, len);
727 2 : return Uint8List.fromList(mem.asTypedList(len));
728 : } finally {
729 1 : malloc.free(mem);
730 : }
731 : }
732 :
733 1 : String pickle(String key) {
734 1 : return _pickle(
735 1 : olm_pickle_pk_decryption_length, olm_pickle_pk_decryption, _inst, key);
736 : }
737 :
738 1 : String unpickle(String key, String data) {
739 1 : final dby = utf8.encode(data);
740 1 : final kby = utf8.encode(key);
741 2 : final outLen = olm_pk_key_length();
742 4 : final mem = malloc.call<Uint8>(dby.length + kby.length + outLen);
743 1 : final keyMem = mem.elementAt(dby.length);
744 1 : final outMem = keyMem.elementAt(kby.length);
745 : try {
746 3 : mem.asTypedList(dby.length).setAll(0, dby);
747 3 : keyMem.asTypedList(kby.length).setAll(0, kby);
748 1 : olm_unpickle_pk_decryption(
749 3 : _inst, keyMem, kby.length, mem, dby.length, outMem, outLen);
750 2 : return utf8.decode(outMem.asTypedList(outLen));
751 : } finally {
752 1 : malloc.free(mem);
753 : }
754 : }
755 :
756 1 : String decrypt(String ephemeral_key, String mac, String ciphertext) {
757 1 : final ephUnits = utf8.encode(ephemeral_key);
758 1 : final macUnits = utf8.encode(mac);
759 1 : final ciphertextUnits = utf8.encode(ciphertext);
760 :
761 : int plaintextLen =
762 3 : olm_pk_max_plaintext_length(_inst, ciphertextUnits.length);
763 2 : final mem = malloc.call<Uint8>(ephUnits.length +
764 2 : macUnits.length +
765 2 : ciphertextUnits.length +
766 : plaintextLen);
767 1 : final macMem = mem.elementAt(ephUnits.length);
768 1 : final ciphertextMem = macMem.elementAt(macUnits.length);
769 1 : final plaintextMem = ciphertextMem.elementAt(ciphertextUnits.length);
770 : try {
771 3 : mem.asTypedList(ephUnits.length).setAll(0, ephUnits);
772 3 : macMem.asTypedList(macUnits.length).setAll(0, macUnits);
773 : ciphertextMem
774 2 : .asTypedList(ciphertextUnits.length)
775 1 : .setAll(0, ciphertextUnits);
776 1 : plaintextLen = olm_pk_decrypt(
777 1 : _inst,
778 : mem,
779 1 : ephUnits.length,
780 : macMem,
781 1 : macUnits.length,
782 : ciphertextMem,
783 1 : ciphertextUnits.length,
784 : plaintextMem,
785 : plaintextLen);
786 2 : return utf8.decode(plaintextMem.asTypedList(plaintextLen));
787 : } finally {
788 1 : malloc.free(mem);
789 : }
790 : }
791 : }
792 :
793 : class PkSigning extends _NativeObject {
794 4 : PkSigning() : super(olm_pk_signing_size, olm_pk_signing);
795 :
796 1 : void free() {
797 2 : olm_clear_pk_signing(_inst);
798 1 : _freed();
799 : }
800 :
801 1 : String init_with_seed(Uint8List seed) {
802 2 : final outLen = olm_pk_signing_public_key_length();
803 2 : final mem = malloc.call<Uint8>(seed.length + outLen);
804 1 : final outMem = mem.elementAt(seed.length);
805 : try {
806 3 : mem.asTypedList(seed.length).setAll(0, seed);
807 3 : olm_pk_signing_key_from_seed(_inst, outMem, outLen, mem, seed.length);
808 2 : return utf8.decode(outMem.asTypedList(outLen));
809 : } finally {
810 1 : malloc.free(mem);
811 : }
812 : }
813 :
814 1 : Uint8List generate_seed() {
815 3 : final result = Uint8List(olm_pk_signing_seed_length());
816 1 : _fillRandom(result);
817 : return result;
818 : }
819 :
820 1 : String sign(String message) {
821 1 : final units = utf8.encode(message);
822 2 : final outLen = olm_pk_signature_length();
823 2 : final mem = malloc.call<Uint8>(units.length + outLen);
824 1 : final outMem = mem.elementAt(units.length);
825 : try {
826 3 : mem.asTypedList(units.length).setAll(0, units);
827 3 : olm_pk_sign(_inst, mem, units.length, outMem, outLen);
828 2 : return utf8.decode(outMem.asTypedList(outLen));
829 : } finally {
830 1 : malloc.free(mem);
831 : }
832 : }
833 : }
|