Browse Source

plugins/digitalbitbox: compatibility with firmware v5.0.0

3.3.3.1
Marko Bencun 6 years ago
parent
commit
92a9cda4fc
  1. 36
      electrum/plugins/digitalbitbox/digitalbitbox.py

36
electrum/plugins/digitalbitbox/digitalbitbox.py

@ -4,7 +4,7 @@
#
try:
from electrum.crypto import sha256d, EncodeAES_base64, DecodeAES_base64
from electrum.crypto import sha256d, EncodeAES_base64, EncodeAES_bytes, DecodeAES_bytes, hmac_oneshot
from electrum.bitcoin import (TYPE_ADDRESS, push_script, var_int, public_key_to_p2pkh,
is_address)
from electrum.bip32 import serialize_xpub, deserialize_xpub
@ -30,6 +30,8 @@ try:
import base64
import os
import sys
import re
import hmac
DIGIBOX = True
except ImportError as e:
DIGIBOX = False
@ -43,6 +45,14 @@ except ImportError as e:
def to_hexstr(s):
return binascii.hexlify(s).decode('ascii')
def derive_keys(x):
h = sha256d(x)
h = hashlib.sha512(h).digest()
return (h[:32],h[32:])
MIN_MAJOR_VERSION = 5
class DigitalBitbox_Client():
def __init__(self, plugin, hidDevice):
@ -110,7 +120,6 @@ class DigitalBitbox_Client():
else:
raise Exception('no reply')
def dbb_has_password(self):
reply = self.hid_send_plain(b'{"ping":""}')
if 'ping' not in reply:
@ -121,7 +130,6 @@ class DigitalBitbox_Client():
def stretch_key(self, key):
import hmac
return to_hexstr(hashlib.pbkdf2_hmac('sha512', key.encode('utf-8'), b'Digital Bitbox', iterations = 20480))
@ -158,6 +166,12 @@ class DigitalBitbox_Client():
def check_device_dialog(self):
match = re.search(r'v([0-9])+\.[0-9]+\.[0-9]+', self.dbb_hid.get_serial_number_string())
if match is None:
raise Exception("error detecting firmware version")
major_version = int(match.group(1))
if major_version < MIN_MAJOR_VERSION:
raise Exception("Please upgrade to the newest firmware using the BitBox Desktop app: https://shiftcrypto.ch/start")
# Set password if fresh device
if self.password is None and not self.dbb_has_password():
if not self.setupRunning:
@ -393,13 +407,21 @@ class DigitalBitbox_Client():
def hid_send_encrypt(self, msg):
sha256_byte_len = 32
reply = ""
try:
secret = sha256d(self.password)
msg = EncodeAES_base64(secret, msg)
reply = self.hid_send_plain(msg)
encryption_key, authentication_key = derive_keys(self.password)
msg = EncodeAES_bytes(encryption_key, msg)
hmac_digest = hmac_oneshot(authentication_key, msg, hashlib.sha256)
authenticated_msg = base64.b64encode(msg + hmac_digest)
reply = self.hid_send_plain(authenticated_msg)
if 'ciphertext' in reply:
reply = DecodeAES_base64(secret, ''.join(reply["ciphertext"]))
b64_unencoded = bytes(base64.b64decode(''.join(reply["ciphertext"])))
reply_hmac = b64_unencoded[-sha256_byte_len:]
hmac_calculated = hmac_oneshot(authentication_key, b64_unencoded[:-sha256_byte_len], hashlib.sha256)
if not hmac.compare_digest(reply_hmac, hmac_calculated):
raise Exception("Failed to validate HMAC")
reply = DecodeAES_bytes(encryption_key, b64_unencoded[:-sha256_byte_len])
reply = to_string(reply, 'utf8')
reply = json.loads(reply)
if 'error' in reply:

Loading…
Cancel
Save