mirror of
https://github.com/polhenarejos/pico-hsm.git
synced 2026-01-17 01:18:06 +00:00
Add key derivation tests (HKDF, PBKDF2 and X963).
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
This commit is contained in:
parent
20c01eb08d
commit
61359c7ebd
5 changed files with 295 additions and 0 deletions
|
|
@ -443,6 +443,8 @@ class Device:
|
|||
algo = b'\x2A\x86\x48\x86\xF7\x0D\x02\x0A'
|
||||
elif (hash == hashes.SHA512):
|
||||
algo = b'\x2A\x86\x48\x86\xF7\x0D\x02\x0B'
|
||||
else:
|
||||
raise ValueError("Hash not supported")
|
||||
data = [0x06, len(algo)] + list(algo) + [0x81, len(data)] + list(data)
|
||||
resp = self.send(cla=0x80, command=0x78, p1=keyid, p2=0x51, data=data)
|
||||
return resp
|
||||
|
|
@ -451,6 +453,55 @@ class Device:
|
|||
resp = self.send(cla=0x80, command=0x78, p1=keyid, p2=Algorithm.ALGO_AES_CMAC.value, data=data)
|
||||
return resp
|
||||
|
||||
def hkdf(self, hash, keyid, data, salt, out_len=None):
|
||||
if (hash == hashes.SHA256):
|
||||
algo = b'\x2A\x86\x48\x86\xF7\x0D\x01\x09\x10\x03\x1D'
|
||||
elif (hash == hashes.SHA384):
|
||||
algo = b'\x2A\x86\x48\x86\xF7\x0D\x01\x09\x10\x03\x1E'
|
||||
elif (hash == hashes.SHA512):
|
||||
algo = b'\x2A\x86\x48\x86\xF7\x0D\x01\x09\x10\x03\x1F'
|
||||
data = [0x06, len(algo)] + list(algo) + [0x81, len(data)] + list(data) + [0x82, len(salt)] + list(salt)
|
||||
resp = self.send(cla=0x80, command=0x78, p1=keyid, p2=0x51, data=data, ne=out_len)
|
||||
return resp
|
||||
|
||||
def pbkdf2(self, hash, keyid, salt, iterations, out_len=None):
|
||||
oid = b'\x2A\x86\x48\x86\xF7\x0D\x01\x05\x0C'
|
||||
salt = b'\x04' + bytes([len(salt)]) + salt
|
||||
iteration = b'\x02' + bytes([len(int_to_bytes(iterations))]) + int_to_bytes(iterations)
|
||||
prf = b'\x30\x0A\x06\x08\x2A\x86\x48\x86\xF7\x0D\x02'
|
||||
if (hash == hashes.SHA1):
|
||||
prf += b'\x07'
|
||||
elif (hash == hashes.SHA224):
|
||||
prf += b'\x08'
|
||||
elif (hash == hashes.SHA256):
|
||||
prf += b'\x09'
|
||||
elif (hash == hashes.SHA384):
|
||||
prf += b'\x0A'
|
||||
elif (hash == hashes.SHA512):
|
||||
prf += b'\x0B'
|
||||
data = list(salt + iteration + prf)
|
||||
data = [0x06, len(oid)] + list(oid) + [0x81, len(data)] + list(data)
|
||||
resp = self.send(cla=0x80, command=0x78, p1=keyid, p2=0x51, data=data, ne=out_len)
|
||||
return resp
|
||||
|
||||
def x963(self, hash, keyid, data, out_len=None):
|
||||
oid = b'\x2B\x81\x05\x10\x86\x48\x3F'
|
||||
enc = b'\x2A\x86\x48\x86\xF7\x0D\x02'
|
||||
if (hash == hashes.SHA1):
|
||||
enc += b'\x07'
|
||||
elif (hash == hashes.SHA224):
|
||||
enc += b'\x08'
|
||||
elif (hash == hashes.SHA256):
|
||||
enc += b'\x09'
|
||||
elif (hash == hashes.SHA384):
|
||||
enc += b'\x0A'
|
||||
elif (hash == hashes.SHA512):
|
||||
enc += b'\x0B'
|
||||
else:
|
||||
raise ValueError("Hash not supported")
|
||||
data = [0x06, len(oid)] + list(oid) + [0x81, len(enc)] + list(enc) + [0x83, len(data)] + list(data)
|
||||
resp = self.send(cla=0x80, command=0x78, p1=keyid, p2=0x51, data=data, ne=out_len)
|
||||
return resp
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def device():
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ def test_mac_hmac(device, size, algo):
|
|||
h = hmac.HMAC(pkey, algo())
|
||||
h.update(MESSAGE)
|
||||
resB = h.finalize()
|
||||
device.delete_file(DOPrefixes.KEY_PREFIX.value << 8 | keyid)
|
||||
assert(bytes(resA) == resB)
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
|
|
@ -56,5 +57,6 @@ def test_mac_cmac(device, size):
|
|||
c = cmac.CMAC(algorithms.AES(pkey))
|
||||
c.update(MESSAGE)
|
||||
resB = c.finalize()
|
||||
device.delete_file(DOPrefixes.KEY_PREFIX.value << 8 | keyid)
|
||||
assert(bytes(resA) == resB)
|
||||
|
||||
|
|
|
|||
81
tests/pico-hsm/test_070_hkdf.py
Normal file
81
tests/pico-hsm/test_070_hkdf.py
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
"""
|
||||
/*
|
||||
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
"""
|
||||
|
||||
import pytest
|
||||
import os
|
||||
from cryptography.hazmat.primitives import hashes
|
||||
from cryptography.hazmat.primitives.kdf.hkdf import HKDF
|
||||
from cryptography import exceptions
|
||||
from const import DEFAULT_DKEK_SHARES, DEFAULT_DKEK
|
||||
from utils import DOPrefixes
|
||||
|
||||
INFO = b'info message'
|
||||
|
||||
def test_prepare_kd(device):
|
||||
device.initialize(dkek_shares=DEFAULT_DKEK_SHARES)
|
||||
resp = device.import_dkek(DEFAULT_DKEK)
|
||||
resp = device.import_dkek(DEFAULT_DKEK)
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"size", [128, 192, 256]
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
"algo", [hashes.SHA256, hashes.SHA384, hashes.SHA512]
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
"out_len", [32, 64, 256, 1024]
|
||||
)
|
||||
class TestHKDF:
|
||||
def test_hkdf_ok(self, device, size, algo, out_len):
|
||||
pkey = os.urandom(size // 8)
|
||||
keyid = device.import_key(pkey)
|
||||
salt = os.urandom(16)
|
||||
resA = device.hkdf(algo, keyid, INFO, salt, out_len=out_len)
|
||||
device.delete_file(DOPrefixes.KEY_PREFIX.value << 8 | keyid)
|
||||
hkdf = HKDF(
|
||||
algorithm=algo(),
|
||||
length=out_len,
|
||||
salt=salt,
|
||||
info=INFO,
|
||||
)
|
||||
resB = hkdf.derive(pkey)
|
||||
assert(bytes(resA) == resB)
|
||||
hkdf = HKDF(
|
||||
algorithm=algo(),
|
||||
length=out_len,
|
||||
salt=salt,
|
||||
info=INFO,
|
||||
)
|
||||
hkdf.verify(pkey, bytes(resA))
|
||||
|
||||
def test_hkdf_fail(self, device, size, algo, out_len):
|
||||
pkey = os.urandom(size // 8)
|
||||
keyid = device.import_key(pkey)
|
||||
salt = os.urandom(16)
|
||||
resA = device.hkdf(algo, keyid, INFO, salt, out_len=out_len)
|
||||
device.delete_file(DOPrefixes.KEY_PREFIX.value << 8 | keyid)
|
||||
hkdf = HKDF(
|
||||
algorithm=algo(),
|
||||
length=out_len,
|
||||
salt=salt,
|
||||
info=INFO,
|
||||
)
|
||||
pkey = os.urandom(size // 8)
|
||||
with pytest.raises(exceptions.InvalidKey):
|
||||
hkdf.verify(pkey, bytes(resA))
|
||||
85
tests/pico-hsm/test_071_pbkdf2.py
Normal file
85
tests/pico-hsm/test_071_pbkdf2.py
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
"""
|
||||
/*
|
||||
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
"""
|
||||
|
||||
import pytest
|
||||
import os
|
||||
from cryptography.hazmat.primitives import hashes
|
||||
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
|
||||
from cryptography import exceptions
|
||||
from const import DEFAULT_DKEK_SHARES, DEFAULT_DKEK
|
||||
from utils import DOPrefixes
|
||||
|
||||
INFO = b'info message'
|
||||
|
||||
def test_prepare_kd(device):
|
||||
device.initialize(dkek_shares=DEFAULT_DKEK_SHARES)
|
||||
resp = device.import_dkek(DEFAULT_DKEK)
|
||||
resp = device.import_dkek(DEFAULT_DKEK)
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"size", [128, 192, 256]
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
"algo", [hashes.SHA1, hashes.SHA224, hashes.SHA256, hashes.SHA384, hashes.SHA512]
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
"out_len", [32, 64, 256, 1024]
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
"iterations", [1024, 2048]
|
||||
)
|
||||
class TestPBKDF2:
|
||||
def test_pbkdf2_ok(self, device, size, algo, out_len, iterations):
|
||||
pkey = os.urandom(size // 8)
|
||||
keyid = device.import_key(pkey)
|
||||
salt = os.urandom(16)
|
||||
resA = device.pbkdf2(algo, keyid, salt, iterations=iterations, out_len=out_len)
|
||||
device.delete_file(DOPrefixes.KEY_PREFIX.value << 8 | keyid)
|
||||
kdf = PBKDF2HMAC(
|
||||
algorithm=algo(),
|
||||
length=out_len,
|
||||
salt=salt,
|
||||
iterations=iterations,
|
||||
)
|
||||
resB = kdf.derive(pkey)
|
||||
assert(bytes(resA) == resB)
|
||||
kdf = PBKDF2HMAC(
|
||||
algorithm=algo(),
|
||||
length=out_len,
|
||||
salt=salt,
|
||||
iterations=iterations,
|
||||
)
|
||||
kdf.verify(pkey, bytes(resA))
|
||||
|
||||
def test_pbkdf2_fail(self, device, size, algo, out_len, iterations):
|
||||
pkey = os.urandom(size // 8)
|
||||
keyid = device.import_key(pkey)
|
||||
salt = os.urandom(16)
|
||||
resA = device.pbkdf2(algo, keyid, salt, iterations=iterations, out_len=out_len)
|
||||
device.delete_file(DOPrefixes.KEY_PREFIX.value << 8 | keyid)
|
||||
|
||||
kdf = PBKDF2HMAC(
|
||||
algorithm=algo(),
|
||||
length=out_len,
|
||||
salt=salt,
|
||||
iterations=iterations,
|
||||
)
|
||||
pkey = os.urandom(size // 8)
|
||||
with pytest.raises(exceptions.InvalidKey):
|
||||
kdf.verify(pkey, bytes(resA))
|
||||
76
tests/pico-hsm/test_072_x963.py
Normal file
76
tests/pico-hsm/test_072_x963.py
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
"""
|
||||
/*
|
||||
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
"""
|
||||
|
||||
import pytest
|
||||
import os
|
||||
from cryptography.hazmat.primitives import hashes
|
||||
from cryptography.hazmat.primitives.kdf.x963kdf import X963KDF
|
||||
from cryptography import exceptions
|
||||
from const import DEFAULT_DKEK_SHARES, DEFAULT_DKEK
|
||||
from utils import DOPrefixes
|
||||
|
||||
INFO = b'shared message'
|
||||
|
||||
def test_prepare_kd(device):
|
||||
device.initialize(dkek_shares=DEFAULT_DKEK_SHARES)
|
||||
resp = device.import_dkek(DEFAULT_DKEK)
|
||||
resp = device.import_dkek(DEFAULT_DKEK)
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"size", [128, 192, 256]
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
"algo", [hashes.SHA1, hashes.SHA224, hashes.SHA256, hashes.SHA384, hashes.SHA512]
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
"out_len", [32, 64, 256, 1024]
|
||||
)
|
||||
class TestX963:
|
||||
def test_x963_ok(self, device, size, algo, out_len):
|
||||
pkey = os.urandom(size // 8)
|
||||
keyid = device.import_key(pkey)
|
||||
resA = device.x963(algo, keyid, INFO, out_len=out_len)
|
||||
device.delete_file(DOPrefixes.KEY_PREFIX.value << 8 | keyid)
|
||||
xkdf = X963KDF(
|
||||
algorithm=algo(),
|
||||
length=out_len,
|
||||
sharedinfo=INFO,
|
||||
)
|
||||
resB = xkdf.derive(pkey)
|
||||
assert(bytes(resA) == resB)
|
||||
xkdf = X963KDF(
|
||||
algorithm=algo(),
|
||||
length=out_len,
|
||||
sharedinfo=INFO,
|
||||
)
|
||||
xkdf.verify(pkey, bytes(resA))
|
||||
|
||||
def test_x963_fail(self, device, size, algo, out_len):
|
||||
pkey = os.urandom(size // 8)
|
||||
keyid = device.import_key(pkey)
|
||||
resA = device.x963(algo, keyid, INFO, out_len=out_len)
|
||||
device.delete_file(DOPrefixes.KEY_PREFIX.value << 8 | keyid)
|
||||
xkdf = X963KDF(
|
||||
algorithm=algo(),
|
||||
length=out_len,
|
||||
sharedinfo=INFO,
|
||||
)
|
||||
pkey = os.urandom(size // 8)
|
||||
with pytest.raises(exceptions.InvalidKey):
|
||||
xkdf.verify(pkey, bytes(resA))
|
||||
Loading…
Add table
Reference in a new issue