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コードポイント: 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]
暗号化プロセスはランダムなノンスにより非決定的である。
以下の暗号化された秘密鍵:
ncryptsec1qgg9947rlpvqu76pj5ecreduf9jxhselq2nae2kghhvd5g7dgjtcxfqtd67p9m0w57lspw8gsq6yphnm8623nsl8xn9j4jdzz84zm3frztj3z7s35vpzmqf6ksu8r89qk5z2zxfmu5gv8th8wclt0h4p
パスワード = 'nostr'およびlog_n=16で復号すると、次の16進数でエンコードされた秘密鍵が生成される:
3501454135014541350145413501453fefb02227e449e57cf4d3a3ce05378683
パスワードは暗号鍵としては不十分である。暗号鍵として使用する前に、次の2つの作業をする必要がある:
- 暗号化鍵は、対象暗号化アルゴリズムの仮定が有効であるような、一様にランダムなビット分布を持つようにパスワードから決定論的に作成する必要がある。そして
- 多くのパスワードを試して復号する総当たり攻撃が大幅に阻止されるよう、低速で不可逆的なアルゴリズムをプロセスに挿入する必要がある。
これらは、パスワードベースの鍵導出関数を使用して実現される。私たちはscryptを使用している。scryptは最大限メモリーハードであることが証明されており、2015年のコンテストでargon2が優勝したにもかかわらず、何人かの暗号学者がargon2よりも優れていると著者に示している。
XChaCha20-Poly1305は通常、暗号学者によってAESよりも好まれており、米国政府とはあまり関係がない。これ(または「X」の付いていない初期のバリアント)は広く使用されており、TLSおよびOpenSSHで使用され、ほとんどの最新の暗号ライブラリで利用できる。
攻撃者が多くの暗号化された秘密鍵を蓄積できると、鍵のクラッキングが容易になる可能性があるため、ユーザーがこれらの暗号化された秘密鍵をnostrに公開することは推奨できない。
クライアントは、パスワードと秘密鍵のメモリを解放する前に、そのメモリをゼロにすることを推奨する。