Now supports reading secretKey from the database to calculate totp。

But there are some known bugs that need to be resolved.
This commit is contained in:
Chenx221 2023-08-23 13:33:38 +08:00
parent a3b6fde6a6
commit a3beff62a0
6 changed files with 290 additions and 13 deletions

4
OTP/Form1.Designer.cs generated
View File

@ -46,6 +46,7 @@
this.listBox1.Name = "listBox1";
this.listBox1.Size = new System.Drawing.Size(473, 368);
this.listBox1.TabIndex = 0;
this.listBox1.SelectedIndexChanged += new System.EventHandler(this.listBox1_SelectedIndexChanged);
//
// label1
//
@ -61,6 +62,7 @@
//
// button1
//
this.button1.Enabled = false;
this.button1.Location = new System.Drawing.Point(556, 294);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(85, 23);
@ -171,6 +173,8 @@
this.Name = "Form1";
this.Text = "Main Window";
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Form1_FormClosing);
this.Load += new System.EventHandler(this.Form1_Load);
this.VisibleChanged += new System.EventHandler(this.Form1_VisibleChanged);
this.ResumeLayout(false);
this.PerformLayout();

View File

@ -8,6 +8,10 @@ using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using OtpNet;
using System.IO;
using System.Data.SQLite;
using System.Reflection;
using ZXing.QrCode.Internal;
namespace OTP
{
@ -16,18 +20,28 @@ namespace OTP
private byte[] secretKey;
private Totp totp;
private Timer timer;
private string connectionString = "Data Source=key.db;Version=3;";
private string embeddedDatabaseResource = "OTP.empty_key.db";
private int runonce=0;
public Form1()
{
InitializeComponent();
secretKey = Base32Encoding.ToBytes("JBSWY3DPEHPK3PXP"); // 示例的 base32 编码
totp = new Totp(secretKey);
//button1.Enabled = false;
//secretKey = Base32Encoding.ToBytes("JBSWY3DPEHPK3PXP"); // 示例的 base32 编码
//totp = new Totp(secretKey);
timer = new Timer();
timer.Interval = 1000; // 设置计时器间隔为 1 秒
timer.Tick += Timer_Tick;
}
public class TitleInfo
{
public int Id { get; set; }
public string Title { get; set; }
public string SecretKey { get; set; }
}
private void Timer_Tick(object sender, EventArgs e)
{
@ -55,16 +69,105 @@ namespace OTP
{
button1.Enabled = false; // 禁用生成按钮
button2.Enabled = true; // 启用复制按钮
GenerateAndDisplayTotp(); // 生成并显示 TOTP 密码
// 开始计时器
timer.Start();
if (totp != null)
{
GenerateAndDisplayTotp(); // 生成并显示 TOTP 密码
timer.Start();// 开始计时器
}
}
private void Form1_Load(object sender, EventArgs e)
{
button1.Enabled = true; // 在窗体加载时启用按钮
//button1.Enabled = true; // 在窗体加载时启用按钮
// 判断是否存在 key.db 数据库文件
if (!File.Exists("key.db"))
{
ExtractEmbeddedDatabase();
}
}
private void ExtractEmbeddedDatabase()
{
// 从嵌入的资源中复制数据库文件到同目录下
try
{
using (Stream resourceStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(embeddedDatabaseResource))
{
using (FileStream fileStream = new FileStream("key.db", FileMode.Create))
{
resourceStream.CopyTo(fileStream);
}
}
}
catch (Exception ex)
{
MessageBox.Show($"An error occurred while extracting embedded database: {ex.Message}");
}
}
private void LoadTitlesToListBox()
{
try
{
using (SQLiteConnection connection = new SQLiteConnection(connectionString))
{
connection.Open();
using (SQLiteCommand command = new SQLiteCommand("SELECT Id, Title, SecretKey FROM TotpData", connection))
{
using (SQLiteDataReader reader = command.ExecuteReader())
{
listBox1.Items.Clear(); // 清空现有数据
while (reader.Read())
{
int id = reader.GetInt32(0);
string title = reader.GetString(1);
string secretKey = reader.GetString(2);
TitleInfo titleInfo = new TitleInfo
{
Id = id,
Title = title,
SecretKey = secretKey
};
listBox1.Items.Add(titleInfo);
}
}
}
}
}
catch (Exception ex)
{
MessageBox.Show($"An error occurred while loading titles: {ex.Message}");
}
}
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (listBox1.SelectedIndex >= 0) // Ensure an item is selected
{
TitleInfo selectedTitleInfo = listBox1.SelectedItem as TitleInfo;
if (selectedTitleInfo != null)
{
if (runonce == 0)
{
button1.Enabled = true;
runonce++;
}
secretKey = Base32Encoding.ToBytes(selectedTitleInfo.SecretKey);
totp = new Totp(secretKey);
//string totpCode = totp.ComputeTotp();
//label1.Text = totpCode;
}
else
{
MessageBox.Show("Selected item is not of the expected type.");
}
}
}
private void button2_Click(object sender, EventArgs e)
{
@ -95,5 +198,21 @@ namespace OTP
// 如果用户选择 Yes什么都不需要做窗体会继续关闭
}
private void Form1_VisibleChanged(object sender, EventArgs e)
{
if (this.Visible) // 检查窗体是否可见
{
LoadTitlesToListBox();
runonce = 0;
label1.Text = "TOTP Code";
button1.Enabled = false;
button2.Enabled = false;
}
else
{
timer.Stop();
}
}
}
}

5
OTP/Form2.Designer.cs generated
View File

@ -81,6 +81,7 @@
this.button2.TabIndex = 2;
this.button2.Text = "Delete Record(s)";
this.button2.UseVisualStyleBackColor = true;
this.button2.Click += new System.EventHandler(this.button2_Click);
//
// button3
//
@ -90,6 +91,7 @@
this.button3.TabIndex = 3;
this.button3.Text = "Save Changes";
this.button3.UseVisualStyleBackColor = true;
this.button3.Click += new System.EventHandler(this.button3_Click);
//
// button4
//
@ -99,17 +101,20 @@
this.button4.TabIndex = 4;
this.button4.Text = "Discard Changes";
this.button4.UseVisualStyleBackColor = true;
this.button4.Click += new System.EventHandler(this.button4_Click);
//
// Form2
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(619, 367);
this.ControlBox = false;
this.Controls.Add(this.button4);
this.Controls.Add(this.button3);
this.Controls.Add(this.button2);
this.Controls.Add(this.button1);
this.Controls.Add(this.panel1);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.Name = "Form2";
this.Text = "Data Manage";
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Form2_FormClosing);

View File

@ -8,19 +8,82 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using System.Security.Cryptography;
namespace OTP
{
public partial class Form2 : Form
{
private string connectionString = "Data Source=key.db;Version=3;";
private string backupPath = "key.db.bak"; // 备份数据库文件的路径
private string sourceFileHash = ""; // 原始数据库文件的哈希值
public Form2()
{
InitializeComponent();
InitializeDataGridView();
// 获取原始数据库文件的哈希值
sourceFileHash = CalculateSHA256Hash("key.db");
// 备份数据库文件并判断完整性
bool backupSuccessful = BackupDatabase();
if (!backupSuccessful)
{
// 备份创建失败,禁用按钮并提示用户
button1.Enabled = false;
button2.Enabled = false;
button3.Enabled = false;
MessageBox.Show("Backup of data failed, modification is prohibited.", "Backup Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
LoadData();
}
private bool BackupDatabase()
{
try
{
if (File.Exists("key.db"))
{
// 备份数据库文件
File.Copy("key.db", backupPath, true);
// 计算备份文件的哈希值
string backupFileHash = CalculateSHA256Hash(backupPath);
// 比较原始文件和备份文件的哈希值
if (sourceFileHash == backupFileHash)
{
return true; // 备份创建成功且完整性通过
}
else
{
return false; // 备份创建成功但完整性未通过
}
}
else
{
return false; // 原始文件不存在,备份创建失败
}
}
catch (Exception)
{
return false; // 备份创建失败
}
}
// 计算文件的SHA-256哈希值
private string CalculateSHA256Hash(string filePath)
{
using (SHA256 sha256 = SHA256.Create())
{
using (FileStream stream = File.OpenRead(filePath))
{
byte[] hashBytes = sha256.ComputeHash(stream);
return BitConverter.ToString(hashBytes).Replace("-", "").ToLower();
}
}
}
private void InitializeDataGridView()
{
@ -34,19 +97,23 @@ namespace OTP
{
connection.Open();
using (SQLiteCommand command = new SQLiteCommand("SELECT Title FROM TotpData", connection))
using (SQLiteCommand command = new SQLiteCommand("SELECT Id, Title FROM TotpData", connection))
{
using (SQLiteDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
dataGridView1.Rows.Add(reader.GetString(0));
int id = reader.GetInt32(0);
string title = reader.GetString(1);
dataGridView1.Rows.Add(title);
dataGridView1.Rows[dataGridView1.Rows.Count - 1].Tag = id; // 将 Id 存储在行的 Tag 属性中
}
}
}
}
}
private void button1_Click(object sender, EventArgs e)
{
using (Form3 form3 = new Form3())
@ -70,6 +137,89 @@ namespace OTP
}
}
private void button2_Click(object sender, EventArgs e)
{
try
{
// 获取选中的行
foreach (DataGridViewRow selectedRow in dataGridView1.SelectedRows)
{
// 获取选中行的数据
int id = (int)selectedRow.Tag; // 从行的 Tag 属性获取 Id 值
// 执行删除数据库记录的操作
DeleteRecordFromDatabase(id);
// 从 DataGridView 中移除选中行
dataGridView1.Rows.Remove(selectedRow);
}
}
catch (Exception ex)
{
MessageBox.Show($"An error occurred while deleting the record: {ex.Message}");
}
}
private void DeleteRecordFromDatabase(int recordId)
{
try
{
using (SQLiteConnection connection = new SQLiteConnection(connectionString))
{
connection.Open();
using (SQLiteCommand command = new SQLiteCommand("DELETE FROM TotpData WHERE ID = @ID", connection))
{
command.Parameters.AddWithValue("@ID", recordId);
command.ExecuteNonQuery();
}
}
}
catch (Exception ex)
{
MessageBox.Show($"An error occurred while deleting the record: {ex.Message}");
}
}
private void button3_Click(object sender, EventArgs e)
{
// 删除备份文件
if (File.Exists(backupPath))
{
File.Delete(backupPath);
}
// 关闭当前的 Form2 实例,返回到 Form1
this.Close();
}
private void button4_Click(object sender, EventArgs e)
{
try
{
// 恢复备份文件
if (File.Exists(backupPath))
{
File.Copy(backupPath, "key.db", true);
// 删除备份文件
File.Delete(backupPath);
MessageBox.Show("The operation was successful.", "Undo Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
MessageBox.Show("No backup file found to undo changes.", "Undo Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
catch (Exception ex)
{
MessageBox.Show($"An error occurred while undoing changes: {ex.Message}", "Undo Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
// 关闭当前的 Form2 实例,返回到 Form1不进行保存操作
this.Close();
}
}
}

View File

@ -156,9 +156,8 @@
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<None Include="key.db">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<EmbeddedResource Include="empty_key.db" />
<None Include="key.db" />
<None Include="packages.config" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>

BIN
OTP/empty_key.db Normal file

Binary file not shown.