mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2024-12-23 20:19:25 +00:00
43e062d1ac
* CW-263-TOTP-2FA-in-security-settings WIP * Implement TOTP 2FA WIP * Implement TOTP 2FA Authentication * chore: Remove unneeded formatting * revert formatting * fixes * CW-263-TOTP-2FA-in-security-settings WIP * Setup TOTP Complete, left with Modify TOTF * CW-263-TOTP-2FA-in-security-settings * CW-263-TOTP-2FA-in-security-settings * CW-263-TOTP-2FA-in-security-settings * fix: Add copy-to-clipboard for qr secret key * fix: Translation * chore: Move strings into translation files * feat: End to end flow for TOTP * hotfix: Switch totp to use sha512 * Update strings; 8 digits and error explanation * fix: Totp 2fa implementation feedback * hotfix: same action for button and alert close * feat: App should show both normal and totp auths when totp is enabled * hotfix: prevent barrier from dismissing * fix: Changes requested during PR review * - Minor Enhancements - Minor UI fixes --------- Co-authored-by: Justin Ehrenhofer <justin.ehrenhofer@gmail.com> Co-authored-by: OmarHatem <omarh.ismail1@gmail.com>
83 lines
2.3 KiB
Dart
83 lines
2.3 KiB
Dart
import 'dart:math';
|
|
import 'package:base32/base32.dart';
|
|
import 'package:crypto/crypto.dart';
|
|
|
|
import 'package:flutter/foundation.dart';
|
|
|
|
//*========================== TOTP 2FA Related Utilities ==========================================
|
|
|
|
String generateRandomBase32SecretKey(int byteLength) {
|
|
final Random _secureRandom = Random.secure();
|
|
// Generate random bytes
|
|
final randomBytes = Uint8List.fromList(
|
|
List<int>.generate(byteLength, (i) => _secureRandom.nextInt(256)),
|
|
);
|
|
|
|
// Encode bytes to base32
|
|
final base32SecretKey = base32.encode(randomBytes);
|
|
|
|
return base32SecretKey;
|
|
}
|
|
|
|
String generateOTP({required String secretKey, required int input}) {
|
|
/// base32 decode the secret
|
|
var hmacKey = base32.decode(secretKey);
|
|
|
|
/// initial the HMAC-SHA1 object
|
|
var hmacSha = Hmac(sha512, hmacKey);
|
|
|
|
/// get hmac answer
|
|
var hmac = hmacSha.convert(intToBytelist(input: input)).bytes;
|
|
|
|
/// calculate the init offset
|
|
int offset = hmac[hmac.length - 1] & 0xf;
|
|
|
|
/// calculate the code
|
|
int code = ((hmac[offset] & 0x7f) << 24 |
|
|
(hmac[offset + 1] & 0xff) << 16 |
|
|
(hmac[offset + 2] & 0xff) << 8 |
|
|
(hmac[offset + 3] & 0xff));
|
|
|
|
/// get the initial string code
|
|
var strCode = (code % pow(10, 8)).toString();
|
|
strCode = strCode.padLeft(8, '0');
|
|
|
|
return strCode;
|
|
}
|
|
|
|
List<int> intToBytelist({required int input, int padding = 8}) {
|
|
List<int> _result = [];
|
|
var _input = input;
|
|
while (_input != 0) {
|
|
_result.add(_input & 0xff);
|
|
_input >>= padding;
|
|
}
|
|
_result.addAll(List<int>.generate(padding, (_) => 0));
|
|
_result = _result.sublist(0, padding);
|
|
_result = _result.reversed.toList();
|
|
return _result;
|
|
}
|
|
|
|
String totpNow(String secretKey) {
|
|
int _formatTime = timeFormat(time: DateTime.now());
|
|
return generateOTP(input: _formatTime, secretKey: secretKey);
|
|
}
|
|
|
|
int timeFormat({required DateTime time}) {
|
|
final _timeStr = time.millisecondsSinceEpoch.toString();
|
|
final _formatTime = _timeStr.substring(0, _timeStr.length - 3);
|
|
|
|
return int.parse(_formatTime) ~/ 30;
|
|
}
|
|
|
|
bool verify({String? otp, DateTime? time, required String secretKey}) {
|
|
if (otp == null) {
|
|
return false;
|
|
}
|
|
|
|
var _time = time ?? DateTime.now();
|
|
var _input = timeFormat(time: _time);
|
|
|
|
String otpTime = generateOTP(input: _input, secretKey: secretKey);
|
|
return otp == otpTime;
|
|
}
|