iT邦幫忙

2024 iThome 鐵人賽

DAY 17
0

Hi all, 來到17天 今天就來解決key 存放的問題吧!!!

目前的想法: 把儲存這份工放在 sdk作業,一方面可以隱藏 BigInteger 的基礎型別,另一方面也比較符合單一職責。

直接來說明下目前想到的作法:

  1. 產生出 一對 key pair 及 一把 session key
  2. 我們保留 private key 及 session key,並把他們轉換成 16 進位置字串後寫進檔案
  3. load key 時,我們需要透過 private key 換算成想對應的 public key

EccGenerator

首先動工的點會在這支類別中,我期望使用端只需透過一個 method GetKeyDomain 就可以取得 key pair 及 session key。

主要邏輯會是: 先查看 key file 存不存在:

  • 有: 讀取 key file 並轉換成 KeyDomain 進行回傳
  • 沒有: 新增 key pair 及 session key,把 private key 及 session key 轉換成 16進位制字串後,再進行檔案寫入。

public static class EccGenerator
{
    private static readonly string KeyPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "key.json");
    private static readonly X9ECParameters Curve = SecNamedCurves.GetByName("secp256k1");
    private static readonly ECDomainParameters Domain = new(Curve.Curve, Curve.G, Curve.N, Curve.H);

    public static KeyPairDomain GetKeyDomain()
    {
        if (File.Exists(KeyPath))
        {
            var keyInText = File.ReadAllText(KeyPath);
            var keyPairSaved = JsonSerializer.Deserialize<KeyPairSaved>(keyInText);
            return LoadEccKeyPair(keyPairSaved);
        }

        return GenerateKeyPairWithSessionKey();
    }

    private static KeyPairDomain GenerateKeyPairWithSessionKey()
    {
        var keyGen = new ECKeyPairGenerator();
        var keyGenParam = new ECKeyGenerationParameters(Domain, new SecureRandom());
        keyGen.Init(keyGenParam);
        var keyPair = keyGen.GenerateKeyPair();
        
        var keyPairDomain = new KeyPairDomain
        {
            PrivateKey = (ECPrivateKeyParameters)keyPair.Private,
            PublicKey = (ECPublicKeyParameters)keyPair.Public,
            SessionKey = new BigInteger(256, new SecureRandom())
        };
        
        keyPairDomain.SaveAsFile(KeyPath);
        return keyPairDomain;
    }

    private static KeyPairDomain LoadEccKeyPair(KeyPairSaved keyPairSaved)
    {
        var privateKeyD = new BigInteger(keyPairSaved.StrPrivateKey, 16);
        var privateKey = new ECPrivateKeyParameters(privateKeyD, Domain);

        var q = Domain.G.Multiply(privateKey.D);
        var publicKey = new ECPublicKeyParameters(q, Domain);

        return new KeyPairDomain
        {
            PrivateKey = privateKey,
            PublicKey = publicKey,
            SessionKey = new BigInteger(keyPairSaved.StrSessionKey, 16)
        };
    }
}

透過測試執行後,確保呼叫兩次 GetKeyDomain 的值都會是一致的

    [Test]
    public void key_should_be_same()
    {
        var keyDomain1 = EccGenerator.GetKeyDomain();
        var keyDomain2 = EccGenerator.GetKeyDomain();
        
        Assert.Multiple(() =>
        {
            Assert.That(keyDomain2.PrivateKey.D, Is.EqualTo(keyDomain1.PrivateKey.D));
            Assert.That(keyDomain2.SessionKey, Is.EqualTo(keyDomain1.SessionKey));
        });
    }

這次儲存的 key.json 預期上要長成這樣

image.png

Conclusion

不愧是 free style 的鐵人賽... 每天遇到的坑都是意料外的,好險都想的到方式解決嗚嗚嗚。

但因為大改 EccGenerator 的緣故,其他計算變色龍雜湊函數的地方都需要修改,當然測試那些也要重寫…

結語: 修完這些要接著修另個 side project 的 bug,我是甚麼專案渣男嗎


上一篇
Day16 難搞之謎
下一篇
Day18 Edit Block
系列文
Side-Project:: 為自己打造個可編輯的區塊鏈30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言