def genAll(bip=False): import random import num.rand as rand import system.address as address import num.enc as enc import encrypt.bip38 as bip38 import hashlib genFile = open('allKeys', 'w') genFile.close() conn = db.open() c = conn.cursor() c.execute('select currency from eskimo_currencies order by currency;') currencies = c.fetchall() for cur in currencies: c.execute('select v.version,v.prefix,v.length,c.id,c.longName from eskimo_versions as v inner join eskimo_currencies as c on c.version = v.id where c.currency=?;', (cur[0].upper(),)) version = c.fetchone() if version is None: continue #randomly choose a prefix if multiples exist prefixes = version[1].split('|') prefix = prefixes[random.randint(0, (len(prefixes)-1))] #generate the private and public keys privateKey = rand.randomKey(random.getrandbits(512)) privK256 = enc.encode(privateKey, 256, 32) WIF = address.privateKey2Wif(privateKey, version[0], prefix, version[2]) publicAddress = address.publicKey2Address(address.privateKey2PublicKey(privateKey), version[0], prefix, version[2]) if bip is True: BIP = bip38.encrypt(privK256, publicAddress, 'biptest', 1) privK, addresshash = bip38.decrypt(BIP, 'biptest', 1) #decode the privK from base 256 privK = enc.decode(privK, 256) #hash the address to check the decryption addr = address.publicKey2Address(address.privateKey2PublicKey(privK), version[0], prefix, version[2]) fail = False if hashlib.sha256(hashlib.sha256(addr).digest()).digest()[0:4] != addresshash: fail = True reason = 'Address Hash doesn\'t match' if privK != privateKey: fail = True reason = 'Private Keys don\'t match' BIPWIF = address.privateKey2Wif(privK, version[0], prefix, version[2]) with open('allKeys', 'a') as outfile: outfile.write('####### ' + cur[0].upper() + ' - ' + version[4] + ' #######\n') outfile.write('Address = ' + publicAddress + '\n') outfile.write('WIF = ' + WIF + '\n') if bip is True: outfile.write('BIP = ' + BIP + '\n') if fail is True: outfile.write('BIP Failed - ' + reason + '\n') else: outfile.write('BIPWIF = ' + BIPWIF + '\n') outfile.write('\n') outfile.close() db.close(conn) return True
def intermediate2privK(intermediate_passphrase_string): """ Steps to create new encrypted private keys given intermediate_passphrase_string from owner (so we have ownerentropy, and passpoint, but we do not have passfactor or the passphrase): """ #get ownerentropy and passpoint from the intermediate key leadingzbytes = len(re.match('^1*',intermediate_passphrase_string).group(0)) data = '\x00' * leadingzbytes + enc.encode(enc.decode(intermediate_passphrase_string,58),256) assert hashlib.sha256(hashlib.sha256(data[:-4]).digest()).digest().encode('hex')[:4] == data[-4:] decodedstring = data[1:-4] ownerentropy = decodedstring[7:15] passpoint = decodedstring[-33:] #1. Set flagbyte. #Turn on bit 0x20 if the Bitcoin address will be formed by hashing the compressed public key (optional, saves space, but many Bitcoin implementations aren't compatible with it) #Turn on bit 0x04 if ownerentropy contains a value for lotsequence. #(While it has no effect on the keypair generation process, the decryption process needs this flag to know how to process ownerentropy) flagbyte = chr(0b00100100) # 00 EC 1 compressed 00 future 1 has lotsequence 00 future #2. Generate 24 random bytes, call this seedb. Take SHA256(SHA256(seedb)) to yield 32 bytes, call this factorb. seedb = os.urandom(24) factorb = hashlib.sha256(hashlib.sha256(seedb).digest()).digest() #3. ECMultiply passpoint by factorb. pub = elip.base10_multiply(enc.decode(factorb, 256), enc.decode(passpoint, 256)) #4. Use the resulting EC point as a public key and hash it into a Bitcoin address using either compressed or uncompressed public key methodology # (specify which methodology is used inside flagbyte). # This is the generated Bitcoin address, call it generatedaddress. publicKey = ('0' + str(2 + (pub[1] % 2)) + enc.encode(pub[0], 16, 64)) generatedaddress = address.publicKey2Address(publicKey) ## Remember to add in the currency details here #5. Take the first four bytes of SHA256(SHA256(generatedaddress)) and call it addresshash. addresshash = hashlib.sha256(hashlib.sha256(generatedaddress).digest()).digest()[:4] #6. Now we will encrypt seedb. Derive a second key from passpoint using scrypt #Parameters: passphrase is passpoint provided from the first party (expressed in binary as 33 bytes). # salt is addresshash + ownerentropy, n=1024, r=1, p=1, length=64. The "+" operator is concatenation. encseedb = scrypt.hash(passpoint, addresshash + ownerentropy, 1024, 1, 1, 64) #7. Split the result into two 32-byte halves and call them derivedhalf1 and derivedhalf2. derivedhalf1 = encseedb[0:32] derivedhalf2 = encseedb[32:64] #8. Do AES256Encrypt(seedb[0...15] xor derivedhalf1[0...15], derivedhalf2), call the 16-byte result encryptedpart1 Aes = aes.Aes(derivedhalf2) encryptedpart1 = Aes.enc(enc.sxor(seedb[:16], derivedhalf1[:16])) #9. Do AES256Encrypt((encryptedpart1[8...15] + seedb[16...23]) xor derivedhalf1[16...31], derivedhalf2), call the 16-byte result encryptedpart2. # The "+" operator is concatenation. encryptedpart2 = Aes.enc(enc.sxor(encryptedpart1[8:16] + seedb[16:24], derivedhalf1[16:32])) #10. The encrypted private key is the Base58Check-encoded concatenation of the following, which totals 39 bytes without Base58 checksum: #0x01 0x43 + flagbyte + addresshash + ownerentropy + encryptedpart1[0...7] + encryptedpart2 inp_fmtd = '\x01\x43' + flagbyte + addresshash + ownerentropy + encryptedpart1[0:8] + encryptedpart2 check = hashlib.sha256(hashlib.sha256(inp_fmtd).digest()).digest()[:4] BIPKey = enc.b58encode(inp_fmtd + check) cnfrmcode = confirmationcode(flagbyte, addresshash, ownerentropy, factorb, derivedhalf1, derivedhalf2) return BIPKey, generatedaddress, cnfrmcode
def confirmcode(confirmationcode, passphrase): """ A confirmation tool, given a passphrase and a confirmation code, can recalculate the address, verify the address hash, and then assert the following: "It is confirmed that Bitcoin address address depends on this passphrase". To recalculate the address: """ #decode the confirmationcode to give addresshash, ownerentropy and encryptedpointb data = enc.b58decode(confirmationcode) checksum = data[-4:] hash = hashlib.sha256(hashlib.sha256(data[:-4]).digest()).digest()[:4] assert hash == checksum addresshash = data[6:10] ownerentropy = data[10:18] encryptedpointb = data[18:51] pointbx1 = encryptedpointb[1:17] pointbx2 = encryptedpointb[17:33] #1. Derive passfactor using scrypt with ownerentropy and the user's passphrase and use it to recompute passpoint passfactor = scrypt.hash(passphrase, ownerentropy, 16384, 8, 8, 32) pub = elip.base10_multiply(elip.G, enc.decode(passfactor, 256)) passpoint = ('0' + str(2 + (pub[1] % 2)) + enc.encode(pub[0], 16, 64)).decode('hex') #2. Derive decryption key for pointb using scrypt with passpoint, addresshash, and ownerentropy key = scrypt.hash(passpoint, addresshash + ownerentropy, 1024, 1, 1, 64) derivedhalf1 = key[0:32] derivedhalf2 = key[32:64] #3. Decrypt encryptedpointb to yield pointb Aes = aes.Aes(derivedhalf2) decryptedhalf1 = Aes.dec(pointbx1) decryptedhalf2 = Aes.dec(pointbx2) pointb = '0' + decryptedhalf1 + decryptedhalf2 pointb = binascii.unhexlify('%064x' % (long(binascii.hexlify(pointb), 16) ^ long(binascii.hexlify(derivedhalf1), 16))) #4. ECMultiply pointb by passfactor. Use the resulting EC point as a public key and hash it into address using either compressed or uncompressed public key # methodology as specified in flagbyte. pub = elip.base10_multiply(pointb, enc.decode(passfactor, 256)) print('pub[0] = ' + str(pub[0])) print('pub[1] = ' + str(pub[1])) publicKey = ('0' + str(2 + (pub[1] % 2)) + enc.encode(pub[0], 16, 64)) print('pubKey = ' + publicKey) generatedaddress = address.publicKey2Address(publicKey) print('generatedaddress = ' + generatedaddress) #print(hashlib.sha256(hashlib.sha256(generatedaddress).digest()).digest()[:4]) #print(addresshash) #assert hashlib.sha256(hashlib.sha256(generatedaddress).digest()).digest()[:4] == addresshash return
def genBIPKey(passphrase, entropy='', privateKey=''): """ Generate a BIP38 private key + public addresses """ # generate the private and public keys if privateKey == '': privateKey = int(rand.randomKey(rand.entropy(entropy))) privK256 = enc.encode(privateKey, 256, 32) bPublicAddress, sPublicAddress = address.publicKey2Address( address.privateKey2PublicKey(privateKey)) #BIP38 encryption BIP = bip38.encrypt(privK256, bPublicAddress, sPublicAddress, str(passphrase)) return BIP, bPublicAddress, sPublicAddress
def confirmcode(confirmationcode, passphrase): """ A confirmation tool, given a passphrase and a confirmation code, can recalculate the address, verify the address hash, and then assert the following: "It is confirmed that Bitcoin address address depends on this passphrase". If applicable: "The lot number is lotnumber and the sequence number is sequencenumber." To recalculate the address: """ #decode the confirmationcode to give addresshash, ownerentropy and encryptedpointb data = enc.encode(enc.decode(confirmationcode, 58), 256) assert hashlib.sha256(hashlib.sha256( data[:-4]).digest()).digest()[:4] == data[-4:] addresshash = data[6:10] ownerentropy = data[10:18] encryptedpointb = data[18:51] pointbprefix = encryptedpointb[:1] pointbx1 = encryptedpointb[1:17] pointbx2 = encryptedpointb[17:] #1. Derive passfactor using scrypt with ownerentropy and the user's passphrase and use it to recompute passpoint prefactor = scrypt.hash(passphrase, ownerentropy[:4], 16384, 8, 8, 32) passfactor = hashlib.sha256( hashlib.sha256(prefactor + ownerentropy).digest()).digest() pub = elip.base10_multiply(elip.G, enc.decode(passfactor, 256)) passpoint = ('0' + str(2 + (pub[1] % 2)) + enc.encode(pub[0], 16, 64)).decode('hex') #2. Derive decryption key for pointb using scrypt with passpoint, addresshash, and ownerentropy key = scrypt.hash(passpoint, addresshash + ownerentropy, 1024, 1, 1, 64) derivedhalf1 = key[0:32] derivedhalf2 = key[32:64] #3. Decrypt encryptedpointb to yield pointb Aes = aes.Aes(derivedhalf2) pointb = pointbprefix + Aes.dec(pointbx1) + Aes.dec(pointbx2) print('pointb = ' + pointb.encode('hex')) #4. ECMultiply pointb by passfactor. Use the resulting EC point as a public key and hash it into address using either compressed or uncompressed public key # methodology as specifid in flagbyte. pub = elip.base10_multiply(enc.decode(passfactor, 256), enc.decode(pointb, 256)) privK = ('0' + str(2 + (pub[1] % 2)) + enc.encode(pub[0], 16, 64)) generatedaddress = address.publicKey2Address(privK) #print(generatedaddress) #print(hashlib.sha256(hashlib.sha256(generatedaddress).digest()).digest()[:4]) #print(addresshash) #assert hashlib.sha256(hashlib.sha256(generatedaddress).digest()).digest()[:4] == addresshash return
def decBIPKey(encrypted_privK, passphrase): """ Decrypt an encrypted Private key Show the corresponding public address """ privK, addresshash = bip38.decrypt(str(encrypted_privK), str(passphrase)) privK = enc.decode(privK, 256) # calculate the addresses from the key bPublicAddress, sPublicAddress = address.publicKey2Address( address.privateKey2PublicKey(privK)) #check our generated address against the address hash from BIP if hashlib.sha256( hashlib.sha256(bPublicAddress + sPublicAddress).digest()).digest( )[0:4] != addresshash: return False, False, False else: return address.privateKey2Wif(privK), bPublicAddress, sPublicAddress
def vanity(currency, string): """ Generate a vanity address """ #using the currencies.json file, get the currency data with open('currencies.json', 'r') as dataFile: currencies = json.load(dataFile) for cur in currencies: if cur['currency'] == currency: break #randomly choose a prefix if multiples exist prefixes = cur['prefix'].split('|') prefix = prefixes[random.randint(0, (len(prefixes)-1))] #generate the private and public keys vanityAddress = '' while vanityAddress[:(len(string)+1)] != prefix + string: privateKey = int(rand.randomKey(random.getrandbits(512))) vanityAddress = address.publicKey2Address(address.privateKey2PublicKey(privateKey), int(cur['version']), prefix, int(cur['length'])) print(vanityAddress) print(vanityAddress, privateKey) return
def genBIPKey(currency, passphrase, entropy='', privateKey='', isCompressed=True): """ Generate a BIP38 privatekey + public address# """ #using the currencies.json file, get the currency data with open('res/json/currencies.json', 'r') as dataFile: currencies = json.load(dataFile) for cur in currencies: if cur['currency'] == currency: break #randomly choose a prefix if multiples exist prefixes = cur['prefix'].split('|') prefix = prefixes[random.randint(0, (len(prefixes) - 1))] #generate the private and public keys if privateKey == '': privateKey = int(rand.randomKey(rand.entropy(entropy))) privK256 = enc.encode(privateKey, 256, 32) publicAddress = address.publicKey2Address(address.privateKey2PublicKey(privateKey, isCompressed), int(cur['version']), prefix, int(cur['length'])) #BIP38 encryption BIP = bip38.encrypt(privK256, publicAddress, str(passphrase), 8) return BIP, publicAddress
def decBIPKey(encrypted_privK, passphrase, currency): """ Decrypt an encrypted Private key Show the corresponding public address """ #using the currencies.json file, get the currency data with open('res/json/currencies.json', 'r') as dataFile: currencies = json.load(dataFile) for cur in currencies: if cur['currency'] == currency: break #randomly choose a prefix if multiples exist prefixes = cur['prefix'].split('|') prefix = prefixes[random.randint(0, (len(prefixes)-1))] #decrypt the BIP key PrivK, Addresshash = bip38.decrypt(str(encrypted_privK), str(passphrase), 8) PrivK = enc.decode(PrivK, 256) #calculate the address from the key publicAddress = address.publicKey2Address(address.privateKey2PublicKey(PrivK), int(cur['version']), prefix, int(cur['length'])) #check our generated address against the address hash from BIP if hashlib.sha256(hashlib.sha256(publicAddress).digest()).digest()[0:4] != Addresshash: return False, False else: return address.privateKey2Wif(PrivK, cur['version'], prefix, cur['length']), publicAddress
def intermediate2privK(intermediate_passphrase_string): """ Steps to create new encrypted private keys given intermediate_passphrase_string from owner (so we have ownerentropy, and passpoint, but we do not have passfactor or the passphrase): """ #get ownerentropy and passpoint from the intermediate key #check the checksum en route decstring = enc.b58decode(intermediate_passphrase_string) checksum = decstring[-4:] if checksum != hashlib.sha256(hashlib.sha256( decstring[:-4]).digest()).digest()[:4]: return False, 'checksum' decodedstring = decstring[:-4] ownerentropy = decodedstring[8:16] passpoint = decodedstring[-33:] print(passpoint) #1. Set flagbyte. #Turn on bit 0x20 if the Bitcoin address will be formed by hashing the compressed public key (optional, saves space, but many Bitcoin implementations aren't compatible with it) #Turn on bit 0x04 if ownerentropy contains a value for lotsequence. #(While it has no effect on the keypair generation process, the decryption process needs this flag to know how to process ownerentropy) flagbyte = chr( 0b00100000 ) # 00 EC 1 compressed 00 future 0 has no lotsequence 00 future #2. Generate 24 random bytes, call this seedb. Take SHA256(SHA256(seedb)) to yield 32 bytes, call this factorb. seedb = os.urandom(24) seedb = b'ABCDEFGHIJKLMNOPQRSTUVWX' #seedb = bytearray(b'ABCDEFGHIJKLMNOPQRSTUVWX') #for c in seedb: print(c) factorb = hashlib.sha256(hashlib.sha256(seedb).digest()).digest() #3. ECMultiply passpoint by factorb. pub = elip.base10_multiply(enc.decode(passpoint, 256), enc.decode(factorb, 256)) #4. Use the resulting EC point as a public key and hash it into a Bitcoin address using either compressed or uncompressed public key methodology # (specify which methodology is used inside flagbyte). # This is the generated Bitcoin address, call it generatedaddress. publicKey = ('0' + str(2 + (pub[1] % 2)) + enc.encode(pub[0], 16, 64)) generatedaddress = address.publicKey2Address( publicKey) ## TODO Remember to add in the currency details here #5. Take the first four bytes of SHA256(SHA256(generatedaddress)) and call it addresshash. addresshash = hashlib.sha256( hashlib.sha256(generatedaddress).digest()).digest()[:4] #6. Now we will encrypt seedb. Derive a second key from passpoint using scrypt #Parameters: passphrase is passpoint provided from the first party (expressed in binary as 33 bytes). # salt is addresshash + ownerentropy, n=1024, r=1, p=1, length=64. The "+" operator is concatenation. encseedb = scrypt.hash(passpoint, addresshash + ownerentropy, 1024, 1, 1, 64) #7. Split the result into two 32-byte halves and call them derivedhalf1 and derivedhalf2. derivedhalf1 = encseedb[0:32] derivedhalf2 = encseedb[32:64] #8. Do AES256Encrypt(seedb[0...15] xor derivedhalf1[0...15], derivedhalf2), call the 16-byte result encryptedpart1 Aes = aes.Aes(derivedhalf2) encryptedpart1 = Aes.enc(enc.sxor(seedb[:16], derivedhalf1[:16])) #9. Do AES256Encrypt((encryptedpart1[8...15] + seedb[16...23]) xor derivedhalf1[16...31], derivedhalf2), call the 16-byte result encryptedpart2. # The "+" operator is concatenation. encryptedpart2 = Aes.enc( enc.sxor(encryptedpart1[8:16] + seedb[16:24], derivedhalf1[16:32])) #10. The encrypted private key is the Base58Check-encoded concatenation of the following, which totals 39 bytes without Base58 checksum: #0x01 0x43 + flagbyte + addresshash + ownerentropy + encryptedpart1[0...7] + encryptedpart2 input = '\x01\x43' + flagbyte + addresshash + ownerentropy + encryptedpart1[ 0:8] + encryptedpart2 checksum = hashlib.sha256(hashlib.sha256(input).digest()).digest()[:4] BIPKey = enc.b58encode(input + checksum) cnfrmcode = confirmationcode(flagbyte, addresshash, ownerentropy, factorb, derivedhalf1, derivedhalf2) return BIPKey, generatedaddress, cnfrmcode
def confirmcode(confirmationcode, passphrase): """ A confirmation tool, given a passphrase and a confirmation code, can recalculate the address, verify the address hash, and then assert the following: "It is confirmed that Bitcoin address address depends on this passphrase". If applicable: "The lot number is lotnumber and the sequence number is sequencenumber." To recalculate the address: """ #decode the confirmationcode to give addresshash, ownerentropy and encryptedpointb data = enc.encode(enc.decode(confirmationcode,58),256) assert hashlib.sha256(hashlib.sha256(data[:-4]).digest()).digest()[:4] == data[-4:] addresshash = data[6:10] ownerentropy = data[10:18] encryptedpointb = data[18:51] pointbprefix = encryptedpointb[:1] pointbx1 = encryptedpointb[1:17] pointbx2 = encryptedpointb[17:] #1. Derive passfactor using scrypt with ownerentropy and the user's passphrase and use it to recompute passpoint prefactor = scrypt.hash(passphrase, ownerentropy[:4], 16384, 8, 8, 32) passfactor = hashlib.sha256(hashlib.sha256(prefactor + ownerentropy).digest()).digest() pub = elip.base10_multiply(elip.G, enc.decode(passfactor, 256)) passpoint = ('0' + str(2 + (pub[1] % 2)) + enc.encode(pub[0], 16, 64)).decode('hex') #2. Derive decryption key for pointb using scrypt with passpoint, addresshash, and ownerentropy key = scrypt.hash(passpoint, addresshash + ownerentropy, 1024, 1, 1, 64) derivedhalf1 = key[0:32] derivedhalf2 = key[32:64] #3. Decrypt encryptedpointb to yield pointb Aes = aes.Aes(derivedhalf2) pointb = pointbprefix + Aes.dec(pointbx1) + Aes.dec(pointbx2) print('pointb = ' + pointb.encode('hex')) #4. ECMultiply pointb by passfactor. Use the resulting EC point as a public key and hash it into address using either compressed or uncompressed public key # methodology as specifid in flagbyte. pub = elip.base10_multiply(enc.decode(passfactor, 256), enc.decode(pointb, 256)) privK = ('0' + str(2 + (pub[1] % 2)) + enc.encode(pub[0], 16, 64)) generatedaddress = address.publicKey2Address(privK) #print(generatedaddress) #print(hashlib.sha256(hashlib.sha256(generatedaddress).digest()).digest()[:4]) #print(addresshash) #assert hashlib.sha256(hashlib.sha256(generatedaddress).digest()).digest()[:4] == addresshash return #Decryption # #Collect encrypted private key and passphrase from user. #Derive passfactor using scrypt with ownerentropy and the user's passphrase and use it to recompute passpoint #Derive decryption key for seedb using scrypt with passpoint, addresshash, and ownersalt #Decrypt encryptedpart2 using AES256Decrypt to yield the last 8 bytes of seedb and the last 8 bytes of encryptedpart1. #Decrypt encryptedpart1 to yield the remainder of seedb. #Use seedb to compute factorb. #Multiply passfactor by factorb mod N to yield the private key associated with generatedaddress. #Convert that private key into a Bitcoin address, honoring the compression preference specified in the encrypted key. #Hash the Bitcoin address, and verify that addresshash from the encrypted private key record matches the hash. If not, report that the passphrase entry was incorrect. #