5 changed files with 199 additions and 173 deletions
			
			
		@ -1,175 +1,5 @@
					 | 
				
			||||
library argon2_ffi_base; | 
				
			||||
 | 
				
			||||
import 'dart:convert'; | 
				
			||||
import 'dart:ffi'; | 
				
			||||
import 'dart:io'; | 
				
			||||
import 'dart:typed_data'; | 
				
			||||
 | 
				
			||||
import 'package:ffi/ffi.dart'; | 
				
			||||
 | 
				
			||||
// ignore_for_file: non_constant_identifier_names, | 
				
			||||
 | 
				
			||||
import 'package:logging/logging.dart'; | 
				
			||||
 | 
				
			||||
final _logger = Logger('argon2_ffi_base'); | 
				
			||||
 | 
				
			||||
typedef Argon2HashNative = Pointer<Utf8> Function( | 
				
			||||
  Pointer<Uint8> key, | 
				
			||||
  Uint32 keyLen, | 
				
			||||
  Pointer<Uint8> salt, | 
				
			||||
  Uint32 saltlen, | 
				
			||||
  Uint32 m_cost, // memory cost | 
				
			||||
  Uint32 t_cost, // time cost (number iterations) | 
				
			||||
  Uint32 parallelism, | 
				
			||||
  IntPtr hashlen, | 
				
			||||
  Uint8 type, | 
				
			||||
  Uint32 version, | 
				
			||||
); | 
				
			||||
 | 
				
			||||
typedef Argon2Hash = Pointer<Utf8> Function( | 
				
			||||
  Pointer<Uint8> key, | 
				
			||||
  int keyLen, | 
				
			||||
  Pointer<Uint8> salt, | 
				
			||||
  int saltlen, | 
				
			||||
  int m_cost, // memory cost | 
				
			||||
  int t_cost, // time cost (number iterations) | 
				
			||||
  int parallelism, | 
				
			||||
  int hashlen, | 
				
			||||
  int type, | 
				
			||||
  int version, | 
				
			||||
); | 
				
			||||
 | 
				
			||||
typedef ResolveLibrary = String Function(String baseName); | 
				
			||||
 | 
				
			||||
class Argon2FfiFlutter extends Argon2Base { | 
				
			||||
  Argon2FfiFlutter({this.resolveLibrary}) { | 
				
			||||
    final argon2lib = _loadLib(); | 
				
			||||
    _nativeAdd = argon2lib | 
				
			||||
        .lookup<NativeFunction<Int32 Function(Int32, Int32)>>('native_add') | 
				
			||||
        .asFunction(); | 
				
			||||
    argon2hash = argon2lib | 
				
			||||
        .lookup<NativeFunction<Argon2HashNative>>('hp_argon2_hash') | 
				
			||||
        .asFunction(); | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  static ResolveLibrary defaultResolveLibrary = (name) => name; | 
				
			||||
 | 
				
			||||
  /// forces loading of dynamic library on MacOS instead of assuming | 
				
			||||
  /// argon2 was statically linked. (ie. flutter usage, vs dart usage) | 
				
			||||
  static bool resolveLibraryForceDynamic = false; | 
				
			||||
 | 
				
			||||
  final ResolveLibrary resolveLibrary; | 
				
			||||
 | 
				
			||||
  int Function(int x, int y) _nativeAdd; | 
				
			||||
  @override | 
				
			||||
  Argon2Hash argon2hash; | 
				
			||||
 | 
				
			||||
  int addIt(int x, int y) => _nativeAdd(x, y); | 
				
			||||
 | 
				
			||||
  DynamicLibrary _loadLib() { | 
				
			||||
    final resolveLibrary = this.resolveLibrary ?? defaultResolveLibrary; | 
				
			||||
 | 
				
			||||
    if (!resolveLibraryForceDynamic && (Platform.isIOS || Platform.isMacOS)) { | 
				
			||||
      return DynamicLibrary.executable(); | 
				
			||||
    } | 
				
			||||
    final libraryNames = [ | 
				
			||||
      [Platform.isAndroid, 'libargon2_ffi.so'], | 
				
			||||
      [Platform.isLinux, './libargon2_ffi_plugin.so'], | 
				
			||||
      [Platform.isWindows, 'argon2_ffi_plugin.dll'], | 
				
			||||
      [Platform.isMacOS, 'libargon2_ffi.dylib'], | 
				
			||||
      [Platform.isIOS, null], // only supports static linking. | 
				
			||||
    ]; | 
				
			||||
    final libraryName = libraryNames.firstWhere((element) => element[0] == true, | 
				
			||||
            orElse: () => throw StateError( | 
				
			||||
                'Unsupported Operating System ${Platform.operatingSystem}'))[1] | 
				
			||||
        as String; | 
				
			||||
    final path = resolveLibrary(libraryName); | 
				
			||||
    try { | 
				
			||||
      return DynamicLibrary.open(libraryName); | 
				
			||||
    } on ArgumentError catch (e, stackTrace) { | 
				
			||||
      _logger.severe( | 
				
			||||
          'Error while loading dynamic library from $path ($libraryName)', | 
				
			||||
          e, | 
				
			||||
          stackTrace); | 
				
			||||
      rethrow; | 
				
			||||
    } | 
				
			||||
  } | 
				
			||||
} | 
				
			||||
 | 
				
			||||
abstract class Argon2 { | 
				
			||||
  Uint8List argon2(Argon2Arguments args); | 
				
			||||
 | 
				
			||||
  Future<Uint8List> argon2Async(Argon2Arguments args); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
class Argon2Arguments { | 
				
			||||
  Argon2Arguments(this.key, this.salt, this.memory, this.iterations, | 
				
			||||
      this.length, this.parallelism, this.type, this.version); | 
				
			||||
 | 
				
			||||
  final Uint8List key; | 
				
			||||
  final Uint8List salt; | 
				
			||||
  final int memory; | 
				
			||||
  final int iterations; | 
				
			||||
  final int length; | 
				
			||||
  final int parallelism; | 
				
			||||
  final int type; | 
				
			||||
  final int version; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
abstract class Argon2Base extends Argon2 { | 
				
			||||
//  @protected | 
				
			||||
  Argon2Hash get argon2hash; | 
				
			||||
 | 
				
			||||
  @override | 
				
			||||
  Uint8List argon2(Argon2Arguments args) { | 
				
			||||
    final keyPtr = Uint8ArrayUtils.toPointer(args.key); | 
				
			||||
    final saltPtr = Uint8ArrayUtils.toPointer(args.salt); | 
				
			||||
//    final saltArray = allocate<Uint8>(count: args.salt.length); | 
				
			||||
//    final saltList = saltArray.asTypedList(args.length); | 
				
			||||
//    saltList.setAll(0, args.salt); | 
				
			||||
//    const memoryCost = 1 << 16; | 
				
			||||
 | 
				
			||||
//    _logger.fine('saltArray: ${ByteUtils.toHexList(saltArray.view)}'); | 
				
			||||
 | 
				
			||||
    final result = argon2hash( | 
				
			||||
      keyPtr, | 
				
			||||
      args.key.length, | 
				
			||||
      saltPtr, | 
				
			||||
      args.salt.length, | 
				
			||||
      args.memory, | 
				
			||||
      args.iterations, | 
				
			||||
      args.parallelism, | 
				
			||||
      args.length, | 
				
			||||
      args.type, | 
				
			||||
      args.version, | 
				
			||||
    ); | 
				
			||||
 | 
				
			||||
    free(keyPtr); | 
				
			||||
    free(saltPtr); | 
				
			||||
//    free(saltArray); | 
				
			||||
    final resultString = Utf8.fromUtf8(result); | 
				
			||||
    return base64.decode(resultString); | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  @override | 
				
			||||
  Future<Uint8List> argon2Async(Argon2Arguments args) async { | 
				
			||||
    return argon2(args); | 
				
			||||
  } | 
				
			||||
} | 
				
			||||
 | 
				
			||||
// from https://github.com/hanabi1224/flutter_native_extensions/blob/master/src/compression/dart_native_compression/lib/utils/uint8_list_utils.dart | 
				
			||||
class Uint8ArrayUtils { | 
				
			||||
  static Uint8List fromPointer(Pointer<Uint8> ptr, int length) { | 
				
			||||
    final view = ptr.asTypedList(length); | 
				
			||||
    final builder = BytesBuilder(copy: false); | 
				
			||||
    builder.add(view); | 
				
			||||
    return builder.takeBytes(); | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  static Pointer<Uint8> toPointer(Uint8List bytes) { | 
				
			||||
    final ptr = allocate<Uint8>(count: bytes.length); | 
				
			||||
    final byteList = ptr.asTypedList(bytes.length); | 
				
			||||
    byteList.setAll(0, bytes); | 
				
			||||
    return ptr.cast(); | 
				
			||||
  } | 
				
			||||
} | 
				
			||||
export 'package:argon2_ffi_base/src/argon2_ffi_base.dart'; | 
				
			||||
export 'package:argon2_ffi_base/src/argon2_ffi_noop.dart' | 
				
			||||
    if (dart.library.io) 'package:argon2_ffi_base/src/argon2_ffi_impl.dart'; | 
				
			||||
					 | 
				
			||||
@ -0,0 +1,21 @@
					 | 
				
			||||
import 'dart:typed_data'; | 
				
			||||
 | 
				
			||||
abstract class Argon2 { | 
				
			||||
  Uint8List argon2(Argon2Arguments args); | 
				
			||||
 | 
				
			||||
  Future<Uint8List> argon2Async(Argon2Arguments args); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
class Argon2Arguments { | 
				
			||||
  Argon2Arguments(this.key, this.salt, this.memory, this.iterations, | 
				
			||||
      this.length, this.parallelism, this.type, this.version); | 
				
			||||
 | 
				
			||||
  final Uint8List key; | 
				
			||||
  final Uint8List salt; | 
				
			||||
  final int memory; | 
				
			||||
  final int iterations; | 
				
			||||
  final int length; | 
				
			||||
  final int parallelism; | 
				
			||||
  final int type; | 
				
			||||
  final int version; | 
				
			||||
} | 
				
			||||
@ -0,0 +1,137 @@
					 | 
				
			||||
import 'dart:convert'; | 
				
			||||
import 'dart:ffi'; | 
				
			||||
import 'dart:io'; | 
				
			||||
import 'dart:typed_data'; | 
				
			||||
 | 
				
			||||
import 'package:argon2_ffi_base/src/argon2_ffi_base.dart'; | 
				
			||||
import 'package:argon2_ffi_base/src/utils.dart'; | 
				
			||||
import 'package:ffi/ffi.dart'; | 
				
			||||
import 'package:logging/logging.dart'; | 
				
			||||
 | 
				
			||||
final _logger = Logger('argon2_ffi_base'); | 
				
			||||
 | 
				
			||||
// ignore_for_file: non_constant_identifier_names, | 
				
			||||
 | 
				
			||||
typedef Argon2HashNative = Pointer<Utf8> Function( | 
				
			||||
  Pointer<Uint8> key, | 
				
			||||
  Uint32 keyLen, | 
				
			||||
  Pointer<Uint8> salt, | 
				
			||||
  Uint32 saltlen, | 
				
			||||
  Uint32 m_cost, // memory cost | 
				
			||||
  Uint32 t_cost, // time cost (number iterations) | 
				
			||||
  Uint32 parallelism, | 
				
			||||
  IntPtr hashlen, | 
				
			||||
  Uint8 type, | 
				
			||||
  Uint32 version, | 
				
			||||
); | 
				
			||||
 | 
				
			||||
typedef Argon2Hash = Pointer<Utf8> Function( | 
				
			||||
  Pointer<Uint8> key, | 
				
			||||
  int keyLen, | 
				
			||||
  Pointer<Uint8> salt, | 
				
			||||
  int saltlen, | 
				
			||||
  int m_cost, // memory cost | 
				
			||||
  int t_cost, // time cost (number iterations) | 
				
			||||
  int parallelism, | 
				
			||||
  int hashlen, | 
				
			||||
  int type, | 
				
			||||
  int version, | 
				
			||||
); | 
				
			||||
 | 
				
			||||
typedef ResolveLibrary = String Function(String baseName); | 
				
			||||
 | 
				
			||||
abstract class Argon2Base extends Argon2 { | 
				
			||||
//  @protected | 
				
			||||
  Argon2Hash get argon2hash; | 
				
			||||
 | 
				
			||||
  @override | 
				
			||||
  Uint8List argon2(Argon2Arguments args) { | 
				
			||||
    final keyPtr = Uint8ArrayUtils.toPointer(args.key); | 
				
			||||
    final saltPtr = Uint8ArrayUtils.toPointer(args.salt); | 
				
			||||
//    final saltArray = allocate<Uint8>(count: args.salt.length); | 
				
			||||
//    final saltList = saltArray.asTypedList(args.length); | 
				
			||||
//    saltList.setAll(0, args.salt); | 
				
			||||
//    const memoryCost = 1 << 16; | 
				
			||||
 | 
				
			||||
//    _logger.fine('saltArray: ${ByteUtils.toHexList(saltArray.view)}'); | 
				
			||||
 | 
				
			||||
    final result = argon2hash( | 
				
			||||
      keyPtr, | 
				
			||||
      args.key.length, | 
				
			||||
      saltPtr, | 
				
			||||
      args.salt.length, | 
				
			||||
      args.memory, | 
				
			||||
      args.iterations, | 
				
			||||
      args.parallelism, | 
				
			||||
      args.length, | 
				
			||||
      args.type, | 
				
			||||
      args.version, | 
				
			||||
    ); | 
				
			||||
 | 
				
			||||
    free(keyPtr); | 
				
			||||
    free(saltPtr); | 
				
			||||
//    free(saltArray); | 
				
			||||
    final resultString = Utf8.fromUtf8(result); | 
				
			||||
    return base64.decode(resultString); | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  @override | 
				
			||||
  Future<Uint8List> argon2Async(Argon2Arguments args) async { | 
				
			||||
    return argon2(args); | 
				
			||||
  } | 
				
			||||
} | 
				
			||||
 | 
				
			||||
class Argon2FfiFlutter extends Argon2Base { | 
				
			||||
  Argon2FfiFlutter({this.resolveLibrary}) { | 
				
			||||
    final argon2lib = _loadLib(); | 
				
			||||
    _nativeAdd = argon2lib | 
				
			||||
        .lookup<NativeFunction<Int32 Function(Int32, Int32)>>('native_add') | 
				
			||||
        .asFunction(); | 
				
			||||
    argon2hash = argon2lib | 
				
			||||
        .lookup<NativeFunction<Argon2HashNative>>('hp_argon2_hash') | 
				
			||||
        .asFunction(); | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  static ResolveLibrary defaultResolveLibrary = (name) => name; | 
				
			||||
 | 
				
			||||
  /// forces loading of dynamic library on MacOS instead of assuming | 
				
			||||
  /// argon2 was statically linked. (ie. flutter usage, vs dart usage) | 
				
			||||
  static bool resolveLibraryForceDynamic = false; | 
				
			||||
 | 
				
			||||
  final ResolveLibrary resolveLibrary; | 
				
			||||
 | 
				
			||||
  int Function(int x, int y) _nativeAdd; | 
				
			||||
  @override | 
				
			||||
  Argon2Hash argon2hash; | 
				
			||||
 | 
				
			||||
  int addIt(int x, int y) => _nativeAdd(x, y); | 
				
			||||
 | 
				
			||||
  DynamicLibrary _loadLib() { | 
				
			||||
    final resolveLibrary = this.resolveLibrary ?? defaultResolveLibrary; | 
				
			||||
 | 
				
			||||
    if (!resolveLibraryForceDynamic && (Platform.isIOS || Platform.isMacOS)) { | 
				
			||||
      return DynamicLibrary.executable(); | 
				
			||||
    } | 
				
			||||
    final libraryNames = [ | 
				
			||||
      [Platform.isAndroid, 'libargon2_ffi.so'], | 
				
			||||
      [Platform.isLinux, './libargon2_ffi_plugin.so'], | 
				
			||||
      [Platform.isWindows, 'argon2_ffi_plugin.dll'], | 
				
			||||
      [Platform.isMacOS, 'libargon2_ffi.dylib'], | 
				
			||||
      [Platform.isIOS, null], // only supports static linking. | 
				
			||||
    ]; | 
				
			||||
    final libraryName = libraryNames.firstWhere((element) => element[0] == true, | 
				
			||||
            orElse: () => throw StateError( | 
				
			||||
                'Unsupported Operating System ${Platform.operatingSystem}'))[1] | 
				
			||||
        as String; | 
				
			||||
    final path = resolveLibrary(libraryName); | 
				
			||||
    try { | 
				
			||||
      return DynamicLibrary.open(libraryName); | 
				
			||||
    } on ArgumentError catch (e, stackTrace) { | 
				
			||||
      _logger.severe( | 
				
			||||
          'Error while loading dynamic library from $path ($libraryName)', | 
				
			||||
          e, | 
				
			||||
          stackTrace); | 
				
			||||
      rethrow; | 
				
			||||
    } | 
				
			||||
  } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,15 @@
					 | 
				
			||||
import 'dart:typed_data'; | 
				
			||||
 | 
				
			||||
import 'package:argon2_ffi_base/src/argon2_ffi_base.dart'; | 
				
			||||
 | 
				
			||||
class Argon2FfiFlutter extends Argon2 { | 
				
			||||
  @override | 
				
			||||
  Uint8List argon2(Argon2Arguments args) { | 
				
			||||
    throw UnimplementedError(); | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  @override | 
				
			||||
  Future<Uint8List> argon2Async(Argon2Arguments args) { | 
				
			||||
    throw UnimplementedError(); | 
				
			||||
  } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,23 @@
					 | 
				
			||||
// from https://github.com/hanabi1224/flutter_native_extensions/blob/master/src/compression/dart_native_compression/lib/utils/uint8_list_utils.dart | 
				
			||||
import 'dart:ffi'; | 
				
			||||
import 'dart:io'; | 
				
			||||
 | 
				
			||||
import 'dart:typed_data'; | 
				
			||||
 | 
				
			||||
import 'package:ffi/ffi.dart'; | 
				
			||||
 | 
				
			||||
class Uint8ArrayUtils { | 
				
			||||
  static Uint8List fromPointer(Pointer<Uint8> ptr, int length) { | 
				
			||||
    final view = ptr.asTypedList(length); | 
				
			||||
    final builder = BytesBuilder(copy: false); | 
				
			||||
    builder.add(view); | 
				
			||||
    return builder.takeBytes(); | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  static Pointer<Uint8> toPointer(Uint8List bytes) { | 
				
			||||
    final ptr = allocate<Uint8>(count: bytes.length); | 
				
			||||
    final byteList = ptr.asTypedList(bytes.length); | 
				
			||||
    byteList.setAll(0, bytes); | 
				
			||||
    return ptr.cast(); | 
				
			||||
  } | 
				
			||||
} | 
				
			||||
					Loading…
					
					
				
		Reference in new issue