Skip to content

Commit 84d28f2

Browse files
author
Akshitij Malik
committed
Add AES Key Derivation Support (ECB,CBC Encrypt)
Additional Information: 1. Added AES Key Derivation mechanisms described in PKCS11 v2.4.0 Section 2.15: - CKM_AES_ECB_ENCRYPT_DATA - CKM_AES_CBC_ENCRYPT_DATA 2. Incorporated code-review comments: - directly sliced the IV data to extract mechanism_params for CBC_ENCRYPT, - added Unit Tests for ECB_ENCRYPT - test_derive_ecb_encrypt - added Unit Tests for CBC_ENCRYPT - test_derive_cbc_encrypt - updated dev-requirements - split the Unit Tests into 2 phases: - key-derivation tests - data encrypyion/decryption tests Sanity Testing: 1. Build Validation: python setup.py build_ext --inplace 2. AES Testing: export PKCS11_MODULE=XXX export PKCS11_TOKEN_LABEL=XXX export PKCS11_TOKEN_PIN=XXX export PKCS11_TOKEN_SO_PIN=XXX pytest ./tests/test_aes.py Signed-off-by: Akshitij Malik
1 parent a88e84e commit 84d28f2

File tree

3 files changed

+110
-18
lines changed

3 files changed

+110
-18
lines changed

dev-requirements.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ setuptools_scm
44
# Used for tests
55
oscrypto
66
cryptography
7+
parameterized
78

89
sphinx
910
sphinx-rtd-theme

dev-requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ markupsafe==1.1.1 # via jinja2
2222
mccabe==0.6.1 # via flake8
2323
oscrypto==1.2.0 # via -r dev-requirements.in
2424
packaging==20.1 # via sphinx
25+
parameterized==0.7.4 # via -r dev-requirements.in
2526
pycodestyle==2.5.0 # via flake8
2627
pycparser==2.19 # via cffi
2728
pyflakes==2.1.1 # via flake8

tests/test_aes.py

Lines changed: 108 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -135,9 +135,8 @@ def test_wrap(self):
135135
])
136136
@requires(Mechanism.AES_ECB_ENCRYPT_DATA)
137137
@FIXME.opencryptoki # can't set key attributes
138-
def test_derive_ecb_encrypt(self, test_type, test_key_length, iv_length):
139-
"""
140-
Function to test AES Key Derivation using the ECB_ENCRYPT Mechanism.
138+
def test_derive_using_ecb_encrypt(self, test_type, test_key_length, iv_length):
139+
"""Function to test AES Key Derivation using the ECB_ENCRYPT Mechanism.
141140
142141
Refer to Section 2.15 of http://docs.oasis-open.org/pkcs11/pkcs11-curr/v2.40/errata01/os/pkcs11-curr-v2.40-errata01-os-complete.html#_Toc441850521
143142
"""
@@ -175,14 +174,59 @@ def test_derive_ecb_encrypt(self, test_type, test_key_length, iv_length):
175174
else:
176175
self.assertTrue(derived_key is not None, f"Failed to derive {test_key_length}-bit Derived Key")
177176

178-
# Test capability of Key to Encrypt/Decrypt data
179-
data = b'HELLO WORLD' * 1024
177+
@parameterized.expand([
178+
("POSITIVE_128_BIT", 128, 16),
179+
("POSITIVE_256_BIT_LONG_IV", 256, 32),
180+
])
181+
@requires(Mechanism.AES_ECB_ENCRYPT_DATA)
182+
@FIXME.opencryptoki # can't set key attributes
183+
def test_encrypt_with_key_derived_using_ecb_encrypt(self, test_type, test_key_length, iv_length):
184+
"""Function to test Data Encryption/Decryption using a Derived AES Key.
185+
186+
Function to test Data Encryption/Decryption using an AES Key
187+
Derived by the ECB_ENCRYPT Mechanism.
188+
189+
Refer to Section 2.15 of http://docs.oasis-open.org/pkcs11/pkcs11-curr/v2.40/errata01/os/pkcs11-curr-v2.40-errata01-os-complete.html#_Toc441850521
190+
"""
180191

181-
iv = self.session.generate_random(128)
182-
crypttext = self.key.encrypt(data, mechanism_param=iv)
183-
text = self.key.decrypt(crypttext, mechanism_param=iv)
192+
# Create the Master Key
193+
capabilities = pkcs11.defaults.DEFAULT_KEY_CAPABILITIES[pkcs11.KeyType.AES]
194+
capabilities |= pkcs11.MechanismFlag.DERIVE
195+
key = self.session.generate_key(pkcs11.KeyType.AES, key_length=test_key_length,
196+
capabilities=capabilities,
197+
template={
198+
pkcs11.Attribute.EXTRACTABLE: True,
199+
pkcs11.Attribute.DERIVE: True,
200+
pkcs11.Attribute.SENSITIVE: False,
201+
})
184202

185-
self.assertEqual(text, data)
203+
self.assertTrue(key is not None, f"Failed to create {test_key_length}-bit Master Key")
204+
205+
# Derive a Key from the Master Key
206+
iv = b'0' * iv_length
207+
try:
208+
derived_key = key.derive_key(pkcs11.KeyType.AES, key_length=test_key_length,
209+
capabilities=capabilities,
210+
mechanism=Mechanism.AES_ECB_ENCRYPT_DATA,
211+
mechanism_param=iv,
212+
template={
213+
pkcs11.Attribute.EXTRACTABLE: True,
214+
pkcs11.Attribute.SENSITIVE: False,
215+
})
216+
except (pkcs11.exceptions.MechanismParamInvalid,
217+
pkcs11.exceptions.FunctionFailed) as e:
218+
derived_key = None
219+
220+
self.assertTrue(derived_key is not None, f"Failed to derive {test_key_length}-bit Derived Key")
221+
222+
# Test capability of Key to Encrypt/Decrypt data
223+
data = b'HELLO WORLD' * 1024
224+
225+
iv = self.session.generate_random(128)
226+
crypttext = self.key.encrypt(data, mechanism_param=iv)
227+
text = self.key.decrypt(crypttext, mechanism_param=iv)
228+
229+
self.assertEqual(text, data)
186230

187231
@parameterized.expand([
188232
("POSITIVE_128_BIT", 128, 16, 16),
@@ -197,9 +241,8 @@ def test_derive_ecb_encrypt(self, test_type, test_key_length, iv_length):
197241
])
198242
@requires(Mechanism.AES_CBC_ENCRYPT_DATA)
199243
@FIXME.opencryptoki # can't set key attributes
200-
def test_derive_cbc_encrypt(self, test_type, test_key_length, iv_length, data_length):
201-
"""
202-
Function to test AES Key Derivation using the CBC_ENCRYPT Mechanism.
244+
def test_derive_using_cbc_encrypt(self, test_type, test_key_length, iv_length, data_length):
245+
"""Function to test AES Key Derivation using the CBC_ENCRYPT Mechanism.
203246
204247
Refer to Section 2.15 of http://docs.oasis-open.org/pkcs11/pkcs11-curr/v2.40/errata01/os/pkcs11-curr-v2.40-errata01-os-complete.html#_Toc441850521
205248
"""
@@ -239,12 +282,59 @@ def test_derive_cbc_encrypt(self, test_type, test_key_length, iv_length, data_le
239282
else:
240283
self.assertTrue(derived_key is not None, f"Failed to derive {test_key_length}-bit Derived Key")
241284

242-
# Test capability of Key to Encrypt/Decrypt data
243-
data = b'HELLO WORLD' * 1024
285+
@parameterized.expand([
286+
("POSITIVE_128_BIT", 128, 16, 16),
287+
("POSITIVE_256_BIT", 256, 16, 32),
288+
("POSITIVE_256_BIT_LONG_DATA", 256, 16, 64),
289+
])
290+
@requires(Mechanism.AES_CBC_ENCRYPT_DATA)
291+
@FIXME.opencryptoki # can't set key attributes
292+
def test_encrypt_with_key_derived_using_cbc_encrypt(self, test_type, test_key_length, iv_length, data_length):
293+
"""Function to test Data Encryption/Decryption using a Derived AES Key.
294+
295+
Function to test Data Encryption/Decryption using an AES Key
296+
Derived by the CBC_ENCRYPT Mechanism.
297+
298+
Refer to Section 2.15 of http://docs.oasis-open.org/pkcs11/pkcs11-curr/v2.40/errata01/os/pkcs11-curr-v2.40-errata01-os-complete.html#_Toc441850521
299+
"""
244300

245-
iv = self.session.generate_random(128)
246-
crypttext = self.key.encrypt(data, mechanism_param=iv)
247-
text = self.key.decrypt(crypttext, mechanism_param=iv)
301+
# Create the Master Key
302+
capabilities = pkcs11.defaults.DEFAULT_KEY_CAPABILITIES[pkcs11.KeyType.AES]
303+
capabilities |= pkcs11.MechanismFlag.DERIVE
304+
key = self.session.generate_key(pkcs11.KeyType.AES, key_length=test_key_length,
305+
capabilities=capabilities,
306+
template={
307+
pkcs11.Attribute.EXTRACTABLE: True,
308+
pkcs11.Attribute.DERIVE: True,
309+
pkcs11.Attribute.SENSITIVE: False,
310+
})
248311

249-
self.assertEqual(text, data)
312+
self.assertTrue(key is not None, f"Failed to create {test_key_length}-bit Master Key")
250313

314+
# Derive a Key from the Master Key
315+
iv = b'0' * iv_length
316+
data = b'1' * data_length
317+
try:
318+
derived_key = key.derive_key(pkcs11.KeyType.AES, key_length=test_key_length,
319+
capabilities=capabilities,
320+
mechanism=Mechanism.AES_CBC_ENCRYPT_DATA,
321+
mechanism_param=(iv, data),
322+
template={
323+
pkcs11.Attribute.EXTRACTABLE: True,
324+
pkcs11.Attribute.SENSITIVE: False,
325+
})
326+
except (pkcs11.exceptions.MechanismParamInvalid,
327+
pkcs11.exceptions.FunctionFailed,
328+
IndexError) as e:
329+
derived_key = None
330+
331+
self.assertTrue(derived_key is not None, f"Failed to derive {test_key_length}-bit Derived Key")
332+
333+
# Test capability of Key to Encrypt/Decrypt data
334+
data = b'HELLO WORLD' * 1024
335+
336+
iv = self.session.generate_random(128)
337+
crypttext = self.key.encrypt(data, mechanism_param=iv)
338+
text = self.key.decrypt(crypttext, mechanism_param=iv)
339+
340+
self.assertEqual(text, data)

0 commit comments

Comments
 (0)