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, Uint8List salt, Hash hash, int iterations, int bits) { 94 2 : final outLen = bits ~/ 8; 95 8 : final mem = malloc.call<Uint8>(passphrase.length + salt.length + outLen); 96 4 : final saltMem = mem.elementAt(passphrase.length); 97 4 : final outMem = saltMem.elementAt(salt.length); 98 : try { 99 6 : mem.asTypedList(passphrase.length).setAll(0, passphrase); 100 6 : saltMem.asTypedList(salt.length).setAll(0, salt); 101 8 : PKCS5_PBKDF2_HMAC(mem, passphrase.length, saltMem, salt.length, iterations, 102 2 : hash.ptr, outLen, outMem); 103 4 : return Uint8List.fromList(outMem.asTypedList(outLen)); 104 : } finally { 105 2 : malloc.free(mem); 106 : } 107 : }