diff --git a/FireWallet/FireWallet.csproj b/FireWallet/FireWallet.csproj
index 066fdc3..7e97c3b 100644
--- a/FireWallet/FireWallet.csproj
+++ b/FireWallet/FireWallet.csproj
@@ -30,6 +30,7 @@
+
diff --git a/FireWallet/MainForm.Designer.cs b/FireWallet/MainForm.Designer.cs
index 2e25f73..1a5dc20 100644
--- a/FireWallet/MainForm.Designer.cs
+++ b/FireWallet/MainForm.Designer.cs
@@ -95,6 +95,7 @@ namespace FireWallet
textBoxReceiveAddress = new TextBox();
labelReceive1 = new Label();
panelDomains = new Panel();
+ labelDomainSort = new Label();
comboBoxDomainSort = new ComboBox();
buttonExportDomains = new Button();
groupBoxDomains = new GroupBox();
@@ -103,6 +104,7 @@ namespace FireWallet
textBoxDomainSearch = new TextBox();
panelSettings = new Panel();
groupBoxSettingsWallet = new GroupBox();
+ buttonSettingsYubikey = new Button();
buttonSettingsRescan = new Button();
buttonSeed = new Button();
groupBoxSettingsMisc = new GroupBox();
@@ -123,7 +125,6 @@ namespace FireWallet
textBoxExAddr = new TextBox();
labelSettings4 = new Label();
textBoxExTX = new TextBox();
- labelDomainSort = new Label();
statusStripmain.SuspendLayout();
panelaccount.SuspendLayout();
groupBoxaccount.SuspendLayout();
@@ -241,7 +242,7 @@ namespace FireWallet
//
panelaccount.BackColor = Color.Transparent;
panelaccount.Controls.Add(groupBoxaccount);
- panelaccount.Location = new Point(1082, 211);
+ panelaccount.Location = new Point(132, 30);
panelaccount.Name = "panelaccount";
panelaccount.Size = new Size(1074, 642);
panelaccount.TabIndex = 1;
@@ -574,7 +575,7 @@ namespace FireWallet
panelSend.Controls.Add(labelSendingTo);
panelSend.Controls.Add(labelSendPrompt);
panelSend.Controls.Add(labelHIPArrow);
- panelSend.Location = new Point(138, 33);
+ panelSend.Location = new Point(880, 441);
panelSend.Name = "panelSend";
panelSend.Size = new Size(974, 521);
panelSend.TabIndex = 2;
@@ -792,12 +793,22 @@ namespace FireWallet
panelDomains.Controls.Add(groupBoxDomains);
panelDomains.Controls.Add(labelDomainSearch);
panelDomains.Controls.Add(textBoxDomainSearch);
- panelDomains.Location = new Point(120, 48);
+ panelDomains.Location = new Point(861, 364);
panelDomains.Name = "panelDomains";
panelDomains.Size = new Size(920, 536);
panelDomains.TabIndex = 18;
panelDomains.Visible = false;
//
+ // labelDomainSort
+ //
+ labelDomainSort.AutoSize = true;
+ labelDomainSort.Font = new Font("Segoe UI", 12F, FontStyle.Regular, GraphicsUnit.Point);
+ labelDomainSort.Location = new Point(638, 15);
+ labelDomainSort.Name = "labelDomainSort";
+ labelDomainSort.Size = new Size(42, 21);
+ labelDomainSort.TabIndex = 12;
+ labelDomainSort.Text = "Sort:";
+ //
// comboBoxDomainSort
//
comboBoxDomainSort.DropDownStyle = ComboBoxStyle.DropDownList;
@@ -871,7 +882,7 @@ namespace FireWallet
panelSettings.Controls.Add(buttonSettingsSave);
panelSettings.Controls.Add(groupBoxSettingsExplorer);
panelSettings.Font = new Font("Segoe UI", 12F, FontStyle.Regular, GraphicsUnit.Point);
- panelSettings.Location = new Point(1065, 51);
+ panelSettings.Location = new Point(848, 306);
panelSettings.Name = "panelSettings";
panelSettings.Size = new Size(930, 550);
panelSettings.TabIndex = 19;
@@ -879,6 +890,7 @@ namespace FireWallet
//
// groupBoxSettingsWallet
//
+ groupBoxSettingsWallet.Controls.Add(buttonSettingsYubikey);
groupBoxSettingsWallet.Controls.Add(buttonSettingsRescan);
groupBoxSettingsWallet.Controls.Add(buttonSeed);
groupBoxSettingsWallet.Location = new Point(507, 16);
@@ -888,6 +900,17 @@ namespace FireWallet
groupBoxSettingsWallet.TabStop = false;
groupBoxSettingsWallet.Text = "Wallet Controls";
//
+ // buttonSettingsYubikey
+ //
+ buttonSettingsYubikey.FlatStyle = FlatStyle.Flat;
+ buttonSettingsYubikey.Location = new Point(6, 133);
+ buttonSettingsYubikey.Name = "buttonSettingsYubikey";
+ buttonSettingsYubikey.Size = new Size(98, 50);
+ buttonSettingsYubikey.TabIndex = 9;
+ buttonSettingsYubikey.Text = "YubiKey";
+ buttonSettingsYubikey.UseVisualStyleBackColor = true;
+ buttonSettingsYubikey.Click += buttonSettingsYubikey_Click;
+ //
// buttonSettingsRescan
//
buttonSettingsRescan.FlatStyle = FlatStyle.Flat;
@@ -1081,25 +1104,15 @@ namespace FireWallet
textBoxExTX.Size = new Size(307, 29);
textBoxExTX.TabIndex = 1;
//
- // labelDomainSort
- //
- labelDomainSort.AutoSize = true;
- labelDomainSort.Font = new Font("Segoe UI", 12F, FontStyle.Regular, GraphicsUnit.Point);
- labelDomainSort.Location = new Point(638, 15);
- labelDomainSort.Name = "labelDomainSort";
- labelDomainSort.Size = new Size(42, 21);
- labelDomainSort.TabIndex = 12;
- labelDomainSort.Text = "Sort:";
- //
// MainForm
//
AutoScaleDimensions = new SizeF(7F, 15F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(1152, 575);
+ Controls.Add(panelaccount);
+ Controls.Add(panelSettings);
Controls.Add(panelDomains);
Controls.Add(panelSend);
- Controls.Add(panelSettings);
- Controls.Add(panelaccount);
Controls.Add(panelPortfolio);
Controls.Add(panelRecieve);
Controls.Add(panelNav);
@@ -1234,5 +1247,6 @@ namespace FireWallet
private Label labelSendingHIPAddress;
private ComboBox comboBoxDomainSort;
private Label labelDomainSort;
+ private Button buttonSettingsYubikey;
}
}
\ No newline at end of file
diff --git a/FireWallet/MainForm.cs b/FireWallet/MainForm.cs
index 67188fa..0bef43a 100644
--- a/FireWallet/MainForm.cs
+++ b/FireWallet/MainForm.cs
@@ -7,13 +7,14 @@ using QRCoder;
using System.Text.RegularExpressions;
using System.Security.Cryptography;
using System.Text;
-using System.Security.Policy;
-using System.Windows.Forms;
using System.Net;
using DnsClient;
using DnsClient.Protocol;
using System.Security.Cryptography.X509Certificates;
using System.Net.Security;
+// Used to use Yubikey to login
+using Yubico.YubiKey;
+using Yubico.YubiKey.Piv;
namespace FireWallet
{
@@ -700,7 +701,27 @@ namespace FireWallet
}
account = comboBoxaccount.Text;
- password = textBoxaccountpassword.Text;
+
+ if (textBoxaccountpassword.Text == "")
+ {
+ if (File.Exists(dir + account + ".yubikey"))
+ {
+ // Check if yubikey is plugged in
+ var devices = YubiKeyDevice.FindAll();
+ if (devices.Count() > 0)
+ {
+ // Get key from yubikey
+ password = YubiUnlock();
+ }
+
+ }
+
+ } else password = textBoxaccountpassword.Text;
+
+
+
+
+
bool loggedin = await Login();
if (loggedin)
{
@@ -2246,5 +2267,155 @@ namespace FireWallet
{
UpdateDomains();
}
+ #region yubikey
+ static bool PinSubmitter(KeyEntryData pin)
+ {
+ string s = "123456";
+ var s_b = Encoding.UTF8.GetBytes(s);
+ pin.SubmitValue(s_b);
+ return true;
+ }
+ private void buttonSettingsYubikey_Click(object sender, EventArgs e)
+ {
+ if (password.Length < 0)
+ {
+ return;
+ }
+
+ NotifyForm notifyForm = new NotifyForm("Insert Yubikey\nThis will use your yubikey to encrypt your account password.");
+ notifyForm.ShowDialog();
+ notifyForm.Dispose();
+
+ NotifyForm yubiLoadingForm = new NotifyForm("Encrypting. . .", false);
+ yubiLoadingForm.Show();
+ // Wait for the form to load
+ Application.DoEvents();
+
+ try
+ {
+ //Assumes there is exactly one yubikey connected and it has a RSA2048 certificate in slot 9d
+ //PIV PIN is assumed to be 123456
+ var devices = YubiKeyDevice.FindAll();
+ var ykDevice = devices.First();
+ PivSession piv = new(ykDevice);
+
+ piv.KeyCollector += PinSubmitter;
+ piv.VerifyPin();
+
+ var slot = PivSlot.KeyManagement;
+
+ X509Certificate2 cert = piv.GetCertificate(slot);
+ if (cert.SignatureAlgorithm.FriendlyName != "sha256RSA")
+ throw new CryptographicException("Certificate must be RSA with SHA256");
+
+ var publicKey = cert.GetRSAPublicKey() ?? throw new CryptographicException("Couldn't get public key from certificate.");
+
+ Aes aesFirst = Aes.Create();
+
+ var encryptedKey = publicKey.Encrypt(aesFirst.Key, RSAEncryptionPadding.Pkcs1);
+ var decryptedKey = piv.Decrypt(slot, encryptedKey);
+
+ //MessageBox.Show($"aesFirst.Key.Length: {aesFirst.Key.Length}");
+ //MessageBox.Show($"encryptedKey.Length: {encryptedKey.Length}");
+ //MessageBox.Show($"decryptedKey.Length: {decryptedKey.Length}");
+
+ // split the message into blocks of 128 bytes
+
+ string message = password;
+ int blockSize = 128;
+ int blockCount = (int)Math.Ceiling((double)message.Length / blockSize);
+
+ string[] strings = new string[blockCount];
+ FileStream sw = new FileStream(dir + account + ".yubikey", FileMode.Create, FileAccess.Write);
+
+ for (int i = 0; i < blockCount; i++)
+ {
+ int size = Math.Min(blockSize, message.Length - i * blockSize);
+ strings[i] = message.Substring(i * blockSize, size);
+
+ byte[] bytes = Encoding.ASCII.GetBytes(strings[i]);
+ var encryptedBytes = publicKey.Encrypt(bytes, RSAEncryptionPadding.Pkcs1);
+ sw.Write(encryptedBytes, 0, encryptedBytes.Length);
+ }
+ sw.Close();
+ sw.Dispose();
+
+ }
+ catch (Exception ex)
+ {
+ AddLog(ex.Message);
+ }
+
+ yubiLoadingForm.CloseNotification();
+ }
+ private string YubiUnlock()
+ {
+ NotifyForm notifyForm = new NotifyForm("Insert Yubikey to unlock");
+ notifyForm.ShowDialog();
+ notifyForm.Dispose();
+ NotifyForm yubiLoadingForm = new NotifyForm("Decrypting. . .", false);
+ yubiLoadingForm.Show();
+ // Wait for the form to load
+ Application.DoEvents();
+ try
+ {
+
+ //Assumes there is exactly one yubikey connected and it has a RSA2048 certificate in slot 9d
+ //PIV PIN is assumed to be 123456
+ var devices = YubiKeyDevice.FindAll();
+ var ykDevice = devices.First();
+ PivSession piv = new(ykDevice);
+
+ piv.KeyCollector += PinSubmitter;
+ piv.VerifyPin();
+
+ var slot = PivSlot.KeyManagement;
+
+ X509Certificate2 cert = piv.GetCertificate(slot);
+ if (cert.SignatureAlgorithm.FriendlyName != "sha256RSA")
+ throw new CryptographicException("Certificate must be RSA with SHA256");
+
+ var publicKey = cert.GetRSAPublicKey() ?? throw new CryptographicException("Couldn't get public key from certificate.");
+
+ Aes aesFirst = Aes.Create();
+
+ var encryptedKey = publicKey.Encrypt(aesFirst.Key, RSAEncryptionPadding.Pkcs1);
+ var decryptedKey = piv.Decrypt(slot, encryptedKey);
+
+ byte[] input = File.ReadAllBytes(dir + account + ".yubikey");
+
+ // decrypt the input
+
+ int blockSize = 256;
+ int blockCount = (int)Math.Ceiling((double)input.Length / blockSize);
+
+ byte[][] blocks = new byte[blockCount][];
+ byte[] decripted = new byte[blockCount * blockSize];
+ string output = "";
+ for (int i = 0; i < blockCount; i++)
+ {
+ int size = Math.Min(blockSize, input.Length - i * blockSize);
+ blocks[i] = new byte[size];
+ Array.Copy(input, i * blockSize, blocks[i], 0, size);
+ var paddedDecryptedBytes = piv.Decrypt(slot, blocks[i]);
+ byte[] decryptedBytes;
+ bool couldParse = Yubico.YubiKey.Cryptography.RsaFormat.TryParsePkcs1Decrypt(paddedDecryptedBytes, out decryptedBytes);
+ Array.Copy(decryptedBytes, 0, decripted, i * blockSize, decryptedBytes.Length);
+
+ output += Encoding.ASCII.GetString(decryptedBytes);
+ }
+ yubiLoadingForm.CloseNotification();
+ return output;
+ }
+ catch (Exception ex)
+ {
+ AddLog(ex.Message);
+ yubiLoadingForm.CloseNotification();
+ return "";
+ }
+
+ }
+
+ #endregion
}
}
\ No newline at end of file