gpt4 book ai didi

.net - 是否有关于如何在 .NET 应用程序中实现 Google Authenticator 的教程?

转载 作者:行者123 更新时间:2023-12-02 05:02:38 26 4
gpt4 key购买 nike

我正在寻找有关如何使用 Google Authenticator 的教程在 .NET 应用程序中。这是否存在,如果存在,我在哪里可以找到它?

据我了解,这可用于向您自己的应用程序添加双因素身份验证。

最佳答案

在使用 Google Authenticator 时,我遇到了这个问题,特别是 Espo 贡献的代码。我个人对从 Java 到 C# 的转换并不满意,所以我想分享我的版本。除了大量重构代码之外:

  • 引入了对小端字节顺序的检查,并根据需要转换为大端字节序。
  • 引入了 HMAC key 的参数。

有关配置 URL 格式的更多信息,另请参阅:https://github.com/google/google-authenticator/wiki/Key-Uri-Format

如果您愿意,请随意使用,感谢 Espo 所做的初始工作。

using System;
using System.Globalization;
using System.Net;
using System.Security.Cryptography;
using System.Text;

public class GoogleAuthenticator
{
const int IntervalLength = 30;
const int PinLength = 6;
static readonly int PinModulo = (int)Math.Pow(10, PinLength);
static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);

/// <summary>
/// Number of intervals that have elapsed.
/// </summary>
static long CurrentInterval
{
get
{
var ElapsedSeconds = (long)Math.Floor((DateTime.UtcNow - UnixEpoch).TotalSeconds);

return ElapsedSeconds/IntervalLength;
}
}

/// <summary>
/// Generates a QR code bitmap for provisioning.
/// </summary>
public byte[] GenerateProvisioningImage(string identifier, byte[] key, int width, int height)
{
var KeyString = Encoder.Base32Encode(key);
var ProvisionUrl = Encoder.UrlEncode(string.Format("otpauth://totp/{0}?secret={1}&issuer=MyCompany", identifier, KeyString));

var ChartUrl = string.Format("https://chart.apis.google.com/chart?cht=qr&chs={0}x{1}&chl={2}", width, height, ProvisionUrl);
using (var Client = new WebClient())
{
return Client.DownloadData(ChartUrl);
}
}

/// <summary>
/// Generates a pin for the given key.
/// </summary>
public string GeneratePin(byte[] key)
{
return GeneratePin(key, CurrentInterval);
}

/// <summary>
/// Generates a pin by hashing a key and counter.
/// </summary>
static string GeneratePin(byte[] key, long counter)
{
const int SizeOfInt32 = 4;

var CounterBytes = BitConverter.GetBytes(counter);

if (BitConverter.IsLittleEndian)
{
//spec requires bytes in big-endian order
Array.Reverse(CounterBytes);
}

var Hash = new HMACSHA1(key).ComputeHash(CounterBytes);
var Offset = Hash[Hash.Length - 1] & 0xF;

var SelectedBytes = new byte[SizeOfInt32];
Buffer.BlockCopy(Hash, Offset, SelectedBytes, 0, SizeOfInt32);

if (BitConverter.IsLittleEndian)
{
//spec interprets bytes in big-endian order
Array.Reverse(SelectedBytes);
}

var SelectedInteger = BitConverter.ToInt32(SelectedBytes, 0);

//remove the most significant bit for interoperability per spec
var TruncatedHash = SelectedInteger & 0x7FFFFFFF;

//generate number of digits for given pin length
var Pin = TruncatedHash%PinModulo;

return Pin.ToString(CultureInfo.InvariantCulture).PadLeft(PinLength, '0');
}

#region Nested type: Encoder

static class Encoder
{
/// <summary>
/// Url Encoding (with upper-case hexadecimal per OATH specification)
/// </summary>
public static string UrlEncode(string value)
{
const string UrlEncodeAlphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~";

var Builder = new StringBuilder();

for (var i = 0; i < value.Length; i++)
{
var Symbol = value[i];

if (UrlEncodeAlphabet.IndexOf(Symbol) != -1)
{
Builder.Append(Symbol);
}
else
{
Builder.Append('%');
Builder.Append(((int)Symbol).ToString("X2"));
}
}

return Builder.ToString();
}

/// <summary>
/// Base-32 Encoding
/// </summary>
public static string Base32Encode(byte[] data)
{
const int InByteSize = 8;
const int OutByteSize = 5;
const string Base32Alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";

int i = 0, index = 0;
var Builder = new StringBuilder((data.Length + 7)*InByteSize/OutByteSize);

while (i < data.Length)
{
int CurrentByte = data[i];
int Digit;

//Is the current digit going to span a byte boundary?
if (index > (InByteSize - OutByteSize))
{
int NextByte;

if ((i + 1) < data.Length)
{
NextByte = data[i + 1];
}
else
{
NextByte = 0;
}

Digit = CurrentByte & (0xFF >> index);
index = (index + OutByteSize)%InByteSize;
Digit <<= index;
Digit |= NextByte >> (InByteSize - index);
i++;
}
else
{
Digit = (CurrentByte >> (InByteSize - (index + OutByteSize))) & 0x1F;
index = (index + OutByteSize)%InByteSize;

if (index == 0)
{
i++;
}
}

Builder.Append(Base32Alphabet[Digit]);
}

return Builder.ToString();
}
}

#endregion
}

关于.net - 是否有关于如何在 .NET 应用程序中实现 Google Authenticator 的教程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6421950/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com