Skip to content

Latest commit

 

History

History
126 lines (78 loc) · 5.66 KB

49.md

File metadata and controls

126 lines (78 loc) · 5.66 KB

NIP-49

秘密鍵暗号化

draft optional

このNIPは、クライアントがパスワードを使用してユーザーの秘密鍵を暗号化(および復号)できる方法を定義する。

対称暗号化鍵の導出

PASSWORD = ユーザーから読み取る。パスワードは、他のコンピュータやクライアントで同じように入力できるよう、UnicodeをNFKC形式に正規化する必要がある。

LOG_N = ユーザーまたは実装者に、scryptのラウンド数として使用される2のべき乗を表す1バイト(e.g. 18は262,144を表す)を選択させる。数値が大きいほど、より多くの時間とより多くのメモリが必要になり、より強力な保護が提供される:

| LOG_N | MEMORY REQUIRED | APPROX TIME ON FAST COMPUTER |
|-------|-----------------|----------------------------- |
| 16    | 64 MiB          | 100 ms                       |
| 18    | 256 MiB         |                              |
| 20    | 1 GiB           | 2 seconds                    |
| 21    | 2 GiB           |                              |
| 22    | 4 GiB           |                              |

SALT = 16ランダムバイト。

SYMMETRIC_KEY = scrypt(password=PASSWORD, salt=SALT, log_n=LOG_N, r=8, p=1)

対称鍵の長さは32バイトである必要がある。

この対称暗号化鍵は一時的なものであり、使用後はゼロにして破棄し、他の目的で保存したり再利用したりしてはいけない。

秘密鍵の暗号化

秘密鍵の暗号化プロセスは次のとおりである:

PRIVATE_KEY = 生の32バイトのユーザーのプライベート(秘密)secp256k1鍵(16進数またはbech32でエンコードされていない!)

KEY_SECURITY_BYTE = 次のいずれか:

  • 0x00 - 鍵が安全に扱われていないことがわかっている場合(暗号化されずに保存されている、暗号化されていないカットアンドペーストなど)
  • 0x01 - 鍵が安全に扱われていないことがわかっていない場合(暗号化されずに保存されている、暗号化されていないカットアンドペーストなど)
  • 0x02 - クライアントがこのデータを追跡しない場合

ASSOCIATED_DATA = KEY_SECURITY_BYTE

NONCE = 24バイトのランダムなナンス。

CIPHERTEXT = XChaCha20-Poly1305( plaintext=PRIVATE_KEY, associated_data=ASSOCIATED_DATA, nonce=NONCE, key=SYMMETRIC_KEY )

VERSION_NUMBER = 0x02

CIPHERTEXT_CONCATENATION = concat( VERSION_NUMBER, LOG_N, SALT, NONCE, ASSOCIATED_DATA, CIPHERTEXT )

ENCRYPTED_PRIVATE_KEY = bech32_encode('ncryptsec', CIPHERTEXT_CONCATENATION)

bech32エンコード前の出力の長さは91バイトである必要がある。

復号プロセスはこの逆に行われる。

テストデータ

パスワードのUnicode正規化

次のパスワード入力: "ÅΩẛ̣":

  • Unicodeコードポイント: U+212B U+2126 U+1E9B U+0323
  • UTF-8バイト: [0xE2, 0x84, 0xAB, 0xE2, 0x84, 0xA6, 0xE1, 0xBA, 0x9B, 0xCC, 0xA3]

scryptで使用する前に、次のようにUnicode正規化されたNFKC形式に変換する必要がある: "ÅΩẛ̣":

  • Unicodeコードポイント: U+00C5 U+03A9 U+1E69
  • UTF-8バイト: [0xC3, 0x85, 0xCE, 0xA9, 0xE1, 0xB9, 0xA9]

暗号化

暗号化プロセスはランダムなノンスにより非決定的である。

Decryption

以下の暗号化された秘密鍵:

ncryptsec1qgg9947rlpvqu76pj5ecreduf9jxhselq2nae2kghhvd5g7dgjtcxfqtd67p9m0w57lspw8gsq6yphnm8623nsl8xn9j4jdzz84zm3frztj3z7s35vpzmqf6ksu8r89qk5z2zxfmu5gv8th8wclt0h4p

パスワード = 'nostr'およびlog_n=16で復号すると、次の16進数でエンコードされた秘密鍵が生成される:

3501454135014541350145413501453fefb02227e449e57cf4d3a3ce05378683

議論

鍵の導出について

パスワードは暗号鍵としては不十分である。暗号鍵として使用する前に、次の2つの作業をする必要がある:

  1. 暗号化鍵は、対象暗号化アルゴリズムの仮定が有効であるような、一様にランダムなビット分布を持つようにパスワードから決定論的に作成する必要がある。そして
  2. 多くのパスワードを試して復号する総当たり攻撃が大幅に阻止されるよう、低速で不可逆的なアルゴリズムをプロセスに挿入する必要がある。

これらは、パスワードベースの鍵導出関数を使用して実現される。私たちはscryptを使用している。scryptは最大限メモリーハードであることが証明されており、2015年のコンテストでargon2が優勝したにもかかわらず、何人かの暗号学者がargon2よりも優れていると著者に示している。

対称暗号化アルゴリズムについて

XChaCha20-Poly1305は通常、暗号学者によってAESよりも好まれており、米国政府とはあまり関係がない。これ(または「X」の付いていない初期のバリアント)は広く使用されており、TLSおよびOpenSSHで使用され、ほとんどの最新の暗号ライブラリで利用できる。

推奨事項

攻撃者が多くの暗号化された秘密鍵を蓄積できると、鍵のクラッキングが容易になる可能性があるため、ユーザーがこれらの暗号化された秘密鍵をnostrに公開することは推奨できない。

クライアントは、パスワードと秘密鍵のメモリを解放する前に、そのメモリをゼロにすることを推奨する。