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:
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: