aboutsummarylogtreecommitdiffstats
path: root/swarm-genkey.py
blob: ab43d4d081db7541447842db2de9609b8823e85b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#!/usr/bin/env python3

import sys
import json
import os
import uuid
from datetime import datetime

import scrypt
from ecdsa import SECP256k1, SigningKey
from Crypto.Cipher import AES
from Crypto.Util import Counter
from Crypto.Hash import keccak

scryptN = 1 << 18
scryptP = 1
scryptR = 8
scryptLen = 32
aesBlockSize = 1 << 7
pkLen = 32
ivLen = 16
saltLen = 32
pwLen = 64
walletVersion = 3

# uuid for the wallet
uu = uuid.uuid1()

# make new wallet example
iv = os.urandom(ivLen)
salt = os.urandom(saltLen)
pw = os.urandom(pwLen)

# save the password to file
fd = os.open(".swarm-pass", os.O_WRONLY | os.O_CREAT, mode=0o600)
c = os.write(fd, pw)
if (c != pwLen):
	raise Exception("Incomplete password write to file")
os.close(fd)

# derive the aes key used to encrypt the private key
key = scrypt.hash(pw, salt, scryptN, scryptR, scryptP, scryptLen)

# generate the keypair
pk = SigningKey.generate(curve=SECP256k1)
pkBytes = pk.to_string()
pubBytes = pk.get_verifying_key().to_string()

# hash and truncate public key to get the ethereum address
hasher = keccak.new(digest_bits=256)
hasher.update(pubBytes)
addrBytes = hasher.digest()[12:]
addrHex = addrBytes.hex()
#print("{}\n{}\n{}\n".format(pkBytes.hex(), pubBytes.hex(), addrHex))

# encrypt the private key with the key generated by the password
ctr = Counter.new(aesBlockSize, initial_value=int.from_bytes(iv, "big"))
cipher = AES.new(key[:16], AES.MODE_CTR, counter=ctr)
cipherText = cipher.encrypt(pkBytes)

# calculate the mac
hasher = keccak.new(digest_bits=256)
hasher.update(key[16:])
hasher.update(cipherText)
mac = hasher.digest()

# format to json wallet
wallet = """{
  "address": \"""" + addrHex + """\",
  "crypto": {
    "cipher": "aes-128-ctr",
    "ciphertext": \"""" + cipherText.hex() + """\",
    "cipherparams": {
      "iv": \"""" + iv.hex() + """\"
    },
    "kdf": "scrypt",
    "kdfparams": {
      "dklen": """ + str(scryptLen) + """,
      "n": """ + str(scryptN) + """,
      "p": """ + str(scryptP) + """,
      "r": """ + str(scryptR) + """,
      "salt": \"""" + salt.hex() + """\"
    },
    "mac": \"""" + mac.hex() + """\"
  },
  "id": \"""" + str(uu) + """\",
  "version": """ + str(walletVersion) + """
}"""

# write wallet to file with standardized filename
now = datetime.now()
walletFilename = now.strftime("UTC--%Y-%m-%dT%H-%M-%S.%f000Z--" + addrHex)
fd = os.open(walletFilename, os.O_WRONLY | os.O_CREAT, 0o600)
c = os.write(fd, wallet.encode('utf-8'))
os.close(fd)