功能更新
This commit is contained in:
@@ -3,6 +3,7 @@ using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
using iNKORE.UI.WPF.Modern;
|
||||
|
||||
@@ -174,7 +175,7 @@ namespace KeyGen
|
||||
Message.Text = ($"导入文件私钥完成");
|
||||
}
|
||||
}
|
||||
private void Button_ToggleTheme_Click(object sender, RoutedEventArgs e)
|
||||
private void ToggleTheme_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (ThemeManager.Current.ApplicationTheme == ApplicationTheme.Dark)
|
||||
{
|
||||
@@ -185,5 +186,61 @@ namespace KeyGen
|
||||
ThemeManager.Current.ApplicationTheme = ApplicationTheme.Dark;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 生成通用的 6 位应急码
|
||||
/// </summary>
|
||||
/// <param name="durationTag">"1D", "7D", 或 "30D"</param>
|
||||
public static string GenerateGlobalOTP(string durationTag, string salt)
|
||||
{
|
||||
string secret = salt + durationTag;
|
||||
|
||||
// 计算天数步长
|
||||
long unixTime = (long)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds;
|
||||
long step = unixTime / 86400;
|
||||
|
||||
byte[] secretBytes = Encoding.UTF8.GetBytes(secret);
|
||||
// 字符表必须严格一致
|
||||
string charset = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
// 步长转 8 字节大端
|
||||
byte[] stepBytes = BitConverter.GetBytes(step);
|
||||
if (BitConverter.IsLittleEndian) Array.Reverse(stepBytes);
|
||||
byte[] msg = new byte[8];
|
||||
Array.Copy(stepBytes, 0, msg, 8 - stepBytes.Length, stepBytes.Length);
|
||||
|
||||
using (var hmac = new HMACSHA1(Encoding.UTF8.GetBytes(secret)))
|
||||
{
|
||||
byte[] hash = hmac.ComputeHash(msg);
|
||||
int offset = hash[hash.Length - 1] & 0xf;
|
||||
uint binary = (uint)(((hash[offset] & 0x7f) << 24) | ((hash[offset + 1] & 0xff) << 16) | ((hash[offset + 2] & 0xff) << 8) | (hash[offset + 3] & 0xff));
|
||||
|
||||
string code = "";
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
code += charset[(int)(binary % (uint)charset.Length)];
|
||||
binary /= (uint)charset.Length;
|
||||
}
|
||||
return code;
|
||||
}
|
||||
}
|
||||
|
||||
private void DynamicLicenseClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (DynamicDurationComboBox.SelectedItem is not ComboBoxItem selectedItem)
|
||||
{
|
||||
Message.Text = ("请选择授权时长");
|
||||
return;
|
||||
}
|
||||
if (string.IsNullOrEmpty(SaltTextBox.Text))
|
||||
{
|
||||
Message.Text = ("请设置Salt值");
|
||||
return;
|
||||
}
|
||||
string durationTag = selectedItem.Tag.ToString();
|
||||
string salt = SaltTextBox.Text.Trim();
|
||||
string globalOTP = GenerateGlobalOTP(durationTag, salt);
|
||||
DynamicLicenseTextBox.Text = globalOTP;
|
||||
Clipboard.SetText(globalOTP);
|
||||
Message.Text = "动态应急码已复制!";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user