mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-22 07:28:10 +00:00
core+legacy: rework code styling checks
This commit is contained in:
parent
9f8ebcf183
commit
8b06598474
1
.gitmodules
vendored
1
.gitmodules
vendored
@ -23,6 +23,7 @@
|
|||||||
[submodule "legacy/vendor/nanopb"]
|
[submodule "legacy/vendor/nanopb"]
|
||||||
path = legacy/vendor/nanopb
|
path = legacy/vendor/nanopb
|
||||||
url = https://github.com/nanopb/nanopb.git
|
url = https://github.com/nanopb/nanopb.git
|
||||||
|
ignore = untracked
|
||||||
[submodule "legacy/vendor/QR-Code-generator"]
|
[submodule "legacy/vendor/QR-Code-generator"]
|
||||||
path = legacy/vendor/QR-Code-generator
|
path = legacy/vendor/QR-Code-generator
|
||||||
url = https://github.com/nayuki/QR-Code-generator.git
|
url = https://github.com/nayuki/QR-Code-generator.git
|
||||||
|
24
Makefile
Normal file
24
Makefile
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
## help commands:
|
||||||
|
|
||||||
|
help: ## show this help
|
||||||
|
@awk -f ./tools/help.awk $(MAKEFILE_LIST)
|
||||||
|
|
||||||
|
## style commands:
|
||||||
|
|
||||||
|
style_check: ## run code style check on application sources and tests
|
||||||
|
flake8 --version
|
||||||
|
isort --version | awk '/VERSION/{print $$2}'
|
||||||
|
black --version
|
||||||
|
flake8 $(shell find -type f -name '*.py' | grep -f ./tools/style.py.include | grep -v -f ./tools/style.py.exclude )
|
||||||
|
isort --check-only $(shell find -type f -name '*.py' | grep -f ./tools/style.py.include | grep -v -f ./tools/style.py.exclude )
|
||||||
|
black --check $(shell find -type f -name '*.py' | grep -f ./tools/style.py.include | grep -v -f ./tools/style.py.exclude )
|
||||||
|
|
||||||
|
style: ## apply code style on application sources and tests
|
||||||
|
isort $(shell find -type f -name '*.py' | grep -f ./tools/style.py.include | grep -v -f ./tools/style.py.exclude )
|
||||||
|
black $(shell find -type f -name '*.py' | grep -f ./tools/style.py.include | grep -v -f ./tools/style.py.exclude )
|
||||||
|
|
||||||
|
cstyle_check: ## run code style check on low-level C code
|
||||||
|
./tools/clang-format-check $(shell find -type f -name '*.c' -o -name '*.h' | grep -f ./tools/style.c.include | grep -v -f ./tools/style.c.exclude )
|
||||||
|
|
||||||
|
cstyle: ## apply code style on low-level C code
|
||||||
|
clang-format -i $(shell find -type f -name '*.c' -o -name '*.h' | grep -f ./tools/style.c.include | grep -v -f ./tools/style.c.exclude )
|
@ -1,13 +1,12 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
import json
|
||||||
import sys
|
import sys
|
||||||
from glob import glob
|
from glob import glob
|
||||||
import json
|
|
||||||
from hashlib import sha256
|
from hashlib import sha256
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
opt = sys.argv[1]
|
opt = sys.argv[1]
|
||||||
except:
|
except IndexError:
|
||||||
print("Usage: gen.py [core|mcu|check])")
|
print("Usage: gen.py [core|mcu|check])")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
@ -22,12 +21,12 @@ def gen_core(data):
|
|||||||
for d in data:
|
for d in data:
|
||||||
if "u2f" in d:
|
if "u2f" in d:
|
||||||
url, label = d["u2f"], d["label"]
|
url, label = d["u2f"], d["label"]
|
||||||
print(" \"%s\": \"%s\"," % (url, label))
|
print(' "%s": "%s",' % (url, label))
|
||||||
print(" # WebAuthn")
|
print(" # WebAuthn")
|
||||||
for d in data:
|
for d in data:
|
||||||
if "webauthn" in d:
|
if "webauthn" in d:
|
||||||
origin, label = d["webauthn"], d["label"]
|
origin, label = d["webauthn"], d["label"]
|
||||||
print(" \"%s\": \"%s\"," % (origin, label))
|
print(' "%s": "%s",' % (origin, label))
|
||||||
print("}")
|
print("}")
|
||||||
|
|
||||||
|
|
||||||
@ -36,12 +35,17 @@ def gen_mcu(data):
|
|||||||
if "u2f" in d:
|
if "u2f" in d:
|
||||||
url, label = d["u2f"], d["label"]
|
url, label = d["u2f"], d["label"]
|
||||||
h = sha256(url.encode()).digest()
|
h = sha256(url.encode()).digest()
|
||||||
print("\t{\n\t\t// U2F: %s\n\t\t%s,\n\t\t\"%s\"\n\t}," % (url, c_bytes(h), label))
|
print(
|
||||||
|
'\t{\n\t\t// U2F: %s\n\t\t%s,\n\t\t"%s"\n\t},'
|
||||||
|
% (url, c_bytes(h), label)
|
||||||
|
)
|
||||||
if "webauthn" in d:
|
if "webauthn" in d:
|
||||||
origin, label = d["webauthn"], d["label"]
|
origin, label = d["webauthn"], d["label"]
|
||||||
h = sha256(origin.encode()).digest()
|
h = sha256(origin.encode()).digest()
|
||||||
print("\t{\n\t\t// WebAuthn: %s\n\t\t%s,\n\t\t\"%s\"\n\t}," % (origin, c_bytes(h), label))
|
print(
|
||||||
|
'\t{\n\t\t// WebAuthn: %s\n\t\t%s,\n\t\t"%s"\n\t},'
|
||||||
|
% (origin, c_bytes(h), label)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
data = []
|
data = []
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
// clang-format off
|
||||||
// TREZORv1 production public keys
|
// TREZORv1 production public keys
|
||||||
"\x04\xd5\x71\xb7\xf1\x48\xc5\xe4\x23\x2c\x38\x14\xf7\x77\xd8\xfa\xea\xf1\xa8\x42\x16\xc7\x8d\x56\x9b\x71\x04\x1f\xfc\x76\x8a\x5b\x2d\x81\x0f\xc3\xbb\x13\x4d\xd0\x26\xb5\x7e\x65\x00\x52\x75\xae\xde\xf4\x3e\x15\x5f\x48\xfc\x11\xa3\x2e\xc7\x90\xa9\x33\x12\xbd\x58",
|
"\x04\xd5\x71\xb7\xf1\x48\xc5\xe4\x23\x2c\x38\x14\xf7\x77\xd8\xfa\xea\xf1\xa8\x42\x16\xc7\x8d\x56\x9b\x71\x04\x1f\xfc\x76\x8a\x5b\x2d\x81\x0f\xc3\xbb\x13\x4d\xd0\x26\xb5\x7e\x65\x00\x52\x75\xae\xde\xf4\x3e\x15\x5f\x48\xfc\x11\xa3\x2e\xc7\x90\xa9\x33\x12\xbd\x58",
|
||||||
"\x04\x63\x27\x9c\x0c\x08\x66\xe5\x0c\x05\xc7\x99\xd3\x2b\xd6\xba\xb0\x18\x8b\x6d\xe0\x65\x36\xd1\x10\x9d\x2e\xd9\xce\x76\xcb\x33\x5c\x49\x0e\x55\xae\xe1\x0c\xc9\x01\x21\x51\x32\xe8\x53\x09\x7d\x54\x32\xed\xa0\x6b\x79\x20\x73\xbd\x77\x40\xc9\x4c\xe4\x51\x6c\xb1",
|
"\x04\x63\x27\x9c\x0c\x08\x66\xe5\x0c\x05\xc7\x99\xd3\x2b\xd6\xba\xb0\x18\x8b\x6d\xe0\x65\x36\xd1\x10\x9d\x2e\xd9\xce\x76\xcb\x33\x5c\x49\x0e\x55\xae\xe1\x0c\xc9\x01\x21\x51\x32\xe8\x53\x09\x7d\x54\x32\xed\xa0\x6b\x79\x20\x73\xbd\x77\x40\xc9\x4c\xe4\x51\x6c\xb1",
|
||||||
|
@ -1,2 +1,3 @@
|
|||||||
|
// clang-format off
|
||||||
// sample public key "correct horse battery staple"
|
// sample public key "correct horse battery staple"
|
||||||
"\x04\x78\xd4\x30\x27\x4f\x8c\x5e\xc1\x32\x13\x38\x15\x1e\x9f\x27\xf4\xc6\x76\xa0\x08\xbd\xf8\x63\x8d\x07\xc0\xb6\xbe\x9a\xb3\x5c\x71\xa1\x51\x80\x63\x24\x3a\xcd\x4d\xfe\x96\xb6\x6e\x3f\x2e\xc8\x01\x3c\x8e\x07\x2c\xd0\x9b\x38\x34\xa1\x9f\x81\xf6\x59\xcc\x34\x55"
|
"\x04\x78\xd4\x30\x27\x4f\x8c\x5e\xc1\x32\x13\x38\x15\x1e\x9f\x27\xf4\xc6\x76\xa0\x08\xbd\xf8\x63\x8d\x07\xc0\xb6\xbe\x9a\xb3\x5c\x71\xa1\x51\x80\x63\x24\x3a\xcd\x4d\xfe\x96\xb6\x6e\x3f\x2e\xc8\x01\x3c\x8e\x07\x2c\xd0\x9b\x38\x34\xa1\x9f\x81\xf6\x59\xcc\x34\x55"
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
from glob import glob
|
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
from glob import glob
|
||||||
|
|
||||||
error = False
|
error = False
|
||||||
|
|
||||||
@ -21,7 +21,9 @@ for fn in sorted(glob(os.path.join(MYDIR, "messages-*.proto"))):
|
|||||||
line = line.strip().split(" ")
|
line = line.strip().split(" ")
|
||||||
if line[0] not in ["enum", "message"]:
|
if line[0] not in ["enum", "message"]:
|
||||||
continue
|
continue
|
||||||
if not line[1].startswith(prefix) and not line[1].startswith("Debug" + prefix):
|
if not line[1].startswith(prefix) and not line[1].startswith(
|
||||||
|
"Debug" + prefix
|
||||||
|
):
|
||||||
print("ERROR:", fn, line[1])
|
print("ERROR:", fn, line[1])
|
||||||
error = True
|
error = True
|
||||||
|
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
from collections import defaultdict, OrderedDict
|
|
||||||
import re
|
|
||||||
import os
|
|
||||||
import json
|
|
||||||
import glob
|
import glob
|
||||||
|
import json
|
||||||
import logging
|
import logging
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
from collections import OrderedDict, defaultdict
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import requests
|
import requests
|
||||||
|
@ -3,38 +3,38 @@ from trezorlib import protobuf as p
|
|||||||
|
|
||||||
class CoinDef(p.MessageType):
|
class CoinDef(p.MessageType):
|
||||||
FIELDS = {
|
FIELDS = {
|
||||||
1: ('coin_name', p.UnicodeType, 0),
|
1: ("coin_name", p.UnicodeType, 0),
|
||||||
2: ('coin_shortcut', p.UnicodeType, 0),
|
2: ("coin_shortcut", p.UnicodeType, 0),
|
||||||
3: ('coin_label', p.UnicodeType, 0),
|
3: ("coin_label", p.UnicodeType, 0),
|
||||||
4: ('curve_name', p.UnicodeType, 0),
|
4: ("curve_name", p.UnicodeType, 0),
|
||||||
5: ('address_type', p.UVarintType, 0),
|
5: ("address_type", p.UVarintType, 0),
|
||||||
6: ('address_type_p2sh', p.UVarintType, 0),
|
6: ("address_type_p2sh", p.UVarintType, 0),
|
||||||
7: ('maxfee_kb', p.UVarintType, 0),
|
7: ("maxfee_kb", p.UVarintType, 0),
|
||||||
8: ('minfee_kb', p.UVarintType, 0),
|
8: ("minfee_kb", p.UVarintType, 0),
|
||||||
9: ('signed_message_header', p.BytesType, 0),
|
9: ("signed_message_header", p.BytesType, 0),
|
||||||
10: ('hash_genesis_block', p.BytesType, 0),
|
10: ("hash_genesis_block", p.BytesType, 0),
|
||||||
11: ('xprv_magic', p.UVarintType, 0),
|
11: ("xprv_magic", p.UVarintType, 0),
|
||||||
12: ('xpub_magic', p.UVarintType, 0),
|
12: ("xpub_magic", p.UVarintType, 0),
|
||||||
13: ('xpub_magic_segwit_p2sh', p.UVarintType, 0),
|
13: ("xpub_magic_segwit_p2sh", p.UVarintType, 0),
|
||||||
14: ('xpub_magic_segwit_native', p.UVarintType, 0),
|
14: ("xpub_magic_segwit_native", p.UVarintType, 0),
|
||||||
15: ('bech32_prefix', p.UnicodeType, 0),
|
15: ("bech32_prefix", p.UnicodeType, 0),
|
||||||
16: ('cashaddr_prefix', p.UnicodeType, 0),
|
16: ("cashaddr_prefix", p.UnicodeType, 0),
|
||||||
17: ('slip44', p.UVarintType, 0),
|
17: ("slip44", p.UVarintType, 0),
|
||||||
18: ('segwit', p.BoolType, 0),
|
18: ("segwit", p.BoolType, 0),
|
||||||
19: ('decred', p.BoolType, 0),
|
19: ("decred", p.BoolType, 0),
|
||||||
20: ('fork_id', p.UVarintType, 0),
|
20: ("fork_id", p.UVarintType, 0),
|
||||||
21: ('force_bip143', p.BoolType, 0),
|
21: ("force_bip143", p.BoolType, 0),
|
||||||
22: ('dust_limit', p.UVarintType, 0),
|
22: ("dust_limit", p.UVarintType, 0),
|
||||||
23: ('uri_prefix', p.UnicodeType, 0),
|
23: ("uri_prefix", p.UnicodeType, 0),
|
||||||
24: ('min_address_length', p.UVarintType, 0),
|
24: ("min_address_length", p.UVarintType, 0),
|
||||||
25: ('max_address_length', p.UVarintType, 0),
|
25: ("max_address_length", p.UVarintType, 0),
|
||||||
26: ('icon', p.BytesType, 0),
|
26: ("icon", p.BytesType, 0),
|
||||||
28: ('website', p.UnicodeType, 0),
|
28: ("website", p.UnicodeType, 0),
|
||||||
29: ('github', p.UnicodeType, 0),
|
29: ("github", p.UnicodeType, 0),
|
||||||
30: ('maintainer', p.UnicodeType, 0),
|
30: ("maintainer", p.UnicodeType, 0),
|
||||||
31: ('blocktime_seconds', p.UVarintType, 0),
|
31: ("blocktime_seconds", p.UVarintType, 0),
|
||||||
32: ('bip115', p.BoolType, 0),
|
32: ("bip115", p.BoolType, 0),
|
||||||
33: ('cooldown', p.UVarintType, 0),
|
33: ("cooldown", p.UVarintType, 0),
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
@ -73,7 +73,7 @@ class CoinDef(p.MessageType):
|
|||||||
default_fee_b: dict = None,
|
default_fee_b: dict = None,
|
||||||
bitcore: dict = None,
|
bitcore: dict = None,
|
||||||
blockbook: dict = None,
|
blockbook: dict = None,
|
||||||
cooldown: int = None
|
cooldown: int = None,
|
||||||
):
|
):
|
||||||
self.coin_name = coin_name
|
self.coin_name = coin_name
|
||||||
self.coin_shortcut = coin_shortcut
|
self.coin_shortcut = coin_shortcut
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""Fetch information about coins and tokens supported by Trezor and update it in coins_details.json."""
|
"""Fetch information about coins and tokens supported by Trezor and update it in coins_details.json."""
|
||||||
import os
|
|
||||||
import time
|
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import requests
|
import os
|
||||||
import sys
|
import sys
|
||||||
import coin_info
|
import time
|
||||||
|
|
||||||
import click
|
import click
|
||||||
|
import requests
|
||||||
|
|
||||||
|
import coin_info
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -149,7 +150,7 @@ def summary(coins, api_key):
|
|||||||
try:
|
try:
|
||||||
ret = coinmarketcap_call("global-metrics/quotes/latest", api_key)
|
ret = coinmarketcap_call("global-metrics/quotes/latest", api_key)
|
||||||
total_marketcap = int(ret["data"]["quote"]["USD"]["total_market_cap"])
|
total_marketcap = int(ret["data"]["quote"]["USD"]["total_market_cap"])
|
||||||
except:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
return dict(
|
return dict(
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
import fnmatch
|
import fnmatch
|
||||||
|
import glob
|
||||||
import io
|
import io
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
import os
|
import os
|
||||||
import glob
|
import re
|
||||||
import struct
|
import struct
|
||||||
|
import sys
|
||||||
import zlib
|
import zlib
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from hashlib import sha256
|
from hashlib import sha256
|
||||||
@ -524,8 +524,7 @@ def cli(colors):
|
|||||||
# fmt: off
|
# fmt: off
|
||||||
@click.option("--backend/--no-backend", "-b", default=False, help="Check blockbook/bitcore responses")
|
@click.option("--backend/--no-backend", "-b", default=False, help="Check blockbook/bitcore responses")
|
||||||
@click.option("--icons/--no-icons", default=True, help="Check icon files")
|
@click.option("--icons/--no-icons", default=True, help="Check icon files")
|
||||||
@click.option("-d", "--show-duplicates", type=click.Choice(("all", "nontoken", "errors")),
|
@click.option("-d", "--show-duplicates", type=click.Choice(("all", "nontoken", "errors")), default="errors", help="How much information about duplicate shortcuts should be shown.")
|
||||||
default="errors", help="How much information about duplicate shortcuts should be shown.")
|
|
||||||
# fmt: on
|
# fmt: on
|
||||||
def check(backend, icons, show_duplicates):
|
def check(backend, icons, show_duplicates):
|
||||||
"""Validate coin definitions.
|
"""Validate coin definitions.
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
import click
|
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import requests
|
|
||||||
import tempfile
|
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import tempfile
|
||||||
|
|
||||||
|
import click
|
||||||
|
import requests
|
||||||
|
|
||||||
LIVE_URL = "https://trezor.io/static/json/coins_details.json"
|
LIVE_URL = "https://trezor.io/static/json/coins_details.json"
|
||||||
COINS_DETAILS = os.path.join(
|
COINS_DETAILS = os.path.join(
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
import re
|
import json
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import click
|
import click
|
||||||
|
|
||||||
import coin_info
|
import coin_info
|
||||||
import json
|
|
||||||
|
|
||||||
SUPPORT_INFO = coin_info.get_support_data()
|
SUPPORT_INFO = coin_info.get_support_data()
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ CFLAGS += -DGITREV=$(GITREV)
|
|||||||
## help commands:
|
## help commands:
|
||||||
|
|
||||||
help: ## show this help
|
help: ## show this help
|
||||||
@awk -f help.awk $(MAKEFILE_LIST)
|
@awk -f ../tools/help.awk $(MAKEFILE_LIST)
|
||||||
|
|
||||||
## dependencies commands:
|
## dependencies commands:
|
||||||
|
|
||||||
@ -71,27 +71,6 @@ test_emu_monero: ## run selected monero device tests from monero-agent
|
|||||||
pylint: ## run pylint on application sources and tests
|
pylint: ## run pylint on application sources and tests
|
||||||
pylint -E $(shell find src tests -name *.py)
|
pylint -E $(shell find src tests -name *.py)
|
||||||
|
|
||||||
## style commands:
|
|
||||||
|
|
||||||
style_check: ## run code style check on application sources and tests
|
|
||||||
flake8 --version
|
|
||||||
isort --version | grep "VERSION"
|
|
||||||
black --version
|
|
||||||
flake8 $(shell find src -name *.py)
|
|
||||||
isort --check-only $(shell find src -name *.py ! -path 'src/trezor/messages/*')
|
|
||||||
black --check $(shell find src -name *.py ! -path 'src/trezor/messages/*')
|
|
||||||
|
|
||||||
style: ## apply code style on application sources and tests
|
|
||||||
isort $(shell find src -name *.py ! -path 'src/trezor/messages/*')
|
|
||||||
black $(shell find src -name *.py ! -path 'src/trezor/messages/*')
|
|
||||||
|
|
||||||
cstyle_check: ## run code style check on low-level C code
|
|
||||||
./tools/clang-format-check embed/*/*.{c,h} embed/extmod/modtrezor*/*.{c,h}
|
|
||||||
|
|
||||||
|
|
||||||
cstyle: ## apply code style on low-level C code
|
|
||||||
clang-format -i embed/*/*.{c,h} embed/extmod/modtrezor*/*.{c,h}
|
|
||||||
|
|
||||||
## code generation:
|
## code generation:
|
||||||
|
|
||||||
templates: ## render Mako templates (for lists of coins, tokens, etc.)
|
templates: ## render Mako templates (for lists of coins, tokens, etc.)
|
||||||
|
@ -241,6 +241,4 @@ void display_refresh(void) {
|
|||||||
HAL_GPIO_WritePin(OLED_DC_PORT, OLED_DC_PIN, GPIO_PIN_RESET); // set to CMD
|
HAL_GPIO_WritePin(OLED_DC_PORT, OLED_DC_PIN, GPIO_PIN_RESET); // set to CMD
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *display_save(const char *prefix) {
|
const char *display_save(const char *prefix) { return NULL; }
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
@ -498,6 +498,4 @@ void display_refresh(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *display_save(const char *prefix) {
|
const char *display_save(const char *prefix) { return NULL; }
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
// clang-format off
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This file is part of the MicroPython project, http://micropython.org/
|
* This file is part of the MicroPython project, http://micropython.org/
|
||||||
*
|
*
|
||||||
|
@ -31,6 +31,6 @@ def get_type(wire_type):
|
|||||||
for msg_name in dir(MessageType):
|
for msg_name in dir(MessageType):
|
||||||
# Modules contain internal variables that may cause exception here.
|
# Modules contain internal variables that may cause exception here.
|
||||||
# No Message begins with underscore so it's safe to skip those.
|
# No Message begins with underscore so it's safe to skip those.
|
||||||
if (msg_name[0] == '_'):
|
if msg_name[0] == "_":
|
||||||
continue
|
continue
|
||||||
type_to_name[getattr(MessageType, msg_name)] = msg_name
|
type_to_name[getattr(MessageType, msg_name)] = msg_name
|
||||||
|
@ -1,2 +0,0 @@
|
|||||||
---
|
|
||||||
BasedOnStyle: Google
|
|
@ -5,9 +5,7 @@ START_TEST(test_ed25519_cardano_sign_vectors) {
|
|||||||
ed25519_secret_key secret_key_extension;
|
ed25519_secret_key secret_key_extension;
|
||||||
ed25519_signature signature;
|
ed25519_signature signature;
|
||||||
|
|
||||||
static const char
|
static const char *vectors[] = {
|
||||||
*vectors[] =
|
|
||||||
{
|
|
||||||
"6065a956b1b34145c4416fdc3ba3276801850e91a77a31a7be782463288aea5"
|
"6065a956b1b34145c4416fdc3ba3276801850e91a77a31a7be782463288aea5"
|
||||||
"3", // private key
|
"3", // private key
|
||||||
"60ba6e25b1a02157fb69c5d1d7b96c4619736e545447069a6a6f0ba90844bc8"
|
"60ba6e25b1a02157fb69c5d1d7b96c4619736e545447069a6a6f0ba90844bc8"
|
||||||
|
@ -5,10 +5,11 @@ import hashlib
|
|||||||
import os
|
import os
|
||||||
import random
|
import random
|
||||||
|
|
||||||
import curve25519
|
|
||||||
import ecdsa
|
import ecdsa
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
import curve25519
|
||||||
|
|
||||||
|
|
||||||
def bytes2num(s):
|
def bytes2num(s):
|
||||||
res = 0
|
res = 0
|
||||||
@ -30,48 +31,48 @@ class Point:
|
|||||||
points = [
|
points = [
|
||||||
Point(
|
Point(
|
||||||
"secp256k1",
|
"secp256k1",
|
||||||
0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798,
|
0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798,
|
||||||
0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8,
|
0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8,
|
||||||
),
|
),
|
||||||
Point(
|
Point(
|
||||||
"secp256k1",
|
"secp256k1",
|
||||||
0x1,
|
0x1,
|
||||||
0x4218f20ae6c646b363db68605822fb14264ca8d2587fdd6fbc750d587e76a7ee,
|
0x4218F20AE6C646B363DB68605822FB14264CA8D2587FDD6FBC750D587E76A7EE,
|
||||||
),
|
),
|
||||||
Point(
|
Point(
|
||||||
"secp256k1",
|
"secp256k1",
|
||||||
0x2,
|
0x2,
|
||||||
0x66fbe727b2ba09e09f5a98d70a5efce8424c5fa425bbda1c511f860657b8535e,
|
0x66FBE727B2BA09E09F5A98D70A5EFCE8424C5FA425BBDA1C511F860657B8535E,
|
||||||
),
|
),
|
||||||
Point(
|
Point(
|
||||||
"secp256k1",
|
"secp256k1",
|
||||||
0x1b,
|
0x1B,
|
||||||
0x1adcea1cf831b0ad1653e769d1a229091d0cc68d4b0328691b9caacc76e37c90,
|
0x1ADCEA1CF831B0AD1653E769D1A229091D0CC68D4B0328691B9CAACC76E37C90,
|
||||||
),
|
),
|
||||||
Point(
|
Point(
|
||||||
"nist256p1",
|
"nist256p1",
|
||||||
0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296,
|
0x6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296,
|
||||||
0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5,
|
0x4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5,
|
||||||
),
|
),
|
||||||
Point(
|
Point(
|
||||||
"nist256p1",
|
"nist256p1",
|
||||||
0x0,
|
0x0,
|
||||||
0x66485c780e2f83d72433bd5d84a06bb6541c2af31dae871728bf856a174f93f4,
|
0x66485C780E2F83D72433BD5D84A06BB6541C2AF31DAE871728BF856A174F93F4,
|
||||||
),
|
),
|
||||||
Point(
|
Point(
|
||||||
"nist256p1",
|
"nist256p1",
|
||||||
0x0,
|
0x0,
|
||||||
0x99b7a386f1d07c29dbcc42a27b5f9449abe3d50de25178e8d7407a95e8b06c0b,
|
0x99B7A386F1D07C29DBCC42A27B5F9449ABE3D50DE25178E8D7407A95E8B06C0B,
|
||||||
),
|
),
|
||||||
Point(
|
Point(
|
||||||
"nist256p1",
|
"nist256p1",
|
||||||
0xaf8bbdfe8cdd5577acbf345b543d28cf402f4e94d3865b97ea0787f2d3aa5d22,
|
0xAF8BBDFE8CDD5577ACBF345B543D28CF402F4E94D3865B97EA0787F2D3AA5D22,
|
||||||
0x35802b8b376b995265918b078bc109c21a535176585c40f519aca52d6afc147c,
|
0x35802B8B376B995265918B078BC109C21A535176585C40F519ACA52D6AFC147C,
|
||||||
),
|
),
|
||||||
Point(
|
Point(
|
||||||
"nist256p1",
|
"nist256p1",
|
||||||
0x80000,
|
0x80000,
|
||||||
0x580610071f440f0dcc14a22e2d5d5afc1224c0cd11a3b4b51b8ecd2224ee1ce2,
|
0x580610071F440F0DCC14A22E2D5D5AFC1224C0CD11A3B4B51B8ECD2224EE1CE2,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -102,7 +102,7 @@ def is_valid_der(data):
|
|||||||
try:
|
try:
|
||||||
structure, _ = der_decode(data)
|
structure, _ = der_decode(data)
|
||||||
return data == der_encode(structure)
|
return data == der_encode(structure)
|
||||||
except:
|
except Exception:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
@ -140,7 +140,7 @@ def parse_ec_pubkey(public_key):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
public_key = bytes(public_key["public_key"].asOctets())
|
public_key = bytes(public_key["public_key"].asOctets())
|
||||||
except:
|
except Exception:
|
||||||
raise ParseError("Not a BER encoded named elliptic curve public key")
|
raise ParseError("Not a BER encoded named elliptic curve public key")
|
||||||
|
|
||||||
return curve_name, public_key
|
return curve_name, public_key
|
||||||
@ -152,13 +152,13 @@ def parse_ecdsa256_signature(signature):
|
|||||||
raise ParseError("Not a valid DER")
|
raise ParseError("Not a valid DER")
|
||||||
try:
|
try:
|
||||||
signature, _ = der_decode(signature, asn1Spec=EcSignature())
|
signature, _ = der_decode(signature, asn1Spec=EcSignature())
|
||||||
except:
|
except Exception:
|
||||||
raise ParseError("Not a valid DER encoded ECDSA signature")
|
raise ParseError("Not a valid DER encoded ECDSA signature")
|
||||||
try:
|
try:
|
||||||
r = int(signature["r"]).to_bytes(32, byteorder="big")
|
r = int(signature["r"]).to_bytes(32, byteorder="big")
|
||||||
s = int(signature["s"]).to_bytes(32, byteorder="big")
|
s = int(signature["s"]).to_bytes(32, byteorder="big")
|
||||||
signature = r + s
|
signature = r + s
|
||||||
except:
|
except Exception:
|
||||||
raise ParseError("Not a valid DER encoded 256 bit ECDSA signature")
|
raise ParseError("Not a valid DER encoded 256 bit ECDSA signature")
|
||||||
return signature
|
return signature
|
||||||
|
|
||||||
@ -281,7 +281,7 @@ def aes_cbc_decrypt(key, iv, ciphertext):
|
|||||||
def load_json_testvectors(filename):
|
def load_json_testvectors(filename):
|
||||||
try:
|
try:
|
||||||
result = json.loads(open(os.path.join(testvectors_directory, filename)).read())
|
result = json.loads(open(os.path.join(testvectors_directory, filename)).read())
|
||||||
except:
|
except Exception:
|
||||||
raise DataError()
|
raise DataError()
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@ -310,7 +310,7 @@ def generate_aes(filename):
|
|||||||
plaintext = unhexlify(test["msg"])
|
plaintext = unhexlify(test["msg"])
|
||||||
ciphertext = unhexlify(test["ct"])
|
ciphertext = unhexlify(test["ct"])
|
||||||
result = parse_result(test["result"])
|
result = parse_result(test["result"])
|
||||||
except:
|
except Exception:
|
||||||
raise DataError()
|
raise DataError()
|
||||||
|
|
||||||
if len(key) not in [128 / 8, 192 / 8, 256 / 8]:
|
if len(key) not in [128 / 8, 192 / 8, 256 / 8]:
|
||||||
@ -359,7 +359,7 @@ def generate_chacha_poly(filename):
|
|||||||
ciphertext = unhexlify(test["ct"])
|
ciphertext = unhexlify(test["ct"])
|
||||||
tag = unhexlify(test["tag"])
|
tag = unhexlify(test["tag"])
|
||||||
result = parse_result(test["result"])
|
result = parse_result(test["result"])
|
||||||
except:
|
except Exception:
|
||||||
raise DataError()
|
raise DataError()
|
||||||
|
|
||||||
if result is None:
|
if result is None:
|
||||||
@ -406,7 +406,7 @@ def generate_curve25519_dh(filename):
|
|||||||
private_key = unhexlify(test["private"])
|
private_key = unhexlify(test["private"])
|
||||||
shared = unhexlify(test["shared"])
|
shared = unhexlify(test["shared"])
|
||||||
result = parse_result(test["result"])
|
result = parse_result(test["result"])
|
||||||
except:
|
except Exception:
|
||||||
raise DataError()
|
raise DataError()
|
||||||
|
|
||||||
if curve_name != "curve25519":
|
if curve_name != "curve25519":
|
||||||
@ -448,7 +448,7 @@ def generate_ecdh(filename):
|
|||||||
private_key = parse_signed_hex(test["private"])
|
private_key = parse_signed_hex(test["private"])
|
||||||
shared = unhexlify(test["shared"])
|
shared = unhexlify(test["shared"])
|
||||||
result = parse_result(test["result"])
|
result = parse_result(test["result"])
|
||||||
except:
|
except Exception:
|
||||||
raise DataError()
|
raise DataError()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -498,7 +498,7 @@ def generate_ecdsa(filename):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
public_key = unhexlify(test_group["keyDer"])
|
public_key = unhexlify(test_group["keyDer"])
|
||||||
except:
|
except Exception:
|
||||||
raise DataError()
|
raise DataError()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -521,7 +521,7 @@ def generate_ecdsa(filename):
|
|||||||
signature = unhexlify(test["sig"])
|
signature = unhexlify(test["sig"])
|
||||||
message = unhexlify(test["msg"])
|
message = unhexlify(test["msg"])
|
||||||
result = parse_result(test["result"])
|
result = parse_result(test["result"])
|
||||||
except:
|
except Exception:
|
||||||
raise DataError()
|
raise DataError()
|
||||||
|
|
||||||
if result is None:
|
if result is None:
|
||||||
@ -563,7 +563,7 @@ def generate_eddsa(filename):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
public_key = unhexlify(test_group["keyDer"])
|
public_key = unhexlify(test_group["keyDer"])
|
||||||
except:
|
except Exception:
|
||||||
raise DataError()
|
raise DataError()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -579,7 +579,7 @@ def generate_eddsa(filename):
|
|||||||
signature = unhexlify(test["sig"])
|
signature = unhexlify(test["sig"])
|
||||||
message = unhexlify(test["msg"])
|
message = unhexlify(test["msg"])
|
||||||
result = parse_result(test["result"])
|
result = parse_result(test["result"])
|
||||||
except:
|
except Exception:
|
||||||
raise DataError()
|
raise DataError()
|
||||||
|
|
||||||
if result is None:
|
if result is None:
|
||||||
|
@ -1,2 +0,0 @@
|
|||||||
---
|
|
||||||
BasedOnStyle: Google
|
|
@ -1,12 +1,12 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
|
||||||
bl = open('bl.bin').read()
|
bl = open("bl.bin").read()
|
||||||
fw = open('fw.bin').read()
|
fw = open("fw.bin").read()
|
||||||
combined = bl + fw[:256] + (32768-256)*'\x00' + fw[256:]
|
combined = bl + fw[:256] + (32768 - 256) * "\x00" + fw[256:]
|
||||||
|
|
||||||
open('combined.bin', 'w').write(combined)
|
open("combined.bin", "w").write(combined)
|
||||||
|
|
||||||
print('bootloader : %d bytes' % len(bl))
|
print("bootloader : %d bytes" % len(bl))
|
||||||
print('firmware : %d bytes' % len(fw))
|
print("firmware : %d bytes" % len(fw))
|
||||||
print('combined : %d bytes' % len(combined))
|
print("combined : %d bytes" % len(combined))
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
import sys
|
|
||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
TOTALSIZE = 32768
|
TOTALSIZE = 32768
|
||||||
MAXSIZE = TOTALSIZE - 32
|
MAXSIZE = TOTALSIZE - 32
|
||||||
@ -8,7 +8,10 @@ MAXSIZE = TOTALSIZE - 32
|
|||||||
fn = sys.argv[1]
|
fn = sys.argv[1]
|
||||||
fs = os.stat(fn).st_size
|
fs = os.stat(fn).st_size
|
||||||
if fs > MAXSIZE:
|
if fs > MAXSIZE:
|
||||||
raise Exception('bootloader has to be smaller than %d bytes (current size is %d)' % (MAXSIZE, fs))
|
raise Exception(
|
||||||
with open(fn, 'ab') as f:
|
"bootloader has to be smaller than %d bytes (current size is %d)"
|
||||||
f.write(b'\x00' * (TOTALSIZE - fs))
|
% (MAXSIZE, fs)
|
||||||
|
)
|
||||||
|
with open(fn, "ab") as f:
|
||||||
|
f.write(b"\x00" * (TOTALSIZE - fs))
|
||||||
f.close()
|
f.close()
|
||||||
|
@ -7,7 +7,6 @@ import struct
|
|||||||
|
|
||||||
import ecdsa
|
import ecdsa
|
||||||
|
|
||||||
|
|
||||||
SLOTS = 3
|
SLOTS = 3
|
||||||
|
|
||||||
pubkeys = {
|
pubkeys = {
|
||||||
@ -94,7 +93,7 @@ def update_hashes_in_header(data):
|
|||||||
data = bytearray(data)
|
data = bytearray(data)
|
||||||
o = 0
|
o = 0
|
||||||
for h in prepare_hashes(data[FWHEADER_SIZE:]):
|
for h in prepare_hashes(data[FWHEADER_SIZE:]):
|
||||||
data[0x20 + o:0x20 + o + 32] = h
|
data[0x20 + o : 0x20 + o + 32] = h
|
||||||
o += 32
|
o += 32
|
||||||
return bytes(data)
|
return bytes(data)
|
||||||
|
|
||||||
@ -112,6 +111,7 @@ def check_size(data):
|
|||||||
size = struct.unpack("<L", data[12:16])[0]
|
size = struct.unpack("<L", data[12:16])[0]
|
||||||
assert size == len(data) - 1024
|
assert size == len(data) - 1024
|
||||||
|
|
||||||
|
|
||||||
def check_signatures(data):
|
def check_signatures(data):
|
||||||
# Analyses given firmware and prints out
|
# Analyses given firmware and prints out
|
||||||
# status of included signatures
|
# status of included signatures
|
||||||
@ -146,7 +146,7 @@ def check_signatures(data):
|
|||||||
used.append(indexes[x])
|
used.append(indexes[x])
|
||||||
print("Slot #%d signature: VALID" % (x + 1), signature.hex())
|
print("Slot #%d signature: VALID" % (x + 1), signature.hex())
|
||||||
|
|
||||||
except:
|
except Exception:
|
||||||
print("Slot #%d signature: INVALID" % (x + 1), signature.hex())
|
print("Slot #%d signature: INVALID" % (x + 1), signature.hex())
|
||||||
|
|
||||||
|
|
||||||
@ -202,7 +202,7 @@ def sign(data, is_pem):
|
|||||||
index = i
|
index = i
|
||||||
break
|
break
|
||||||
|
|
||||||
if index == None:
|
if index is None:
|
||||||
raise Exception("Unable to find private key index. Unknown private key?")
|
raise Exception("Unable to find private key index. Unknown private key?")
|
||||||
|
|
||||||
signature = key.sign_deterministic(to_sign, hashfunc=hashlib.sha256)
|
signature = key.sign_deterministic(to_sign, hashfunc=hashlib.sha256)
|
||||||
|
@ -2,29 +2,37 @@
|
|||||||
import hashlib
|
import hashlib
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import ecdsa
|
|
||||||
from binascii import hexlify, unhexlify
|
from binascii import hexlify, unhexlify
|
||||||
|
|
||||||
print('master secret:', end='')
|
import ecdsa
|
||||||
|
|
||||||
|
print("master secret:", end="")
|
||||||
h = input()
|
h = input()
|
||||||
if h:
|
if h:
|
||||||
h = unhexlify(h).encode('ascii')
|
h = unhexlify(h).encode("ascii")
|
||||||
else:
|
else:
|
||||||
h = hashlib.sha256(os.urandom(1024)).digest()
|
h = hashlib.sha256(os.urandom(1024)).digest()
|
||||||
|
|
||||||
print()
|
print()
|
||||||
print('master secret:', hexlify(h))
|
print("master secret:", hexlify(h))
|
||||||
print()
|
print()
|
||||||
|
|
||||||
for i in range(1, 6):
|
for i in range(1, 6):
|
||||||
se = hashlib.sha256(h + chr(i).encode('ascii')).hexdigest()
|
se = hashlib.sha256(h + chr(i).encode("ascii")).hexdigest()
|
||||||
print('seckey', i, ':', se)
|
print("seckey", i, ":", se)
|
||||||
sk = ecdsa.SigningKey.from_secret_exponent(secexp = int(se, 16), curve=ecdsa.curves.SECP256k1, hashfunc=hashlib.sha256)
|
sk = ecdsa.SigningKey.from_secret_exponent(
|
||||||
print('pubkey', i, ':', (b'04' + hexlify(sk.get_verifying_key().to_string())).decode('ascii'))
|
secexp=int(se, 16), curve=ecdsa.curves.SECP256k1, hashfunc=hashlib.sha256
|
||||||
print(sk.to_pem().decode('ascii'))
|
)
|
||||||
|
print(
|
||||||
|
"pubkey",
|
||||||
|
i,
|
||||||
|
":",
|
||||||
|
(b"04" + hexlify(sk.get_verifying_key().to_string())).decode("ascii"),
|
||||||
|
)
|
||||||
|
print(sk.to_pem().decode("ascii"))
|
||||||
|
|
||||||
p = subprocess.Popen('ssss-split -t 3 -n 5 -x'.split(' '), stdin = subprocess.PIPE)
|
p = subprocess.Popen("ssss-split -t 3 -n 5 -x".split(" "), stdin=subprocess.PIPE)
|
||||||
p.communicate(input = hexlify(h) + '\n')
|
p.communicate(input=hexlify(h) + "\n")
|
||||||
|
|
||||||
# to recover use:
|
# to recover use:
|
||||||
# $ ssss-combine -t 3 -x
|
# $ ssss-combine -t 3 -x
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
from hashlib import sha256
|
from hashlib import sha256
|
||||||
|
|
||||||
fn = '../bootloader/bootloader.bin'
|
fn = "../bootloader/bootloader.bin"
|
||||||
|
|
||||||
data = open(fn, 'rb').read()
|
data = open(fn, "rb").read()
|
||||||
if len(data) > 32768:
|
if len(data) > 32768:
|
||||||
raise Exception('bootloader has to be smaller than 32768 bytes')
|
raise Exception("bootloader has to be smaller than 32768 bytes")
|
||||||
|
|
||||||
data += b'\x00' * (32768 - len(data))
|
data += b"\x00" * (32768 - len(data))
|
||||||
|
|
||||||
h = sha256(sha256(data).digest()).digest()
|
h = sha256(sha256(data).digest()).digest()
|
||||||
|
|
||||||
bl_hash = ', '.join('0x%02x' % x for x in bytearray(h))
|
bl_hash = ", ".join("0x%02x" % x for x in bytearray(h))
|
||||||
bl_data = ', '.join('0x%02x' % x for x in bytearray(data))
|
bl_data = ", ".join("0x%02x" % x for x in bytearray(data))
|
||||||
|
|
||||||
with open('bl_data.h', 'wt') as f:
|
with open("bl_data.h", "wt") as f:
|
||||||
f.write('static const uint8_t bl_hash[32] = {%s};\n' % bl_hash)
|
f.write("static const uint8_t bl_hash[32] = {%s};\n" % bl_hash)
|
||||||
f.write('static const uint8_t bl_data[32768] = {%s};\n' % bl_data)
|
f.write("static const uint8_t bl_data[32768] = {%s};\n" % bl_data)
|
||||||
|
@ -256,12 +256,12 @@ void fsm_msgEntropyAck(const EntropyAck *msg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void fsm_msgBackupDevice(const BackupDevice *msg) {
|
void fsm_msgBackupDevice(const BackupDevice *msg) {
|
||||||
|
(void)msg;
|
||||||
|
|
||||||
CHECK_INITIALIZED
|
CHECK_INITIALIZED
|
||||||
|
|
||||||
CHECK_PIN_UNCACHED
|
CHECK_PIN_UNCACHED
|
||||||
|
|
||||||
(void)
|
|
||||||
msg;
|
|
||||||
char mnemonic[MAX_MNEMONIC_LEN + 1];
|
char mnemonic[MAX_MNEMONIC_LEN + 1];
|
||||||
if (config_getMnemonic(mnemonic, sizeof(mnemonic))) {
|
if (config_getMnemonic(mnemonic, sizeof(mnemonic))) {
|
||||||
reset_backup(true, mnemonic);
|
reset_backup(true, mnemonic);
|
||||||
|
@ -1,11 +1,16 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from messages_pb2 import MessageType
|
|
||||||
from messages_pb2 import wire_in, wire_out
|
from messages_pb2 import (
|
||||||
from messages_pb2 import wire_debug_in, wire_debug_out
|
MessageType,
|
||||||
from messages_pb2 import wire_bootloader, wire_no_fsm
|
wire_bootloader,
|
||||||
|
wire_debug_in,
|
||||||
|
wire_debug_out,
|
||||||
|
wire_in,
|
||||||
|
wire_no_fsm,
|
||||||
|
wire_out,
|
||||||
|
)
|
||||||
|
|
||||||
fh = open("messages_map.h", "wt")
|
fh = open("messages_map.h", "wt")
|
||||||
fl = open("messages_map_limits.h", "wt")
|
fl = open("messages_map_limits.h", "wt")
|
||||||
@ -24,7 +29,7 @@ LABELS = {
|
|||||||
def handle_message(fh, fl, skipped, message, extension):
|
def handle_message(fh, fl, skipped, message, extension):
|
||||||
name = message.name
|
name = message.name
|
||||||
short_name = name.split("MessageType_", 1).pop()
|
short_name = name.split("MessageType_", 1).pop()
|
||||||
assert(short_name != name)
|
assert short_name != name
|
||||||
|
|
||||||
for s in skipped:
|
for s in skipped:
|
||||||
if short_name.startswith(s):
|
if short_name.startswith(s):
|
||||||
@ -37,14 +42,14 @@ def handle_message(fh, fl, skipped, message, extension):
|
|||||||
bootloader = options.Extensions[wire_bootloader]
|
bootloader = options.Extensions[wire_bootloader]
|
||||||
no_fsm = options.Extensions[wire_no_fsm]
|
no_fsm = options.Extensions[wire_no_fsm]
|
||||||
|
|
||||||
if getattr(options, 'deprecated', None):
|
if getattr(options, "deprecated", None):
|
||||||
fh.write('\t// Message %s is deprecated\n' % short_name)
|
fh.write("\t// Message %s is deprecated\n" % short_name)
|
||||||
return
|
return
|
||||||
if bootloader:
|
if bootloader:
|
||||||
fh.write('\t// Message %s is used in bootloader mode only\n' % short_name)
|
fh.write("\t// Message %s is used in bootloader mode only\n" % short_name)
|
||||||
return
|
return
|
||||||
if no_fsm:
|
if no_fsm:
|
||||||
fh.write('\t// Message %s is not used in FSM\n' % short_name)
|
fh.write("\t// Message %s is not used in FSM\n" % short_name)
|
||||||
return
|
return
|
||||||
|
|
||||||
if direction == "i":
|
if direction == "i":
|
||||||
@ -52,13 +57,15 @@ def handle_message(fh, fl, skipped, message, extension):
|
|||||||
else:
|
else:
|
||||||
process_func = "0"
|
process_func = "0"
|
||||||
|
|
||||||
fh.write(TEMPLATE.format(
|
fh.write(
|
||||||
|
TEMPLATE.format(
|
||||||
type="'%c'," % interface,
|
type="'%c'," % interface,
|
||||||
dir="'%c'," % direction,
|
dir="'%c'," % direction,
|
||||||
msg_id="MessageType_%s," % name,
|
msg_id="MessageType_%s," % name,
|
||||||
fields="%s_fields," % short_name,
|
fields="%s_fields," % short_name,
|
||||||
process_func=process_func,
|
process_func=process_func,
|
||||||
))
|
)
|
||||||
|
)
|
||||||
|
|
||||||
bufsize = None
|
bufsize = None
|
||||||
t = interface + direction
|
t = interface + direction
|
||||||
@ -69,13 +76,20 @@ def handle_message(fh, fl, skipped, message, extension):
|
|||||||
elif t == "do":
|
elif t == "do":
|
||||||
bufsize = "MSG_DEBUG_OUT_SIZE"
|
bufsize = "MSG_DEBUG_OUT_SIZE"
|
||||||
if bufsize:
|
if bufsize:
|
||||||
fl.write("_Static_assert(%s >= sizeof(%s), \"msg buffer too small\");\n" % (bufsize, short_name))
|
fl.write(
|
||||||
|
'_Static_assert(%s >= sizeof(%s), "msg buffer too small");\n'
|
||||||
|
% (bufsize, short_name)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
skipped = sys.argv[1:]
|
skipped = sys.argv[1:]
|
||||||
|
|
||||||
fh.write("\t// This file is automatically generated by messages_map.py -- DO NOT EDIT!\n")
|
fh.write(
|
||||||
fl.write("// This file is automatically generated by messages_map.py -- DO NOT EDIT!\n\n")
|
"\t// This file is automatically generated by messages_map.py -- DO NOT EDIT!\n"
|
||||||
|
)
|
||||||
|
fl.write(
|
||||||
|
"// This file is automatically generated by messages_map.py -- DO NOT EDIT!\n\n"
|
||||||
|
)
|
||||||
|
|
||||||
messages = defaultdict(list)
|
messages = defaultdict(list)
|
||||||
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
// clang-format off
|
||||||
/**
|
/**
|
||||||
* Copyright FIDO Alliance, 2017
|
* Copyright FIDO Alliance, 2017
|
||||||
*
|
*
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
// clang-format off
|
||||||
/**
|
/**
|
||||||
* Copyright FIDO Alliance, 2017
|
* Copyright FIDO Alliance, 2017
|
||||||
*
|
*
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
// clang-format off
|
||||||
#include "bitmaps.h"
|
#include "bitmaps.h"
|
||||||
|
|
||||||
const uint8_t bmp_digit0_data[] = { 0xff, 0xff, 0xf8, 0x1f, 0xf0, 0x0f, 0xe1, 0x87, 0xe1, 0x87, 0xe1, 0x87, 0xe1, 0x87, 0xe1, 0x87, 0xe1, 0x87, 0xe1, 0x87, 0xe1, 0x87, 0xe1, 0x87, 0xe1, 0x87, 0xf0, 0x0f, 0xf8, 0x1f, 0xff, 0xff, };
|
const uint8_t bmp_digit0_data[] = { 0xff, 0xff, 0xf8, 0x1f, 0xf0, 0x0f, 0xe1, 0x87, 0xe1, 0x87, 0xe1, 0x87, 0xe1, 0x87, 0xe1, 0x87, 0xe1, 0x87, 0xe1, 0x87, 0xe1, 0x87, 0xe1, 0x87, 0xe1, 0x87, 0xf0, 0x0f, 0xf8, 0x1f, 0xff, 0xff, };
|
||||||
|
@ -1,45 +1,50 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
import glob
|
import glob
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
hdrs = []
|
hdrs = []
|
||||||
data = []
|
data = []
|
||||||
imgs = []
|
imgs = []
|
||||||
|
|
||||||
|
|
||||||
def encode_pixels(img):
|
def encode_pixels(img):
|
||||||
r = ''
|
r = ""
|
||||||
img = [ (x[0] + x[1] + x[2] > 384 and '1' or '0') for x in img]
|
img = [(x[0] + x[1] + x[2] > 384 and "1" or "0") for x in img]
|
||||||
for i in range(len(img) // 8):
|
for i in range(len(img) // 8):
|
||||||
c = ''.join(img[i * 8 : i * 8 + 8])
|
c = "".join(img[i * 8 : i * 8 + 8])
|
||||||
r += '0x%02x, ' % int(c, 2)
|
r += "0x%02x, " % int(c, 2)
|
||||||
return r
|
return r
|
||||||
|
|
||||||
|
|
||||||
cnt = 0
|
cnt = 0
|
||||||
for fn in sorted(glob.glob('*.png')):
|
for fn in sorted(glob.glob("*.png")):
|
||||||
print('Processing:', fn)
|
print("Processing:", fn)
|
||||||
im = Image.open(fn)
|
im = Image.open(fn)
|
||||||
name = os.path.splitext(fn)[0]
|
name = os.path.splitext(fn)[0]
|
||||||
w, h = im.size
|
w, h = im.size
|
||||||
if w % 8 != 0:
|
if w % 8 != 0:
|
||||||
raise Exception('Width must be divisable by 8! (%s is %dx%d)' % (fn, w, h))
|
raise Exception("Width must be divisable by 8! (%s is %dx%d)" % (fn, w, h))
|
||||||
img = list(im.getdata())
|
img = list(im.getdata())
|
||||||
hdrs.append('extern const BITMAP bmp_%s;\n' % name)
|
hdrs.append("extern const BITMAP bmp_%s;\n" % name)
|
||||||
imgs.append('const BITMAP bmp_%s = {%d, %d, bmp_%s_data};\n' % (name, w, h, name))
|
imgs.append("const BITMAP bmp_%s = {%d, %d, bmp_%s_data};\n" % (name, w, h, name))
|
||||||
data.append('const uint8_t bmp_%s_data[] = { %s};\n' % (name, encode_pixels(img)))
|
data.append("const uint8_t bmp_%s_data[] = { %s};\n" % (name, encode_pixels(img)))
|
||||||
cnt += 1
|
cnt += 1
|
||||||
|
|
||||||
with open('../bitmaps.c', 'wt') as f:
|
with open("../bitmaps.c", "wt") as f:
|
||||||
|
f.write("// clang-format off\n")
|
||||||
f.write('#include "bitmaps.h"\n\n')
|
f.write('#include "bitmaps.h"\n\n')
|
||||||
for i in range(cnt):
|
for i in range(cnt):
|
||||||
f.write(data[i])
|
f.write(data[i])
|
||||||
f.write('\n')
|
f.write("\n")
|
||||||
for i in range(cnt):
|
for i in range(cnt):
|
||||||
f.write(imgs[i])
|
f.write(imgs[i])
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
with open('../bitmaps.h', 'wt') as f:
|
with open("../bitmaps.h", "wt") as f:
|
||||||
f.write('''#ifndef __BITMAPS_H__
|
f.write(
|
||||||
|
"""#ifndef __BITMAPS_H__
|
||||||
#define __BITMAPS_H__
|
#define __BITMAPS_H__
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@ -49,10 +54,11 @@ typedef struct {
|
|||||||
const uint8_t *data;
|
const uint8_t *data;
|
||||||
} BITMAP;
|
} BITMAP;
|
||||||
|
|
||||||
''')
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
for i in range(cnt):
|
for i in range(cnt):
|
||||||
f.write(hdrs[i])
|
f.write(hdrs[i])
|
||||||
|
|
||||||
f.write('\n#endif\n')
|
f.write("\n#endif\n")
|
||||||
f.close()
|
f.close()
|
||||||
|
@ -1,17 +1,15 @@
|
|||||||
#include "fonts.h"
|
#include "fonts.h"
|
||||||
|
|
||||||
const uint8_t * const font_data[2][128] = {
|
const uint8_t *const font_data[2][128] = {
|
||||||
{
|
{
|
||||||
#include"font.inc"
|
#include "font.inc"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
#include"fontfixed.inc"
|
#include "fontfixed.inc"
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
int fontCharWidth(int font, char c) {
|
int fontCharWidth(int font, char c) { return font_data[font][c & 0x7f][0]; }
|
||||||
return font_data[font][c & 0x7f][0];
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint8_t *fontCharData(int font, char c) {
|
const uint8_t *fontCharData(int font, char c) {
|
||||||
return font_data[font][c & 0x7f] + 1;
|
return font_data[font][c & 0x7f] + 1;
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
#define FONT_FIXED 1
|
#define FONT_FIXED 1
|
||||||
#define FONT_DOUBLE 0x80
|
#define FONT_DOUBLE 0x80
|
||||||
|
|
||||||
extern const uint8_t * const font_data[2][128];
|
extern const uint8_t *const font_data[2][128];
|
||||||
|
|
||||||
int fontCharWidth(int font, char c);
|
int fontCharWidth(int font, char c);
|
||||||
const uint8_t *fontCharData(int font, char c);
|
const uint8_t *fontCharData(int font, char c);
|
||||||
|
@ -1,39 +1,40 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
class Img(object):
|
|
||||||
|
|
||||||
|
class Img(object):
|
||||||
def __init__(self, fn):
|
def __init__(self, fn):
|
||||||
im = Image.open(fn)
|
im = Image.open(fn)
|
||||||
self.w, self.h = im.size
|
self.w, self.h = im.size
|
||||||
self.data = list(im.getdata())
|
self.data = list(im.getdata())
|
||||||
|
|
||||||
def pixel(self, r, c):
|
def pixel(self, r, c):
|
||||||
p = self.data[ r + c * self.w ]
|
p = self.data[r + c * self.w]
|
||||||
if p == (255, 255, 255):
|
if p == (255, 255, 255):
|
||||||
return '0'
|
return "0"
|
||||||
if p == (0, 0, 0):
|
if p == (0, 0, 0):
|
||||||
return '1'
|
return "1"
|
||||||
if p == (255, 0, 255):
|
if p == (255, 0, 255):
|
||||||
return None
|
return None
|
||||||
raise Exception('Unknown color', p)
|
raise Exception("Unknown color", p)
|
||||||
|
|
||||||
|
|
||||||
def convert(imgfile, outfile):
|
def convert(imgfile, outfile):
|
||||||
img = Img(imgfile)
|
img = Img(imgfile)
|
||||||
cur = ''
|
cur = ""
|
||||||
with open(outfile, 'w') as f:
|
with open(outfile, "w") as f:
|
||||||
for i in range(128):
|
for i in range(128):
|
||||||
x = (i % 16) * 10
|
x = (i % 16) * 10
|
||||||
y = (i // 16) * 10
|
y = (i // 16) * 10
|
||||||
cur = ''
|
cur = ""
|
||||||
while img.pixel(x, y) != None:
|
while img.pixel(x, y) is not None:
|
||||||
val = ''.join(img.pixel(x, y + j) for j in range(8))
|
val = "".join(img.pixel(x, y + j) for j in range(8))
|
||||||
x += 1
|
x += 1
|
||||||
cur += '\\x%02x' % int(val, 2)
|
cur += "\\x%02x" % int(val, 2)
|
||||||
cur = '\\x%02x' % (len(cur) // 4) + cur
|
cur = "\\x%02x" % (len(cur) // 4) + cur
|
||||||
ch = chr(i) if i >= 32 and i <= 126 else '_'
|
ch = chr(i) if i >= 32 and i <= 126 else "_"
|
||||||
f.write('\t/* 0x%02x %c */ (uint8_t *)"%s",\n' % (i, ch , cur))
|
f.write('\t/* 0x%02x %c */ (uint8_t *)"%s",\n' % (i, ch, cur))
|
||||||
|
|
||||||
convert('fonts/fontfixed.png', 'fontfixed.inc')
|
|
||||||
convert('fonts/font.png', 'font.inc')
|
convert("fonts/fontfixed.png", "fontfixed.inc")
|
||||||
|
convert("fonts/font.png", "font.inc")
|
||||||
|
@ -2,99 +2,102 @@
|
|||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
|
||||||
handlers = [
|
handlers = [
|
||||||
'hard_fault_handler',
|
"hard_fault_handler",
|
||||||
'mem_manage_handler',
|
"mem_manage_handler",
|
||||||
'bus_fault_handler',
|
"bus_fault_handler",
|
||||||
'usage_fault_handler',
|
"usage_fault_handler",
|
||||||
'nvic_wwdg_isr',
|
"nvic_wwdg_isr",
|
||||||
'pvd_isr',
|
"pvd_isr",
|
||||||
'tamp_stamp_isr',
|
"tamp_stamp_isr",
|
||||||
'rtc_wkup_isr',
|
"rtc_wkup_isr",
|
||||||
'flash_isr',
|
"flash_isr",
|
||||||
'rcc_isr',
|
"rcc_isr",
|
||||||
'exti0_isr',
|
"exti0_isr",
|
||||||
'exti1_isr',
|
"exti1_isr",
|
||||||
'exti2_isr',
|
"exti2_isr",
|
||||||
'exti3_isr',
|
"exti3_isr",
|
||||||
'exti4_isr',
|
"exti4_isr",
|
||||||
'dma1_stream0_isr',
|
"dma1_stream0_isr",
|
||||||
'dma1_stream1_isr',
|
"dma1_stream1_isr",
|
||||||
'dma1_stream2_isr',
|
"dma1_stream2_isr",
|
||||||
'dma1_stream3_isr',
|
"dma1_stream3_isr",
|
||||||
'dma1_stream4_isr',
|
"dma1_stream4_isr",
|
||||||
'dma1_stream5_isr',
|
"dma1_stream5_isr",
|
||||||
'dma1_stream6_isr',
|
"dma1_stream6_isr",
|
||||||
'adc_isr',
|
"adc_isr",
|
||||||
'can1_tx_isr',
|
"can1_tx_isr",
|
||||||
'can1_rx0_isr',
|
"can1_rx0_isr",
|
||||||
'can1_rx1_isr',
|
"can1_rx1_isr",
|
||||||
'can1_sce_isr',
|
"can1_sce_isr",
|
||||||
'exti9_5_isr',
|
"exti9_5_isr",
|
||||||
'tim1_brk_tim9_isr',
|
"tim1_brk_tim9_isr",
|
||||||
'tim1_up_tim10_isr',
|
"tim1_up_tim10_isr",
|
||||||
'tim1_trg_com_tim11_isr',
|
"tim1_trg_com_tim11_isr",
|
||||||
'tim1_cc_isr',
|
"tim1_cc_isr",
|
||||||
'tim2_isr',
|
"tim2_isr",
|
||||||
'tim3_isr',
|
"tim3_isr",
|
||||||
'tim4_isr',
|
"tim4_isr",
|
||||||
'i2c1_ev_isr',
|
"i2c1_ev_isr",
|
||||||
'i2c1_er_isr',
|
"i2c1_er_isr",
|
||||||
'i2c2_ev_isr',
|
"i2c2_ev_isr",
|
||||||
'i2c2_er_isr',
|
"i2c2_er_isr",
|
||||||
'spi1_isr',
|
"spi1_isr",
|
||||||
'spi2_isr',
|
"spi2_isr",
|
||||||
'usart1_isr',
|
"usart1_isr",
|
||||||
'usart2_isr',
|
"usart2_isr",
|
||||||
'usart3_isr',
|
"usart3_isr",
|
||||||
'exti15_10_isr',
|
"exti15_10_isr",
|
||||||
'rtc_alarm_isr',
|
"rtc_alarm_isr",
|
||||||
'usb_fs_wkup_isr',
|
"usb_fs_wkup_isr",
|
||||||
'tim8_brk_tim12_isr',
|
"tim8_brk_tim12_isr",
|
||||||
'tim8_up_tim13_isr',
|
"tim8_up_tim13_isr",
|
||||||
'tim8_trg_com_tim14_isr',
|
"tim8_trg_com_tim14_isr",
|
||||||
'tim8_cc_isr',
|
"tim8_cc_isr",
|
||||||
'dma1_stream7_isr',
|
"dma1_stream7_isr",
|
||||||
'fsmc_isr',
|
"fsmc_isr",
|
||||||
'sdio_isr',
|
"sdio_isr",
|
||||||
'tim5_isr',
|
"tim5_isr",
|
||||||
'spi3_isr',
|
"spi3_isr",
|
||||||
'uart4_isr',
|
"uart4_isr",
|
||||||
'uart5_isr',
|
"uart5_isr",
|
||||||
'tim6_dac_isr',
|
"tim6_dac_isr",
|
||||||
'tim7_isr',
|
"tim7_isr",
|
||||||
'dma2_stream0_isr',
|
"dma2_stream0_isr",
|
||||||
'dma2_stream1_isr',
|
"dma2_stream1_isr",
|
||||||
'dma2_stream2_isr',
|
"dma2_stream2_isr",
|
||||||
'dma2_stream3_isr',
|
"dma2_stream3_isr",
|
||||||
'dma2_stream4_isr',
|
"dma2_stream4_isr",
|
||||||
'eth_isr',
|
"eth_isr",
|
||||||
'eth_wkup_isr',
|
"eth_wkup_isr",
|
||||||
'can2_tx_isr',
|
"can2_tx_isr",
|
||||||
'can2_rx0_isr',
|
"can2_rx0_isr",
|
||||||
'can2_rx1_isr',
|
"can2_rx1_isr",
|
||||||
'can2_sce_isr',
|
"can2_sce_isr",
|
||||||
'otg_fs_isr',
|
"otg_fs_isr",
|
||||||
'dma2_stream5_isr',
|
"dma2_stream5_isr",
|
||||||
'dma2_stream6_isr',
|
"dma2_stream6_isr",
|
||||||
'dma2_stream7_isr',
|
"dma2_stream7_isr",
|
||||||
'usart6_isr',
|
"usart6_isr",
|
||||||
'i2c3_ev_isr',
|
"i2c3_ev_isr",
|
||||||
'i2c3_er_isr',
|
"i2c3_er_isr",
|
||||||
'otg_hs_ep1_out_isr',
|
"otg_hs_ep1_out_isr",
|
||||||
'otg_hs_ep1_in_isr',
|
"otg_hs_ep1_in_isr",
|
||||||
'otg_hs_wkup_isr',
|
"otg_hs_wkup_isr",
|
||||||
'otg_hs_isr',
|
"otg_hs_isr",
|
||||||
'dcmi_isr',
|
"dcmi_isr",
|
||||||
'cryp_isr',
|
"cryp_isr",
|
||||||
'hash_rng_isr',
|
"hash_rng_isr",
|
||||||
]
|
]
|
||||||
|
|
||||||
with open('handlers.c', 'wt') as f:
|
with open("handlers.c", "wt") as f:
|
||||||
f.write('#include "layout.h"\n')
|
f.write('#include "layout.h"\n')
|
||||||
f.write('#include "oled.h"\n\n')
|
f.write('#include "oled.h"\n\n')
|
||||||
for i in handlers:
|
for i in handlers:
|
||||||
f.write('void __attribute__((noreturn)) %s(void)\n' % i)
|
f.write("void __attribute__((noreturn)) %s(void)\n" % i)
|
||||||
f.write('{\n')
|
f.write("{\n")
|
||||||
f.write('\tlayoutDialog(DIALOG_ICON_ERROR, NULL, NULL, NULL, "Encountered", NULL, "%s", NULL, "Please restart", "the device.");\n' % i.upper())
|
f.write(
|
||||||
f.write('\tfor (;;) {} // loop forever\n')
|
'\tlayoutDialog(DIALOG_ICON_ERROR, NULL, NULL, NULL, "Encountered", NULL, "%s", NULL, "Please restart", "the device.");\n'
|
||||||
f.write('}\n\n')
|
% i.upper()
|
||||||
|
)
|
||||||
|
f.write("\tfor (;;) {} // loop forever\n")
|
||||||
|
f.write("}\n\n")
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
|
#include <readline/history.h>
|
||||||
|
#include <readline/readline.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <readline/readline.h>
|
|
||||||
#include <readline/history.h>
|
|
||||||
|
|
||||||
#include "fonts.h"
|
#include "fonts.h"
|
||||||
|
|
||||||
|
35
setup.cfg
Normal file
35
setup.cfg
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
[flake8]
|
||||||
|
ignore =
|
||||||
|
# E203 whitespace before ':'
|
||||||
|
E203,
|
||||||
|
# E221: multiple spaces before operator
|
||||||
|
E221,
|
||||||
|
# E241: multiple spaces after ':'
|
||||||
|
E241,
|
||||||
|
# E402: module level import not at top of file
|
||||||
|
E402,
|
||||||
|
# E501: line too long
|
||||||
|
E501,
|
||||||
|
# E741 ambiguous variable name
|
||||||
|
E741,
|
||||||
|
# F403: star import used, unable to detect undefined names
|
||||||
|
F403,
|
||||||
|
# F405: name may be undefined, or defined from star imports
|
||||||
|
F405,
|
||||||
|
# W503: line break before binary operator
|
||||||
|
W503
|
||||||
|
|
||||||
|
[isort]
|
||||||
|
multi_line_output = 3
|
||||||
|
include_trailing_comma = True
|
||||||
|
force_grid_wrap = 0
|
||||||
|
combine_as_imports = True
|
||||||
|
line_length = 88
|
||||||
|
not_skip=__init__.py
|
||||||
|
forced_separate = apps
|
||||||
|
known_standard_library = micropython,ubinascii,ustruct,uctypes,utime,utimeq,trezorio,trezorui,trezorutils,trezorconfig
|
||||||
|
|
||||||
|
[tool:pytest]
|
||||||
|
addopts = --pyargs trezorlib.tests.device_tests
|
||||||
|
xfail_strict = true
|
||||||
|
run_xfail =
|
136
storage/norcow.c
136
storage/norcow.c
@ -19,9 +19,9 @@
|
|||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "norcow.h"
|
|
||||||
#include "flash.h"
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "flash.h"
|
||||||
|
#include "norcow.h"
|
||||||
|
|
||||||
// NRC2 = 4e524332
|
// NRC2 = 4e524332
|
||||||
#define NORCOW_MAGIC ((uint32_t)0x3243524e)
|
#define NORCOW_MAGIC ((uint32_t)0x3243524e)
|
||||||
@ -40,12 +40,14 @@
|
|||||||
#define NORCOW_KEY_DELETED (0x0000)
|
#define NORCOW_KEY_DELETED (0x0000)
|
||||||
|
|
||||||
// The offset from the beginning of the sector where stored items start.
|
// The offset from the beginning of the sector where stored items start.
|
||||||
#define NORCOW_STORAGE_START (NORCOW_HEADER_LEN + NORCOW_MAGIC_LEN + NORCOW_VERSION_LEN)
|
#define NORCOW_STORAGE_START \
|
||||||
|
(NORCOW_HEADER_LEN + NORCOW_MAGIC_LEN + NORCOW_VERSION_LEN)
|
||||||
|
|
||||||
// Map from sector index to sector number.
|
// Map from sector index to sector number.
|
||||||
static const uint8_t norcow_sectors[NORCOW_SECTOR_COUNT] = NORCOW_SECTORS;
|
static const uint8_t norcow_sectors[NORCOW_SECTOR_COUNT] = NORCOW_SECTORS;
|
||||||
|
|
||||||
// The index of the active reading sector and writing sector. These should be equal except when storage version upgrade or compaction is in progress.
|
// The index of the active reading sector and writing sector. These should be
|
||||||
|
// equal except when storage version upgrade or compaction is in progress.
|
||||||
static uint8_t norcow_active_sector = 0;
|
static uint8_t norcow_active_sector = 0;
|
||||||
static uint8_t norcow_write_sector = 0;
|
static uint8_t norcow_write_sector = 0;
|
||||||
|
|
||||||
@ -59,8 +61,7 @@ static uint32_t norcow_free_offset = 0;
|
|||||||
* Returns pointer to sector, starting with offset
|
* Returns pointer to sector, starting with offset
|
||||||
* Fails when there is not enough space for data of given size
|
* Fails when there is not enough space for data of given size
|
||||||
*/
|
*/
|
||||||
static const void *norcow_ptr(uint8_t sector, uint32_t offset, uint32_t size)
|
static const void *norcow_ptr(uint8_t sector, uint32_t offset, uint32_t size) {
|
||||||
{
|
|
||||||
ensure(sectrue * (sector <= NORCOW_SECTOR_COUNT), "invalid sector");
|
ensure(sectrue * (sector <= NORCOW_SECTOR_COUNT), "invalid sector");
|
||||||
return flash_get_address(norcow_sectors[sector], offset, size);
|
return flash_get_address(norcow_sectors[sector], offset, size);
|
||||||
}
|
}
|
||||||
@ -68,8 +69,8 @@ static const void *norcow_ptr(uint8_t sector, uint32_t offset, uint32_t size)
|
|||||||
/*
|
/*
|
||||||
* Writes data to given sector, starting from offset
|
* Writes data to given sector, starting from offset
|
||||||
*/
|
*/
|
||||||
static secbool norcow_write(uint8_t sector, uint32_t offset, uint32_t prefix, const uint8_t *data, uint16_t len)
|
static secbool norcow_write(uint8_t sector, uint32_t offset, uint32_t prefix,
|
||||||
{
|
const uint8_t *data, uint16_t len) {
|
||||||
if (sector >= NORCOW_SECTOR_COUNT) {
|
if (sector >= NORCOW_SECTOR_COUNT) {
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
@ -105,11 +106,10 @@ static secbool norcow_write(uint8_t sector, uint32_t offset, uint32_t prefix, co
|
|||||||
/*
|
/*
|
||||||
* Erases sector (and sets a magic)
|
* Erases sector (and sets a magic)
|
||||||
*/
|
*/
|
||||||
static void erase_sector(uint8_t sector, secbool set_magic)
|
static void erase_sector(uint8_t sector, secbool set_magic) {
|
||||||
{
|
|
||||||
#if NORCOW_HEADER_LEN > 0
|
#if NORCOW_HEADER_LEN > 0
|
||||||
// Backup the sector header.
|
// Backup the sector header.
|
||||||
uint32_t header_backup[NORCOW_HEADER_LEN/sizeof(uint32_t)];
|
uint32_t header_backup[NORCOW_HEADER_LEN / sizeof(uint32_t)];
|
||||||
const void *sector_start = norcow_ptr(sector, 0, NORCOW_HEADER_LEN);
|
const void *sector_start = norcow_ptr(sector, 0, NORCOW_HEADER_LEN);
|
||||||
memcpy(header_backup, sector_start, sizeof(header_backup));
|
memcpy(header_backup, sector_start, sizeof(header_backup));
|
||||||
#endif
|
#endif
|
||||||
@ -119,15 +119,20 @@ static void erase_sector(uint8_t sector, secbool set_magic)
|
|||||||
#if NORCOW_HEADER_LEN > 0
|
#if NORCOW_HEADER_LEN > 0
|
||||||
// Copy the sector header back.
|
// Copy the sector header back.
|
||||||
ensure(flash_unlock_write(), NULL);
|
ensure(flash_unlock_write(), NULL);
|
||||||
for (uint32_t i = 0; i < NORCOW_HEADER_LEN/sizeof(uint32_t); ++i) {
|
for (uint32_t i = 0; i < NORCOW_HEADER_LEN / sizeof(uint32_t); ++i) {
|
||||||
ensure(flash_write_word(norcow_sectors[sector], i*sizeof(uint32_t), header_backup[i]), NULL);
|
ensure(flash_write_word(norcow_sectors[sector], i * sizeof(uint32_t),
|
||||||
|
header_backup[i]),
|
||||||
|
NULL);
|
||||||
}
|
}
|
||||||
ensure(flash_lock_write(), NULL);
|
ensure(flash_lock_write(), NULL);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (sectrue == set_magic) {
|
if (sectrue == set_magic) {
|
||||||
ensure(norcow_write(sector, NORCOW_HEADER_LEN, NORCOW_MAGIC, NULL, 0), "set magic failed");
|
ensure(norcow_write(sector, NORCOW_HEADER_LEN, NORCOW_MAGIC, NULL, 0),
|
||||||
ensure(norcow_write(sector, NORCOW_HEADER_LEN + NORCOW_MAGIC_LEN, ~NORCOW_VERSION, NULL, 0), "set version failed");
|
"set magic failed");
|
||||||
|
ensure(norcow_write(sector, NORCOW_HEADER_LEN + NORCOW_MAGIC_LEN,
|
||||||
|
~NORCOW_VERSION, NULL, 0),
|
||||||
|
"set version failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,8 +141,8 @@ static void erase_sector(uint8_t sector, secbool set_magic)
|
|||||||
/*
|
/*
|
||||||
* Reads one item starting from offset
|
* Reads one item starting from offset
|
||||||
*/
|
*/
|
||||||
static secbool read_item(uint8_t sector, uint32_t offset, uint16_t *key, const void **val, uint16_t *len, uint32_t *pos)
|
static secbool read_item(uint8_t sector, uint32_t offset, uint16_t *key,
|
||||||
{
|
const void **val, uint16_t *len, uint32_t *pos) {
|
||||||
*pos = offset;
|
*pos = offset;
|
||||||
|
|
||||||
const void *k = norcow_ptr(sector, *pos, 2);
|
const void *k = norcow_ptr(sector, *pos, 2);
|
||||||
@ -163,8 +168,8 @@ static secbool read_item(uint8_t sector, uint32_t offset, uint16_t *key, const v
|
|||||||
/*
|
/*
|
||||||
* Writes one item starting from offset
|
* Writes one item starting from offset
|
||||||
*/
|
*/
|
||||||
static secbool write_item(uint8_t sector, uint32_t offset, uint16_t key, const void *val, uint16_t len, uint32_t *pos)
|
static secbool write_item(uint8_t sector, uint32_t offset, uint16_t key,
|
||||||
{
|
const void *val, uint16_t len, uint32_t *pos) {
|
||||||
uint32_t prefix = ((uint32_t)len << 16) | key;
|
uint32_t prefix = ((uint32_t)len << 16) | key;
|
||||||
*pos = offset + NORCOW_PREFIX_LEN + len;
|
*pos = offset + NORCOW_PREFIX_LEN + len;
|
||||||
ALIGN4(*pos);
|
ALIGN4(*pos);
|
||||||
@ -174,9 +179,10 @@ static secbool write_item(uint8_t sector, uint32_t offset, uint16_t key, const v
|
|||||||
/*
|
/*
|
||||||
* Finds the offset from the beginning of the sector where stored items start.
|
* Finds the offset from the beginning of the sector where stored items start.
|
||||||
*/
|
*/
|
||||||
static secbool find_start_offset(uint8_t sector, uint32_t *offset, uint32_t *version)
|
static secbool find_start_offset(uint8_t sector, uint32_t *offset,
|
||||||
{
|
uint32_t *version) {
|
||||||
const uint32_t *magic = norcow_ptr(sector, NORCOW_HEADER_LEN, NORCOW_MAGIC_LEN + NORCOW_VERSION_LEN);
|
const uint32_t *magic = norcow_ptr(sector, NORCOW_HEADER_LEN,
|
||||||
|
NORCOW_MAGIC_LEN + NORCOW_VERSION_LEN);
|
||||||
if (magic == NULL) {
|
if (magic == NULL) {
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
@ -197,8 +203,8 @@ static secbool find_start_offset(uint8_t sector, uint32_t *offset, uint32_t *ver
|
|||||||
/*
|
/*
|
||||||
* Finds item in given sector
|
* Finds item in given sector
|
||||||
*/
|
*/
|
||||||
static secbool find_item(uint8_t sector, uint16_t key, const void **val, uint16_t *len)
|
static secbool find_item(uint8_t sector, uint16_t key, const void **val,
|
||||||
{
|
uint16_t *len) {
|
||||||
*val = NULL;
|
*val = NULL;
|
||||||
*len = 0;
|
*len = 0;
|
||||||
|
|
||||||
@ -227,8 +233,7 @@ static secbool find_item(uint8_t sector, uint16_t key, const void **val, uint16_
|
|||||||
/*
|
/*
|
||||||
* Finds first unused offset in given sector
|
* Finds first unused offset in given sector
|
||||||
*/
|
*/
|
||||||
static uint32_t find_free_offset(uint8_t sector)
|
static uint32_t find_free_offset(uint8_t sector) {
|
||||||
{
|
|
||||||
uint32_t offset;
|
uint32_t offset;
|
||||||
uint32_t version;
|
uint32_t version;
|
||||||
if (sectrue != find_start_offset(sector, &offset, &version)) {
|
if (sectrue != find_start_offset(sector, &offset, &version)) {
|
||||||
@ -250,8 +255,7 @@ static uint32_t find_free_offset(uint8_t sector)
|
|||||||
/*
|
/*
|
||||||
* Compacts active sector and sets new active sector
|
* Compacts active sector and sets new active sector
|
||||||
*/
|
*/
|
||||||
static void compact(void)
|
static void compact(void) {
|
||||||
{
|
|
||||||
uint32_t offsetr;
|
uint32_t offsetr;
|
||||||
uint32_t version;
|
uint32_t version;
|
||||||
if (sectrue != find_start_offset(norcow_active_sector, &offsetr, &version)) {
|
if (sectrue != find_start_offset(norcow_active_sector, &offsetr, &version)) {
|
||||||
@ -280,7 +284,8 @@ static void compact(void)
|
|||||||
|
|
||||||
// copy the item
|
// copy the item
|
||||||
uint32_t posw;
|
uint32_t posw;
|
||||||
ensure(write_item(norcow_write_sector, offsetw, k, v, l, &posw), "compaction write failed");
|
ensure(write_item(norcow_write_sector, offsetw, k, v, l, &posw),
|
||||||
|
"compaction write failed");
|
||||||
offsetw = posw;
|
offsetw = posw;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -293,15 +298,15 @@ static void compact(void)
|
|||||||
/*
|
/*
|
||||||
* Initializes storage
|
* Initializes storage
|
||||||
*/
|
*/
|
||||||
void norcow_init(uint32_t *norcow_version)
|
void norcow_init(uint32_t *norcow_version) {
|
||||||
{
|
|
||||||
flash_init();
|
flash_init();
|
||||||
secbool found = secfalse;
|
secbool found = secfalse;
|
||||||
*norcow_version = 0;
|
*norcow_version = 0;
|
||||||
// detect active sector - starts with magic and has highest version
|
// detect active sector - starts with magic and has highest version
|
||||||
for (uint8_t i = 0; i < NORCOW_SECTOR_COUNT; i++) {
|
for (uint8_t i = 0; i < NORCOW_SECTOR_COUNT; i++) {
|
||||||
uint32_t offset;
|
uint32_t offset;
|
||||||
if (sectrue == find_start_offset(i, &offset, &norcow_active_version) && norcow_active_version >= *norcow_version) {
|
if (sectrue == find_start_offset(i, &offset, &norcow_active_version) &&
|
||||||
|
norcow_active_version >= *norcow_version) {
|
||||||
found = sectrue;
|
found = sectrue;
|
||||||
norcow_active_sector = i;
|
norcow_active_sector = i;
|
||||||
*norcow_version = norcow_active_version;
|
*norcow_version = norcow_active_version;
|
||||||
@ -326,8 +331,7 @@ void norcow_init(uint32_t *norcow_version)
|
|||||||
/*
|
/*
|
||||||
* Wipe the storage
|
* Wipe the storage
|
||||||
*/
|
*/
|
||||||
void norcow_wipe(void)
|
void norcow_wipe(void) {
|
||||||
{
|
|
||||||
erase_sector(0, sectrue);
|
erase_sector(0, sectrue);
|
||||||
for (uint8_t i = 1; i < NORCOW_SECTOR_COUNT; i++) {
|
for (uint8_t i = 1; i < NORCOW_SECTOR_COUNT; i++) {
|
||||||
erase_sector(i, secfalse);
|
erase_sector(i, secfalse);
|
||||||
@ -341,16 +345,16 @@ void norcow_wipe(void)
|
|||||||
/*
|
/*
|
||||||
* Looks for the given key, returns status of the operation
|
* Looks for the given key, returns status of the operation
|
||||||
*/
|
*/
|
||||||
secbool norcow_get(uint16_t key, const void **val, uint16_t *len)
|
secbool norcow_get(uint16_t key, const void **val, uint16_t *len) {
|
||||||
{
|
|
||||||
return find_item(norcow_active_sector, key, val, len);
|
return find_item(norcow_active_sector, key, val, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reads the next entry in the storage starting at offset. Returns secfalse if there is none.
|
* Reads the next entry in the storage starting at offset. Returns secfalse if
|
||||||
|
* there is none.
|
||||||
*/
|
*/
|
||||||
secbool norcow_get_next(uint32_t *offset, uint16_t *key, const void **val, uint16_t *len)
|
secbool norcow_get_next(uint32_t *offset, uint16_t *key, const void **val,
|
||||||
{
|
uint16_t *len) {
|
||||||
if (*offset == 0) {
|
if (*offset == 0) {
|
||||||
uint32_t version;
|
uint32_t version;
|
||||||
if (sectrue != find_start_offset(norcow_active_sector, offset, &version)) {
|
if (sectrue != find_start_offset(norcow_active_sector, offset, &version)) {
|
||||||
@ -400,14 +404,13 @@ secbool norcow_get_next(uint32_t *offset, uint16_t *key, const void **val, uint1
|
|||||||
* as val, then norcow_set allocates a new key of size len. The value should
|
* as val, then norcow_set allocates a new key of size len. The value should
|
||||||
* then be written using norcow_update_bytes().
|
* then be written using norcow_update_bytes().
|
||||||
*/
|
*/
|
||||||
secbool norcow_set(uint16_t key, const void *val, uint16_t len)
|
secbool norcow_set(uint16_t key, const void *val, uint16_t len) {
|
||||||
{
|
|
||||||
secbool found;
|
secbool found;
|
||||||
return norcow_set_ex(key, val, len, &found);
|
return norcow_set_ex(key, val, len, &found);
|
||||||
}
|
}
|
||||||
|
|
||||||
secbool norcow_set_ex(uint16_t key, const void *val, uint16_t len, secbool *found)
|
secbool norcow_set_ex(uint16_t key, const void *val, uint16_t len,
|
||||||
{
|
secbool *found) {
|
||||||
// Key 0xffff is used as a marker to indicate that the entry is not set.
|
// Key 0xffff is used as a marker to indicate that the entry is not set.
|
||||||
if (key == NORCOW_KEY_FREE) {
|
if (key == NORCOW_KEY_FREE) {
|
||||||
return secfalse;
|
return secfalse;
|
||||||
@ -422,12 +425,15 @@ secbool norcow_set_ex(uint16_t key, const void *val, uint16_t len, secbool *foun
|
|||||||
// Try to update the entry if it already exists.
|
// Try to update the entry if it already exists.
|
||||||
uint32_t offset = 0;
|
uint32_t offset = 0;
|
||||||
if (sectrue == *found) {
|
if (sectrue == *found) {
|
||||||
offset = (const uint8_t*) ptr - (const uint8_t *)norcow_ptr(norcow_write_sector, 0, NORCOW_SECTOR_SIZE);
|
offset =
|
||||||
|
(const uint8_t *)ptr -
|
||||||
|
(const uint8_t *)norcow_ptr(norcow_write_sector, 0, NORCOW_SECTOR_SIZE);
|
||||||
if (val != NULL && len_old == len) {
|
if (val != NULL && len_old == len) {
|
||||||
ret = sectrue;
|
ret = sectrue;
|
||||||
ensure(flash_unlock_write(), NULL);
|
ensure(flash_unlock_write(), NULL);
|
||||||
for (uint16_t i = 0; i < len; i++) {
|
for (uint16_t i = 0; i < len; i++) {
|
||||||
if (sectrue != flash_write_byte(sector_num, offset + i, ((const uint8_t*)val)[i])) {
|
if (sectrue != flash_write_byte(sector_num, offset + i,
|
||||||
|
((const uint8_t *)val)[i])) {
|
||||||
ret = secfalse;
|
ret = secfalse;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -444,7 +450,8 @@ secbool norcow_set_ex(uint16_t key, const void *val, uint16_t len, secbool *foun
|
|||||||
|
|
||||||
// Update the prefix to indicate that the old item has been deleted.
|
// Update the prefix to indicate that the old item has been deleted.
|
||||||
uint32_t prefix = (uint32_t)len_old << 16;
|
uint32_t prefix = (uint32_t)len_old << 16;
|
||||||
ensure(flash_write_word(sector_num, offset - NORCOW_PREFIX_LEN, prefix), NULL);
|
ensure(flash_write_word(sector_num, offset - NORCOW_PREFIX_LEN, prefix),
|
||||||
|
NULL);
|
||||||
|
|
||||||
// Delete the old item data.
|
// Delete the old item data.
|
||||||
uint32_t end = offset + len_old;
|
uint32_t end = offset + len_old;
|
||||||
@ -461,7 +468,8 @@ secbool norcow_set_ex(uint16_t key, const void *val, uint16_t len, secbool *foun
|
|||||||
}
|
}
|
||||||
// Write new item.
|
// Write new item.
|
||||||
uint32_t pos;
|
uint32_t pos;
|
||||||
ret = write_item(norcow_write_sector, norcow_free_offset, key, val, len, &pos);
|
ret = write_item(norcow_write_sector, norcow_free_offset, key, val, len,
|
||||||
|
&pos);
|
||||||
if (sectrue == ret) {
|
if (sectrue == ret) {
|
||||||
norcow_free_offset = pos;
|
norcow_free_offset = pos;
|
||||||
}
|
}
|
||||||
@ -472,8 +480,7 @@ secbool norcow_set_ex(uint16_t key, const void *val, uint16_t len, secbool *foun
|
|||||||
/*
|
/*
|
||||||
* Deletes the given key, returns status of the operation.
|
* Deletes the given key, returns status of the operation.
|
||||||
*/
|
*/
|
||||||
secbool norcow_delete(uint16_t key)
|
secbool norcow_delete(uint16_t key) {
|
||||||
{
|
|
||||||
// Key 0xffff is used as a marker to indicate that the entry is not set.
|
// Key 0xffff is used as a marker to indicate that the entry is not set.
|
||||||
if (key == NORCOW_KEY_FREE) {
|
if (key == NORCOW_KEY_FREE) {
|
||||||
return secfalse;
|
return secfalse;
|
||||||
@ -486,13 +493,16 @@ secbool norcow_delete(uint16_t key)
|
|||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t offset = (const uint8_t*) ptr - (const uint8_t *)norcow_ptr(norcow_write_sector, 0, NORCOW_SECTOR_SIZE);
|
uint32_t offset =
|
||||||
|
(const uint8_t *)ptr -
|
||||||
|
(const uint8_t *)norcow_ptr(norcow_write_sector, 0, NORCOW_SECTOR_SIZE);
|
||||||
|
|
||||||
ensure(flash_unlock_write(), NULL);
|
ensure(flash_unlock_write(), NULL);
|
||||||
|
|
||||||
// Update the prefix to indicate that the item has been deleted.
|
// Update the prefix to indicate that the item has been deleted.
|
||||||
uint32_t prefix = (uint32_t)len << 16;
|
uint32_t prefix = (uint32_t)len << 16;
|
||||||
ensure(flash_write_word(sector_num, offset - NORCOW_PREFIX_LEN, prefix), NULL);
|
ensure(flash_write_word(sector_num, offset - NORCOW_PREFIX_LEN, prefix),
|
||||||
|
NULL);
|
||||||
|
|
||||||
// Delete the item data.
|
// Delete the item data.
|
||||||
uint32_t end = offset + len;
|
uint32_t end = offset + len;
|
||||||
@ -510,8 +520,7 @@ secbool norcow_delete(uint16_t key)
|
|||||||
* Update a word in flash at the given pointer. The pointer must point
|
* Update a word in flash at the given pointer. The pointer must point
|
||||||
* into the NORCOW area.
|
* into the NORCOW area.
|
||||||
*/
|
*/
|
||||||
secbool norcow_update_word(uint16_t key, uint16_t offset, uint32_t value)
|
secbool norcow_update_word(uint16_t key, uint16_t offset, uint32_t value) {
|
||||||
{
|
|
||||||
const void *ptr;
|
const void *ptr;
|
||||||
uint16_t len;
|
uint16_t len;
|
||||||
if (sectrue != find_item(norcow_write_sector, key, &ptr, &len)) {
|
if (sectrue != find_item(norcow_write_sector, key, &ptr, &len)) {
|
||||||
@ -520,9 +529,14 @@ secbool norcow_update_word(uint16_t key, uint16_t offset, uint32_t value)
|
|||||||
if ((offset & 3) != 0 || offset >= len) {
|
if ((offset & 3) != 0 || offset >= len) {
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
uint32_t sector_offset = (const uint8_t*) ptr - (const uint8_t *)norcow_ptr(norcow_write_sector, 0, NORCOW_SECTOR_SIZE) + offset;
|
uint32_t sector_offset =
|
||||||
|
(const uint8_t *)ptr -
|
||||||
|
(const uint8_t *)norcow_ptr(norcow_write_sector, 0, NORCOW_SECTOR_SIZE) +
|
||||||
|
offset;
|
||||||
ensure(flash_unlock_write(), NULL);
|
ensure(flash_unlock_write(), NULL);
|
||||||
ensure(flash_write_word(norcow_sectors[norcow_write_sector], sector_offset, value), NULL);
|
ensure(flash_write_word(norcow_sectors[norcow_write_sector], sector_offset,
|
||||||
|
value),
|
||||||
|
NULL);
|
||||||
ensure(flash_lock_write(), NULL);
|
ensure(flash_lock_write(), NULL);
|
||||||
return sectrue;
|
return sectrue;
|
||||||
}
|
}
|
||||||
@ -530,8 +544,8 @@ secbool norcow_update_word(uint16_t key, uint16_t offset, uint32_t value)
|
|||||||
/*
|
/*
|
||||||
* Update the value of the given key starting at the given offset.
|
* Update the value of the given key starting at the given offset.
|
||||||
*/
|
*/
|
||||||
secbool norcow_update_bytes(const uint16_t key, const uint16_t offset, const uint8_t *data, const uint16_t len)
|
secbool norcow_update_bytes(const uint16_t key, const uint16_t offset,
|
||||||
{
|
const uint8_t *data, const uint16_t len) {
|
||||||
const void *ptr;
|
const void *ptr;
|
||||||
uint16_t allocated_len;
|
uint16_t allocated_len;
|
||||||
if (sectrue != find_item(norcow_write_sector, key, &ptr, &allocated_len)) {
|
if (sectrue != find_item(norcow_write_sector, key, &ptr, &allocated_len)) {
|
||||||
@ -540,7 +554,10 @@ secbool norcow_update_bytes(const uint16_t key, const uint16_t offset, const uin
|
|||||||
if (offset + len > allocated_len) {
|
if (offset + len > allocated_len) {
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
uint32_t sector_offset = (const uint8_t*) ptr - (const uint8_t *)norcow_ptr(norcow_write_sector, 0, NORCOW_SECTOR_SIZE) + offset;
|
uint32_t sector_offset =
|
||||||
|
(const uint8_t *)ptr -
|
||||||
|
(const uint8_t *)norcow_ptr(norcow_write_sector, 0, NORCOW_SECTOR_SIZE) +
|
||||||
|
offset;
|
||||||
uint8_t sector = norcow_sectors[norcow_write_sector];
|
uint8_t sector = norcow_sectors[norcow_write_sector];
|
||||||
ensure(flash_unlock_write(), NULL);
|
ensure(flash_unlock_write(), NULL);
|
||||||
for (uint16_t i = 0; i < len; i++, sector_offset++) {
|
for (uint16_t i = 0; i < len; i++, sector_offset++) {
|
||||||
@ -553,8 +570,7 @@ secbool norcow_update_bytes(const uint16_t key, const uint16_t offset, const uin
|
|||||||
/*
|
/*
|
||||||
* Complete storage version upgrade
|
* Complete storage version upgrade
|
||||||
*/
|
*/
|
||||||
secbool norcow_upgrade_finish(void)
|
secbool norcow_upgrade_finish(void) {
|
||||||
{
|
|
||||||
erase_sector(norcow_active_sector, secfalse);
|
erase_sector(norcow_active_sector, secfalse);
|
||||||
norcow_active_sector = norcow_write_sector;
|
norcow_active_sector = norcow_write_sector;
|
||||||
norcow_active_version = NORCOW_VERSION;
|
norcow_active_version = NORCOW_VERSION;
|
||||||
|
@ -45,9 +45,11 @@ void norcow_wipe(void);
|
|||||||
secbool norcow_get(uint16_t key, const void **val, uint16_t *len);
|
secbool norcow_get(uint16_t key, const void **val, uint16_t *len);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reads the next entry in the storage starting at offset. Returns secfalse if there is none.
|
* Reads the next entry in the storage starting at offset. Returns secfalse if
|
||||||
|
* there is none.
|
||||||
*/
|
*/
|
||||||
secbool norcow_get_next(uint32_t *offset, uint16_t *key, const void **val, uint16_t *len);
|
secbool norcow_get_next(uint32_t *offset, uint16_t *key, const void **val,
|
||||||
|
uint16_t *len);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Sets the given key, returns status of the operation. If NULL is passed
|
* Sets the given key, returns status of the operation. If NULL is passed
|
||||||
@ -55,7 +57,8 @@ secbool norcow_get_next(uint32_t *offset, uint16_t *key, const void **val, uint1
|
|||||||
* then be written using norcow_update_bytes().
|
* then be written using norcow_update_bytes().
|
||||||
*/
|
*/
|
||||||
secbool norcow_set(uint16_t key, const void *val, uint16_t len);
|
secbool norcow_set(uint16_t key, const void *val, uint16_t len);
|
||||||
secbool norcow_set_ex(uint16_t key, const void *val, uint16_t len, secbool *found);
|
secbool norcow_set_ex(uint16_t key, const void *val, uint16_t len,
|
||||||
|
secbool *found);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Deletes the given key, returns status of the operation.
|
* Deletes the given key, returns status of the operation.
|
||||||
@ -72,7 +75,8 @@ secbool norcow_update_word(uint16_t key, uint16_t offset, uint32_t value);
|
|||||||
* Update the value of the given key starting at the given offset.
|
* Update the value of the given key starting at the given offset.
|
||||||
* Note that you can only change bits from 1 to 0.
|
* Note that you can only change bits from 1 to 0.
|
||||||
*/
|
*/
|
||||||
secbool norcow_update_bytes(const uint16_t key, const uint16_t offset, const uint8_t *data, const uint16_t len);
|
secbool norcow_update_bytes(const uint16_t key, const uint16_t offset,
|
||||||
|
const uint8_t *data, const uint16_t len);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Complete storage version upgrade
|
* Complete storage version upgrade
|
||||||
|
@ -19,15 +19,15 @@
|
|||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
#include "norcow.h"
|
|
||||||
#include "storage.h"
|
|
||||||
#include "pbkdf2.h"
|
|
||||||
#include "sha2.h"
|
|
||||||
#include "hmac.h"
|
|
||||||
#include "rand.h"
|
|
||||||
#include "memzero.h"
|
|
||||||
#include "chacha20poly1305/rfc7539.h"
|
#include "chacha20poly1305/rfc7539.h"
|
||||||
|
#include "common.h"
|
||||||
|
#include "hmac.h"
|
||||||
|
#include "memzero.h"
|
||||||
|
#include "norcow.h"
|
||||||
|
#include "pbkdf2.h"
|
||||||
|
#include "rand.h"
|
||||||
|
#include "sha2.h"
|
||||||
|
#include "storage.h"
|
||||||
|
|
||||||
#define LOW_MASK 0x55555555
|
#define LOW_MASK 0x55555555
|
||||||
|
|
||||||
@ -37,7 +37,8 @@
|
|||||||
// Norcow storage key of the PIN entry log and PIN success log.
|
// Norcow storage key of the PIN entry log and PIN success log.
|
||||||
#define PIN_LOGS_KEY ((APP_STORAGE << 8) | 0x01)
|
#define PIN_LOGS_KEY ((APP_STORAGE << 8) | 0x01)
|
||||||
|
|
||||||
// Norcow storage key of the combined salt, EDEK, ESAK and PIN verification code entry.
|
// Norcow storage key of the combined salt, EDEK, ESAK and PIN verification code
|
||||||
|
// entry.
|
||||||
#define EDEK_PVC_KEY ((APP_STORAGE << 8) | 0x02)
|
#define EDEK_PVC_KEY ((APP_STORAGE << 8) | 0x02)
|
||||||
|
|
||||||
// Norcow storage key of the PIN set flag.
|
// Norcow storage key of the PIN set flag.
|
||||||
@ -53,7 +54,8 @@
|
|||||||
#define PIN_EMPTY 1
|
#define PIN_EMPTY 1
|
||||||
|
|
||||||
// Maximum number of failed unlock attempts.
|
// Maximum number of failed unlock attempts.
|
||||||
// NOTE: The PIN counter logic relies on this constant being less than or equal to 16.
|
// NOTE: The PIN counter logic relies on this constant being less than or equal
|
||||||
|
// to 16.
|
||||||
#define PIN_MAX_TRIES 16
|
#define PIN_MAX_TRIES 16
|
||||||
|
|
||||||
// The total number of iterations to use in PBKDF2.
|
// The total number of iterations to use in PBKDF2.
|
||||||
@ -90,7 +92,8 @@
|
|||||||
// The length of the storage authentication key in bytes.
|
// The length of the storage authentication key in bytes.
|
||||||
#define SAK_SIZE 16
|
#define SAK_SIZE 16
|
||||||
|
|
||||||
// The combined length of the data encryption key and the storage authentication key in bytes.
|
// The combined length of the data encryption key and the storage authentication
|
||||||
|
// key in bytes.
|
||||||
#define KEYS_SIZE (DEK_SIZE + SAK_SIZE)
|
#define KEYS_SIZE (DEK_SIZE + SAK_SIZE)
|
||||||
|
|
||||||
// The length of the PIN verification code in bytes.
|
// The length of the PIN verification code in bytes.
|
||||||
@ -115,9 +118,9 @@
|
|||||||
#define GUARD_KEY_MODULUS 6311
|
#define GUARD_KEY_MODULUS 6311
|
||||||
#define GUARD_KEY_REMAINDER 15
|
#define GUARD_KEY_REMAINDER 15
|
||||||
|
|
||||||
const char* const VERIFYING_PIN_MSG = "Verifying PIN";
|
const char *const VERIFYING_PIN_MSG = "Verifying PIN";
|
||||||
const char* const PROCESSING_MSG = "Processing";
|
const char *const PROCESSING_MSG = "Processing";
|
||||||
const char* const STARTING_MSG = "Starting up";
|
const char *const STARTING_MSG = "Starting up";
|
||||||
|
|
||||||
static secbool initialized = secfalse;
|
static secbool initialized = secfalse;
|
||||||
static secbool unlocked = secfalse;
|
static secbool unlocked = secfalse;
|
||||||
@ -134,16 +137,19 @@ static uint32_t norcow_active_version = 0;
|
|||||||
static const uint8_t TRUE_BYTE = 0x01;
|
static const uint8_t TRUE_BYTE = 0x01;
|
||||||
static const uint8_t FALSE_BYTE = 0x00;
|
static const uint8_t FALSE_BYTE = 0x00;
|
||||||
|
|
||||||
static void __handle_fault(const char *msg, const char *file, int line, const char *func);
|
static void __handle_fault(const char *msg, const char *file, int line,
|
||||||
|
const char *func);
|
||||||
#define handle_fault(msg) (__handle_fault(msg, __FILE__, __LINE__, __func__))
|
#define handle_fault(msg) (__handle_fault(msg, __FILE__, __LINE__, __func__))
|
||||||
|
|
||||||
static secbool storage_upgrade(void);
|
static secbool storage_upgrade(void);
|
||||||
static secbool storage_set_encrypted(const uint16_t key, const void *val, const uint16_t len);
|
static secbool storage_set_encrypted(const uint16_t key, const void *val,
|
||||||
static secbool storage_get_encrypted(const uint16_t key, void *val_dest, const uint16_t max_len, uint16_t *len);
|
const uint16_t len);
|
||||||
|
static secbool storage_get_encrypted(const uint16_t key, void *val_dest,
|
||||||
|
const uint16_t max_len, uint16_t *len);
|
||||||
|
|
||||||
static secbool secequal(const void* ptr1, const void* ptr2, size_t n) {
|
static secbool secequal(const void *ptr1, const void *ptr2, size_t n) {
|
||||||
const uint8_t* p1 = ptr1;
|
const uint8_t *p1 = ptr1;
|
||||||
const uint8_t* p2 = ptr2;
|
const uint8_t *p2 = ptr2;
|
||||||
uint8_t diff = 0;
|
uint8_t diff = 0;
|
||||||
size_t i;
|
size_t i;
|
||||||
for (i = 0; i < n; ++i) {
|
for (i = 0; i < n; ++i) {
|
||||||
@ -160,7 +166,8 @@ static secbool secequal(const void* ptr1, const void* ptr2, size_t n) {
|
|||||||
return diff ? secfalse : sectrue;
|
return diff ? secfalse : sectrue;
|
||||||
}
|
}
|
||||||
|
|
||||||
static secbool secequal32(const uint32_t* ptr1, const uint32_t* ptr2, size_t n) {
|
static secbool secequal32(const uint32_t *ptr1, const uint32_t *ptr2,
|
||||||
|
size_t n) {
|
||||||
uint32_t diff = 0;
|
uint32_t diff = 0;
|
||||||
size_t i;
|
size_t i;
|
||||||
for (i = 0; i < n; ++i) {
|
for (i = 0; i < n; ++i) {
|
||||||
@ -189,7 +196,8 @@ static secbool is_protected(uint16_t key) {
|
|||||||
static secbool auth_init(void) {
|
static secbool auth_init(void) {
|
||||||
uint8_t tag[SHA256_DIGEST_LENGTH];
|
uint8_t tag[SHA256_DIGEST_LENGTH];
|
||||||
memzero(authentication_sum, sizeof(authentication_sum));
|
memzero(authentication_sum, sizeof(authentication_sum));
|
||||||
hmac_sha256(cached_sak, SAK_SIZE, authentication_sum, sizeof(authentication_sum), tag);
|
hmac_sha256(cached_sak, SAK_SIZE, authentication_sum,
|
||||||
|
sizeof(authentication_sum), tag);
|
||||||
return norcow_set(STORAGE_TAG_KEY, tag, STORAGE_TAG_SIZE);
|
return norcow_set(STORAGE_TAG_KEY, tag, STORAGE_TAG_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -202,16 +210,18 @@ static secbool auth_update(uint16_t key) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint8_t tag[SHA256_DIGEST_LENGTH];
|
uint8_t tag[SHA256_DIGEST_LENGTH];
|
||||||
hmac_sha256(cached_sak, SAK_SIZE, (uint8_t*)&key, sizeof(key), tag);
|
hmac_sha256(cached_sak, SAK_SIZE, (uint8_t *)&key, sizeof(key), tag);
|
||||||
for (uint32_t i = 0; i < SHA256_DIGEST_LENGTH; i++) {
|
for (uint32_t i = 0; i < SHA256_DIGEST_LENGTH; i++) {
|
||||||
authentication_sum[i] ^= tag[i];
|
authentication_sum[i] ^= tag[i];
|
||||||
}
|
}
|
||||||
hmac_sha256(cached_sak, SAK_SIZE, authentication_sum, sizeof(authentication_sum), tag);
|
hmac_sha256(cached_sak, SAK_SIZE, authentication_sum,
|
||||||
|
sizeof(authentication_sum), tag);
|
||||||
return norcow_set(STORAGE_TAG_KEY, tag, STORAGE_TAG_SIZE);
|
return norcow_set(STORAGE_TAG_KEY, tag, STORAGE_TAG_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A secure version of norcow_set(), which updates the storage authentication tag.
|
* A secure version of norcow_set(), which updates the storage authentication
|
||||||
|
* tag.
|
||||||
*/
|
*/
|
||||||
static secbool auth_set(uint16_t key, const void *val, uint16_t len) {
|
static secbool auth_set(uint16_t key, const void *val, uint16_t len) {
|
||||||
secbool found;
|
secbool found;
|
||||||
@ -226,13 +236,13 @@ static secbool auth_set(uint16_t key, const void *val, uint16_t len) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A secure version of norcow_get(), which checks the storage authentication tag.
|
* A secure version of norcow_get(), which checks the storage authentication
|
||||||
|
* tag.
|
||||||
*/
|
*/
|
||||||
static secbool auth_get(uint16_t key, const void **val, uint16_t *len)
|
static secbool auth_get(uint16_t key, const void **val, uint16_t *len) {
|
||||||
{
|
|
||||||
*val = NULL;
|
*val = NULL;
|
||||||
*len = 0;
|
*len = 0;
|
||||||
uint32_t sum[SHA256_DIGEST_LENGTH/sizeof(uint32_t)] = {0};
|
uint32_t sum[SHA256_DIGEST_LENGTH / sizeof(uint32_t)] = {0};
|
||||||
|
|
||||||
// Prepare inner and outer digest.
|
// Prepare inner and outer digest.
|
||||||
uint32_t odig[SHA256_DIGEST_LENGTH / sizeof(uint32_t)];
|
uint32_t odig[SHA256_DIGEST_LENGTH / sizeof(uint32_t)];
|
||||||
@ -269,10 +279,11 @@ static secbool auth_get(uint16_t key, const void **val, uint16_t *len)
|
|||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
g[0] = (((uint32_t)k & 0xff) << 24) | (((uint32_t)k & 0xff00) << 8) | 0x8000; // Add SHA message padding.
|
g[0] = (((uint32_t)k & 0xff) << 24) | (((uint32_t)k & 0xff00) << 8) |
|
||||||
|
0x8000; // Add SHA message padding.
|
||||||
sha256_Transform(idig, g, h);
|
sha256_Transform(idig, g, h);
|
||||||
sha256_Transform(odig, h, h);
|
sha256_Transform(odig, h, h);
|
||||||
for (uint32_t i = 0; i < SHA256_DIGEST_LENGTH/sizeof(uint32_t); i++) {
|
for (uint32_t i = 0; i < SHA256_DIGEST_LENGTH / sizeof(uint32_t); i++) {
|
||||||
sum[i] ^= h[i];
|
sum[i] ^= h[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -285,11 +296,11 @@ static secbool auth_get(uint16_t key, const void **val, uint16_t *len)
|
|||||||
memzero(idig, sizeof(idig));
|
memzero(idig, sizeof(idig));
|
||||||
|
|
||||||
// Cache the authentication sum.
|
// Cache the authentication sum.
|
||||||
for (size_t i = 0; i < SHA256_DIGEST_LENGTH/sizeof(uint32_t); i++) {
|
for (size_t i = 0; i < SHA256_DIGEST_LENGTH / sizeof(uint32_t); i++) {
|
||||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||||
REVERSE32(sum[i], ((uint32_t*)authentication_sum)[i]);
|
REVERSE32(sum[i], ((uint32_t *)authentication_sum)[i]);
|
||||||
#else
|
#else
|
||||||
((uint32_t*)authentication_sum)[i] = sum[i];
|
((uint32_t *)authentication_sum)[i] = sum[i];
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -300,11 +311,12 @@ static secbool auth_get(uint16_t key, const void **val, uint16_t *len)
|
|||||||
|
|
||||||
// Check storage authentication tag.
|
// Check storage authentication tag.
|
||||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||||
for (size_t i = 0; i < SHA256_DIGEST_LENGTH/sizeof(uint32_t); i++) {
|
for (size_t i = 0; i < SHA256_DIGEST_LENGTH / sizeof(uint32_t); i++) {
|
||||||
REVERSE32(h[i], h[i]);
|
REVERSE32(h[i], h[i]);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (tag_val == NULL || tag_len != STORAGE_TAG_SIZE || sectrue != secequal(h, tag_val, STORAGE_TAG_SIZE)) {
|
if (tag_val == NULL || tag_len != STORAGE_TAG_SIZE ||
|
||||||
|
sectrue != secequal(h, tag_val, STORAGE_TAG_SIZE)) {
|
||||||
handle_fault("storage tag check");
|
handle_fault("storage tag check");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -319,10 +331,10 @@ static secbool auth_get(uint16_t key, const void **val, uint16_t *len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generates a delay of random length. Use this to protect sensitive code against fault injection.
|
* Generates a delay of random length. Use this to protect sensitive code
|
||||||
|
* against fault injection.
|
||||||
*/
|
*/
|
||||||
static void wait_random(void)
|
static void wait_random(void) {
|
||||||
{
|
|
||||||
#ifndef TREZOR_STORAGE_TEST
|
#ifndef TREZOR_STORAGE_TEST
|
||||||
int wait = random32() & 0xff;
|
int wait = random32() & 0xff;
|
||||||
volatile int i = 0;
|
volatile int i = 0;
|
||||||
@ -342,8 +354,9 @@ static void wait_random(void)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void derive_kek(uint32_t pin, const uint8_t *random_salt, uint8_t kek[SHA256_DIGEST_LENGTH], uint8_t keiv[SHA256_DIGEST_LENGTH])
|
static void derive_kek(uint32_t pin, const uint8_t *random_salt,
|
||||||
{
|
uint8_t kek[SHA256_DIGEST_LENGTH],
|
||||||
|
uint8_t keiv[SHA256_DIGEST_LENGTH]) {
|
||||||
#if BYTE_ORDER == BIG_ENDIAN
|
#if BYTE_ORDER == BIG_ENDIAN
|
||||||
REVERSE32(pin, pin);
|
REVERSE32(pin, pin);
|
||||||
#endif
|
#endif
|
||||||
@ -358,21 +371,25 @@ static void derive_kek(uint32_t pin, const uint8_t *random_salt, uint8_t kek[SHA
|
|||||||
}
|
}
|
||||||
|
|
||||||
PBKDF2_HMAC_SHA256_CTX ctx;
|
PBKDF2_HMAC_SHA256_CTX ctx;
|
||||||
pbkdf2_hmac_sha256_Init(&ctx, (const uint8_t*) &pin, sizeof(pin), salt, sizeof(salt), 1);
|
pbkdf2_hmac_sha256_Init(&ctx, (const uint8_t *)&pin, sizeof(pin), salt,
|
||||||
|
sizeof(salt), 1);
|
||||||
for (int i = 1; i <= 5; i++) {
|
for (int i = 1; i <= 5; i++) {
|
||||||
pbkdf2_hmac_sha256_Update(&ctx, PIN_ITER_COUNT / 10);
|
pbkdf2_hmac_sha256_Update(&ctx, PIN_ITER_COUNT / 10);
|
||||||
if (ui_callback && ui_message) {
|
if (ui_callback && ui_message) {
|
||||||
progress = ((ui_total - ui_rem) * 1000 + i * DERIVE_SECS * 100) / ui_total;
|
progress =
|
||||||
|
((ui_total - ui_rem) * 1000 + i * DERIVE_SECS * 100) / ui_total;
|
||||||
ui_callback(ui_rem - i * DERIVE_SECS / 10, progress, ui_message);
|
ui_callback(ui_rem - i * DERIVE_SECS / 10, progress, ui_message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pbkdf2_hmac_sha256_Final(&ctx, kek);
|
pbkdf2_hmac_sha256_Final(&ctx, kek);
|
||||||
|
|
||||||
pbkdf2_hmac_sha256_Init(&ctx, (const uint8_t*) &pin, sizeof(pin), salt, sizeof(salt), 2);
|
pbkdf2_hmac_sha256_Init(&ctx, (const uint8_t *)&pin, sizeof(pin), salt,
|
||||||
|
sizeof(salt), 2);
|
||||||
for (int i = 6; i <= 10; i++) {
|
for (int i = 6; i <= 10; i++) {
|
||||||
pbkdf2_hmac_sha256_Update(&ctx, PIN_ITER_COUNT / 10);
|
pbkdf2_hmac_sha256_Update(&ctx, PIN_ITER_COUNT / 10);
|
||||||
if (ui_callback && ui_message) {
|
if (ui_callback && ui_message) {
|
||||||
progress = ((ui_total - ui_rem) * 1000 + i * DERIVE_SECS * 100) / ui_total;
|
progress =
|
||||||
|
((ui_total - ui_rem) * 1000 + i * DERIVE_SECS * 100) / ui_total;
|
||||||
ui_callback(ui_rem - i * DERIVE_SECS / 10, progress, ui_message);
|
ui_callback(ui_rem - i * DERIVE_SECS / 10, progress, ui_message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -384,8 +401,7 @@ static void derive_kek(uint32_t pin, const uint8_t *random_salt, uint8_t kek[SHA
|
|||||||
memzero(&salt, sizeof(salt));
|
memzero(&salt, sizeof(salt));
|
||||||
}
|
}
|
||||||
|
|
||||||
static secbool set_pin(uint32_t pin)
|
static secbool set_pin(uint32_t pin) {
|
||||||
{
|
|
||||||
uint8_t buffer[RANDOM_SALT_SIZE + KEYS_SIZE + POLY1305_TAG_SIZE];
|
uint8_t buffer[RANDOM_SALT_SIZE + KEYS_SIZE + POLY1305_TAG_SIZE];
|
||||||
uint8_t *salt = buffer;
|
uint8_t *salt = buffer;
|
||||||
uint8_t *ekeys = buffer + RANDOM_SALT_SIZE;
|
uint8_t *ekeys = buffer + RANDOM_SALT_SIZE;
|
||||||
@ -402,11 +418,11 @@ static secbool set_pin(uint32_t pin)
|
|||||||
chacha20poly1305_encrypt(&ctx, cached_keys, ekeys, KEYS_SIZE);
|
chacha20poly1305_encrypt(&ctx, cached_keys, ekeys, KEYS_SIZE);
|
||||||
rfc7539_finish(&ctx, 0, KEYS_SIZE, pvc);
|
rfc7539_finish(&ctx, 0, KEYS_SIZE, pvc);
|
||||||
memzero(&ctx, sizeof(ctx));
|
memzero(&ctx, sizeof(ctx));
|
||||||
secbool ret = norcow_set(EDEK_PVC_KEY, buffer, RANDOM_SALT_SIZE + KEYS_SIZE + PVC_SIZE);
|
secbool ret =
|
||||||
|
norcow_set(EDEK_PVC_KEY, buffer, RANDOM_SALT_SIZE + KEYS_SIZE + PVC_SIZE);
|
||||||
memzero(buffer, sizeof(buffer));
|
memzero(buffer, sizeof(buffer));
|
||||||
|
|
||||||
if (ret == sectrue)
|
if (ret == sectrue) {
|
||||||
{
|
|
||||||
if (pin == PIN_EMPTY) {
|
if (pin == PIN_EMPTY) {
|
||||||
ret = norcow_set(PIN_NOT_SET_KEY, &TRUE_BYTE, sizeof(TRUE_BYTE));
|
ret = norcow_set(PIN_NOT_SET_KEY, &TRUE_BYTE, sizeof(TRUE_BYTE));
|
||||||
} else {
|
} else {
|
||||||
@ -418,8 +434,7 @@ static secbool set_pin(uint32_t pin)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static secbool check_guard_key(const uint32_t guard_key)
|
static secbool check_guard_key(const uint32_t guard_key) {
|
||||||
{
|
|
||||||
if (guard_key % GUARD_KEY_MODULUS != GUARD_KEY_REMAINDER) {
|
if (guard_key % GUARD_KEY_MODULUS != GUARD_KEY_REMAINDER) {
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
@ -431,7 +446,8 @@ static secbool check_guard_key(const uint32_t guard_key)
|
|||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that the guard_key does not contain a run of 5 (or more) zeros or ones.
|
// Check that the guard_key does not contain a run of 5 (or more) zeros or
|
||||||
|
// ones.
|
||||||
uint32_t zero_runs = ~guard_key;
|
uint32_t zero_runs = ~guard_key;
|
||||||
zero_runs = zero_runs & (zero_runs >> 2);
|
zero_runs = zero_runs & (zero_runs >> 2);
|
||||||
zero_runs = zero_runs & (zero_runs >> 1);
|
zero_runs = zero_runs & (zero_runs >> 1);
|
||||||
@ -449,35 +465,37 @@ static secbool check_guard_key(const uint32_t guard_key)
|
|||||||
return sectrue;
|
return sectrue;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t generate_guard_key(void)
|
static uint32_t generate_guard_key(void) {
|
||||||
{
|
|
||||||
uint32_t guard_key = 0;
|
uint32_t guard_key = 0;
|
||||||
do {
|
do {
|
||||||
guard_key = random_uniform((UINT32_MAX/GUARD_KEY_MODULUS) + 1) * GUARD_KEY_MODULUS + GUARD_KEY_REMAINDER;
|
guard_key = random_uniform((UINT32_MAX / GUARD_KEY_MODULUS) + 1) *
|
||||||
|
GUARD_KEY_MODULUS +
|
||||||
|
GUARD_KEY_REMAINDER;
|
||||||
} while (sectrue != check_guard_key(guard_key));
|
} while (sectrue != check_guard_key(guard_key));
|
||||||
return guard_key;
|
return guard_key;
|
||||||
}
|
}
|
||||||
|
|
||||||
static secbool expand_guard_key(const uint32_t guard_key, uint32_t *guard_mask, uint32_t *guard)
|
static secbool expand_guard_key(const uint32_t guard_key, uint32_t *guard_mask,
|
||||||
{
|
uint32_t *guard) {
|
||||||
if (sectrue != check_guard_key(guard_key)) {
|
if (sectrue != check_guard_key(guard_key)) {
|
||||||
handle_fault("guard key check");
|
handle_fault("guard key check");
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
*guard_mask = ((guard_key & LOW_MASK) << 1) | ((~guard_key) & LOW_MASK);
|
*guard_mask = ((guard_key & LOW_MASK) << 1) | ((~guard_key) & LOW_MASK);
|
||||||
*guard = (((guard_key & LOW_MASK) << 1) & guard_key) | (((~guard_key) & LOW_MASK) & (guard_key >> 1));
|
*guard = (((guard_key & LOW_MASK) << 1) & guard_key) |
|
||||||
|
(((~guard_key) & LOW_MASK) & (guard_key >> 1));
|
||||||
return sectrue;
|
return sectrue;
|
||||||
}
|
}
|
||||||
|
|
||||||
static secbool pin_logs_init(uint32_t fails)
|
static secbool pin_logs_init(uint32_t fails) {
|
||||||
{
|
|
||||||
if (fails >= PIN_MAX_TRIES) {
|
if (fails >= PIN_MAX_TRIES) {
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The format of the PIN_LOGS_KEY entry is:
|
// The format of the PIN_LOGS_KEY entry is:
|
||||||
// guard_key (1 word), pin_success_log (PIN_LOG_WORDS), pin_entry_log (PIN_LOG_WORDS)
|
// guard_key (1 word), pin_success_log (PIN_LOG_WORDS), pin_entry_log
|
||||||
uint32_t logs[GUARD_KEY_WORDS + 2*PIN_LOG_WORDS];
|
// (PIN_LOG_WORDS)
|
||||||
|
uint32_t logs[GUARD_KEY_WORDS + 2 * PIN_LOG_WORDS];
|
||||||
|
|
||||||
logs[0] = generate_guard_key();
|
logs[0] = generate_guard_key();
|
||||||
|
|
||||||
@ -489,30 +507,34 @@ static secbool pin_logs_init(uint32_t fails)
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint32_t unused = guard | ~guard_mask;
|
uint32_t unused = guard | ~guard_mask;
|
||||||
for (size_t i = 0; i < 2*PIN_LOG_WORDS; ++i) {
|
for (size_t i = 0; i < 2 * PIN_LOG_WORDS; ++i) {
|
||||||
logs[GUARD_KEY_WORDS + i] = unused;
|
logs[GUARD_KEY_WORDS + i] = unused;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the first word of the PIN entry log to indicate the requested number of fails.
|
// Set the first word of the PIN entry log to indicate the requested number of
|
||||||
logs[GUARD_KEY_WORDS + PIN_LOG_WORDS] = ((((uint32_t)0xFFFFFFFF) >> (2*fails)) & ~guard_mask) | guard;
|
// fails.
|
||||||
|
logs[GUARD_KEY_WORDS + PIN_LOG_WORDS] =
|
||||||
|
((((uint32_t)0xFFFFFFFF) >> (2 * fails)) & ~guard_mask) | guard;
|
||||||
|
|
||||||
return norcow_set(PIN_LOGS_KEY, logs, sizeof(logs));
|
return norcow_set(PIN_LOGS_KEY, logs, sizeof(logs));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initializes the values of VERSION_KEY, EDEK_PVC_KEY, PIN_NOT_SET_KEY and PIN_LOGS_KEY using an empty PIN.
|
* Initializes the values of VERSION_KEY, EDEK_PVC_KEY, PIN_NOT_SET_KEY and
|
||||||
* This function should be called to initialize freshly wiped storage.
|
* PIN_LOGS_KEY using an empty PIN. This function should be called to initialize
|
||||||
|
* freshly wiped storage.
|
||||||
*/
|
*/
|
||||||
static void init_wiped_storage(void)
|
static void init_wiped_storage(void) {
|
||||||
{
|
|
||||||
if (sectrue != initialized) {
|
if (sectrue != initialized) {
|
||||||
// We cannot initialize the storage contents if the hardware_salt is not set.
|
// We cannot initialize the storage contents if the hardware_salt is not
|
||||||
|
// set.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
random_buffer(cached_keys, sizeof(cached_keys));
|
random_buffer(cached_keys, sizeof(cached_keys));
|
||||||
uint32_t version = NORCOW_VERSION;
|
uint32_t version = NORCOW_VERSION;
|
||||||
ensure(auth_init(), "set_storage_auth_tag failed");
|
ensure(auth_init(), "set_storage_auth_tag failed");
|
||||||
ensure(storage_set_encrypted(VERSION_KEY, &version, sizeof(version)), "set_storage_version failed");
|
ensure(storage_set_encrypted(VERSION_KEY, &version, sizeof(version)),
|
||||||
|
"set_storage_version failed");
|
||||||
ensure(pin_logs_init(0), "init_pin_logs failed");
|
ensure(pin_logs_init(0), "init_pin_logs failed");
|
||||||
ui_total = DERIVE_SECS;
|
ui_total = DERIVE_SECS;
|
||||||
ui_rem = ui_total;
|
ui_rem = ui_total;
|
||||||
@ -523,8 +545,8 @@ static void init_wiped_storage(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void storage_init(PIN_UI_WAIT_CALLBACK callback, const uint8_t *salt, const uint16_t salt_len)
|
void storage_init(PIN_UI_WAIT_CALLBACK callback, const uint8_t *salt,
|
||||||
{
|
const uint16_t salt_len) {
|
||||||
initialized = secfalse;
|
initialized = secfalse;
|
||||||
unlocked = secfalse;
|
unlocked = secfalse;
|
||||||
norcow_init(&norcow_active_version);
|
norcow_init(&norcow_active_version);
|
||||||
@ -549,31 +571,34 @@ void storage_init(PIN_UI_WAIT_CALLBACK callback, const uint8_t *salt, const uint
|
|||||||
memzero(cached_keys, sizeof(cached_keys));
|
memzero(cached_keys, sizeof(cached_keys));
|
||||||
}
|
}
|
||||||
|
|
||||||
static secbool pin_fails_reset(void)
|
static secbool pin_fails_reset(void) {
|
||||||
{
|
|
||||||
const void *logs = NULL;
|
const void *logs = NULL;
|
||||||
uint16_t len = 0;
|
uint16_t len = 0;
|
||||||
|
|
||||||
if (sectrue != norcow_get(PIN_LOGS_KEY, &logs, &len) || len != WORD_SIZE*(GUARD_KEY_WORDS + 2*PIN_LOG_WORDS)) {
|
if (sectrue != norcow_get(PIN_LOGS_KEY, &logs, &len) ||
|
||||||
|
len != WORD_SIZE * (GUARD_KEY_WORDS + 2 * PIN_LOG_WORDS)) {
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t guard_mask;
|
uint32_t guard_mask;
|
||||||
uint32_t guard;
|
uint32_t guard;
|
||||||
wait_random();
|
wait_random();
|
||||||
if (sectrue != expand_guard_key(*(const uint32_t*)logs, &guard_mask, &guard)) {
|
if (sectrue !=
|
||||||
|
expand_guard_key(*(const uint32_t *)logs, &guard_mask, &guard)) {
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t unused = guard | ~guard_mask;
|
uint32_t unused = guard | ~guard_mask;
|
||||||
const uint32_t *success_log = ((const uint32_t*)logs) + GUARD_KEY_WORDS;
|
const uint32_t *success_log = ((const uint32_t *)logs) + GUARD_KEY_WORDS;
|
||||||
const uint32_t *entry_log = success_log + PIN_LOG_WORDS;
|
const uint32_t *entry_log = success_log + PIN_LOG_WORDS;
|
||||||
for (size_t i = 0; i < PIN_LOG_WORDS; ++i) {
|
for (size_t i = 0; i < PIN_LOG_WORDS; ++i) {
|
||||||
if (entry_log[i] == unused) {
|
if (entry_log[i] == unused) {
|
||||||
return sectrue;
|
return sectrue;
|
||||||
}
|
}
|
||||||
if (success_log[i] != guard) {
|
if (success_log[i] != guard) {
|
||||||
if (sectrue != norcow_update_word(PIN_LOGS_KEY, sizeof(uint32_t)*(i + GUARD_KEY_WORDS), entry_log[i])) {
|
if (sectrue != norcow_update_word(
|
||||||
|
PIN_LOGS_KEY, sizeof(uint32_t) * (i + GUARD_KEY_WORDS),
|
||||||
|
entry_log[i])) {
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -581,8 +606,7 @@ static secbool pin_fails_reset(void)
|
|||||||
return pin_logs_init(0);
|
return pin_logs_init(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
secbool storage_pin_fails_increase(void)
|
secbool storage_pin_fails_increase(void) {
|
||||||
{
|
|
||||||
if (sectrue != initialized) {
|
if (sectrue != initialized) {
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
@ -591,7 +615,8 @@ secbool storage_pin_fails_increase(void)
|
|||||||
uint16_t len = 0;
|
uint16_t len = 0;
|
||||||
|
|
||||||
wait_random();
|
wait_random();
|
||||||
if (sectrue != norcow_get(PIN_LOGS_KEY, &logs, &len) || len != WORD_SIZE*(GUARD_KEY_WORDS + 2*PIN_LOG_WORDS)) {
|
if (sectrue != norcow_get(PIN_LOGS_KEY, &logs, &len) ||
|
||||||
|
len != WORD_SIZE * (GUARD_KEY_WORDS + 2 * PIN_LOG_WORDS)) {
|
||||||
handle_fault("no PIN logs");
|
handle_fault("no PIN logs");
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
@ -599,12 +624,14 @@ secbool storage_pin_fails_increase(void)
|
|||||||
uint32_t guard_mask;
|
uint32_t guard_mask;
|
||||||
uint32_t guard;
|
uint32_t guard;
|
||||||
wait_random();
|
wait_random();
|
||||||
if (sectrue != expand_guard_key(*(const uint32_t*)logs, &guard_mask, &guard)) {
|
if (sectrue !=
|
||||||
|
expand_guard_key(*(const uint32_t *)logs, &guard_mask, &guard)) {
|
||||||
handle_fault("guard key expansion");
|
handle_fault("guard key expansion");
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint32_t *entry_log = ((const uint32_t*)logs) + GUARD_KEY_WORDS + PIN_LOG_WORDS;
|
const uint32_t *entry_log =
|
||||||
|
((const uint32_t *)logs) + GUARD_KEY_WORDS + PIN_LOG_WORDS;
|
||||||
for (size_t i = 0; i < PIN_LOG_WORDS; ++i) {
|
for (size_t i = 0; i < PIN_LOG_WORDS; ++i) {
|
||||||
wait_random();
|
wait_random();
|
||||||
if ((entry_log[i] & guard_mask) != guard) {
|
if ((entry_log[i] & guard_mask) != guard) {
|
||||||
@ -618,20 +645,22 @@ secbool storage_pin_fails_increase(void)
|
|||||||
word = (word >> 2) | (word >> 1);
|
word = (word >> 2) | (word >> 1);
|
||||||
|
|
||||||
wait_random();
|
wait_random();
|
||||||
if (sectrue != norcow_update_word(PIN_LOGS_KEY, sizeof(uint32_t)*(i + GUARD_KEY_WORDS + PIN_LOG_WORDS), (word & ~guard_mask) | guard)) {
|
if (sectrue !=
|
||||||
|
norcow_update_word(
|
||||||
|
PIN_LOGS_KEY,
|
||||||
|
sizeof(uint32_t) * (i + GUARD_KEY_WORDS + PIN_LOG_WORDS),
|
||||||
|
(word & ~guard_mask) | guard)) {
|
||||||
handle_fault("PIN logs update");
|
handle_fault("PIN logs update");
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
return sectrue;
|
return sectrue;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
handle_fault("PIN log exhausted");
|
handle_fault("PIN log exhausted");
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t hamming_weight(uint32_t value)
|
static uint32_t hamming_weight(uint32_t value) {
|
||||||
{
|
|
||||||
value = value - ((value >> 1) & 0x55555555);
|
value = value - ((value >> 1) & 0x55555555);
|
||||||
value = (value & 0x33333333) + ((value >> 2) & 0x33333333);
|
value = (value & 0x33333333) + ((value >> 2) & 0x33333333);
|
||||||
value = (value + (value >> 4)) & 0x0F0F0F0F;
|
value = (value + (value >> 4)) & 0x0F0F0F0F;
|
||||||
@ -640,14 +669,14 @@ static uint32_t hamming_weight(uint32_t value)
|
|||||||
return value & 0x3F;
|
return value & 0x3F;
|
||||||
}
|
}
|
||||||
|
|
||||||
static secbool pin_get_fails(uint32_t *ctr)
|
static secbool pin_get_fails(uint32_t *ctr) {
|
||||||
{
|
|
||||||
*ctr = PIN_MAX_TRIES;
|
*ctr = PIN_MAX_TRIES;
|
||||||
|
|
||||||
const void *logs = NULL;
|
const void *logs = NULL;
|
||||||
uint16_t len = 0;
|
uint16_t len = 0;
|
||||||
wait_random();
|
wait_random();
|
||||||
if (sectrue != norcow_get(PIN_LOGS_KEY, &logs, &len) || len != WORD_SIZE*(GUARD_KEY_WORDS + 2*PIN_LOG_WORDS)) {
|
if (sectrue != norcow_get(PIN_LOGS_KEY, &logs, &len) ||
|
||||||
|
len != WORD_SIZE * (GUARD_KEY_WORDS + 2 * PIN_LOG_WORDS)) {
|
||||||
handle_fault("no PIN logs");
|
handle_fault("no PIN logs");
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
@ -655,18 +684,21 @@ static secbool pin_get_fails(uint32_t *ctr)
|
|||||||
uint32_t guard_mask;
|
uint32_t guard_mask;
|
||||||
uint32_t guard;
|
uint32_t guard;
|
||||||
wait_random();
|
wait_random();
|
||||||
if (sectrue != expand_guard_key(*(const uint32_t*)logs, &guard_mask, &guard)) {
|
if (sectrue !=
|
||||||
|
expand_guard_key(*(const uint32_t *)logs, &guard_mask, &guard)) {
|
||||||
handle_fault("guard key expansion");
|
handle_fault("guard key expansion");
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
const uint32_t unused = guard | ~guard_mask;
|
const uint32_t unused = guard | ~guard_mask;
|
||||||
|
|
||||||
const uint32_t *success_log = ((const uint32_t*)logs) + GUARD_KEY_WORDS;
|
const uint32_t *success_log = ((const uint32_t *)logs) + GUARD_KEY_WORDS;
|
||||||
const uint32_t *entry_log = success_log + PIN_LOG_WORDS;
|
const uint32_t *entry_log = success_log + PIN_LOG_WORDS;
|
||||||
volatile int current = -1;
|
volatile int current = -1;
|
||||||
volatile size_t i;
|
volatile size_t i;
|
||||||
for (i = 0; i < PIN_LOG_WORDS; ++i) {
|
for (i = 0; i < PIN_LOG_WORDS; ++i) {
|
||||||
if ((entry_log[i] & guard_mask) != guard || (success_log[i] & guard_mask) != guard || (entry_log[i] & success_log[i]) != entry_log[i]) {
|
if ((entry_log[i] & guard_mask) != guard ||
|
||||||
|
(success_log[i] & guard_mask) != guard ||
|
||||||
|
(entry_log[i] & success_log[i]) != entry_log[i]) {
|
||||||
handle_fault("PIN logs format check");
|
handle_fault("PIN logs format check");
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
@ -688,10 +720,11 @@ static secbool pin_get_fails(uint32_t *ctr)
|
|||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Strip the guard bits from the current entry word and duplicate each data bit.
|
// Strip the guard bits from the current entry word and duplicate each data
|
||||||
|
// bit.
|
||||||
wait_random();
|
wait_random();
|
||||||
uint32_t word = entry_log[current] & ~guard_mask;
|
uint32_t word = entry_log[current] & ~guard_mask;
|
||||||
word = ((word >> 1) | word ) & LOW_MASK;
|
word = ((word >> 1) | word) & LOW_MASK;
|
||||||
word = word | (word << 1);
|
word = word | (word << 1);
|
||||||
// Verify that the entry word has form 0*1*.
|
// Verify that the entry word has form 0*1*.
|
||||||
if ((word & (word + 1)) != 0) {
|
if ((word & (word + 1)) != 0) {
|
||||||
@ -705,12 +738,12 @@ static secbool pin_get_fails(uint32_t *ctr)
|
|||||||
|
|
||||||
// Count the number of set bits in the two current words of the success log.
|
// Count the number of set bits in the two current words of the success log.
|
||||||
wait_random();
|
wait_random();
|
||||||
*ctr = hamming_weight(success_log[current-1] ^ entry_log[current-1]) + hamming_weight(success_log[current] ^ entry_log[current]);
|
*ctr = hamming_weight(success_log[current - 1] ^ entry_log[current - 1]) +
|
||||||
|
hamming_weight(success_log[current] ^ entry_log[current]);
|
||||||
return sectrue;
|
return sectrue;
|
||||||
}
|
}
|
||||||
|
|
||||||
secbool storage_is_unlocked(void)
|
secbool storage_is_unlocked(void) {
|
||||||
{
|
|
||||||
if (sectrue != initialized) {
|
if (sectrue != initialized) {
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
@ -718,24 +751,25 @@ secbool storage_is_unlocked(void)
|
|||||||
return unlocked;
|
return unlocked;
|
||||||
}
|
}
|
||||||
|
|
||||||
void storage_lock(void)
|
void storage_lock(void) {
|
||||||
{
|
|
||||||
unlocked = secfalse;
|
unlocked = secfalse;
|
||||||
memzero(cached_keys, sizeof(cached_keys));
|
memzero(cached_keys, sizeof(cached_keys));
|
||||||
memzero(authentication_sum, sizeof(authentication_sum));
|
memzero(authentication_sum, sizeof(authentication_sum));
|
||||||
}
|
}
|
||||||
|
|
||||||
static secbool decrypt_dek(const uint8_t *kek, const uint8_t *keiv)
|
static secbool decrypt_dek(const uint8_t *kek, const uint8_t *keiv) {
|
||||||
{
|
|
||||||
const void *buffer = NULL;
|
const void *buffer = NULL;
|
||||||
uint16_t len = 0;
|
uint16_t len = 0;
|
||||||
if (sectrue != initialized || sectrue != norcow_get(EDEK_PVC_KEY, &buffer, &len) || len != RANDOM_SALT_SIZE + KEYS_SIZE + PVC_SIZE) {
|
if (sectrue != initialized ||
|
||||||
|
sectrue != norcow_get(EDEK_PVC_KEY, &buffer, &len) ||
|
||||||
|
len != RANDOM_SALT_SIZE + KEYS_SIZE + PVC_SIZE) {
|
||||||
handle_fault("no EDEK");
|
handle_fault("no EDEK");
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint8_t *ekeys = (const uint8_t*) buffer + RANDOM_SALT_SIZE;
|
const uint8_t *ekeys = (const uint8_t *)buffer + RANDOM_SALT_SIZE;
|
||||||
const uint32_t *pvc = (const uint32_t*) buffer + (RANDOM_SALT_SIZE + KEYS_SIZE)/sizeof(uint32_t);
|
const uint32_t *pvc = (const uint32_t *)buffer +
|
||||||
|
(RANDOM_SALT_SIZE + KEYS_SIZE) / sizeof(uint32_t);
|
||||||
_Static_assert(((RANDOM_SALT_SIZE + KEYS_SIZE) & 3) == 0, "PVC unaligned");
|
_Static_assert(((RANDOM_SALT_SIZE + KEYS_SIZE) & 3) == 0, "PVC unaligned");
|
||||||
_Static_assert((PVC_SIZE & 3) == 0, "PVC size unaligned");
|
_Static_assert((PVC_SIZE & 3) == 0, "PVC size unaligned");
|
||||||
|
|
||||||
@ -743,13 +777,15 @@ static secbool decrypt_dek(const uint8_t *kek, const uint8_t *keiv)
|
|||||||
uint8_t tag[POLY1305_TAG_SIZE] __attribute__((aligned(sizeof(uint32_t))));
|
uint8_t tag[POLY1305_TAG_SIZE] __attribute__((aligned(sizeof(uint32_t))));
|
||||||
chacha20poly1305_ctx ctx;
|
chacha20poly1305_ctx ctx;
|
||||||
|
|
||||||
// Decrypt the data encryption key and the storage authentication key and check the PIN verification code.
|
// Decrypt the data encryption key and the storage authentication key and
|
||||||
|
// check the PIN verification code.
|
||||||
rfc7539_init(&ctx, kek, keiv);
|
rfc7539_init(&ctx, kek, keiv);
|
||||||
chacha20poly1305_decrypt(&ctx, ekeys, keys, KEYS_SIZE);
|
chacha20poly1305_decrypt(&ctx, ekeys, keys, KEYS_SIZE);
|
||||||
rfc7539_finish(&ctx, 0, KEYS_SIZE, tag);
|
rfc7539_finish(&ctx, 0, KEYS_SIZE, tag);
|
||||||
memzero(&ctx, sizeof(ctx));
|
memzero(&ctx, sizeof(ctx));
|
||||||
wait_random();
|
wait_random();
|
||||||
if (secequal32((const uint32_t*) tag, pvc, PVC_SIZE/sizeof(uint32_t)) != sectrue) {
|
if (secequal32((const uint32_t *)tag, pvc, PVC_SIZE / sizeof(uint32_t)) !=
|
||||||
|
sectrue) {
|
||||||
memzero(keys, sizeof(keys));
|
memzero(keys, sizeof(keys));
|
||||||
memzero(tag, sizeof(tag));
|
memzero(tag, sizeof(tag));
|
||||||
return secfalse;
|
return secfalse;
|
||||||
@ -759,9 +795,12 @@ static secbool decrypt_dek(const uint8_t *kek, const uint8_t *keiv)
|
|||||||
memzero(tag, sizeof(tag));
|
memzero(tag, sizeof(tag));
|
||||||
|
|
||||||
// Check that the authenticated version number matches the norcow version.
|
// Check that the authenticated version number matches the norcow version.
|
||||||
// NOTE: storage_get_encrypted() calls auth_get(), which initializes the authentication_sum.
|
// NOTE: storage_get_encrypted() calls auth_get(), which initializes the
|
||||||
|
// authentication_sum.
|
||||||
uint32_t version;
|
uint32_t version;
|
||||||
if (sectrue != storage_get_encrypted(VERSION_KEY, &version, sizeof(version), &len) || len != sizeof(version) || version != norcow_active_version) {
|
if (sectrue !=
|
||||||
|
storage_get_encrypted(VERSION_KEY, &version, sizeof(version), &len) ||
|
||||||
|
len != sizeof(version) || version != norcow_active_version) {
|
||||||
handle_fault("storage version check");
|
handle_fault("storage version check");
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
@ -769,8 +808,7 @@ static secbool decrypt_dek(const uint8_t *kek, const uint8_t *keiv)
|
|||||||
return sectrue;
|
return sectrue;
|
||||||
}
|
}
|
||||||
|
|
||||||
static secbool unlock(uint32_t pin)
|
static secbool unlock(uint32_t pin) {
|
||||||
{
|
|
||||||
if (sectrue != initialized) {
|
if (sectrue != initialized) {
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
@ -786,7 +824,8 @@ static secbool unlock(uint32_t pin)
|
|||||||
wait_random();
|
wait_random();
|
||||||
if (ctr >= PIN_MAX_TRIES) {
|
if (ctr >= PIN_MAX_TRIES) {
|
||||||
storage_wipe();
|
storage_wipe();
|
||||||
error_shutdown("Too many wrong PIN", "attempts. Storage has", "been wiped.", NULL);
|
error_shutdown("Too many wrong PIN", "attempts. Storage has", "been wiped.",
|
||||||
|
NULL);
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -810,17 +849,20 @@ static secbool unlock(uint32_t pin)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the random salt from EDEK_PVC_KEY and use it to derive the KEK and KEIV from the PIN.
|
// Read the random salt from EDEK_PVC_KEY and use it to derive the KEK and
|
||||||
|
// KEIV from the PIN.
|
||||||
const void *salt = NULL;
|
const void *salt = NULL;
|
||||||
uint16_t len = 0;
|
uint16_t len = 0;
|
||||||
if (sectrue != initialized || sectrue != norcow_get(EDEK_PVC_KEY, &salt, &len) || len != RANDOM_SALT_SIZE + KEYS_SIZE + PVC_SIZE) {
|
if (sectrue != initialized ||
|
||||||
|
sectrue != norcow_get(EDEK_PVC_KEY, &salt, &len) ||
|
||||||
|
len != RANDOM_SALT_SIZE + KEYS_SIZE + PVC_SIZE) {
|
||||||
memzero(&pin, sizeof(pin));
|
memzero(&pin, sizeof(pin));
|
||||||
handle_fault("no EDEK");
|
handle_fault("no EDEK");
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
uint8_t kek[SHA256_DIGEST_LENGTH];
|
uint8_t kek[SHA256_DIGEST_LENGTH];
|
||||||
uint8_t keiv[SHA256_DIGEST_LENGTH];
|
uint8_t keiv[SHA256_DIGEST_LENGTH];
|
||||||
derive_kek(pin, (const uint8_t*) salt, kek, keiv);
|
derive_kek(pin, (const uint8_t *)salt, kek, keiv);
|
||||||
memzero(&pin, sizeof(pin));
|
memzero(&pin, sizeof(pin));
|
||||||
|
|
||||||
// First, we increase PIN fail counter in storage, even before checking the
|
// First, we increase PIN fail counter in storage, even before checking the
|
||||||
@ -843,7 +885,8 @@ static secbool unlock(uint32_t pin)
|
|||||||
wait_random();
|
wait_random();
|
||||||
if (ctr + 1 >= PIN_MAX_TRIES) {
|
if (ctr + 1 >= PIN_MAX_TRIES) {
|
||||||
storage_wipe();
|
storage_wipe();
|
||||||
error_shutdown("Too many wrong PIN", "attempts. Storage has", "been wiped.", NULL);
|
error_shutdown("Too many wrong PIN", "attempts. Storage has",
|
||||||
|
"been wiped.", NULL);
|
||||||
}
|
}
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
@ -856,8 +899,7 @@ static secbool unlock(uint32_t pin)
|
|||||||
return pin_fails_reset();
|
return pin_fails_reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
secbool storage_unlock(uint32_t pin)
|
secbool storage_unlock(uint32_t pin) {
|
||||||
{
|
|
||||||
ui_total = DERIVE_SECS;
|
ui_total = DERIVE_SECS;
|
||||||
ui_rem = ui_total;
|
ui_rem = ui_total;
|
||||||
if (pin == PIN_EMPTY) {
|
if (pin == PIN_EMPTY) {
|
||||||
@ -877,8 +919,8 @@ secbool storage_unlock(uint32_t pin)
|
|||||||
* If val_dest is not NULL and max_len >= len, then the data is decrypted
|
* If val_dest is not NULL and max_len >= len, then the data is decrypted
|
||||||
* to val_dest using cached_dek as the decryption key.
|
* to val_dest using cached_dek as the decryption key.
|
||||||
*/
|
*/
|
||||||
static secbool storage_get_encrypted(const uint16_t key, void *val_dest, const uint16_t max_len, uint16_t *len)
|
static secbool storage_get_encrypted(const uint16_t key, void *val_dest,
|
||||||
{
|
const uint16_t max_len, uint16_t *len) {
|
||||||
const void *val_stored = NULL;
|
const void *val_stored = NULL;
|
||||||
|
|
||||||
if (sectrue != auth_get(key, &val_stored, len)) {
|
if (sectrue != auth_get(key, &val_stored, len)) {
|
||||||
@ -899,14 +941,15 @@ static secbool storage_get_encrypted(const uint16_t key, void *val_dest, const u
|
|||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint8_t *iv = (const uint8_t*) val_stored;
|
const uint8_t *iv = (const uint8_t *)val_stored;
|
||||||
const uint8_t *tag_stored = (const uint8_t*) val_stored + CHACHA20_IV_SIZE;
|
const uint8_t *tag_stored = (const uint8_t *)val_stored + CHACHA20_IV_SIZE;
|
||||||
const uint8_t *ciphertext = (const uint8_t*) val_stored + CHACHA20_IV_SIZE + POLY1305_TAG_SIZE;
|
const uint8_t *ciphertext =
|
||||||
|
(const uint8_t *)val_stored + CHACHA20_IV_SIZE + POLY1305_TAG_SIZE;
|
||||||
uint8_t tag_computed[POLY1305_TAG_SIZE];
|
uint8_t tag_computed[POLY1305_TAG_SIZE];
|
||||||
chacha20poly1305_ctx ctx;
|
chacha20poly1305_ctx ctx;
|
||||||
rfc7539_init(&ctx, cached_dek, iv);
|
rfc7539_init(&ctx, cached_dek, iv);
|
||||||
rfc7539_auth(&ctx, (const uint8_t*)&key, sizeof(key));
|
rfc7539_auth(&ctx, (const uint8_t *)&key, sizeof(key));
|
||||||
chacha20poly1305_decrypt(&ctx, ciphertext, (uint8_t*) val_dest, *len);
|
chacha20poly1305_decrypt(&ctx, ciphertext, (uint8_t *)val_dest, *len);
|
||||||
rfc7539_finish(&ctx, sizeof(key), *len, tag_computed);
|
rfc7539_finish(&ctx, sizeof(key), *len, tag_computed);
|
||||||
memzero(&ctx, sizeof(ctx));
|
memzero(&ctx, sizeof(ctx));
|
||||||
|
|
||||||
@ -926,15 +969,16 @@ static secbool storage_get_encrypted(const uint16_t key, void *val_dest, const u
|
|||||||
* Finds the data stored under key and writes its length to len. If val_dest is
|
* Finds the data stored under key and writes its length to len. If val_dest is
|
||||||
* not NULL and max_len >= len, then the data is copied to val_dest.
|
* not NULL and max_len >= len, then the data is copied to val_dest.
|
||||||
*/
|
*/
|
||||||
secbool storage_get(const uint16_t key, void *val_dest, const uint16_t max_len, uint16_t *len)
|
secbool storage_get(const uint16_t key, void *val_dest, const uint16_t max_len,
|
||||||
{
|
uint16_t *len) {
|
||||||
const uint8_t app = key >> 8;
|
const uint8_t app = key >> 8;
|
||||||
// APP == 0 is reserved for PIN related values
|
// APP == 0 is reserved for PIN related values
|
||||||
if (sectrue != initialized || app == APP_STORAGE) {
|
if (sectrue != initialized || app == APP_STORAGE) {
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the top bit of APP is set, then the value is not encrypted and can be read from a locked device.
|
// If the top bit of APP is set, then the value is not encrypted and can be
|
||||||
|
// read from a locked device.
|
||||||
secbool ret = secfalse;
|
secbool ret = secfalse;
|
||||||
if ((app & FLAG_PUBLIC) != 0) {
|
if ((app & FLAG_PUBLIC) != 0) {
|
||||||
const void *val_stored = NULL;
|
const void *val_stored = NULL;
|
||||||
@ -960,16 +1004,18 @@ secbool storage_get(const uint16_t key, void *val_dest, const uint16_t max_len,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Encrypts the data at val using cached_dek as the encryption key and stores the ciphertext under key.
|
* Encrypts the data at val using cached_dek as the encryption key and stores
|
||||||
|
* the ciphertext under key.
|
||||||
*/
|
*/
|
||||||
static secbool storage_set_encrypted(const uint16_t key, const void *val, const uint16_t len)
|
static secbool storage_set_encrypted(const uint16_t key, const void *val,
|
||||||
{
|
const uint16_t len) {
|
||||||
if (len > UINT16_MAX - CHACHA20_IV_SIZE - POLY1305_TAG_SIZE) {
|
if (len > UINT16_MAX - CHACHA20_IV_SIZE - POLY1305_TAG_SIZE) {
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Preallocate space on the flash storage.
|
// Preallocate space on the flash storage.
|
||||||
if (sectrue != auth_set(key, NULL, CHACHA20_IV_SIZE + POLY1305_TAG_SIZE + len)) {
|
if (sectrue !=
|
||||||
|
auth_set(key, NULL, CHACHA20_IV_SIZE + POLY1305_TAG_SIZE + len)) {
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -985,11 +1031,14 @@ static secbool storage_set_encrypted(const uint16_t key, const void *val, const
|
|||||||
// Encrypt all blocks except for the last one.
|
// Encrypt all blocks except for the last one.
|
||||||
chacha20poly1305_ctx ctx;
|
chacha20poly1305_ctx ctx;
|
||||||
rfc7539_init(&ctx, cached_dek, buffer);
|
rfc7539_init(&ctx, cached_dek, buffer);
|
||||||
rfc7539_auth(&ctx, (const uint8_t*)&key, sizeof(key));
|
rfc7539_auth(&ctx, (const uint8_t *)&key, sizeof(key));
|
||||||
size_t i;
|
size_t i;
|
||||||
for (i = 0; i + CHACHA20_BLOCK_SIZE < len; i += CHACHA20_BLOCK_SIZE, offset += CHACHA20_BLOCK_SIZE) {
|
for (i = 0; i + CHACHA20_BLOCK_SIZE < len;
|
||||||
chacha20poly1305_encrypt(&ctx, ((const uint8_t*) val) + i, buffer, CHACHA20_BLOCK_SIZE);
|
i += CHACHA20_BLOCK_SIZE, offset += CHACHA20_BLOCK_SIZE) {
|
||||||
if (sectrue != norcow_update_bytes(key, offset, buffer, CHACHA20_BLOCK_SIZE)) {
|
chacha20poly1305_encrypt(&ctx, ((const uint8_t *)val) + i, buffer,
|
||||||
|
CHACHA20_BLOCK_SIZE);
|
||||||
|
if (sectrue !=
|
||||||
|
norcow_update_bytes(key, offset, buffer, CHACHA20_BLOCK_SIZE)) {
|
||||||
memzero(&ctx, sizeof(ctx));
|
memzero(&ctx, sizeof(ctx));
|
||||||
memzero(buffer, sizeof(buffer));
|
memzero(buffer, sizeof(buffer));
|
||||||
return secfalse;
|
return secfalse;
|
||||||
@ -997,7 +1046,7 @@ static secbool storage_set_encrypted(const uint16_t key, const void *val, const
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Encrypt final block and compute message authentication tag.
|
// Encrypt final block and compute message authentication tag.
|
||||||
chacha20poly1305_encrypt(&ctx, ((const uint8_t*) val) + i, buffer, len - i);
|
chacha20poly1305_encrypt(&ctx, ((const uint8_t *)val) + i, buffer, len - i);
|
||||||
secbool ret = norcow_update_bytes(key, offset, buffer, len - i);
|
secbool ret = norcow_update_bytes(key, offset, buffer, len - i);
|
||||||
if (sectrue == ret) {
|
if (sectrue == ret) {
|
||||||
rfc7539_finish(&ctx, sizeof(key), len, buffer);
|
rfc7539_finish(&ctx, sizeof(key), len, buffer);
|
||||||
@ -1008,8 +1057,7 @@ static secbool storage_set_encrypted(const uint16_t key, const void *val, const
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
secbool storage_set(const uint16_t key, const void *val, const uint16_t len)
|
secbool storage_set(const uint16_t key, const void *val, const uint16_t len) {
|
||||||
{
|
|
||||||
const uint8_t app = key >> 8;
|
const uint8_t app = key >> 8;
|
||||||
|
|
||||||
// APP == 0 is reserved for PIN related values
|
// APP == 0 is reserved for PIN related values
|
||||||
@ -1030,8 +1078,7 @@ secbool storage_set(const uint16_t key, const void *val, const uint16_t len)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
secbool storage_delete(const uint16_t key)
|
secbool storage_delete(const uint16_t key) {
|
||||||
{
|
|
||||||
const uint8_t app = key >> 8;
|
const uint8_t app = key >> 8;
|
||||||
|
|
||||||
// APP == 0 is reserved for storage related values
|
// APP == 0 is reserved for storage related values
|
||||||
@ -1050,8 +1097,7 @@ secbool storage_delete(const uint16_t key)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
secbool storage_set_counter(const uint16_t key, const uint32_t count)
|
secbool storage_set_counter(const uint16_t key, const uint32_t count) {
|
||||||
{
|
|
||||||
const uint8_t app = key >> 8;
|
const uint8_t app = key >> 8;
|
||||||
if ((app & FLAG_PUBLIC) == 0) {
|
if ((app & FLAG_PUBLIC) == 0) {
|
||||||
return secfalse;
|
return secfalse;
|
||||||
@ -1065,11 +1111,11 @@ secbool storage_set_counter(const uint16_t key, const uint32_t count)
|
|||||||
return storage_set(key, value, sizeof(value));
|
return storage_set(key, value, sizeof(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
secbool storage_next_counter(const uint16_t key, uint32_t *count)
|
secbool storage_next_counter(const uint16_t key, uint32_t *count) {
|
||||||
{
|
|
||||||
const uint8_t app = key >> 8;
|
const uint8_t app = key >> 8;
|
||||||
// APP == 0 is reserved for PIN related values
|
// APP == 0 is reserved for PIN related values
|
||||||
if (sectrue != initialized || app == APP_STORAGE || (app & FLAG_PUBLIC) == 0) {
|
if (sectrue != initialized || app == APP_STORAGE ||
|
||||||
|
(app & FLAG_PUBLIC) == 0) {
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1079,7 +1125,7 @@ secbool storage_next_counter(const uint16_t key, uint32_t *count)
|
|||||||
|
|
||||||
uint16_t len = 0;
|
uint16_t len = 0;
|
||||||
const uint32_t *val_stored = NULL;
|
const uint32_t *val_stored = NULL;
|
||||||
if (sectrue != norcow_get(key, (const void**)&val_stored, &len)) {
|
if (sectrue != norcow_get(key, (const void **)&val_stored, &len)) {
|
||||||
*count = 0;
|
*count = 0;
|
||||||
return storage_set_counter(key, 0);
|
return storage_set_counter(key, 0);
|
||||||
}
|
}
|
||||||
@ -1104,22 +1150,21 @@ secbool storage_next_counter(const uint16_t key, uint32_t *count)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
secbool storage_has_pin(void)
|
secbool storage_has_pin(void) {
|
||||||
{
|
|
||||||
if (sectrue != initialized) {
|
if (sectrue != initialized) {
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
|
|
||||||
const void *val = NULL;
|
const void *val = NULL;
|
||||||
uint16_t len;
|
uint16_t len;
|
||||||
if (sectrue != norcow_get(PIN_NOT_SET_KEY, &val, &len) || (len > 0 && *(uint8_t*)val != FALSE_BYTE)) {
|
if (sectrue != norcow_get(PIN_NOT_SET_KEY, &val, &len) ||
|
||||||
|
(len > 0 && *(uint8_t *)val != FALSE_BYTE)) {
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
return sectrue;
|
return sectrue;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t storage_get_pin_rem(void)
|
uint32_t storage_get_pin_rem(void) {
|
||||||
{
|
|
||||||
if (sectrue != initialized) {
|
if (sectrue != initialized) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1131,15 +1176,15 @@ uint32_t storage_get_pin_rem(void)
|
|||||||
return PIN_MAX_TRIES - ctr;
|
return PIN_MAX_TRIES - ctr;
|
||||||
}
|
}
|
||||||
|
|
||||||
secbool storage_change_pin(uint32_t oldpin, uint32_t newpin)
|
secbool storage_change_pin(uint32_t oldpin, uint32_t newpin) {
|
||||||
{
|
|
||||||
if (sectrue != initialized) {
|
if (sectrue != initialized) {
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
|
|
||||||
ui_total = 2 * DERIVE_SECS;
|
ui_total = 2 * DERIVE_SECS;
|
||||||
ui_rem = ui_total;
|
ui_rem = ui_total;
|
||||||
ui_message = (oldpin != PIN_EMPTY && newpin == PIN_EMPTY) ? VERIFYING_PIN_MSG : PROCESSING_MSG;
|
ui_message = (oldpin != PIN_EMPTY && newpin == PIN_EMPTY) ? VERIFYING_PIN_MSG
|
||||||
|
: PROCESSING_MSG;
|
||||||
|
|
||||||
if (sectrue != unlock(oldpin)) {
|
if (sectrue != unlock(oldpin)) {
|
||||||
return secfalse;
|
return secfalse;
|
||||||
@ -1150,8 +1195,7 @@ secbool storage_change_pin(uint32_t oldpin, uint32_t newpin)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void storage_wipe(void)
|
void storage_wipe(void) {
|
||||||
{
|
|
||||||
norcow_wipe();
|
norcow_wipe();
|
||||||
norcow_active_version = NORCOW_VERSION;
|
norcow_active_version = NORCOW_VERSION;
|
||||||
memzero(authentication_sum, sizeof(authentication_sum));
|
memzero(authentication_sum, sizeof(authentication_sum));
|
||||||
@ -1159,17 +1203,19 @@ void storage_wipe(void)
|
|||||||
init_wiped_storage();
|
init_wiped_storage();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __handle_fault(const char *msg, const char *file, int line, const char *func)
|
static void __handle_fault(const char *msg, const char *file, int line,
|
||||||
{
|
const char *func) {
|
||||||
static secbool in_progress = secfalse;
|
static secbool in_progress = secfalse;
|
||||||
|
|
||||||
// If fault handling is already in progress, then we are probably facing a fault injection attack, so wipe.
|
// If fault handling is already in progress, then we are probably facing a
|
||||||
|
// fault injection attack, so wipe.
|
||||||
if (secfalse != in_progress) {
|
if (secfalse != in_progress) {
|
||||||
storage_wipe();
|
storage_wipe();
|
||||||
__fatal_error("Fault detected", msg, file, line, func);
|
__fatal_error("Fault detected", msg, file, line, func);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We use the PIN fail counter as a fault counter. Increment the counter, check that it was incremented and halt.
|
// We use the PIN fail counter as a fault counter. Increment the counter,
|
||||||
|
// check that it was incremented and halt.
|
||||||
in_progress = sectrue;
|
in_progress = sectrue;
|
||||||
uint32_t ctr;
|
uint32_t ctr;
|
||||||
if (sectrue != pin_get_fails(&ctr)) {
|
if (sectrue != pin_get_fails(&ctr)) {
|
||||||
@ -1190,10 +1236,10 @@ static void __handle_fault(const char *msg, const char *file, int line, const ch
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reads the PIN fail counter in version 0 format. Returns the current number of failed PIN entries.
|
* Reads the PIN fail counter in version 0 format. Returns the current number of
|
||||||
|
* failed PIN entries.
|
||||||
*/
|
*/
|
||||||
static secbool v0_pin_get_fails(uint32_t *ctr)
|
static secbool v0_pin_get_fails(uint32_t *ctr) {
|
||||||
{
|
|
||||||
const uint16_t V0_PIN_FAIL_KEY = 0x0001;
|
const uint16_t V0_PIN_FAIL_KEY = 0x0001;
|
||||||
// The PIN_FAIL_KEY points to an area of words, initialized to
|
// The PIN_FAIL_KEY points to an area of words, initialized to
|
||||||
// 0xffffffff (meaning no PIN failures). The first non-zero word
|
// 0xffffffff (meaning no PIN failures). The first non-zero word
|
||||||
@ -1208,7 +1254,7 @@ static secbool v0_pin_get_fails(uint32_t *ctr)
|
|||||||
uint16_t len = 0;
|
uint16_t len = 0;
|
||||||
if (secfalse != norcow_get(V0_PIN_FAIL_KEY, &val, &len)) {
|
if (secfalse != norcow_get(V0_PIN_FAIL_KEY, &val, &len)) {
|
||||||
for (unsigned int i = 0; i < len / sizeof(uint32_t); i++) {
|
for (unsigned int i = 0; i < len / sizeof(uint32_t); i++) {
|
||||||
uint32_t word = ((const uint32_t*)val)[i];
|
uint32_t word = ((const uint32_t *)val)[i];
|
||||||
if (word != 0) {
|
if (word != 0) {
|
||||||
*ctr = hamming_weight(~word);
|
*ctr = hamming_weight(~word);
|
||||||
return sectrue;
|
return sectrue;
|
||||||
@ -1221,8 +1267,7 @@ static secbool v0_pin_get_fails(uint32_t *ctr)
|
|||||||
return sectrue;
|
return sectrue;
|
||||||
}
|
}
|
||||||
|
|
||||||
static secbool storage_upgrade(void)
|
static secbool storage_upgrade(void) {
|
||||||
{
|
|
||||||
const uint16_t V0_PIN_KEY = 0x0000;
|
const uint16_t V0_PIN_KEY = 0x0000;
|
||||||
const uint16_t V0_PIN_FAIL_KEY = 0x0001;
|
const uint16_t V0_PIN_FAIL_KEY = 0x0001;
|
||||||
uint16_t key = 0;
|
uint16_t key = 0;
|
||||||
@ -1237,7 +1282,8 @@ static secbool storage_upgrade(void)
|
|||||||
|
|
||||||
// Set the new storage version number.
|
// Set the new storage version number.
|
||||||
uint32_t version = NORCOW_VERSION;
|
uint32_t version = NORCOW_VERSION;
|
||||||
if (sectrue != storage_set_encrypted(VERSION_KEY, &version, sizeof(version))) {
|
if (sectrue !=
|
||||||
|
storage_set_encrypted(VERSION_KEY, &version, sizeof(version))) {
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1246,7 +1292,7 @@ static secbool storage_upgrade(void)
|
|||||||
ui_rem = ui_total;
|
ui_rem = ui_total;
|
||||||
ui_message = PROCESSING_MSG;
|
ui_message = PROCESSING_MSG;
|
||||||
if (sectrue == norcow_get(V0_PIN_KEY, &val, &len)) {
|
if (sectrue == norcow_get(V0_PIN_KEY, &val, &len)) {
|
||||||
set_pin(*(const uint32_t*)val);
|
set_pin(*(const uint32_t *)val);
|
||||||
} else {
|
} else {
|
||||||
set_pin(PIN_EMPTY);
|
set_pin(PIN_EMPTY);
|
||||||
}
|
}
|
||||||
|
@ -20,13 +20,15 @@
|
|||||||
#ifndef __STORAGE_H__
|
#ifndef __STORAGE_H__
|
||||||
#define __STORAGE_H__
|
#define __STORAGE_H__
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
#include "secbool.h"
|
#include "secbool.h"
|
||||||
|
|
||||||
typedef secbool (*PIN_UI_WAIT_CALLBACK)(uint32_t wait, uint32_t progress, const char* message);
|
typedef secbool (*PIN_UI_WAIT_CALLBACK)(uint32_t wait, uint32_t progress,
|
||||||
|
const char *message);
|
||||||
|
|
||||||
void storage_init(PIN_UI_WAIT_CALLBACK callback, const uint8_t *salt, const uint16_t salt_len);
|
void storage_init(PIN_UI_WAIT_CALLBACK callback, const uint8_t *salt,
|
||||||
|
const uint16_t salt_len);
|
||||||
void storage_wipe(void);
|
void storage_wipe(void);
|
||||||
secbool storage_is_unlocked(void);
|
secbool storage_is_unlocked(void);
|
||||||
void storage_lock(void);
|
void storage_lock(void);
|
||||||
@ -35,7 +37,8 @@ secbool storage_has_pin(void);
|
|||||||
secbool storage_pin_fails_increase(void);
|
secbool storage_pin_fails_increase(void);
|
||||||
uint32_t storage_get_pin_rem(void);
|
uint32_t storage_get_pin_rem(void);
|
||||||
secbool storage_change_pin(const uint32_t oldpin, const uint32_t newpin);
|
secbool storage_change_pin(const uint32_t oldpin, const uint32_t newpin);
|
||||||
secbool storage_get(const uint16_t key, void *val, const uint16_t max_len, uint16_t *len);
|
secbool storage_get(const uint16_t key, void *val, const uint16_t max_len,
|
||||||
|
uint16_t *len);
|
||||||
secbool storage_set(const uint16_t key, const void *val, uint16_t len);
|
secbool storage_set(const uint16_t key, const void *val, uint16_t len);
|
||||||
secbool storage_delete(const uint16_t key);
|
secbool storage_delete(const uint16_t key);
|
||||||
secbool storage_set_counter(const uint16_t key, const uint32_t count);
|
secbool storage_set_counter(const uint16_t key, const uint32_t count);
|
||||||
|
15
tools/style.c.exclude
Normal file
15
tools/style.c.exclude
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
^\./core/embed/bootloader/protob/
|
||||||
|
^\./crypto/aes/
|
||||||
|
^\./crypto/chacha20poly1305/
|
||||||
|
^\./crypto/ed25519-donna/
|
||||||
|
^\./crypto/gui/
|
||||||
|
^\./crypto/monero/base58
|
||||||
|
^\./crypto/monero/int-util
|
||||||
|
^\./crypto/blake2
|
||||||
|
^\./crypto/check_mem
|
||||||
|
^\./crypto/groestl
|
||||||
|
^\./crypto/ripemd160
|
||||||
|
^\./crypto/segwit_addr
|
||||||
|
^\./crypto/sha2
|
||||||
|
^\./crypto/sha3
|
||||||
|
^\./legacy/vendor
|
5
tools/style.c.include
Normal file
5
tools/style.c.include
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
^\./common/
|
||||||
|
^\./core/embed/
|
||||||
|
^\./crypto/
|
||||||
|
^\./legacy/
|
||||||
|
^\./storage/
|
2
tools/style.py.exclude
Normal file
2
tools/style.py.exclude
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
^\./legacy/firmware/protob/messages_pb2\.py
|
||||||
|
^\./legacy/vendor
|
4
tools/style.py.include
Normal file
4
tools/style.py.include
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
^\./common/
|
||||||
|
^\./core/src/
|
||||||
|
^\./crypto/
|
||||||
|
^\./legacy/
|
Loading…
Reference in New Issue
Block a user