Skip to content
This repository has been archived by the owner on Mar 11, 2019. It is now read-only.

Commit

Permalink
python3 compatibility. speed up tests for travis
Browse files Browse the repository at this point in the history
  • Loading branch information
Anthchirp committed Oct 13, 2017
1 parent 82f57d7 commit a8b43b2
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 25 deletions.
3 changes: 2 additions & 1 deletion coldwallet/command_line.py
@@ -1,11 +1,12 @@
from __future__ import absolute_import, division, print_function

import argparse
import sys

import coldwallet
import coldwallet.bitcoin
import coldwallet.crypto
import coldwallet.encoding
import sys

def main():
parser = argparse.ArgumentParser()
Expand Down
36 changes: 21 additions & 15 deletions coldwallet/crypto.py
Expand Up @@ -5,8 +5,9 @@
import base64
import math
import os
import pylibscrypt

import coldwallet.aes
import pylibscrypt

def disable_randomness():
'''Make the random number generator produce deterministic (ie. non-random)
Expand All @@ -17,8 +18,13 @@ def disable_randomness():
import sys
sys.stderr.write('\n-- coldwallet running in test mode - random number generation disabled --\n\n')
def fakerandom(b):
return "".join(chr(random.randrange(256)) for x in range(b))
random.seed(0)
# bytes/bytearray conversion and use and rounding of
# random.random() is required for Python2/3 compatibility.
return bytes(bytearray((int(round(random.random(), 10) * 256) for x in range(b))))
if sys.hexversion >= 0x03000000:
random.seed(a=0, version=1)
else:
random.seed(a=0)
os.urandom = fakerandom

def generate_random_string(bits):
Expand All @@ -33,35 +39,35 @@ def generate_random_string(bits):
zero_padding = stringbytes * 8 - bits
if zero_padding:
mask = 0x100 - (2 ** zero_padding)
rand_string = rand_string[:-1] + chr(ord(rand_string[-1]) & mask)
rand_string = rand_string[:-1] + bytes(bytearray((ord(rand_string[-1:]) & mask,)))

return rand_string

def encrypt_secret_key(secret, coldkey, public_address):
def encrypt_secret_key(secret, coldkey, public_address, scrypt_N=2**14, scrypt_p=1):
'''Encrypt a secret exponent using an individual symmetric key. The symmetric
key is generated from the shared coldwallet key and the public bitcoin
address using the memory-hard scrypt hash. The result is returned in base64
encoding.
key is generated from the shared coldwallet key (given as byte string) and
the public bitcoin address (given in human readable format) using the
memory-hard scrypt hash. The result is returned in base64 encoding.
'''
# Generate the symmetric key from the coldwallet key and the public bitcoin address
symmetric_key = pylibscrypt.scrypt(coldkey, public_address, N=2**15, p=3, olen=32)
# Generate a 256 bit symmetric key from the coldwallet key and the public bitcoin address
symmetric_key = pylibscrypt.scrypt(coldkey, public_address.encode('ascii'), olen=32, N=scrypt_N, p=scrypt_p)

# Encrypt the secret exponent with the symmetric key
encrypted_secret = coldwallet.aes.encrypt_block(secret, symmetric_key)

# Base64 encode the result
return base64.b64encode(encrypted_secret)
return base64.b64encode(encrypted_secret).decode('ascii')

def decrypt_secret_key(code, coldkey, public_address):
def decrypt_secret_key(code, coldkey, public_address, scrypt_N=2**14, scrypt_p=1):
'''Decrypt a secret exponent, given in base64 encoding, using an individual
symmetric key. The symmetric key is generated as above. The result is
returned as a byte string.
'''
# Base64 decode the input
code = base64.b64decode(code)
code = base64.b64decode(code.encode('ascii'))

# Generate the symmetric key from the coldwallet key and the public bitcoin address
symmetric_key = pylibscrypt.scrypt(coldkey, public_address, N=2**15, p=3, olen=32)
# Generate a 256 bit symmetric key from the coldwallet key and the public bitcoin address
symmetric_key = pylibscrypt.scrypt(coldkey, public_address.encode('ascii'), olen=32, N=scrypt_N, p=scrypt_p)

# Decrypt the secret exponent with the symmetric key
secret = coldwallet.aes.decrypt_block(code, symmetric_key)
Expand Down
3 changes: 2 additions & 1 deletion tests/test_command_line.py
@@ -1,8 +1,9 @@
from __future__ import absolute_import, division

import pytest
import sys

import pytest

def test_get_command_line_help(capsys):
import coldwallet.command_line
sys.argv = [ 'coldwallet', '--help' ]
Expand Down
19 changes: 11 additions & 8 deletions tests/test_crypto.py
Expand Up @@ -26,7 +26,7 @@ def test_random_string_generation():
# If number of bits is not divisble by 8 then the remaining bits must be 0
rand = coldwallet.crypto.generate_random_string(bits=36)
assert len(rand) == 5
assert ord(rand[4]) & 0x0F == 0
assert bytearray(rand)[4] & 0x0F == 0

def test_random_string_padding():
import coldwallet.crypto
Expand Down Expand Up @@ -61,26 +61,29 @@ def test_encoding_and_decoding_secret_key():
# Generate a coldwallet key
coldkey = coldwallet.crypto.generate_random_string(bits=36*8)

# Use weaker scrypt parameter setting to speed up testing
N = 2**8 # default: 2**14

# Encrypt one with the other
code = coldwallet.crypto.encrypt_secret_key(private_key, coldkey, public_address)
assert code == "I06olv7sBr0mZ0DOV5qR8edp1rLF2x+nolKlAV+/kOj8aGp4jAHW1VuTawB90+fU"
code = coldwallet.crypto.encrypt_secret_key(private_key, coldkey, public_address, scrypt_N=N)
assert code == "I06olv7sBr0mZ0DOV5qR8RyvXPWt8yGjFbuhlj1vDO+clw/KLpS3mhEerUyRKgft"

# Encrypt one with the other again
code = coldwallet.crypto.encrypt_secret_key(private_key, coldkey, public_address)
code = coldwallet.crypto.encrypt_secret_key(private_key, coldkey, public_address, scrypt_N=N)
# A new initialization vector is used, so the resulting code changes
assert code == "70vfOobHgodn7ICiLPWlbBgQKSc6X4c8ZUAalNq6URJ3UeNJJptdPEzbt4ceQMWs"
assert code == "70vfOobHgodn7ICiLPWlbPAlhoCCCt5enrC9fM/Ml0uyM7gqGuiGZPPyAa5kRpK4"

# Decrypt the private key again
verify_key = coldwallet.crypto.decrypt_secret_key(code, coldkey, public_address)
verify_key = coldwallet.crypto.decrypt_secret_key(code, coldkey, public_address, scrypt_N=N)
assert verify_key == private_key

# Attempt decryption with wrong public address
public_address = "3DR2Dp74CqtqXhU9MznV2r4qTuZBGYagP"
verify_key = coldwallet.crypto.decrypt_secret_key(code, coldkey, public_address)
verify_key = coldwallet.crypto.decrypt_secret_key(code, coldkey, public_address, scrypt_N=N)
assert verify_key != private_key

# Attempt decryption with wrong coldwallet key
public_address = "1DR2Dp74CqtqXhU9MznV2r4qTuZBGYagP"
coldkey = coldwallet.crypto.generate_random_string(bits=36*8)
verify_key = coldwallet.crypto.decrypt_secret_key(code, coldkey, public_address)
verify_key = coldwallet.crypto.decrypt_secret_key(code, coldkey, public_address, scrypt_N=N)
assert verify_key != private_key

0 comments on commit a8b43b2

Please sign in to comment.