blob: 29eb84a98be5e62eca9f7d49cdcc1e89c2833f18 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
|
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace TwoStepsAuthenticator
{
public abstract class Authenticator
{
#if CORE
private static readonly RandomNumberGenerator Random = RandomNumberGenerator.Create();
#else
private static readonly RNGCryptoServiceProvider Random = new RNGCryptoServiceProvider();
#endif
private static readonly string AvailableKeyChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
public static string GenerateKey(int keyLength = 16) {
var keyChars = new char[keyLength];
for (int i = 0; i < keyChars.Length; i++) {
keyChars[i] = AvailableKeyChars[RandomInt(AvailableKeyChars.Length)];
}
return new String(keyChars);
}
protected string GetCodeInternal(string secret, ulong challengeValue) {
ulong chlg = challengeValue;
byte[] challenge = new byte[8];
for (int j = 7; j >= 0; j--) {
challenge[j] = (byte)((int)chlg & 0xff);
chlg >>= 8;
}
var key = Base32Encoding.ToBytes(secret);
for (int i = secret.Length; i < key.Length; i++) {
key[i] = 0;
}
HMACSHA1 mac = new HMACSHA1(key);
var hash = mac.ComputeHash(challenge);
int offset = hash[hash.Length - 1] & 0xf;
int truncatedHash = 0;
for (int j = 0; j < 4; j++) {
truncatedHash <<= 8;
truncatedHash |= hash[offset + j];
}
truncatedHash &= 0x7FFFFFFF;
truncatedHash %= 1000000;
string code = truncatedHash.ToString();
return code.PadLeft(6, '0');
}
protected bool ConstantTimeEquals(string a, string b) {
uint diff = (uint)a.Length ^ (uint)b.Length;
for (int i = 0; i < a.Length && i < b.Length; i++) {
diff |= (uint)a[i] ^ (uint)b[i];
}
return diff == 0;
}
protected static int RandomInt(int max) {
var randomBytes = new byte[4];
Random.GetBytes(randomBytes);
return Math.Abs((int)BitConverter.ToUInt32(randomBytes, 0) % max);
}
}
}
|