dev
dart 83 lines 2.27 KB
Raw
1 import 'dart:math';
2 import 'package:base32/base32.dart';
3 import 'package:crypto/crypto.dart';
4
5 import 'package:flutter/foundation.dart';
6
7 //*========================== TOTP 2FA Related Utilities ==========================================
8
9 String generateRandomBase32SecretKey(int byteLength) {
10 final Random _secureRandom = Random.secure();
11 // Generate random bytes
12 final randomBytes = Uint8List.fromList(
13 List<int>.generate(byteLength, (i) => _secureRandom.nextInt(256)),
14 );
15
16 // Encode bytes to base32
17 final base32SecretKey = base32.encode(randomBytes);
18
19 return base32SecretKey;
20 }
21
22 String generateOTP({required String secretKey, required int input}) {
23 /// base32 decode the secret
24 var hmacKey = base32.decode(secretKey);
25
26 /// initial the HMAC-SHA1 object
27 var hmacSha = Hmac(sha512, hmacKey);
28
29 /// get hmac answer
30 var hmac = hmacSha.convert(intToBytelist(input: input)).bytes;
31
32 /// calculate the init offset
33 int offset = hmac[hmac.length - 1] & 0xf;
34
35 /// calculate the code
36 int code = ((hmac[offset] & 0x7f) << 24 |
37 (hmac[offset + 1] & 0xff) << 16 |
38 (hmac[offset + 2] & 0xff) << 8 |
39 (hmac[offset + 3] & 0xff));
40
41 /// get the initial string code
42 var strCode = (code % pow(10, 8)).toString();
43 strCode = strCode.padLeft(8, '0');
44
45 return strCode;
46 }
47
48 List<int> intToBytelist({required int input, int padding = 8}) {
49 List<int> _result = [];
50 var _input = input;
51 while (_input != 0) {
52 _result.add(_input & 0xff);
53 _input >>= padding;
54 }
55 _result.addAll(List<int>.generate(padding, (_) => 0));
56 _result = _result.sublist(0, padding);
57 _result = _result.reversed.toList();
58 return _result;
59 }
60
61 String totpNow(String secretKey) {
62 int _formatTime = timeFormat(time: DateTime.now());
63 return generateOTP(input: _formatTime, secretKey: secretKey);
64 }
65
66 int timeFormat({required DateTime time}) {
67 final _timeStr = time.millisecondsSinceEpoch.toString();
68 final _formatTime = _timeStr.substring(0, _timeStr.length - 3);
69
70 return int.parse(_formatTime) ~/ 30;
71 }
72
73 bool verify({String? otp, DateTime? time, required String secretKey}) {
74 if (otp == null) {
75 return false;
76 }
77
78 var _time = time ?? DateTime.now();
79 var _input = timeFormat(time: _time);
80
81 String otpTime = generateOTP(input: _input, secretKey: secretKey);
82 return otp == otpTime;
83 }