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:
parent
395fbcd0f0
commit
67594e9f53
|
@ -179,12 +179,11 @@ class addressGenerator(StoppableThread):
|
|||
nonceTrialsPerByte))
|
||||
BMConfigParser().set(address, 'payloadlengthextrabytes', str(
|
||||
payloadLengthExtraBytes))
|
||||
BMConfigParser().set(
|
||||
address, 'privsigningkey', privSigningKeyWIF)
|
||||
BMConfigParser().set(
|
||||
address, 'privencryptionkey', privEncryptionKeyWIF)
|
||||
BMConfigParser().save()
|
||||
|
||||
shared.keystore.push_keys(
|
||||
address, (privEncryptionKeyWIF, privSigningKeyWIF))
|
||||
|
||||
# The API and the join and create Chan functionality
|
||||
# both need information back from the address generator.
|
||||
queues.apiAddressGeneratorReturnQueue.put(address)
|
||||
|
|
|
@ -183,16 +183,11 @@ class singleWorker(StoppableThread):
|
|||
logger.info("Quitting...")
|
||||
|
||||
def _getKeysForAddress(self, address):
|
||||
privSigningKeyBase58 = BMConfigParser().get(
|
||||
privSigningKeyHex = shared.keystore.fetch_key(
|
||||
address, 'privsigningkey')
|
||||
privEncryptionKeyBase58 = BMConfigParser().get(
|
||||
privEncryptionKeyHex = shared.keystore.fetch_key(
|
||||
address, 'privencryptionkey')
|
||||
|
||||
privSigningKeyHex = hexlify(shared.decodeWalletImportFormat(
|
||||
privSigningKeyBase58))
|
||||
privEncryptionKeyHex = hexlify(shared.decodeWalletImportFormat(
|
||||
privEncryptionKeyBase58))
|
||||
|
||||
# The \x04 on the beginning of the public keys are not sent.
|
||||
# This way there is only one acceptable way to encode
|
||||
# and send a public key.
|
||||
|
|
|
@ -7,8 +7,8 @@ import stat
|
|||
import threading
|
||||
import hashlib
|
||||
import subprocess
|
||||
from binascii import hexlify
|
||||
from pyelliptic import arithmetic
|
||||
from binascii import hexlify, unhexlify
|
||||
from pyelliptic import arithmetic, Cipher
|
||||
|
||||
# Project imports.
|
||||
import state
|
||||
|
@ -18,6 +18,10 @@ from debug import logger
|
|||
from addresses import decodeAddress, encodeVarint
|
||||
from helper_sql import sqlQuery
|
||||
|
||||
try:
|
||||
from plugins.plugin import get_plugin
|
||||
except ImportError:
|
||||
get_plugin = False
|
||||
|
||||
verbose = 1
|
||||
# This is obsolete with the change to protocol v3
|
||||
|
@ -114,6 +118,83 @@ def decodeWalletImportFormat(WIFstring):
|
|||
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():
|
||||
logger.debug('reloading keys from keys.dat file')
|
||||
myECCryptorObjects.clear()
|
||||
|
@ -133,9 +214,7 @@ def reloadMyAddressHashes():
|
|||
if addressVersionNumber in (2, 3, 4):
|
||||
# Returns a simple 32 bytes of information encoded
|
||||
# in 64 Hex characters, or null if there was an error.
|
||||
privEncryptionKey = hexlify(decodeWalletImportFormat(
|
||||
BMConfigParser().get(addressInKeysFile, 'privencryptionkey'))
|
||||
)
|
||||
privEncryptionKey = keystore.fetch_key(addressInKeysFile)
|
||||
|
||||
# It is 32 bytes encoded as 64 hex characters
|
||||
if len(privEncryptionKey) == 64:
|
||||
|
|
Reference in New Issue
Block a user