keyUtils.dart 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. import 'dart:convert';
  2. import 'dart:typed_data';
  3. import 'dart:math';
  4. import 'package:pointycastle/pointycastle.dart';
  5. import 'package:pointycastle/key_derivators/pbkdf2.dart';
  6. import 'package:pointycastle/digests/sha256.dart';
  7. import 'package:pointycastle/macs/hmac.dart';
  8. // 随机字符串
  9. String randomString(int len) {
  10. if (len <= 0) {
  11. len = 16;
  12. }
  13. // 安全字符集(去掉Base64中的特殊字符 + / =)
  14. const charset = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-';
  15. final random = Random.secure();
  16. final result = StringBuffer();
  17. for (int i = 0; i < len; i++) {
  18. final index = random.nextInt(charset.length);
  19. result.write(charset[index]);
  20. }
  21. return result.toString();
  22. }
  23. String randomStringEx(int len, {
  24. final bool includeLowercase = true,
  25. final bool includeUppercase = true,
  26. final bool includeDigits = true,
  27. final bool includeSpecialChars = true,
  28. final String? customCharset,
  29. }) {
  30. if (len <= 0) {
  31. len = 16;
  32. }
  33. String? charset;
  34. if (customCharset != null) {
  35. charset = customCharset;
  36. } else {
  37. final buffer = StringBuffer();
  38. if (includeLowercase) buffer.write('abcdefghijklmnopqrstuvwxyz');
  39. if (includeUppercase) buffer.write('ABCDEFGHIJKLMNOPQRSTUVWXYZ');
  40. if (includeDigits) buffer.write('0123456789');
  41. if (includeSpecialChars) buffer.write('_-');
  42. charset = buffer.toString();
  43. }
  44. if (charset.isEmpty) {
  45. throw StateError('empty charset');
  46. }
  47. final random = Random.secure();
  48. final result = StringBuffer();
  49. for (int i = 0; i < len; i++) {
  50. final index = random.nextInt(charset.length);
  51. result.write(charset[index]);
  52. }
  53. return result.toString();
  54. }
  55. /// password to PBKDF2 password
  56. String passwordWithPBKDF2({
  57. required String password,
  58. required String salt,
  59. int iterations = 100000,
  60. int keyLength = 32,
  61. }) {
  62. final seed = utf8.encode(password);
  63. final saltBytes = utf8.encode(salt);
  64. // 1. 初始化 PBKDF2 派生器(HMAC-SHA256 作为伪随机函数)
  65. final pbkdf2 = PBKDF2KeyDerivator(
  66. HMac(SHA256Digest(), 64), // HMAC-SHA256,64字节块大小
  67. );
  68. // 2. 设置参数:盐值 + 迭代次数 + 密钥长度(AES-256 需要 32 字节)
  69. final params = Pbkdf2Parameters(
  70. saltBytes,
  71. iterations, // 迭代次数(越高越安全,建议 10万+)
  72. keyLength, // 输出密钥长度(32字节 = 256位,适配 AES-256)
  73. );
  74. pbkdf2.init(params);
  75. // 3. 派生密钥(返回 32 字节的 AES-256 密钥)
  76. final keyBytes = pbkdf2.process(seed);
  77. return base64Encode(keyBytes);
  78. }
  79. Uint8List randomKeyList({int length = 32}) {
  80. if (![16, 24, 32].contains(length)) {
  81. throw ArgumentError('Key length must be 16, 24 or 32 byte');
  82. }
  83. final secureRandom = SecureRandom('Fortuna');
  84. secureRandom.seed(KeyParameter(Uint8List.fromList(
  85. List.generate(length, (_) => DateTime.now().microsecond))));
  86. return secureRandom.nextBytes(length);
  87. }
  88. //
  89. // /// ---------- 使用 HMAC-SHA256 实现 PBKDF2 ----------
  90. // ///
  91. // /// - [password]: 用户密码(UTF-8 编码后的字节)
  92. // /// - [salt]: 盐(建议随机生成)
  93. // /// - [iterations]: 迭代次数(如 10000)
  94. // /// - [keyLength]: 派生密钥长度(字节,如 32 = 256 位)
  95. //
  96. // String generatePasswordWithPBKDF2({
  97. // required String password,
  98. // required String salt,
  99. // int iterations = 10000,
  100. // int keyLength = 32,
  101. // }) {
  102. // final key = base64.encode(pbkdf2HmacSha256(
  103. // password: utf8.encode(password),
  104. // salt: utf8.encode(salt),
  105. // iterations: iterations,
  106. // keyLength: keyLength,
  107. // ));
  108. // return key;
  109. // }
  110. //
  111. // Uint8List pbkdf2HmacSha256({
  112. // required Uint8List password,
  113. // required Uint8List salt,
  114. // int iterations = 100000,
  115. // int keyLength = 32,
  116. // }) {
  117. // if (iterations < 1) throw ArgumentError('Iterations must be >= 1');
  118. // if (keyLength <= 0) throw ArgumentError('Key length must be > 0');
  119. //
  120. // final List<int> derivedKey = [];
  121. // final int hLen = 32; // SHA-256 输出长度(字节)
  122. // final int l = (keyLength + hLen - 1) ~/ hLen; // 块数
  123. //
  124. // for (int i = 1; i <= l; i++) {
  125. // // T_i = F(Password, Salt, Iterations, i)
  126. // final blockSalt = _concat(salt, _encodeInt(i));
  127. // final Uint8List u = hmacSha256(password, blockSalt);
  128. // Uint8List t = u;
  129. //
  130. // for (int j = 1; j < iterations; j++) {
  131. // final Uint8List uNext = hmacSha256(password, u);
  132. // t = _xor(t, uNext);
  133. // u.setAll(0, uNext); // 更新 u 为 uNext
  134. // }
  135. //
  136. // derivedKey.addAll(t);
  137. // }
  138. //
  139. // return Uint8List.fromList(derivedKey.sublist(0, keyLength));
  140. // }
  141. //
  142. // // HMAC-SHA256 辅助函数
  143. // Uint8List hmacSha256(Uint8List key, Uint8List data) {
  144. // final hmac = Hmac(sha256, key);
  145. // final digest = hmac.convert(data);
  146. // return Uint8List.fromList(digest.bytes);
  147. // }
  148. //
  149. // // 将整数编码为大端 4 字节(符合 RFC 2898)
  150. // Uint8List _encodeInt(int i) {
  151. // return Uint8List.fromList([
  152. // (i >> 24) & 0xFF,
  153. // (i >> 16) & 0xFF,
  154. // (i >> 8) & 0xFF,
  155. // i & 0xFF,
  156. // ]);
  157. // }
  158. //
  159. // // 拼接两个 Uint8List
  160. // Uint8List _concat(Uint8List a, Uint8List b) {
  161. // final result = Uint8List(a.length + b.length);
  162. // result.setAll(0, a);
  163. // result.setAll(a.length, b);
  164. // return result;
  165. // }
  166. //
  167. // // 按字节异或两个等长 Uint8List
  168. // Uint8List _xor(Uint8List a, Uint8List b) {
  169. // if (a.length != b.length) {
  170. // throw ArgumentError('XOR requires equal-length inputs');
  171. // }
  172. // final result = Uint8List(a.length);
  173. // for (int i = 0; i < a.length; i++) {
  174. // result[i] = a[i] ^ b[i];
  175. // }
  176. // return result;
  177. // }