Line data Source code
1 : // ignore_for_file: deprecated_member_use
2 : // ignoring the elementAt deprecation because this would make the SDK
3 : // incompatible with older flutter versions than 3.19.0 or dart 3.3.0
4 :
5 : import 'dart:async';
6 : import 'dart:ffi';
7 : import 'dart:typed_data';
8 :
9 : import 'package:ffi/ffi.dart';
10 :
11 : import 'package:matrix/src/utils/crypto/ffi.dart';
12 :
13 : abstract class Hash {
14 4 : Hash._(this.ptr);
15 : Pointer<NativeType> ptr;
16 :
17 2 : FutureOr<Uint8List> call(Uint8List data) {
18 6 : final outSize = EVP_MD_size(ptr);
19 4 : final mem = malloc.call<Uint8>(outSize + data.length);
20 2 : final dataMem = mem.elementAt(outSize);
21 : try {
22 6 : dataMem.asTypedList(data.length).setAll(0, data);
23 12 : EVP_Digest(dataMem, data.length, mem, nullptr, ptr, nullptr);
24 4 : return Uint8List.fromList(mem.asTypedList(outSize));
25 : } finally {
26 2 : malloc.free(mem);
27 : }
28 : }
29 : }
30 :
31 0 : final Hash sha1 = _Sha1();
32 6 : final Hash sha256 = _Sha256();
33 6 : final Hash sha512 = _Sha512();
34 :
35 : class _Sha1 extends Hash {
36 0 : _Sha1() : super._(EVP_sha1());
37 : }
38 :
39 : class _Sha256 extends Hash {
40 8 : _Sha256() : super._(EVP_sha256());
41 : }
42 :
43 : class _Sha512 extends Hash {
44 8 : _Sha512() : super._(EVP_sha512());
45 : }
46 :
47 : abstract class Cipher {
48 9 : Cipher._();
49 : Pointer<NativeType> getAlg(int keysize);
50 9 : FutureOr<Uint8List> encrypt(Uint8List input, Uint8List key, Uint8List iv) {
51 27 : final alg = getAlg(key.length * 8);
52 : final mem = malloc
53 54 : .call<Uint8>(sizeOf<IntPtr>() + key.length + iv.length + input.length);
54 9 : final lenMem = mem.cast<IntPtr>();
55 9 : final keyMem = mem.elementAt(sizeOf<IntPtr>());
56 18 : final ivMem = keyMem.elementAt(key.length);
57 18 : final dataMem = ivMem.elementAt(iv.length);
58 : try {
59 27 : keyMem.asTypedList(key.length).setAll(0, key);
60 27 : ivMem.asTypedList(iv.length).setAll(0, iv);
61 27 : dataMem.asTypedList(input.length).setAll(0, input);
62 18 : final ctx = EVP_CIPHER_CTX_new();
63 27 : EVP_EncryptInit_ex(ctx, alg, nullptr, keyMem, ivMem);
64 27 : EVP_EncryptUpdate(ctx, dataMem, lenMem, dataMem, input.length);
65 27 : EVP_EncryptFinal_ex(ctx, dataMem.elementAt(lenMem.value), lenMem);
66 18 : EVP_CIPHER_CTX_free(ctx);
67 27 : return Uint8List.fromList(dataMem.asTypedList(input.length));
68 : } finally {
69 9 : malloc.free(mem);
70 : }
71 : }
72 : }
73 :
74 27 : final Cipher aesCtr = _AesCtr();
75 :
76 : class _AesCtr extends Cipher {
77 18 : _AesCtr() : super._();
78 :
79 9 : @override
80 : Pointer<NativeType> getAlg(int keysize) {
81 : switch (keysize) {
82 9 : case 128:
83 0 : return EVP_aes_128_ctr();
84 9 : case 256:
85 18 : return EVP_aes_256_ctr();
86 : default:
87 0 : throw ArgumentError('invalid key size');
88 : }
89 : }
90 : }
91 :
92 2 : FutureOr<Uint8List> pbkdf2(
93 : Uint8List passphrase,
94 : Uint8List salt,
95 : Hash hash,
96 : int iterations,
97 : int bits,
98 : ) {
99 2 : final outLen = bits ~/ 8;
100 8 : final mem = malloc.call<Uint8>(passphrase.length + salt.length + outLen);
101 4 : final saltMem = mem.elementAt(passphrase.length);
102 4 : final outMem = saltMem.elementAt(salt.length);
103 : try {
104 6 : mem.asTypedList(passphrase.length).setAll(0, passphrase);
105 6 : saltMem.asTypedList(salt.length).setAll(0, salt);
106 4 : PKCS5_PBKDF2_HMAC(
107 : mem,
108 2 : passphrase.length,
109 : saltMem,
110 2 : salt.length,
111 : iterations,
112 2 : hash.ptr,
113 : outLen,
114 : outMem,
115 : );
116 4 : return Uint8List.fromList(outMem.asTypedList(outLen));
117 : } finally {
118 2 : malloc.free(mem);
119 : }
120 : }
|