Esempio n. 1
0
 async def process_host_command(self, stream, show_fn):
     """
     If command with one of the prefixes is received
     it will be passed to this method.
     Should return a tuple:
     - stream (file, BytesIO etc)
     - meta object with title and note
     """
     # reads prefix from the stream (until first space)
     prefix = self.get_prefix(stream)
     if prefix != b"getrandom":
         # WTF? It's not our data...
         raise AppError("Prefix is not valid: %s" % prefix.decode())
     # by default we return 32 bytes
     num_bytes = 32
     try:
         num_bytes = int(stream.read().decode().strip())
     except:
         pass
     if num_bytes < 0:
         raise AppError("Seriously? %d bytes? No..." % num_bytes)
     if num_bytes > 1000:
         raise AppError("Sorry, 1k bytes max.")
     obj = {"title": "Here is your entropy", "note": "%d bytes" % num_bytes}
     return BytesIO(hexlify(get_random_bytes(num_bytes))), obj
Esempio n. 2
0
 def load_enc_secret(self):
     fpath = self.path + "/enc_secret"
     if platform.file_exists(fpath):
         _, secret = self.load_aead(fpath, self.pin_secret)
     else:
         # create new key if it doesn't exist
         secret = get_random_bytes(32)
         self.save_aead(fpath, plaintext=secret, key=self.pin_secret)
     self.enc_secret = secret
Esempio n. 3
0
 def create_new_secret(self, path):
     """Generate new secret and default PIN config"""
     # generate new and save
     secret = get_random_bytes(32)
     # save secret
     with open(path + "/secret", "wb") as f:
         f.write(secret)
     self.secret = secret
     return secret
Esempio n. 4
0
    def __init__(self, title="Enter your PIN code", note=None, get_word=None, subtitle=None):
        super().__init__()
        self.title = add_label(title, scr=self, y=PADDING, style="title")
        if subtitle is not None:
            lbl = add_label(subtitle, scr=self, style="hint")
            lbl.set_recolor(True)
            lbl.align(self.title, lv.ALIGN.OUT_BOTTOM_MID, 0, 10)
        if note is not None:
            lbl = add_label(note, scr=self, style="hint")
            lbl.align(self.title, lv.ALIGN.OUT_BOTTOM_MID, 0, 180)
        self.get_word = get_word
        if get_word is not None:
            self.words = add_label(get_word(b""), scr=self)
            self.words.align(self.title, lv.ALIGN.OUT_BOTTOM_MID, 0, 210)
        btnm = lv.btnm(self)
        # shuffle numbers to make sure
        # no constant fingerprints left on screen
        buttons = ["%d" % i for i in range(0, 10)]
        btnmap = []
        for j in range(3):
            for i in range(3):
                v = rng.get_random_bytes(1)[0] % len(buttons)
                btnmap.append(buttons.pop(v))
            btnmap.append("\n")
        btnmap = btnmap + [lv.SYMBOL.CLOSE, buttons.pop(), lv.SYMBOL.OK, ""]
        btnm.set_map(btnmap)
        btnm.set_width(HOR_RES)
        btnm.set_height(HOR_RES)
        btnm.align(self, lv.ALIGN.IN_BOTTOM_MID, 0, 0)
        # increase font size
        style = lv.style_t()
        lv.style_copy(style, btnm.get_style(lv.btnm.STYLE.BTN_REL))
        style.text.font = lv.font_roboto_28
        # remove feedback on press to avoid sidechannels
        btnm.set_style(lv.btnm.STYLE.BTN_REL, style)
        btnm.set_style(lv.btnm.STYLE.BTN_PR, style)

        self.pin = lv.ta(self)
        self.pin.set_text("")
        self.pin.set_pwd_mode(True)
        style = lv.style_t()
        lv.style_copy(style, styles["theme"].style.ta.oneline)
        style.text.font = lv.font_roboto_28
        style.text.color = styles["theme"].style.scr.text.color
        style.text.letter_space = 15
        self.pin.set_style(lv.label.STYLE.MAIN, style)
        self.pin.set_width(HOR_RES - 2 * PADDING)
        self.pin.set_x(PADDING)
        self.pin.set_y(PADDING + 50)
        self.pin.set_cursor_type(lv.CURSOR.HIDDEN)
        self.pin.set_one_line(True)
        self.pin.set_text_align(lv.label.ALIGN.CENTER)
        self.pin.set_pwd_show_time(0)
        self.pin.align(btnm, lv.ALIGN.OUT_TOP_MID, 0, -150)

        btnm.set_event_cb(feed_rng(self.cb))
Esempio n. 5
0
def encrypt(plain: bytes, key: bytes) -> bytes:
    """Encrypt data with bit padding (0x80...)"""
    iv = rng.get_random_bytes(IV_SIZE)
    crypto = aes(key, AES_CBC, iv)
    # encrypted data should be mod 16 (blocksize)
    # add padding
    plain += b'\x80'
    if len(plain) % AES_BLOCK != 0:
        # fill with zeroes
        plain += b"\x00" * (AES_BLOCK - (len(plain) % AES_BLOCK))
    return iv + crypto.encrypt(plain)
Esempio n. 6
0
 def create_new_secret(self, path):
     """Generate new secret and default PIN config"""
     # generate new and save
     secret = get_random_bytes(32)
     # save secret
     with open(path + "/secret", "wb") as f:
         f.write(secret)
     # set pin object
     self.pin = None
     self._pin_attempts_max = 10
     self._pin_attempts_left = 10
     self.secret = secret
     self.save_state()
     return secret
Esempio n. 7
0
 def set_pin(self, pin):
     """Saves hmac of the PIN code for verification later"""
     # set up pin
     key = tagged_hash("pin", self.secret)
     self.pin = hmac.new(key=key, msg=pin, digestmod="sha256").digest()
     self.pin_secret = tagged_hash("pin", self.secret + pin.encode())
     self.save_state()
     # update encryption secret
     if self.enc_secret is None:
         self.enc_secret = get_random_bytes(32)
     self.save_aead(self.path + "/enc_secret",
                    plaintext=self.enc_secret,
                    key=self.pin_secret)
     # call unlock now
     self.unlock(pin)
Esempio n. 8
0
 def load_enc_secret(self):
     data = self.applet.get_secret()
     # no data yet
     if len(data) == 0:
         # create new key if it doesn't exist
         secret = get_random_bytes(32)
         # format: magic, 01 len enc_secret, 02 len entropy
         d = self.serialize_data({"enc": secret})
         self.applet.save_secret(d)
         self._is_key_saved = False
     else:
         try:
             d = self.parse_data(data)
             secret = d["enc"]
             if "entropy" in d:
                 self._is_key_saved = True
         except KeyStoreError as e:
             # wrong data on the card - not a big deal
             # just generate a new key
             self.enc_secret = get_random_bytes(32)
             self._is_key_saved = False
             # notify the user about the error
             raise e
     self.enc_secret = secret
Esempio n. 9
0
def save_entropy_encrypted():
    try:
        Key.iv = get_random_bytes(16)
        entropy_encrypted = entropy_encrypt(entropy)
        hmac_entropy_encrypted = hmac_sha512(Key.key, entropy_encrypted)
        obj = {
            "entropy": hexlify(entropy_encrypted).decode('utf-8'),
            "iv": hexlify(Key.iv).decode('utf-8'),
            "hmac": hexlify(hmac_entropy_encrypted).decode('utf-8')
        }
        with open(reckless_fname, "w") as f:
            f.write(json.dumps(obj))
        with open(reckless_fname, "r") as f:
            d = json.loads(f.read())
        if "entropy" in d and d["entropy"] == hexlify(entropy_encrypted).decode('utf-8') and \
                unhexlify(d["hmac"]) == hmac_entropy_encrypted and entropy == entropy_decrypt(entropy_encrypted):
            gui.alert("Success!", "Your encrypted key is saved in the memory now")
        else:
            gui.error("Something went wrong")
    except Exception as e:
        gui.error("Fail: %r" % e)
Esempio n. 10
0
def gen_mnemonic(num_words: int) -> str:
    """Generates a mnemonic with num_words"""
    if num_words < 12 or num_words > 24 or num_words % 3 != 0:
        raise RuntimeError("Invalid word count")
    return bip39.mnemonic_from_bytes(rng.get_random_bytes(num_words * 4 // 3))
Esempio n. 11
0
 def sign(self, tx):
     # good practice to randomize context
     # it reduces chances of side-channel attacks
     secp256k1.context_randomize(get_random_bytes(32))
     tx.sign_with(self.root)
     return tx
Esempio n. 12
0
 def open(self, mode=None):
     """Opens a secure channel.
     Mode can be "es" - ephemeral-static
              or "ee" - ephemeral-ephemenral
     """
     # save mode for later - i.e. reestablish secure channel
     if mode is None:
         mode = self.mode
     else:
         self.mode = mode
     # check if we know pubkey already
     if self.card_pubkey is None:
         self.get_card_pubkey()
     # generate ephimerial key
     secret = get_random_bytes(32)
     host_prv = secret
     host_pub = secp256k1.ec_pubkey_create(secret)
     # ee mode - ask card to create ephimerial key and send it to us
     if mode == "ee":
         data = secp256k1.ec_pubkey_serialize(host_pub,
                                              secp256k1.EC_UNCOMPRESSED)
         # get ephimerial pubkey from the card
         res = self.applet.request(self.OPEN_EE + encode(data))
         s = BytesIO(res)
         data = s.read(65)
         pub = secp256k1.ec_pubkey_parse(data)
         secp256k1.ec_pubkey_tweak_mul(pub, secret)
         shared_secret = hashlib.sha256(
             secp256k1.ec_pubkey_serialize(pub)[1:33]).digest()
         shared_fingerprint = self.derive_keys(shared_secret)
         recv_hmac = s.read(MAC_SIZE)
         h = hmac.new(self.card_mac_key, digestmod="sha256")
         h.update(data)
         expected_hmac = h.digest()[:MAC_SIZE]
         if expected_hmac != recv_hmac:
             raise SecureChannelError("Wrong HMAC.")
         data += recv_hmac
         raw_sig = s.read()
         sig = secp256k1.ecdsa_signature_parse_der(raw_sig)
         # in case card doesn't follow low s rule (but it should)
         sig = secp256k1.ecdsa_signature_normalize(sig)
         if not secp256k1.ecdsa_verify(sig,
                                       hashlib.sha256(data).digest(),
                                       self.card_pubkey):
             raise SecureChannelError("Signature is invalid.")
     # se mode - use our ephimerial key with card's static key
     else:
         data = secp256k1.ec_pubkey_serialize(host_pub,
                                              secp256k1.EC_UNCOMPRESSED)
         # ugly copy
         pub = secp256k1.ec_pubkey_parse(
             secp256k1.ec_pubkey_serialize(self.card_pubkey))
         secp256k1.ec_pubkey_tweak_mul(pub, secret)
         shared_secret = secp256k1.ec_pubkey_serialize(pub)[1:33]
         res = self.applet.request(self.OPEN_SE + encode(data))
         s = BytesIO(res)
         nonce_card = s.read(32)
         recv_hmac = s.read(MAC_SIZE)
         secret_with_nonces = hashlib.sha256(shared_secret +
                                             nonce_card).digest()
         shared_fingerprint = self.derive_keys(secret_with_nonces)
         data = nonce_card
         h = hmac.new(self.card_mac_key, digestmod="sha256")
         h.update(data)
         expected_hmac = h.digest()[:MAC_SIZE]
         if expected_hmac != recv_hmac:
             raise SecureChannelError("Wrong HMAC.")
         data += recv_hmac
         sig = secp256k1.ecdsa_signature_parse_der(s.read())
         # in case card doesn't follow low s rule (but it should)
         sig = secp256k1.ecdsa_signature_normalize(sig)
         if not secp256k1.ecdsa_verify(sig,
                                       hashlib.sha256(data).digest(),
                                       self.card_pubkey):
             raise SecureChannelError("Signature is invalid")
     # reset iv
     self.iv = 0
     self.is_open = True
Esempio n. 13
0
def get_new_mnemonic(words=12):
    entropy_len = words*4//3
    global entropy
    entropy = get_random_bytes(entropy_len)
    return bip39.mnemonic_from_bytes(entropy)
Esempio n. 14
0
def ask_pin(first_time_usage, callback):
    scr = switch_to_new_screen()
    first_time_title = "Choose a PIN code"
    title = "Enter your PIN code"
    if first_time_usage:
        title = first_time_title
    title_lbl = add_label(title, y=PADDING, style="title")
    btnm = lv.btnm(scr)
    # shuffle numbers to make sure 
    # no constant fingerprints left on screen
    buttons = ["%d" % i for i in range(0,10)]
    btnmap = []
    for j in range(3):
        for i in range(3):
            v = rng.get_random_bytes(1)[0] % len(buttons)
            btnmap.append(buttons.pop(v))
        btnmap.append("\n")
    btnmap = btnmap+[lv.SYMBOL.CLOSE, buttons.pop(), lv.SYMBOL.OK, ""]
    btnm.set_map(btnmap)
    btnm.set_width(HOR_RES)
    btnm.set_height(HOR_RES)
    btnm.align(scr, lv.ALIGN.IN_BOTTOM_MID, 0, 0)
    # remove feedback on press to avoid sidechannels
    btnm.set_style(lv.btnm.STYLE.BTN_PR,btnm.get_style(lv.btnm.STYLE.BTN_REL))

    pin_lbl = lv.ta(scr)
    pin_lbl.set_text("")
    pin_lbl.set_pwd_mode(True)
    style = lv.style_t()
    lv.style_copy(style, styles["theme"].style.ta.oneline)
    style.text.font = lv.font_roboto_28
    style.text.color = lv.color_hex(0xffffff)
    style.text.letter_space = 15
    pin_lbl.set_style(lv.label.STYLE.MAIN, style)
    pin_lbl.set_width(HOR_RES-2*PADDING)
    pin_lbl.set_x(PADDING)
    pin_lbl.set_y(PADDING+50)
    pin_lbl.set_cursor_type(lv.CURSOR.HIDDEN)
    pin_lbl.set_one_line(True)
    pin_lbl.set_text_align(lv.label.ALIGN.CENTER)
    pin_lbl.set_pwd_show_time(0)

    instruct_txt = "Device tamper check.\nThese words should remain #ffffff the same every time#:"
    instruct_label = add_label(instruct_txt, 180, style="hint")
    instruct_label.set_recolor(True)
    antiphish_label = add_label(antiphishing_word(""), 250)
    Pin.read_counter()

    @feed_rng
    def cb(obj, event):
        nonlocal first_time_usage
        if event == lv.EVENT.RELEASED:
            c = obj.get_active_btn_text()
            if c is None:
                return
            if c == lv.SYMBOL.CLOSE:
                pin_lbl.set_text("")
                antiphish_label.set_text(antiphishing_word(""))
            elif c == lv.SYMBOL.OK:
                # FIXME: check PIN len
                Key.generate_key(pin_lbl.get_text());
                if first_time_usage:
                    Secret.save_secret(alert);
                    callback()
                else:
                    Pin.counter -= 1
                    Pin.save_counter(alert)
                    if Pin.is_pin_valid():
                        Pin.reset_counter(alert)
                        callback()
                    else:
                        instruct_label.set_text("#f07070 Wrong pin: %d/%d #" % (Pin.counter, Pin.ATTEMPTS_MAX))
                        if Pin.counter <= 0:
                            Factory_settings.restore(alert)
                            Secret.generate_secret()
                            alert("Security","Device has been factory reset!")
                            first_time_usage = True
                            title_lbl.set_text(first_time_title)
                            instruct_label.set_text(instruct_txt)
                pin_lbl.set_text("")
                antiphish_label.set_text(antiphishing_word(""))
            else:
                instruct_label.set_text(instruct_txt)
                pin_lbl.add_text(c)
                word = antiphishing_word(pin_lbl.get_text())
                antiphish_label.set_text(antiphish_label.get_text() + " " + word)

    btnm.set_event_cb(cb);
Esempio n. 15
0
 def generate_secret():
     Secret.secret = get_random_bytes(32)
Esempio n. 16
0
def roll_dice(sides=6):
    """ return 1 ... sides """
    d = get_random_bytes(1)
    print (sides)
    print (d)
    return 1+int.from_bytes(d, 'big') % sides