代码源自 Microsoft.AspNet.Identity 程序集.
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 using System; 2 using System.Net; 3 using System.Security.Cryptography; 4 using System.Text; 5 6 namespace Authentication 7 { 8 internal static class Rfc6238AuthenticationService 9 { 10 private static readonly DateTime _unixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); 11 private static readonly TimeSpan _timestep = TimeSpan.FromMinutes(3.0); 12 private static readonly Encoding _encoding = new UTF8Encoding(false, true); 13 14 private static int ComputeTotp(HashAlgorithm hashAlgorithm, ulong timestepNumber, string modifier) 15 { 16 byte[] bytes = BitConverter.GetBytes(IPAddress.HostToNetworkOrder((long)timestepNumber)); 17 byte[] array = hashAlgorithm.ComputeHash(ApplyModifier(bytes, modifier)); 18 int num = (int)(array[array.Length - 1] & 15); 19 int num2 = (int)(array[num] & 127) << 24 | (int)(array[num + 1] & 255) << 16 | 20 (int)(array[num + 2] & 255) << 8 | (int)(array[num + 3] & 255); 21 return num2 % 1000000; 22 } 23 24 private static byte[] ApplyModifier(byte[] input, string modifier) 25 { 26 if (string.IsNullOrEmpty(modifier)) 27 { 28 return input; 29 } 30 byte[] bytes = _encoding.GetBytes(modifier); 31 byte[] array = new byte[checked(input.Length + bytes.Length)]; 32 Buffer.BlockCopy(input, 0, array, 0, input.Length); 33 Buffer.BlockCopy(bytes, 0, array, input.Length, bytes.Length); 34 return array; 35 } 36 37 private static ulong GetCurrentTimeStepNumber() 38 { 39 return 40 (ulong) 41 ((DateTime.UtcNow - _unixEpoch).Ticks / 42 _timestep.Ticks); 43 } 44 45 public static int GenerateCode(SecurityToken securityToken, string modifier = null) 46 { 47 if (securityToken == null) 48 { 49 throw new ArgumentNullException("securityToken"); 50 } 51 ulong currentTimeStepNumber = GetCurrentTimeStepNumber(); 52 int result; 53 using (HMACSHA1 hMACSHA = new HMACSHA1(securityToken.GetDataNoClone())) 54 { 55 result = ComputeTotp(hMACSHA, currentTimeStepNumber, modifier); 56 } 57 return result; 58 } 59 } 60 61 internal sealed class SecurityToken 62 { 63 private readonly byte[] _data; 64 public SecurityToken(byte[] data) 65 { 66 this._data = (byte[])data.Clone(); 67 } 68 internal byte[] GetDataNoClone() 69 { 70 return this._data; 71 } 72 } 73 }
var stampCode ="123";
var code = Rfc6238AuthenticationService.GenerateCode(new SecurityToken(Encoding.Unicode.GetBytes(stampCode)));
生成时需要更换种子 stampCode。