mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-24 15:28:10 +00:00
core/crypto: Add functions for verifying DER encoded signatures.
This commit is contained in:
parent
9459c5a5c2
commit
3b6c1e5e6b
@ -5,7 +5,8 @@ from trezor.crypto import bech32, bip32, der
|
||||
from trezor.crypto.curve import secp256k1
|
||||
from trezor.utils import ensure
|
||||
|
||||
from apps.common.coininfo import CoinInfo
|
||||
if False:
|
||||
from apps.common.coininfo import CoinInfo
|
||||
|
||||
# supported witness version for bech32 addresses
|
||||
_BECH32_WITVER = const(0x00)
|
||||
|
@ -1,3 +1,9 @@
|
||||
from apps.common.readers import BytearrayReader
|
||||
|
||||
if False:
|
||||
from typing import List
|
||||
|
||||
|
||||
def encode_length(l: int) -> bytes:
|
||||
if l < 0x80:
|
||||
return bytes([l])
|
||||
@ -9,15 +15,80 @@ def encode_length(l: int) -> bytes:
|
||||
raise ValueError
|
||||
|
||||
|
||||
def decode_length(r: BytearrayReader) -> int:
|
||||
init = r.get()
|
||||
if init < 0x80:
|
||||
# short form encodes length in initial octet
|
||||
return init
|
||||
|
||||
if init == 0x80 or init == 0xFF or r.peek() == 0x00:
|
||||
raise ValueError # indefinite length, RFU or not shortest possible
|
||||
|
||||
# long form
|
||||
n = 0
|
||||
for _ in range(init & 0x7F):
|
||||
n = n * 0x100 + r.get()
|
||||
|
||||
if n < 128:
|
||||
raise ValueError # encoding is not the shortest possible
|
||||
|
||||
return n
|
||||
|
||||
|
||||
def encode_int(i: bytes) -> bytes:
|
||||
i = i.lstrip(b"\x00")
|
||||
if not i:
|
||||
i = b"\00"
|
||||
|
||||
if i[0] >= 0x80:
|
||||
i = b"\x00" + i
|
||||
return b"\x02" + encode_length(len(i)) + i
|
||||
|
||||
|
||||
def decode_int(r: BytearrayReader) -> bytes:
|
||||
if r.get() != 0x02:
|
||||
raise ValueError
|
||||
|
||||
n = decode_length(r)
|
||||
if n == 0:
|
||||
raise ValueError
|
||||
|
||||
if r.peek() & 0x80:
|
||||
raise ValueError # negative integer
|
||||
|
||||
if r.peek() == 0x00 and n > 1:
|
||||
r.get()
|
||||
n -= 1
|
||||
if r.peek() & 0x80 == 0x00:
|
||||
raise ValueError # excessive zero-padding
|
||||
|
||||
if r.peek() == 0x00:
|
||||
raise ValueError # excessive zero-padding
|
||||
|
||||
return r.read(n)
|
||||
|
||||
|
||||
def encode_seq(seq: tuple) -> bytes:
|
||||
res = b""
|
||||
for i in seq:
|
||||
res += encode_int(i)
|
||||
return b"\x30" + encode_length(len(res)) + res
|
||||
|
||||
|
||||
def decode_seq(data: bytes) -> List[bytes]:
|
||||
r = BytearrayReader(data)
|
||||
|
||||
if r.get() != 0x30:
|
||||
raise ValueError
|
||||
n = decode_length(r)
|
||||
|
||||
seq = []
|
||||
end = r.offset + n
|
||||
while r.offset < end:
|
||||
i = decode_int(r)
|
||||
seq.append(i)
|
||||
|
||||
if r.offset != end or r.remaining_count():
|
||||
raise ValueError
|
||||
|
||||
return seq
|
||||
|
@ -46,11 +46,26 @@ class TestCryptoDer(unittest.TestCase):
|
||||
def test_der_encode_seq(self):
|
||||
|
||||
for s, d in self.vectors_seq:
|
||||
s = (unhexlify(i) for i in s)
|
||||
s = tuple(unhexlify(i) for i in s)
|
||||
d = unhexlify(d)
|
||||
d2 = der.encode_seq(s)
|
||||
self.assertEqual(d, d2)
|
||||
self.assertEqual(d2, d)
|
||||
s = [i.lstrip(b"\x00") for i in s]
|
||||
s2 = der.decode_seq(d)
|
||||
self.assertEqual(s2, s)
|
||||
|
||||
def test_der_encode_decode_long_seq(self):
|
||||
for length in (1, 127, 128, 129, 255, 256, 257):
|
||||
raw_int = bytes((i & 0xfe) + 1 for i in range(length))
|
||||
for leading_zeros in range(3):
|
||||
encoded = der.encode_seq((b"\x00" * leading_zeros + raw_int,))
|
||||
decoded = der.decode_seq(encoded)
|
||||
self.assertEqual(decoded, [raw_int])
|
||||
|
||||
for zeroes in range(3):
|
||||
encoded = der.encode_seq((b"\x00" * zeroes,))
|
||||
decoded = der.decode_seq(encoded)
|
||||
self.assertEqual(decoded, [b"\x00"])
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
Loading…
Reference in New Issue
Block a user