upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/49.md
diff options
context:
space:
mode:
authorMichael Dilger <mike@mikedilger.com>2024-01-30 04:45:16 +1300
committerGitHub <noreply@github.com>2024-01-29 12:45:16 -0300
commit7ec060375c5aa8697e8b26c2d1088c9077bfa910 (patch)
tree7ae465749c523ef5dd101113a8e8ff95ed46cadc /49.md
parentff8e2040614c2f442adb3a16bd31f42d443dee27 (diff)
NIP-49: Private key encryption (#133)
* Key export/import as implemented by gossip * Added test data * Last push didn't make sense, only this direction works * Multiple updates: 100k rounds, random salt, version number, length indications * Rename to NIP-49, include in README * Change encoding to bech32 (ncryptsec) * Major rework of the algorithm. NIP is now incomplete as I haven't coded it yet. * renamed * spelling * minor fix * formatting * MORE CHANGES: scrypt, spelt out more detail of the steps to take * spelling * Mostly just removing some unnecesary stuff * Remove the cafebabe note * Remove confusing nonce statement * Change title (and a bit of wording) * remove author * remove legacy event * rename on README --------- Co-authored-by: Mike Dilger <mike@ezicheq.com> Co-authored-by: fiatjaf_ <fiatjaf@gmail.com>
Diffstat (limited to '49.md')
-rw-r--r--49.md112
1 files changed, 112 insertions, 0 deletions
diff --git a/49.md b/49.md
new file mode 100644
index 0000000..becc586
--- /dev/null
+++ b/49.md
@@ -0,0 +1,112 @@
1
2NIP-49
3======
4
5Private Key Encryption
6----------------------
7
8`draft` `optional`
9
10This NIP defines a method by which clients can encrypt (and decrypt) a user's private key with a passphrase.
11
12Symmetric Encryption Key derivation
13-----------------------------------
14
15PASSPHRASE = read from the user
16
17LOG\_N = Let the user or implementer choose one byte representing a power of 2 (e.g. 18 represents 262,144) which is used as the number of rounds for scrypt. Larger numbers take more time and more memory, and offer better protection:
18
19 | LOG\_N | MEMORY REQUIRED | APPROX TIME ON FAST COMPUTER |
20 |--------|-----------------|----------------------------- |
21 | 16 | 64 MiB | 100 ms |
22 | 18 | 256 MiB | |
23 | 20 | 1 GiB | 2 seconds |
24 | 21 | 2 GiB | |
25 | 22 | 4 GiB | |
26
27SALT = 16 random bytes
28
29SYMMETRIC_KEY = scrypt(passphrase=PASSPHRASE, salt=SALT, log\_n=LOG\_N, r=8, p=1)
30
31The symmetric key should be 32 bytes long.
32
33This symmetric encryption key is temporary and should be zeroed and discarded after use and not stored or reused for any other purpose.
34
35
36Encrypting a private key
37------------------------
38
39The private key encryption process is as follows:
40
41PRIVATE\_KEY = User's private (secret) secp256k1 key as 32 raw bytes (not hex or bech32 encoded!)
42
43KEY\_SECURITY\_BYTE = one of:
44
45* 0x00 - if the key has been known to have been handled insecurely (stored unencrypted, cut and paste unencrypted, etc)
46* 0x01 - if the key has NOT been known to have been handled insecurely (stored unencrypted, cut and paste unencrypted, etc)
47 * 0x02 - if the client does not track this data
48
49ASSOCIATED\_DATA = KEY\_SECURITY\_BYTE
50
51NONCE = 24 byte random nonce
52
53CIPHERTEXT = XChaCha20-Poly1305(
54 plaintext=PRIVATE\_KEY,
55 associated_data=ASSOCIATED\_DATA,
56 nonce=NONCE,
57 key=SYMMETRIC\_KEY
58)
59
60VERSION\_NUMBER = 0x02
61
62CIPHERTEXT_CONCATENATION = concat(
63 VERSION\_NUMBER,
64 LOG\_N,
65 SALT,
66 NONCE,
67 ASSOCIATED\_DATA,
68 CIPHERTEXT
69)
70
71ENCRYPTED\_PRIVATE\_KEY = bech32_encode('ncryptsec', CIPHERTEXT\_CONCATENATION)
72
73The output prior to bech32 encoding should be 91 bytes long.
74
75The decryption process operates in the reverse.
76
77
78Test Data
79---------
80
81The following encrypted private key:
82
83`ncryptsec1qgg9947rlpvqu76pj5ecreduf9jxhselq2nae2kghhvd5g7dgjtcxfqtd67p9m0w57lspw8gsq6yphnm8623nsl8xn9j4jdzz84zm3frztj3z7s35vpzmqf6ksu8r89qk5z2zxfmu5gv8th8wclt0h4p`
84
85When decrypted with password='nostr' and log_n=16 yields the following hex-encoded private key:
86
87`3501454135014541350145413501453fefb02227e449e57cf4d3a3ce05378683`
88
89The reverse process is non-deterministic due to the random nonce.
90
91Discussion
92----------
93
94### On Key Derivation
95
96Passwords make poor cryptographic keys. Prior to use as a cryptographic key, two things need to happen:
97
981. An encryption key needs to be deterministically created from the password such that is has a uniform functionally random distribution of bits, such that the symmetric encryption algorithm's assumptions are valid, and
992. A slow irreversible algorithm should be injected into the process, so that brute-force attempts to decrypt by trying many passwords are severely hampered.
100
101These are achieved using a password-based key derivation function. We use scrypt, which has been proven to be maximally memory hard and which several cryptographers have indicated to the author is better than argon2 even though argon2 won a competition in 2015.
102
103### On the symmetric encryption algorithm
104
105XChaCha20-Poly1305 is typically favored by cryptographers over AES and is less associated with the U.S. government. It (or it's earlier variant without the 'X') is gaining wide usage, is used in TLS and OpenSSH, and is available in most modern crypto libraries.
106
107Recommendations
108---------
109
110It is not recommended that users publish these encrypted private keys to nostr, as cracking a key may become easier when an attacker can amass many encrypted private keys.
111
112It is recommended that clients zero out the memory of passwords and private keys before freeing that memory.