class Keystorage implements common key storage logic.

.fetch_key(address, key_type) fetches a key of given type
  .push_keys(address, keys) stores a pair of keys

  Workflow depends on plugin availability and settings:

    keysencrypted = True - encrypt keys with plugin
    keystore = keys:<Plugin> - use Plugin to store keys
    keystore = password:<Plugin> - store encryption password
This commit is contained in:
Dmitri Bogomolov 2017-09-21 18:36:35 +03:00
parent 395fbcd0f0
commit 67594e9f53
Signed by untrusted user: g1itch
GPG Key ID: 720A756F18DEED13
3 changed files with 89 additions and 16 deletions

View File

@ -179,12 +179,11 @@ class addressGenerator(StoppableThread):
nonceTrialsPerByte)) nonceTrialsPerByte))
BMConfigParser().set(address, 'payloadlengthextrabytes', str( BMConfigParser().set(address, 'payloadlengthextrabytes', str(
payloadLengthExtraBytes)) payloadLengthExtraBytes))
BMConfigParser().set(
address, 'privsigningkey', privSigningKeyWIF)
BMConfigParser().set(
address, 'privencryptionkey', privEncryptionKeyWIF)
BMConfigParser().save() BMConfigParser().save()
shared.keystore.push_keys(
address, (privEncryptionKeyWIF, privSigningKeyWIF))
# The API and the join and create Chan functionality # The API and the join and create Chan functionality
# both need information back from the address generator. # both need information back from the address generator.
queues.apiAddressGeneratorReturnQueue.put(address) queues.apiAddressGeneratorReturnQueue.put(address)

View File

@ -183,16 +183,11 @@ class singleWorker(StoppableThread):
logger.info("Quitting...") logger.info("Quitting...")
def _getKeysForAddress(self, address): def _getKeysForAddress(self, address):
privSigningKeyBase58 = BMConfigParser().get( privSigningKeyHex = shared.keystore.fetch_key(
address, 'privsigningkey') address, 'privsigningkey')
privEncryptionKeyBase58 = BMConfigParser().get( privEncryptionKeyHex = shared.keystore.fetch_key(
address, 'privencryptionkey') address, 'privencryptionkey')
privSigningKeyHex = hexlify(shared.decodeWalletImportFormat(
privSigningKeyBase58))
privEncryptionKeyHex = hexlify(shared.decodeWalletImportFormat(
privEncryptionKeyBase58))
# The \x04 on the beginning of the public keys are not sent. # The \x04 on the beginning of the public keys are not sent.
# This way there is only one acceptable way to encode # This way there is only one acceptable way to encode
# and send a public key. # and send a public key.

View File

@ -7,8 +7,8 @@ import stat
import threading import threading
import hashlib import hashlib
import subprocess import subprocess
from binascii import hexlify from binascii import hexlify, unhexlify
from pyelliptic import arithmetic from pyelliptic import arithmetic, Cipher
# Project imports. # Project imports.
import state import state
@ -18,6 +18,10 @@ from debug import logger
from addresses import decodeAddress, encodeVarint from addresses import decodeAddress, encodeVarint
from helper_sql import sqlQuery from helper_sql import sqlQuery
try:
from plugins.plugin import get_plugin
except ImportError:
get_plugin = False
verbose = 1 verbose = 1
# This is obsolete with the change to protocol v3 # This is obsolete with the change to protocol v3
@ -114,6 +118,83 @@ def decodeWalletImportFormat(WIFstring):
os._exit(0) os._exit(0)
class Keystore(object):
"""Class implementing common key storage workflow"""
def __init__(self):
self.config = BMConfigParser()
keysencrypted = self.config.safeGetBoolean(
'bitmessagesettings', 'keysencrypted')
def noop(key):
return key
self.fetch = self._get_key
self.push = self._set_keys
self.encrypt = self.decrypt = noop
try:
content, plugin = self.config.safeGet(
'bitmessagesettings', 'keystore').split(':')
plugin = get_plugin('keystore', name=plugin)(self)
except (ValueError, TypeError):
plugin = None
if not plugin:
if keysencrypted:
logger.warning(
'Key encryption plugin not found or unimplemented!')
return
try:
if content == 'password' and keysencrypted:
self.decrypt = plugin.decrypt
self.encrypt = plugin.encrypt
elif content == 'keys':
self.fetch = plugin.fetch
self.push = plugin.push
except AttributeError:
pass
def fetch_key(self, address, key_type='privencryptionkey'):
"""Fetch address key of type key_type from keystore"""
try:
return hexlify(decodeWalletImportFormat(
self.decrypt(self.fetch(address, key_type))
))
except TypeError:
pass # handle in reloadMyAddressHashes etc
def push_keys(self, address, keys):
"""Push the address keys in WIF into keystore"""
self.push(address, [self.encrypt(key) for key in keys])
def _get_key(self, address, key_type='privencryptionkey'):
return self.config.get(address, key_type)
def _set_keys(self, address, keys):
for key, key_type in zip(
keys, ('privencryptionkey', 'privsigningkey')):
self.config.set(address, key_type, key)
self.config.save()
# simmetric encryption from pyelliptic example:
# https://github.com/yann2192/pyelliptic
def _encrypt_AES_CFB(self, data, password):
nonce = Cipher.gen_IV('aes-256-cfb')
ctx = Cipher(password, nonce, 1, ciphername='aes-256-cfb')
encrypted = ctx.update(data)
encrypted += ctx.final()
return ':'.join(hexlify(i) for i in (encrypted, nonce))
def _decrypt_AES_CFB(self, data, password):
encrypted, nonce = [unhexlify(part) for part in data.split(':')]
ctx = Cipher(password, nonce, 0, ciphername='aes-256-cfb')
return ctx.ciphering(encrypted)
keystore = Keystore()
def reloadMyAddressHashes(): def reloadMyAddressHashes():
logger.debug('reloading keys from keys.dat file') logger.debug('reloading keys from keys.dat file')
myECCryptorObjects.clear() myECCryptorObjects.clear()
@ -133,9 +214,7 @@ def reloadMyAddressHashes():
if addressVersionNumber in (2, 3, 4): if addressVersionNumber in (2, 3, 4):
# Returns a simple 32 bytes of information encoded # Returns a simple 32 bytes of information encoded
# in 64 Hex characters, or null if there was an error. # in 64 Hex characters, or null if there was an error.
privEncryptionKey = hexlify(decodeWalletImportFormat( privEncryptionKey = keystore.fetch_key(addressInKeysFile)
BMConfigParser().get(addressInKeysFile, 'privencryptionkey'))
)
# It is 32 bytes encoded as 64 hex characters # It is 32 bytes encoded as 64 hex characters
if len(privEncryptionKey) == 64: if len(privEncryptionKey) == 64: