electrum

Electrum Bitcoin wallet
git clone https://git.parazyd.org/electrum
Log | Files | Refs | Submodules

commit 2a5f108d4ab2145c5784934063293bc2decce67a
parent bc6010303a0010c9c027b99d8c65c68481d2c585
Author: tiagotrs <tiago@posteo.de>
Date:   Wed, 22 Aug 2018 22:25:12 +0200

change prng, add warning against encrypting multiple secrets (#4649)

* substitute python prng generator with hmac_drbg

* add warning, change version

* brick cards version 0

* separate python-drbg module, include tests and license

* import to match PEP 8

* fix line break, minor changes in wording

* fixes noise_seed formatting errors

* fix import, include license exclude tests drbg module

Diffstat:
Aelectrum/plugins/revealer/hmac_drbg.py | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Melectrum/plugins/revealer/qt.py | 39++++++++++++++++++++++++++++-----------
2 files changed, 79 insertions(+), 11 deletions(-)

diff --git a/electrum/plugins/revealer/hmac_drbg.py b/electrum/plugins/revealer/hmac_drbg.py @@ -0,0 +1,51 @@ +''' +Copyright (c) 2014 David Lazar <lazard@mit.edu> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +''' + +import hashlib +import hmac + +class DRBG(object): + def __init__(self, seed): + self.key = b'\x00' * 64 + self.val = b'\x01' * 64 + self.reseed(seed) + + def hmac(self, key, val): + return hmac.new(key, val, hashlib.sha512).digest() + + def reseed(self, data=b''): + self.key = self.hmac(self.key, self.val + b'\x00' + data) + self.val = self.hmac(self.key, self.val) + + if data: + self.key = self.hmac(self.key, self.val + b'\x01' + data) + self.val = self.hmac(self.key, self.val) + + def generate(self, n): + xs = b'' + while len(xs) < n: + self.val = self.hmac(self.key, self.val) + xs += self.val + + self.reseed() + + return xs[:n] diff --git a/electrum/plugins/revealer/qt.py b/electrum/plugins/revealer/qt.py @@ -22,16 +22,17 @@ import qrcode import traceback from hashlib import sha256 from decimal import Decimal +import binascii from PyQt5.QtPrintSupport import QPrinter from electrum.plugin import BasePlugin, hook from electrum.i18n import _ from electrum.util import to_bytes, make_dir - from electrum.gui.qt.util import * from electrum.gui.qt.qrtextedit import ScanQRTextEdit +from .hmac_drbg import DRBG class Plugin(BasePlugin): @@ -47,7 +48,7 @@ class Plugin(BasePlugin): self.calibration_h = self.config.get('calibration_h') self.calibration_v = self.config.get('calibration_v') - self.version = '0' + self.version = '1' self.size = (159, 97) self.f_size = QSize(1014*2, 642*2) self.abstand_h = 21 @@ -130,7 +131,7 @@ class Plugin(BasePlugin): s = self.get_noise() b = self.is_noise(s) if b: - self.noise_seed = s[:-3] + self.noise_seed = s[1:-3] self.user_input = True self.next_button.setEnabled(b) @@ -155,6 +156,9 @@ class Plugin(BasePlugin): else: return False else: + + if (len(txt)>0 and txt[0]=='0'): + self.d.show_message(''.join(["<b>",_("Warning: "), "</b>", _("Revealers starting with 0 had a vulnerability and are not supported.")])) self.user_input = False return False @@ -211,12 +215,12 @@ class Plugin(BasePlugin): grid = QGridLayout() self.vbox.addLayout(grid) - cprint = QPushButton(_("Generate encrypted seed PDF")) + cprint = QPushButton(_("Generate encrypted seed backup")) cprint.clicked.connect(partial(self.seed_img, True)) self.vbox.addWidget(cprint) self.vbox.addSpacing(14) - self.vbox.addWidget(WWLabel(_("and/or type any secret below:"))) + self.vbox.addWidget(WWLabel(_("OR type any secret below:"))) self.text = ScanQRTextEdit() self.text.setTabChangesFocus(True) self.text.setMaximumHeight(70) @@ -231,12 +235,19 @@ class Plugin(BasePlugin): self.vbox.addWidget(self.max_chars) self.max_chars.setVisible(False) - self.ctext = QPushButton(_("Generate custom secret encrypted PDF")) + self.ctext = QPushButton(_("Generate custom secret encrypted backup")) self.ctext.clicked.connect(self.t) self.vbox.addWidget(self.ctext) self.ctext.setEnabled(False) + self.vbox.addSpacing(11) + self.vbox.addWidget( + QLabel(''.join(["<b>" + _("WARNING") + "</b>: " + _("Revealer is a one-time-pad and should be used only once."), '<br/>', + _("Multiple secrets encrypted for the same Revealer can be attacked."), '<br/>', + ]))) + self.vbox.addSpacing(11) + self.vbox.addSpacing(21) self.vbox.addLayout(Buttons(CloseButton(d))) return bool(d.exec_()) @@ -305,21 +316,27 @@ class Plugin(BasePlugin): if(self.noise_seed == False): self.noise_seed = random.SystemRandom().getrandbits(128) - self.hex_noise = format(self.noise_seed, '02x') + self.hex_noise = format(self.noise_seed, '032x') self.hex_noise = self.version + str(self.hex_noise) if (self.user_input == True): self.noise_seed = int(self.noise_seed, 16) - self.hex_noise = self.version + str(format(self.noise_seed, '02x')) - + self.hex_noise = self.version + str(format(self.noise_seed, '032x')) self.code_id = self.code_hashid(self.hex_noise) self.hex_noise = ' '.join(self.hex_noise[i:i+4] for i in range(0,len(self.hex_noise),4)) - random.seed(self.noise_seed) + entropy = binascii.unhexlify(str(format(self.noise_seed, '032x'))) + code_id = binascii.unhexlify(self.version + self.code_id) + + drbg = DRBG(entropy + code_id) + noise_array=bin(int.from_bytes(drbg.generate(1929), 'big'))[2:] + + i=0 for x in range(w): for y in range(h): - rawnoise.setPixel(x,y,random.randint(0, 1)) + rawnoise.setPixel(x,y,int(noise_array[i])) + i+=1 self.rawnoise = rawnoise if create_revealer==True: