#! python3
# -*- coding: utf-8 -*-
"""Some tests for ``cryptosyspki`` the Python interface to CryptoSys PKI"""
# test_pki.py: version 22.1.0
# $Date: 2024-01-01 07:47:00 $
# ************************** LICENSE *****************************************
# Copyright (C) 2016-24 David Ireland, DI Management Services Pty Limited.
# All rights reserved. <www.di-mgt.com.au> <www.cryptosys.net>
# The code in this module is licensed under the terms of the MIT license.
# @license MIT
# For a copy, see <http://opensource.org/licenses/MIT>
# ****************************************************************************
from cryptosyspki import * # @UnusedWildImport
import cryptosyspki as pki # for pki.__version__
import os
import sys
import pytest
import shutil
from glob import iglob
_MIN_PKI_VERSION = 220100
# Show some info about the core CryptoSys PKI DLL
print("PKI version =", Gen.version())
print("module_name =", Gen.module_name())
print("compile_time =", Gen.compile_time())
print("platform =", Gen.core_platform())
print("licence_type =", Gen.licence_type())
print("module_info =", Gen.module_info())
# Show some system values
print("sys.getdefaultencoding()=", sys.getdefaultencoding())
print("sys.getfilesystemencoding()=", sys.getfilesystemencoding())
print("sys.platform()=", sys.platform)
print("cwd =", os.getcwd())
if Gen.version() < _MIN_PKI_VERSION:
raise Exception('Require PKI version ' +
str(_MIN_PKI_VERSION) + ' or greater')
# GLOBAL VARS
# Remember CWD where we started
start_dir = os.getcwd()
# Temp directory to use as CWD for tests - set by `setup_temp_dir()`
ourtmp_dir = ""
# Flag to delete tmp directory when finished - used in `reset_start_dir()`
# Change with command-line argument `nodelete` - see `main()`
delete_tmp_dir = True
# JIGGERY-POKERY FOR A TEMP WORKING DIRECTORY
# start_dir/
# test_py # this module
# work/ # this _must_ exist
# <all required test files>
# pki_tmp.XXXXXXXX/ # created by `setup_temp_dir()`
# <copy of all required test files>
# <files created by tests>
def setup_temp_dir():
"""Set up a fresh temp directory to work in"""
global ourtmp_dir
# `work` should be a sub-directory of the cwd and must exist
work_dir = os.path.join(start_dir, "work")
print("\nExpecting to find work dir:", work_dir)
assert os.path.isdir(work_dir)
# It should contain all the required test files
# Create a temp sub-directory in `work`
ourtmp_dir = os.path.join(work_dir, "pki_tmp." + Cnv.tohex(Rng.bytestring(4)))
os.mkdir(ourtmp_dir)
assert (os.path.isdir(ourtmp_dir))
# copy the required temp files
for f in iglob(os.path.join(work_dir, "*.*")):
if (os.path.isfile(f) and not f.endswith('.zip')):
shutil.copy(f, ourtmp_dir)
# Set CWD to be inside temp
os.chdir(ourtmp_dir)
print("Working in new temp directory:", os.getcwd())
def reset_start_dir():
if not os.path.isdir(start_dir):
return
if (ourtmp_dir == start_dir):
return
os.chdir(start_dir)
print("")
# print("CWD:", os.getcwd())
# Remove the temp direcory
if (delete_tmp_dir and 'pki_tmp' in ourtmp_dir):
print("Removing temp directory:", ourtmp_dir)
# time.sleep(2)
shutil.rmtree(ourtmp_dir, ignore_errors=True)
# MORE JIGGERY_POKERY FOR py.test
@pytest.fixture(scope="module", autouse=True)
def divider_module(request):
print("\n --- module %s() start ---" % request.module.__name__)
setup_temp_dir()
def fin():
print("\n --- module %s() done ---" % request.module.__name__)
reset_start_dir()
request.addfinalizer(fin)
@pytest.fixture(scope="function", autouse=True)
def divider_function(request):
print("\n --- function %s() start ---" % request.function.__name__)
os.chdir(ourtmp_dir)
def fin():
print("\n --- function %s() done ---" % request.function.__name__)
os.chdir(start_dir)
request.addfinalizer(fin)
# FILE-RELATED UTILITIES
def read_binary_file(fname):
with open(fname, "rb") as f:
return bytearray(f.read())
def write_binary_file(fname, data):
with open(fname, "wb") as f:
f.write(data)
def read_text_file(fname, enc='utf8'):
with open(fname, encoding=enc) as f:
return f.read()
def write_text_file(fname, s, enc='utf8'):
with open(fname, "w", encoding=enc) as f:
f.write(s)
def _print_file(fname):
"""Print contents of text file."""
s = read_text_file(fname)
print(s)
def _print_file_hex(fname):
"""Print contents of file encoded in hexadecimal."""
b = read_binary_file(fname)
print(Cnv.tohex(b))
def _dump_file(fname):
"""Print contents of text file with filename header and rulers."""
s = read_text_file(fname)
ndash = (24 if len(s) > 24 else len(s))
print("FILE:", fname)
print("-" * ndash)
print(s)
print("-" * ndash)
def _dump_and_print_asn1(fname, opts=0):
print("FILE:", fname)
try:
s = Asn1.text_dump_tostring(fname, opts)
print(s)
except PKIError as e:
print("Woops! PKIError:", e)
def _dump_and_print_x509(fname, opts=0):
try:
s = X509.text_dump_tostring(fname, opts)
print(s)
except PKIError as e:
print("Woops! PKIError:", e)
def textwrap(text, width=64):
"""Simple textwrap to display string."""
return "\n".join([text[i:i + width] for i in range(0, len(text) - 1, width)])
#############
# THE TESTS #
#############
def test_version():
assert Gen.version() >= _MIN_PKI_VERSION
def test_error_lookup():
print("\nLOOKUP SOME ERROR CODES...")
for n in range(10):
s = Gen.error_lookup(n)
print("error_lookup(" + str(n) + ")=" + s)
assert (len(s) > 0)
def test_cnv():
print("\nTEST CNV FUNCTIONS...")
# hex --> bytes --> base64
b = Cnv.fromhex("FE DC BA 98 76 54 32 10")
print("b=0x" + Cnv.tohex(b))
print("b64(b)=" + Cnv.tobase64(b))
assert (Cnv.tobase64(b) == "/ty6mHZUMhA=")
# base64 --> bytes --> hex --> base64
b = Cnv.frombase64("/ty6mHZUMhA=")
print("b=0x" + Cnv.tohex(b))
assert (Cnv.tohex(b) == "FEDCBA9876543210")
print("b64(b)=" + Cnv.tobase64(b))
assert (Cnv.tobase64(b) == "/ty6mHZUMhA=")
# hex --> bytes --> base58
b = Cnv.fromhex("00010966776006953D5567439E5E39F86A0D273BEED61967F6")
print("b=0x" + Cnv.tohex(b))
print("b58(b)=" + Cnv.tobase58(b))
assert (Cnv.tobase58(b) == "16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM")
# base58 --> bytes --> hex
h = Cnv.tohex(Cnv.frombase58("16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM"))
print(h)
assert (h == "00010966776006953D5567439E5E39F86A0D273BEED61967F6")
# reverse bytes
print("Using Cnv.reverse_bytes()...")
b = Cnv.fromhex("DEADBEEF01")
print("INPUT: ", Cnv.tohex(b))
r = Cnv.reverse_bytes(b)
print("OUTPUT:", Cnv.tohex(r))
assert (Cnv.tohex(r) == "01EFBEADDE")
# Possible corner cases...
print("Test empty string...")
b = Cnv.fromhex("")
print("INPUT: ", Cnv.tohex(b))
r = Cnv.reverse_bytes(b)
print("OUTPUT:", Cnv.tohex(r))
assert (Cnv.tohex(r) == "")
b = Cnv.fromhex("01")
print("INPUT: ", Cnv.tohex(b))
r = Cnv.reverse_bytes(b)
print("OUTPUT:", Cnv.tohex(r))
assert (Cnv.tohex(r) == "01")
b = Cnv.fromhex("0102")
print("INPUT: ", Cnv.tohex(b))
r = Cnv.reverse_bytes(b)
print("OUTPUT:", Cnv.tohex(r))
assert (Cnv.tohex(r) == "0201")
print("Using Cnv.num_from_bytes()...")
b = Cnv.fromhex("DEADBEEF")
print("INPUT:", Cnv.tohex(b))
# Default big-endian order
n = Cnv.num_from_bytes(b)
print("BE:", hex(n))
assert (0xdeadbeef == n)
# Little-endian order
n = Cnv.num_from_bytes(b, endn=Cnv.EndianNess.LITTLE_ENDIAN)
print("LE:", hex(n))
assert (0xEFBEADDE == n)
# Input shorter than 4 bytes is padded on the right with zeros
b = b[:3]
print("INPUT:", Cnv.tohex(b))
n = Cnv.num_from_bytes(b)
print("BE:", hex(n))
assert (0xDEADBE00 == n)
n = Cnv.num_from_bytes(b, endn=Cnv.EndianNess.LITTLE_ENDIAN)
print("LE:", hex(n))
assert (0xBEADDE == n)
print("Using Cnv.num_to_bytes()...")
n = 0xDEADBEEF
b = Cnv.num_to_bytes(n)
print("BE:", Cnv.tohex(b))
b = Cnv.num_to_bytes(n, endn=Cnv.EndianNess.LITTLE_ENDIAN)
print("LE:", Cnv.tohex(b))
n = 0x01
b = Cnv.num_to_bytes(n)
print("BE:", Cnv.tohex(b))
b = Cnv.num_to_bytes(n, endn=Cnv.EndianNess.LITTLE_ENDIAN)
print("LE:", Cnv.tohex(b))
def test_cnv_utf8():
print("\nTEST CNV UTF-8 CHECKS...")
print("Bytes representing simple ASCII characters")
s = b'abc'
print("s=0x" + Cnv.tohex(s))
n = Cnv.utf8_check(s)
print("Cnv.utf8_check(s)=", n, "(expecting 1)")
print(n, '==>', Cnv.utf8_check_to_string(n))
assert (1 == n)
# A string containing a Latin-1 character, LATIN SMALL LETTER E WITH ACUTE
# -- this is invalid UTF-8
print("Bytes representing a string containing a Latin-1 character")
s = b"M\xe9xico"
print("s=0x" + Cnv.tohex(s))
n = Cnv.utf8_check(s)
print("Cnv.utf8_check(s)=", n, "(expecting 0)")
print(n, '==>', Cnv.utf8_check_to_string(n))
assert (0 == n)
# A byte array with a valid UTF-8-encoded array of chinese characters:
# zhong guo (U+4E2D, U+56FD)
b = Cnv.fromhex('e4b8ade59bbd')
print("Chinese characters: zhong guo (U+4E2D, U+56FD) encoded in UTF-8")
print("b=0x" + Cnv.tohex(b))
n = Cnv.utf8_check(b)
print("Cnv.utf8_check(b)=", n, "(expecting 3)")
print(n, '==>', Cnv.utf8_check_to_string(n))
assert (3 == n)
# lookup invalid code
print("Cnv.utf8_check_to_string(42)=>", Cnv.utf8_check_to_string(42))
print("Bad UTF-8 (chopped)")
b = b"\xc3\xb3\xc3\xa9\xc3\xad\xc3\xa1\xc3"
print("b=0x" + Cnv.tohex(b))
n = Cnv.utf8_check(b)
print("Cnv.utf8_check(b)=", n, "(expecting 0)")
print(n, '==>', Cnv.utf8_check_to_string(n))
assert (0 == n)
print("Bad UTF-8 (illegal)")
b = b"\xef\xbf\xbf"
print("b=0x" + Cnv.tohex(b))
n = Cnv.utf8_check(b)
print("Cnv.utf8_check(b)=", n, "(expecting 0)")
print(n, '==>', Cnv.utf8_check_to_string(n))
assert (0 == n)
print("Check some files...")
fname = 'test-iso88591.xml'
n = Cnv.utf8_check_file(fname)
print("Cnv.utf8_check_file('" + fname + "')=", n, "(expecting 0)")
print(n, '==>', Cnv.utf8_check_to_string(n))
assert (0 == n)
fname = 'test-utf8.xml'
n = Cnv.utf8_check_file(fname)
print("Cnv.utf8_check_file('" + fname + "')=", n, "(expecting 2)")
print(n, '==>', Cnv.utf8_check_to_string(n))
assert (2 == n)
fname = 'test-daiwei.xml'
n = Cnv.utf8_check_file(fname)
print("Cnv.utf8_check_file('" + fname + "')=", n, "(expecting 3)")
print(n, '==>', Cnv.utf8_check_to_string(n))
assert (3 == n)
def test_cipher():
print("\nTEST BLOCK CIPHER FUNCTIONS...")
algstr = "Tdea/CBC/PKCS5"
print(algstr)
key = bytearray.fromhex('737C791F25EAD0E04629254352F7DC6291E5CB26917ADA32')
iv = bytearray.fromhex("B36B6BFB6231084E")
pt = bytearray.fromhex("5468697320736F6D652073616D706520636F6E74656E742E")
ct = Cipher.encrypt(pt, key, iv, algstr)
print(Cnv.tohex(ct))
b = bytearray.fromhex("5468697320736F6D652073616D706520636F6E74656E742E")
print(b)
assert (ct == bytearray.fromhex(
"D76FD1178FBD02F84231F5C1D2A2F74A4159482964F675248254223DAF9AF8E4"))
p1 = Cipher.decrypt(ct, key, iv, algstr)
print(p1)
assert (p1 == pt)
print("Use default ECB mode (IV is ignored)")
ct = Cipher.encrypt(pt, key, alg=Cipher.Alg.TDEA)
print(Cnv.tohex(ct))
p1 = Cipher.decrypt(ct, key, alg=Cipher.Alg.TDEA)
print(p1)
assert (p1 == pt)
ct = Cipher.encrypt(pt, key, iv, mode=Cipher.Mode.CBC,
alg=Cipher.Alg.TDEA)
print(Cnv.tohex(ct))
p1 = Cipher.decrypt(ct, key, iv, mode=Cipher.Mode.CBC,
alg=Cipher.Alg.TDEA)
print(p1)
assert (p1 == pt)
algstr = "Aes128/CBC/pkcs5"
print(algstr)
key = bytearray.fromhex('0123456789ABCDEFF0E1D2C3B4A59687')
iv = bytearray.fromhex("FEDCBA9876543210FEDCBA9876543210")
# In Python 3 we must must pass plaintext as bytes; ASCII strings no longer work
pt = b"Now is the time for all good men to"
ct = Cipher.encrypt(pt, key, iv, algstr)
print(Cnv.tohex(ct))
assert (ct == bytearray.fromhex(
"C3153108A8DD340C0BCB1DFE8D25D2320EE0E66BD2BB4A313FB75C5638E9E17753C7E8DF5975A36677355F5C6584228B"))
# Now decrypt using flags instead of alg string
p1 = Cipher.decrypt(ct, key, iv, alg=Cipher.Alg.AES128,
mode=Cipher.Mode.CBC, pad=Cipher.Pad.PKCS5)
print("P':", p1)
assert (p1 == pt)
algstr = "Aes128/ECB/OneAndZeroes"
print(algstr)
ct = Cipher.encrypt(pt, key, algmodepad=algstr)
print("CT:", Cnv.tohex(ct))
p1 = Cipher.decrypt(ct, key, algmodepad="Aes128/ECB/NoPad")
print("Pn:", Cnv.tohex(p1))
p1 = Cipher.decrypt(ct, key, algmodepad=algstr)
print("P':", Cnv.tohex(p1))
print("P':", p1)
assert (p1 == pt)
def test_cipher_hex():
print("\nTEST CIPHER FUNCTIONS USING HEX-ENCODED PARAMETERS...")
algstr = "Tdea/CBC/PKCS5"
print("ALG:", algstr)
keyhex = '737C791F25EAD0E04629254352F7DC6291E5CB26917ADA32'
ivhex = "B36B6BFB6231084E"
pthex = "5468697320736F6D652073616D706520636F6E74656E742E"
okhex = "D76FD1178FBD02F84231F5C1D2A2F74A4159482964F675248254223DAF9AF8E4"
print("KY:", keyhex)
print("IV:", ivhex)
print("PT:", pthex)
cthex = Cipher.encrypt_hex(pthex, keyhex, ivhex, algstr)
print("CT:", cthex)
print("OK:", okhex)
assert cthex == okhex, "Cipher.encrypt_hex failed"
print("About to decrypt...")
# Decrypt using flags instead of alg string
p1hex = Cipher.decrypt_hex(cthex, keyhex, ivhex, alg=Cipher.Alg.TDEA, mode=Cipher.Mode.CBC, pad=Cipher.Pad.PKCS5)
print("P':", p1hex)
assert p1hex == pthex
# Another example, this time with the IV prefixed to the ciphertext
algstr = "Aes128/CBC/OneAndZeroes"
keyhex = '0123456789ABCDEFF0E1D2C3B4A59687'
ivhex = "FEDCBA9876543210FEDCBA9876543210"
pthex = "4E6F77206973207468652074696D6520666F7220616C6C20676F6F64206D656E20746F"
# IV||CT
okhex = "FEDCBA9876543210FEDCBA9876543210C3153108A8DD340C0BCB1DFE8D25D2320EE0E66BD2BB4A313FB75C5638E9E1771D4CDA34FBFB7E74B321F9A2CF4EA61B"
print("KY:", keyhex)
print("IV:", ivhex)
print("PT:", pthex)
cthex = Cipher.encrypt_hex(pthex, keyhex, ivhex, algstr, opts=Cipher.Opts.PREFIXIV)
print("CT:", cthex)
print("OK:", okhex)
assert cthex == okhex, "Cipher.encrypt_hex failed"
# Decrypt using flags instead of alg string - this time we don't need the IV argument
p1hex = Cipher.decrypt_hex(cthex, keyhex, None, alg=Cipher.Alg.AES128, mode=Cipher.Mode.CBC,
pad=Cipher.Pad.ONEANDZEROES, opts=Cipher.Opts.PREFIXIV)
print("P':", p1hex)
assert (p1hex == pthex)
def test_cipher_block():
print("\nTEST CIPHER FUNCTIONS WITH EXACT BLOCK LENGTHS...")
key = Cnv.fromhex("0123456789ABCDEFF0E1D2C3B4A59687")
iv = Cnv.fromhex("FEDCBA9876543210FEDCBA9876543210")
print("KY:", Cnv.tohex(key))
print("IV:", Cnv.tohex(iv))
# In Python 3 plaintext must be bytes, not ASCII string
pt = b"Now is the time for all good men"
print("PT:", pt)
print("PT:", Cnv.tohex(pt))
okhex = "C3153108A8DD340C0BCB1DFE8D25D2320EE0E66BD2BB4A313FB75C5638E9E177"
ct = Cipher.encrypt_block(
pt, key, iv, alg=Cipher.Alg.AES128, mode=Cipher.Mode.CBC)
print("CT:", Cnv.tohex(ct))
print("OK:", okhex)
assert (okhex.upper() == Cnv.tohex(ct))
p1 = Cipher.decrypt_block(
ct, key, iv, alg=Cipher.Alg.AES128, mode=Cipher.Mode.CBC)
print("P1:", Cnv.tohex(p1))
print("P1:", p1)
# Using defaults (TDEA/ECB)
key = Rng.bytestring(Cipher.keybytes(Cipher.Alg.TDEA))
print("KY:", Cnv.tohex(key))
ct = Cipher.encrypt_block(pt, key, iv)
print("CT:", Cnv.tohex(ct))
p1 = Cipher.decrypt_block(ct, key, iv)
print("P1:", Cnv.tohex(p1))
print("P1:", p1)
def test_cipher_file():
print("\nTEST CIPHER FILE FUNCTIONS...")
file_pt = "hello.txt"
write_text_file(file_pt, "hello world\r\n")
print(file_pt + ":", )
_print_file_hex(file_pt)
key = Cnv.fromhex("fedcba9876543210fedcba9876543210")
iv = Rng.bytestring(Cipher.blockbytes(Cipher.Alg.AES128))
print("IV:", Cnv.tohex(iv))
file_ct = "hello.aes128.enc.dat"
n = Cipher.file_encrypt(file_ct, file_pt, key, iv, "aes128-ctr", opts=Cipher.Opts.PREFIXIV)
assert (n == 0)
print(file_ct + ":", )
_print_file_hex(file_ct)
file_chk = "hello.aes128.chk.txt"
n = Cipher.file_decrypt(file_chk, file_ct, key, iv, "aes128-ctr", opts=Cipher.Opts.PREFIXIV)
assert (n == 0)
print(file_chk + ":", )
_print_file_hex(file_chk)
# check files are equal
assert (read_binary_file(file_pt) == read_binary_file(file_chk))
def test_cipher_gcm():
print("\nTEST CIPHER GCM...")
file_pt = "hello.txt"
write_text_file(file_pt, "hello world\r\n")
print(file_pt + ":", )
_print_file_hex(file_pt)
key = Cnv.fromhex("fedcba9876543210fedcba9876543210")
print("KY:", Cnv.tohex(key))
# NB Require exact 12-byte IV for GCM
iv = Cnv.fromhex("000102030405060708090A0B")
print("IV:", Cnv.tohex(iv))
file_ct = "hello.aes128.gcm.enc.dat"
n = Cipher.file_encrypt(file_ct, file_pt, key, iv, "aes128-gcm", opts=Cipher.Opts.PREFIXIV)
assert (n == 0)
print(file_ct + ":", )
_print_file_hex(file_ct)
file_chk = "hello.aes128.gcm.chk.txt"
n = Cipher.file_decrypt(file_chk, file_ct, key, iv, "aes128-gcm", opts=Cipher.Opts.PREFIXIV)
assert (n == 0)
print(file_chk + ":", )
_print_file_hex(file_chk)
# check files are equal
assert (read_binary_file(file_pt) == read_binary_file(file_chk))
print("Encrypt using AES-GCM with hex-encoded parameters...")
# Same as EncryptAEAD except without AAD and with hex-encoded arguments
keyhex = "2B7E151628AED2A6ABF7158809CF4F3C"
ivhex = "000102030405060708090A0B"
pthex = Cnv.tohex("This is some sample content.".encode())
print("PT =", pthex)
cthex = Cipher.encrypt_hex(pthex, keyhex, ivhex, "aes128-gcm")
print("CT =", cthex)
# CT = 0FA752259801FD6293B779E382FAD5FA7B5664D62EB63AA66064E189024C709ED4D580FB5E04E001C2D8DF97
assert len(cthex) > 0
dthex = Cipher.decrypt_hex(cthex, keyhex, ivhex, "aes128-gcm")
print("DT =", dthex)
assert len(dthex) > 0, "Cipher.decrypt failed"
print("DT =", Cnv.fromhex(dthex).decode())
# Check decrypted hex is equal to original
assert dthex.upper() == pthex.upper()
def test_cipher_keywrap():
print("\nTEST CIPHER KEY WRAP FUNCTIONS...")
# AES-128
keydata = Cnv.fromhex("00112233 44556677 8899aabb ccddeeff")
kek = Cnv.fromhex("c17a44e8 e28d7d64 81d1ddd5 0a3b8914")
wk = Cipher.key_wrap(keydata, kek, Cipher.Alg.AES128)
print("WK=", Cnv.tohex(wk))
assert (Cnv.tohex(wk) == "503D75C73630A7B02ECF51B9B29B907749310B77B0B2E054")
# Unwrap
k = Cipher.key_unwrap(wk, kek, Cipher.Alg.AES128)
print("UNWRAPPED K=", Cnv.tohex(k))
assert (k == keydata)
# AES-256
keydata = Cnv.fromhex(
"8cbedec4 8d063e1b a46be8e3 69a9c398 d8e30ee5 42bc347c 4f30e928 ddd7db49")
kek = Cnv.fromhex(
"9e84ee99 e6a84b50 c76cd414 a2d2ec05 8af41bfe 4bf3715b f894c8da 1cd445f6")
wk = Cipher.key_wrap(keydata, kek, Cipher.Alg.AES256)
print("WK=", Cnv.tohex(wk))
assert (Cnv.tohex(
wk) == "EAFB901F82B98D37F17497063DE3E5EC7246AB57200AE73EDDDDF24AA403DAFA0C5AE151D1746FA4")
# Unwrap
k = Cipher.key_unwrap(wk, kek, Cipher.Alg.AES256)
print("UNWRAPPED K=", Cnv.tohex(k))
assert (k == keydata)
# Triple DES
print("Using Triple DES the result is always different, but will be 16 bytes longer...")
keydata = Cnv.fromhex(
"84e7f2d8 78f89fcc cd2d5eba fc56daf7 3300f27e f771cd68")
kek = Cnv.fromhex("8ad8274e 56f46773 8edd83d4 394e5e29 af7c4089 e4f8d9f4")
wk = Cipher.key_wrap(keydata, kek, Cipher.Alg.TDEA)
print("WK=", Cnv.tohex(wk))
assert len(wk) == len(keydata) + 16
# Unwrap
k = Cipher.key_unwrap(wk, kek, Cipher.Alg.TDEA)
print("UNWRAPPED K=", Cnv.tohex(k))
assert (k == keydata)
def test_cipher_pad():
print("\nTEST CIPHER PAD....")
data = Cnv.fromhex('FFFFFFFFFF')
print("Input data :", Cnv.tohex(data))
padded = Cipher.pad(data, Cipher.Alg.TDEA)
print("Padded data:", Cnv.tohex(padded))
unpadded = Cipher.unpad(padded, Cipher.Alg.TDEA)
print("Unpadded :", Cnv.tohex(unpadded))
padded = Cipher.pad(data, Cipher.Alg.TDEA,
Cipher.Pad.ONEANDZEROES)
print("Padded data:", Cnv.tohex(padded))
unpadded = Cipher.unpad(padded, Cipher.Alg.TDEA,
Cipher.Pad.ONEANDZEROES)
print("Unpadded :", Cnv.tohex(unpadded))
# Pad the empty string
data = Cnv.fromhex('')
print("Input data :", Cnv.tohex(data))
padded = Cipher.pad(data, Cipher.Alg.AES128)
print("Padded data:", Cnv.tohex(padded))
unpadded = Cipher.unpad(padded, Cipher.Alg.AES128)
print("Unpadded :", Cnv.tohex(unpadded))
# Pass data as hex strings
datahex = 'aaaaaa'
print("Input data :", datahex)
paddedhex = Cipher.pad_hex(datahex, Cipher.Alg.TDEA)
print("Padded data:", paddedhex)
unpaddedhex = Cipher.unpad_hex(paddedhex, Cipher.Alg.TDEA)
print("Unpadded :", unpaddedhex)
paddedhex = Cipher.pad_hex(
datahex, Cipher.Alg.TDEA, Cipher.Pad.ONEANDZEROES)
print("Padded data:", paddedhex)
unpaddedhex = Cipher.unpad_hex(
paddedhex, Cipher.Alg.TDEA, Cipher.Pad.ONEANDZEROES)
print("Unpadded :", unpaddedhex)
def test_rsa_makekeys():
print("\nTEST RSA KEY FUNCTIONS....")
print("Making a new 512-bit RSA key pair...")
rsaprikeyfile = "myrsaprivate.p8"
rsapubkeyfile = "myrsapublic.p1"
# We use 512 bits here for speed. In practice 512 bits is insecure. Use at
# least 1024
r = Rsa.make_keys(rsapubkeyfile, rsaprikeyfile, 512,
Rsa.PublicExponent.RSAEXP_EQ_65537, 'password')
assert (0 == r)
# Read from new key file into an "internal" key string
prikeystr = Rsa.read_private_key(rsaprikeyfile, 'password')
# Internal key string should be treated as a "blob".
print("prikeystr =", prikeystr)
assert (len(prikeystr) > 0)
nbits = Rsa.key_bits(prikeystr)
print("nbits = ", nbits)
assert (nbits > 0)
print("hashcode =", Rsa.key_hashcode(prikeystr))
pubkeystr = Rsa.read_public_key(rsapubkeyfile)
print("pubkeystr =", pubkeystr)
assert (len(pubkeystr) > 0)
nbits = Rsa.key_bits(pubkeystr)
print("nbits = ", nbits)
assert (nbits > 0)
print("hashcode =", Rsa.key_hashcode(pubkeystr))
s = Rsa.key_value(pubkeystr, "Exponent")
print("exponent in base64:", s)
s = Rsa.key_value(pubkeystr, "MODULUS")
print("modulus in base64:", s)
# Create an XML representation of the internal string - force values in
# non-standard hex
s = Rsa.to_xmlstring(pubkeystr, Rsa.XmlOptions.HEXBINARY)
print("xml (hex):", s)
# Again using standard default base64 values
s = Rsa.to_xmlstring(pubkeystr)
print("xml:", s)
# Go back from XML string to a new internal string (this will not be the
# same as before)
s = Rsa.from_xmlstring(s)
print("new keystr:", s)
# But should have the same key hashcode
print("hashcode =", Rsa.key_hashcode(s))
def test_rsa_errors():
print("\nTry to use an invalid keystr...")
try:
Rsa.key_hashcode('')
except PKIError as e:
print("(Expected) PKIError:", e)
def test_rsa_savekeys():
print("\nTEST READING RSA KEYS THEN RE-SAVING IN DIFFERENT FORMAT....")
# Read in a private key
fname = "AlicePrivRSASign.p8e"
print("FILE:", fname)
prikeystr = Rsa.read_private_key(fname, "password")
print("KeyBits:", Rsa.key_bits(prikeystr))
print("KeyIsPrivate:", Rsa.key_isprivate(prikeystr))
print("KeyHashCode:", Rsa.key_hashcode(prikeystr))
print("Save with stronger encryption...")
fname = "alice-stronger.p8e"
Rsa.save_enc_key(fname, prikeystr, "password123", # Note stronger password here :-)
pbescheme=Rsa.PbeScheme.PBKDF2_AES128, params="count=5999", fileformat=Rsa.Format.PEM)
# Note change [v22.0] here. Formerly it would have been
# pbescheme=Rsa.PbeScheme.PBKDF2_AES128, count=5999, fileformat=Rsa.Format.PEM)
_dump_and_print_asn1(fname)
print("FILE:", fname, "-->", Asn1.type(fname))
# Check we can read and that key is the same
keystrchk = Rsa.read_private_key(fname, "password123")
print("KeyHashCode:", Rsa.key_hashcode(keystrchk))
assert (Rsa.key_hashcode(keystrchk) == Rsa.key_hashcode(prikeystr))
print("Save without encryption...")
fname = "alice-noencrypt.p8"
Rsa.save_key(fname, prikeystr)
print("FILE:", fname, "-->", Asn1.type(fname))
# Check we can read and that key is the same
keystrchk = Rsa.read_private_key(fname)
print("KeyHashCode:", Rsa.key_hashcode(keystrchk))
assert (Rsa.key_hashcode(keystrchk) == Rsa.key_hashcode(prikeystr))
print("Convert private key string to a public key...")
pubkeystr = Rsa.publickey_from_private(prikeystr)
print("KeyBits:", Rsa.key_bits(pubkeystr))
print("KeyIsPrivate:", Rsa.key_isprivate(pubkeystr))
print("KeyHashCode:", Rsa.key_hashcode(pubkeystr))
print("Check the public and private key strings are matched...")
ismatch = Rsa.key_match(prikeystr, pubkeystr)
print("Rsa.key_match() returns", ismatch)
assert (ismatch)
print("Save to a new file in Open-SSL format...")
fname = "alice-ssl.pub"
Rsa.save_key(fname, pubkeystr, fileformat=Rsa.Format.SSL)
print("FILE:", fname, "-->", Asn1.type(fname))
# Check we can read and that key is the same
keystrchk = Rsa.read_public_key(fname)
print("KeyHashCode:", Rsa.key_hashcode(keystrchk))
assert (Rsa.key_hashcode(keystrchk) == Rsa.key_hashcode(pubkeystr))
def test_rsa_sign():
print("\nTEST RSA SIGN....")
print("Sign in two parts: encode then do raw RSA with private key...")
# See also Sig.sign() for a cleaner way
# Read in a private key
prikeystr = Rsa.read_private_key("AlicePrivRSASign.p8e", "password")
print(prikeystr)
message = b'abc'
# We need the length of the RSA key modulus in bytes
keybytes = Rsa.key_bytes(prikeystr)
print("KEYBYTES =", keybytes)
# 1. Encode the message in a block of the correct size
# -- this computes the message digest value automatically
b = Rsa.encode_msg_for_signature(keybytes, message)
print("BLK=[" + Cnv.tohex(b) + "]")
# 2. Encrypt the block using "raw" RSA transform
sig = Rsa.raw_private(b, prikeystr)
print("SIG=[" + Cnv.tohex(sig) + "]")
# To verify the signature we read in the public key
pubkeystr = Rsa.read_public_key("AliceRSASignByCarl.cer")
print(pubkeystr)
# 1. Decrypt the signature to a block using "raw" RSA transform
blk = Rsa.raw_public(sig, pubkeystr)
print("BLK=[" + Cnv.tohex(blk) + "]")
# 2a. Decode to extract the full digestinfo
# -- normally we don't do this, but we test it here
dig = Rsa.decode_digest_for_signature(blk, True)
print("DIGINFO=[" + Cnv.tohex(dig) + "]")
# 2b. Decode to extract the digest
dig = Rsa.decode_digest_for_signature(blk)
print("DIG=[" + Cnv.tohex(dig) + "]")
# Check we got a match
digvalue = Hash.data(b'abc')
print("SHA1('abc')=", Cnv.tohex(digvalue))
assert (dig == digvalue)
print("Do again but start with digest value, and use SHA-256...")
digvalue = Hash.data(b'abc', Hash.Alg.SHA256)
print("SHA256('abc')=", Cnv.tohex(digvalue))
b = Rsa.encode_msg_for_signature(
keybytes, digvalue, hashalg=Hash.Alg.SHA256, digest_only=True)
print("BLK=[" + Cnv.tohex(b) + "]")
sig = Rsa.raw_private(b, prikeystr)
print("SIG=[" + Cnv.tohex(sig) + "]")
print("BLK=[" + Cnv.tohex(b) + "]")
# decode to extract the digest
dig = Rsa.decode_digest_for_signature(b)
print("DIG=[" + Cnv.tohex(dig) + "]")
def test_rsa_encrypt():
print("\nTEST RSA ENCRYPT....")
print("Encrypt in two parts: encode then do raw RSA with public key...")
message = b'Hi Bob.' # Note usually we use RSA to encrypt a session key.
print("MSG:", message)
# Read in Bob's public key
pubkeystr = Rsa.read_public_key("BobRSASignByCarl.cer")
print(pubkeystr)
# We need the length of the RSA key modulus in bytes
keybytes = Rsa.key_bytes(pubkeystr)
print("KEYBYTES =", keybytes)
blk = Rsa.encode_msg_for_encryption(keybytes, message)
print("BLK=[" + Cnv.tohex(blk) + "]")
ct = Rsa.raw_public(blk, pubkeystr)
print("Note that the ciphertext block will be different each time...")
print("CT =[" + Cnv.tohex(ct) + "]")
print("Decrypt in two parts: do raw RSA with private key then decode...")
# Read in a private key
prikeystr = Rsa.read_private_key("BobPrivRSAEncrypt.p8e", "password")
print(prikeystr)
blk = Rsa.raw_private(ct, prikeystr)
print("BLK=[" + Cnv.tohex(blk) + "]")
pt = Rsa.decode_msg_for_encryption(blk)
print("PT =[" + Cnv.tohex(ct) + "]")
# in this case we expect plain ASCII text
print("PT='" + str(pt) + "'")
assert (pt == message)
print("Again using one-step encrypt() and decrypt() this time with OEAP method...")
# Use key strings we read in above
print("MSG:", message)
ct = Rsa.encrypt(message, pubkeystr, method=Rsa.EME.OAEP)
print("CT =[" + Cnv.tohex(ct) + "]")
pt = Rsa.decrypt(ct, prikeystr, method=Rsa.EME.OAEP)
print("PT='" + str(pt) + "'")
assert (pt == message)
print("")
print("RSAES-OAEP Encryption Example 1.1 from `oaep-vect.txt` in `pkcs-1v2-1-vec.zip`")
print("Encrypt using RSA-OAEP but set seed to be a fixed value to compare with test vector")
# Use key files directly: RSA key file 1024-bit
pubkeyfile = "rsa-oaep-1.pub"
prikeyfile = "rsa-oaep-1.p8" # unencrypted, no password
# Message to be encrypted
msg = Cnv.fromhex("6628194e12073db03ba94cda9ef9532397d50dba79b987004afefe34")
print("MSG:", Cnv.tohex(msg))
ct = Rsa.encrypt(msg, pubkeyfile, method=Rsa.EME.OAEP, params="seed=18b776ea21069d69776a33e96bad48e1dda0a5ef")
print("CT = " + Cnv.tohex(ct))
# Known answer from test vector
okhex = "354fe67b4a126d5d35fe36c777791a3f7ba13def484e2d3908aff722fad468fb21696de95d0be911c2d3174f8afcc201035f7b6d8e69402de5451618c21a535fa9d7bfc5b8dd9fc243f8cf927db31322d6e881eaa91a996170e657a05a266426d98c88003f8477c1227094a0d9fa1e8c4024309ce1ecccb5210035d47ac72e8a"
print("OK = " + okhex)
assert (Cnv.tohex(ct).lower() == okhex.lower())
# Decrypt - the private key is unencrypted with no password
pt = Rsa.decrypt(ct, prikeyfile, "", method=Rsa.EME.OAEP)
print("PT = " + Cnv.tohex(pt))
assert (Cnv.tohex(pt).lower() == Cnv.tohex(msg).lower())
print("Encrypt using RSA-OAEP using SHA-256 for encoding hash function and SHA-1 for MGF hash function...")
# The result will be different each time
ct = Rsa.encrypt(msg, pubkeyfile, method=Rsa.EME.OAEP, hashalg=Rsa.HashAlg.SHA256, advopts=Rsa.AdvOpts.MGF1_SHA1)
print("CT = " + Cnv.tohex(ct))
# Decrypt - we must specify the parameters used to encrypt
pt = Rsa.decrypt(ct, prikeyfile, "", method=Rsa.EME.OAEP, hashalg=Rsa.HashAlg.SHA256, advopts=Rsa.AdvOpts.MGF1_SHA1)
print("PT = " + Cnv.tohex(pt))
assert (Cnv.tohex(pt).lower() == Cnv.tohex(msg).lower())
def test_x509_generate():
print("\nTEST X509 FUNCTIONS....")
# For convenience we hardcode the password - DON'T DO THIS IN PRACTICE!
mypassword = 'password'
print("Make a self-signed X.509 certificate:")
# Generate a new RSA key pair for the CA
# (in practice, do this once)
print("Generating a new RSA keypair for the CA...")
ca_prikeyfile = 'thecaprikey.p8'
ca_pubkeyfile = 'thecapubkey.p1'
n = Rsa.make_keys(ca_pubkeyfile, ca_prikeyfile, 1024,
Rsa.PublicExponent.RSAEXP_EQ_65537, mypassword)
assert (0 == n)
assert (os.path.isfile(ca_prikeyfile))
assert (os.path.isfile(ca_pubkeyfile))
# Now use these to create a self-signed X.509 certificate (we only need
# the private key file)
ca_certfile = 'theca.cer'
n = X509.make_cert_self(ca_certfile, ca_prikeyfile,
mypassword, 0x01, 5, "C=AU;CN=theCA")
print("X509.make_cert_self() returns:", n)
assert (0 == n)
assert (os.path.isfile(ca_certfile))
print("Created new self-signed X.509 certificate '" + ca_certfile + "'")
# Show its contents...
_dump_and_print_x509(ca_certfile)
# Generate a new RSA key pair for the user
# (in practice, do this once)
print("Generating a new RSA 1024-bit keypair for the USER...")
user_prikeyfile = 'myuserprikey.p8'
user_pubkeyfile = 'myuserpubkey.p1'
n = Rsa.make_keys(user_pubkeyfile, user_prikeyfile, 1024,
Rsa.PublicExponent.RSAEXP_EQ_65537, mypassword)
assert (0 == n)
assert (os.path.isfile(ca_prikeyfile))
assert (os.path.isfile(ca_pubkeyfile))
# Use the user's public key as the subject of an X.509 cert issued by the
# CA
my_certfile = 'mycert.cer'
n = X509.make_cert(my_certfile, ca_certfile, user_pubkeyfile, ca_prikeyfile, mypassword, 0x101, 4, "C=AU;CN=me",
extns="rfc822name=me@myorg.com;keyusage=digitalSignature,nonRepudiation;notBefore=2017-01-01")
print("X509.make_cert() returns:", n)
assert (0 == n)
assert (os.path.isfile(my_certfile))
print("Created X.509 certificate '" + my_certfile + "'")
_dump_and_print_x509(my_certfile)
# Create a Certificate Signing Request for the user
my_csrfile = 'mycsr.p10'
n = X509.cert_request(my_csrfile, user_prikeyfile, mypassword, "C=AU;CN=me;O=myorg",
extns="rfc822name=me.again@myorg.com;keyusage=dataEncipherment,keyAgreement;ipaddress=127.0.0.1")
print("X509.cert_request() returns:", n)
assert (0 == n)
assert (os.path.isfile(my_csrfile))
print("Created PKCS#10 certificate signing request '" + my_csrfile + "'")
_dump_and_print_x509(my_csrfile)
# Now use this CSR to create another X.509 cert issued by the CA
# -- set `distname = ""` and pass the CSR file in the `subject_pubkeyfile` parameter
my_certfilefromcsr = 'mycertfromcsr.cer'
n = X509.make_cert(my_certfilefromcsr, ca_certfile, my_csrfile, ca_prikeyfile, mypassword, 0x102, 2, "",
sigalg=X509.SigAlg.RSA_SHA256)
print("X509.make_cert() returns:", n)
assert (0 == n)
assert (os.path.isfile(my_certfilefromcsr))
print("Created X.509 certificate '" + my_certfilefromcsr + "'")
_dump_and_print_x509(my_certfilefromcsr)
print("Check the keyUsage flags...")
n = X509.key_usage_flags(my_certfilefromcsr)
print("keyUsage bits: n =", format(n, "#08b"))
mask = X509.KeyUsageFlags.DATAENCIPHERMENT
print("n & KeyUsageFlags.DATAENCIPHERMENT =", bool(n & mask))
mask = X509.KeyUsageFlags.KEYAGREEMENT
print("n & KeyUsageFlags.KEYAGREEMENT =", bool(n & mask))
mask = X509.KeyUsageFlags.CRLSIGN
print("n & KeyUsageFlags.CRLSIGN =", bool(n & mask))
# Create a Certificate Revocation List (CRL) revoking the cert made above with serial number 0x101
# (Dates need to be hardcoded)
ca_crlfile = 'theca.crl'
revokedcertlist = "#x101,2020-04-25"
n = X509.make_crl(ca_crlfile, ca_certfile, ca_prikeyfile, mypassword, revokedcertlist,
extns="thisUpdate=2020-04-25T00:01;nextUpdate=2020-12-31",
sigalg=X509.SigAlg.RSA_SHA256,
opts=X509.Opts.FORMAT_PEM)
print("X509.make_crl() returns:", n)
assert (0 == n)
assert (os.path.isfile(ca_crlfile))
print("Created CRL file '" + ca_crlfile + "'")
_dump_and_print_x509(ca_crlfile)
# Query the certificates we made above
fname = ca_certfile
query = 'subjectName'
res = X509.query_cert(fname, query)
print("X509.query_cert(" + fname + ", " + query + "):", res)
query = 'isCA'
res = X509.query_cert(fname, query)
print("X509.query_cert(" + fname + ", " + query + "):", res)
fname = my_certfile
res = X509.query_cert(fname, query)
print("X509.query_cert(" + fname + ", " + query + "):", res)
fname = my_certfilefromcsr
query = 'keyUsageString'
res = X509.query_cert(fname, query)
print("X509.query_cert(" + fname + ", " + query + "):", res)
print("\nTry an invalid query string...")
try:
res = X509.query_cert(fname, 'badquery')
except PKIError as e:
print("(Expected) PKIError:", e)
print("\nSee if our certificates have been revoked at any time...")
# This cert has not been revoked
fname = my_certfilefromcsr
isrevoked = X509.cert_is_revoked(fname, ca_crlfile)
print("X509.cert_is_revoked('" + fname + "') returns", isrevoked)
assert (not isrevoked)
# This cert was revoked on 2020-04-25 (yes, we can work in the future!)
fname = my_certfile
print(fname, X509.query_cert(fname, "serialNumber"))
isrevoked = X509.cert_is_revoked(fname, ca_crlfile)
print("X509.cert_is_revoked('" + fname + "') returns", isrevoked)
assert (isrevoked)
print("See if certificate was revoked on a certain date...")
fname = my_certfile
isodate = "2016-01-01"
isrevoked = X509.cert_is_revoked(fname, ca_crlfile, isodate=isodate)
print("X509.cert_is_revoked('" + fname + ", " + isodate + "') returns", isrevoked)
assert (not isrevoked)
print("\nRead in X.509 cert as a base64 string")
s = X509.read_string_from_file(my_certfile)
print(s)
print("Now save from this string to a new file in PEM textual format...")
fname = 'newcert.cer'
n = X509.save_file_from_string(fname, s, in_pem_format=True)
print("Created new cert file '" + fname + "'")
assert (os.path.isfile(fname))
_dump_file(fname)
print("\nCheck if certs are valid now...")
fname = 'AliceRSASignByCarl.cer'
print("FILE:", fname)
isvalid = X509.cert_is_valid_now(fname)
s = X509.query_cert(fname, "NotAfter")
print(s)
print("X509.cert_is_valid_now('" + fname + "')=", isvalid)
assert (isvalid) # CAUTION: will not work after year 2039!
fname = 'dims.cer'
isvalid = X509.cert_is_valid_now(fname)
print("X509.cert_is_valid_now('" + fname + "')=", isvalid)
assert (not isvalid)
print("\nCompute cert thumbprints...")
fname = 'AliceRSASignByCarl.cer'
print("FILE:", fname)
thumb = X509.cert_thumb(fname)
print("X509.cert_thumb(SHA-1):", thumb)
assert (thumb == 'b30c48855055c2e64ce3196492d4b83831a6b3cb')
thumb = X509.cert_thumb(fname, X509.HashAlg.SHA256)
print("X509.cert_thumb(SHA-256):", thumb)
def test_x509_analyze():
print("\nTESTING X.509 ANALYZE...")
fname = 'AliceRSASignByCarl.cer'
print("FILE:", fname)
query = "serialNumber"
res = X509.query_cert(fname, query)
print("X509.query_cert(" + query + "):", res)
print("Use `opts=X509.Opts.DECIMAL`...")
res = X509.query_cert(fname, query, opts=X509.Opts.DECIMAL)
print("X509.query_cert(" + query + "):", res)
h = X509.cert_thumb(fname)
print("cert_thumb():", h)
h = X509.cert_hashissuersn(fname)
print("hash(issuer+serialnumber):", h)
fname = 'dims.cer'
print("FILE:", fname)
query = "issuerName"
res = X509.query_cert(fname, query)
print("X509.query_cert(" + query + "):", res)
print("Use `opts=X509.Opts.LDAP`...")
res = X509.query_cert(fname, query, opts=X509.Opts.LDAP)
print("X509.query_cert(" + query + "):", res)
fname = 'smallca.cer'
print("FILE:", fname)
query = "notAfter"
res = X509.query_cert(fname, query)
print("X509.query_cert(" + query + "):", res)
query = "cRLDistributionPointsURI"
res = X509.query_cert(fname, query)
print("X509.query_cert(" + query + "):", res)
# Test UTF-8-encoded output for a certificate with both Spanish and Chinese chars
# CAUTION: these may not print properly in a console or may cause a 'UnicodeEncodeError' if stdout is redirected to a file
fname = "maria-mx.cer"
print("FILE:", fname)
query = "issuerName"
res = X509.query_cert(fname, query, opts=X509.Opts.UTF8)
print("X509.query_cert(" + query + "):", res)
query = "subjectName"
res = X509.query_cert(fname, query, opts=X509.Opts.UTF8)
print("X509.query_cert(" + query + "):", res)
print(X509.text_dump_tostring(fname, opts=X509.Opts.UTF8))
# Extract the public key from the X.509 cert
keystr = Rsa.read_public_key(fname)
print("Public key bits:", Rsa.key_bits(keystr))
hcode = Rsa.key_hashcode(keystr)
print("Rsa.key_hashcode():", hcode)
h = X509.cert_thumb(fname, X509.HashAlg.MD5)
print("X509.cert_thumb(MD5):", h)
h = X509.cert_hashissuersn(fname)
print("hash(issuer+serialnumber):", h)
def test_x509_validate():
print("\nTESTING X.509 VALIDATE...")
print("1. A valid certificate and its issuer:")
certfile = "AliceRSASignByCarl.cer"
issuerfile = "CarlRSASelf.cer"
print("CERTFILE:", certfile)
print("ISSUERFILE:", issuerfile)
print("Is cert valid now?")
isok = X509.cert_is_valid_now(certfile)
print("cert_is_valid_now:", isok)
# This will fail in the year 2040 :-)
assert (isok)
print("Was cert signed by issuer?")
isok = X509.cert_is_verified(certfile, issuerfile)
print("cert_is_verified:", isok)
assert (isok)
print("Validate the certificate path...")
certlist = certfile + ";" + issuerfile
print("CERTLIST:", certlist)
isok = X509.cert_path_is_valid(certlist)
print("cert_path_is_valid:", isok)
assert (isok)
print("2. A valid but expired certificate and its issuer:")
certfile = "dims.cer"
issuerfile = "UTNUSERFirst-Object.cer"
print("CERTFILE:", certfile)
print("ISSUERFILE:", issuerfile)
print("Is cert valid now?")
d = X509.query_cert(certfile, "notAfter")
print(" X509.query_cert('notAfter'):", d)
isok = X509.cert_is_valid_now(certfile)
print("cert_is_valid_now:", isok, "(expected False)")
# This will fail if you go back in time to before Nov 2011 :-)
assert (not isok)
print("Was cert signed by issuer?")
isok = X509.cert_is_verified(certfile, issuerfile)
print("cert_is_verified:", isok)
assert (isok)
print("Validate the certificate path...")
certlist = certfile + ";" + issuerfile
print("CERTLIST:", certlist)
print("a) This will fail because a cert has expired...")
try:
isok = X509.cert_path_is_valid(certlist)
except PKIError as e:
print("(Expected):", e)
print("b) Now try again with X509.Opts.NO_TIMECHECK...")
isok = X509.cert_path_is_valid(certlist, no_timecheck=True)
print("cert_path_is_valid(NO_TIMECHECK):", isok)
print("3. A valid certificate but the wrong issuer:")
certfile = "AliceRSASignByCarl.cer"
issuerfile = "UTNUSERFirst-Object.cer"
print("CERTFILE:", certfile)
print("ISSUERFILE:", issuerfile)
print("Was cert signed by issuer?")
isok = X509.cert_is_verified(certfile, issuerfile)
print("cert_is_verified:", isok, "(expected False)")
assert (not isok)
def test_x509_extract():
print("\nTESTING X.509 EXTRACT...")
print("Extract cert files from a P7 chain file")
p7file = "bob.p7b"
print("P7 FILE:", p7file)
n = X509.get_cert_count_from_p7(p7file)
print("X509.get_cert_count_from_p7()=", n)
assert (n > 0)
# Extract each cer file from p7 file
for i in range(1, n + 1):
print("Count:", i)
fname = "bobcert" + str(i) + ".cer"
print(" OUTFILE:", fname)
r = X509.get_cert_from_p7(fname, p7file, i)
print(" X509.get_cert_from_p7() returns:", r)
assert (r > 0)
print(" X509_thumb():", X509.cert_thumb(fname))
print("Extract cert files from a PFX (p12) file")
pfxfile = "alice.pfx"
print("PFX FILE:", pfxfile)
fname = 'alice_cert.cer'
print(" OUTFILE:", fname)
r = X509.get_cert_from_pfx(fname, pfxfile, "password")
assert (r > 0)
print(" ASN1 TYPE(" + fname + ")=" + Asn1.type(fname))
print(" X509_thumb():", X509.cert_thumb(fname))
# Show thumbprints of known certificate files...
print("X509_thumb(Carl): ", X509.cert_thumb("CarlRSASelf.cer"))
print("X509_thumb(Alice):", X509.cert_thumb("AliceRSASignByCarl.cer"))
print("X509_thumb(Bob): ", X509.cert_thumb("BobRSASignByCarl.cer"))
print("Extract all cert files as P7 chain from a PFX file")
pfxfile = "alice.pfx"
print("PFX FILE:", pfxfile)
fname = 'alice_certs.p7'
print(" OUTFILE:", fname)
r = X509.get_p7chain_from_pfx(fname, pfxfile, "password")
assert (r > 0)
print(" ASN1 TYPE(" + fname + ")=" + Asn1.type(fname))
def test_rng():
print("\nTESTING RANDOM NUMBER GENERATOR...")
# Initialize from seed file. File is created if it does not exist.
# Optional but recommended for extra security
seedfile = 'myseedfile.dat'
n = Rng.initialize(seedfile)
assert (0 == n)
print(f"Rng.initialize() returns {n}.")
sd = read_binary_file(seedfile)
# print(textwrap(Cnv.tohex(sd)))
assert (len(sd) == Rng.SEED_BYTES)
print("5 random byte arrays")
for i in (16,24,32,48,64):
b = Rng.bytestring(i)
print(Cnv.tohex(b).lower())
print("5 random numbers in the range [-1 million, +1 million]")
for i in range(5):
r = Rng.number(-1000000, 1000000)
print(r)
assert (-1000000 <= r <= 1000000)
print("10 random octet values")
s = "" # form string to do in one line
for i in range(10):
r = Rng.octet()
assert (0 <= r <= 255)
s += str(r) + " "
print(s)
# Update seedfile
n = Rng.update_seedfile(seedfile)
assert (0 == n)
print(f"Rng.update_seedfile() returns {n}. Contents of seed file:")
sd = read_binary_file(seedfile)
print(textwrap(Cnv.tohex(sd)))
assert (len(sd) == Rng.SEED_BYTES)
# Carry out DRBGVS test
# Ref: drbgtestvectors/drbgvectors_pr_false/HMAC_DRBG.txt (line 22654)
# CAVS 14.3 DRBG800-90A information for "drbg_pr" COUNT = 0
s = Rng.test_drbgvs(2048, "da740cbc36057a8e282ae717fe7dfbb245e9e5d49908a0119c5dbcf0a1f2d5ab", "46561ff612217ba3ff91baa06d4b5440",
"fc227293523ecb5b1e28c87863626627d958acc558a672b148ce19e2abd2dde4", "b7998998eaf9e5d34e64ff7f03de765b31f407899d20535573e670c1b402c26a",
"1d61d4d8a41c3254b92104fd555adae0569d1835bb52657ec7fbba0fe03579c5", "b9ed8e35ad018a375b61189c8d365b00507cb1b4510d21cac212356b5bbaa8b2",
"2089d49d63e0c4df58879d0cb1ba998e5b3d1a7786b785e7cf13ca5ea5e33cfd")
ok = "5b70f3e4da95264233efbab155b828d4e231b67cc92757feca407cc9615a6608" + \
"71cb07ad1a2e9a99412feda8ee34dc9c57fa08d3f8225b30d29887d20907d123" + \
"30fffd14d1697ba0756d37491b0a8814106e46c8677d49d9157109c402ad0c24" + \
"7a2f50cd5d99e538c850b906937a05dbb8888d984bc77f6ca00b0e3bc97b16d6" + \
"d25814a54aa12143afddd8b2263690565d545f4137e593bb3ca88a37b0aadf79" + \
"726b95c61906257e6dc47acd5b6b7e4b534243b13c16ad5a0a1163c0099fce43" + \
"f428cd27c3e6463cf5e9a9621f4b3d0b3d4654316f4707675df39278d5783823" + \
"049477dcce8c57fdbd576711c91301e9bd6bb0d3e72dc46d480ed8f61fd63811"
print("Rng.test_drbgvs returns:")
print(textwrap(s))
print("Expected:\n", ok[:64], '\n... ', ok[-32:], sep='')
assert(s == ok)
def test_rng_initialize_ex():
print("\nTESTING RNG_INITIALIZE_EX...")
n = Rng.initialize_ex()
print(f"Rng.initialize_ex returns {n} (if >0 then Intel(R) DRNG is supported)")
# Explicitly turn off support for rest of session
n = Rng.initialize_ex(Rng.Opts.NO_INTEL_DRNG)
print(f"Rng.initialize_ex(NO_INTEL_DRNG) returns {n} (expected -214)")
# Check again, should now be off
n = Rng.initialize_ex()
print(f"Rng.initialize_ex returns {n} (expected -214)")
# Explicity call this function to test the random-number generator prompts
# This does not begin with "test_" so as not to fire in py.test
def do_rng_prompt():
# FUNCS THAT OPEN A DIALOG BOX FOR KEYBOARD PROMPTS...
n = Rng.make_seedfile('newseed.dat', strength=Rng.Strength.BITS_128)
print("crsysapi.Rng.make_seedfile returns", n)
b = Rng.bytes_with_prompt(32, Rng.Strength.BITS_192, "Type random keys until done")
print("crsysapi.Rng.bytes_with_prompt:", Cnv.tohex(b).lower())
def test_hash():
print("\nTESTING Hash...")
# write a file containing the 3 bytes 'abc'
write_text_file('abc.txt', 'abc')
_dump_file('abc.txt')
abc_hex = Cnv.tohex(b'abc')
print("'abc' in hex:", abc_hex)
# Use default SHA-1 algorithm
print("Using default SHA-1...")
b = Hash.data(b'abc')
print("Hash.data('abc'):", Cnv.tohex(b))
h = Hash.hex_from_data(b'abc')
print("Hash.hex_from_data('abc'):", h)
h = Hash.hex_from_data(bytearray.fromhex('616263'))
print("Hash.hex_from_data('abc'):", h)
h = Hash.hex_from_hex(abc_hex)
print("Hash.hex_from_hex(abc_hex):", h)
b = Hash.file('abc.txt')
print("Hash.file('abc.txt'):", Cnv.tohex(b))
h = Hash.hex_from_file('abc.txt')
print("Hash.hex_from_file('abc.txt'):", h)
print("Using SHA-256...")
b = Hash.data(b'abc', Hash.Alg.SHA256)
print("Hash.data('abc'):", Cnv.tohex(b))
h = Hash.hex_from_hex(abc_hex, Hash.Alg.SHA256)
print("Hash.hex_from_hex(abc_hex):", h)
b = Hash.file('abc.txt', Hash.Alg.SHA256)
print("Hash.file('abc.txt'):", Cnv.tohex(b))
h = Hash.hex_from_file('abc.txt', Hash.Alg.SHA256)
print("Hash.hex_from_file('abc.txt'):", h)
# compute SHA256(SHA256('abc')) using Hash.double()
b = Hash.double(b'abc', Hash.Alg.SHA256)
print("Hash.double('abc',SHA256):", Cnv.tohex(b))
# and again by composition
b2 = Hash.data(Hash.data(b'abc', Hash.Alg.SHA256),
Hash.Alg.SHA256)
print("SHA256(SHA256('abc')): ", Cnv.tohex(b2))
def test_hash_sha3():
print("\nTESTING Hash(SHA3)...")
# write a file containing the 3 bytes 'abc'
write_text_file('abc.txt', 'abc')
_dump_file('abc.txt')
abc_hex = Cnv.tohex(b'abc')
print("'abc' in hex:", abc_hex)
b = Hash.data(b'abc', Hash.Alg.SHA3_224)
print("Hash.data('abc'):", Cnv.tohex(b))
assert (b == Cnv.fromhex('e642824c3f8cf24ad09234ee7d3c766fc9a3a5168d0c94ad73b46fdf'))
h = Hash.hex_from_hex(abc_hex, Hash.Alg.SHA3_256)
print("Hash.hex_from_hex(abc_hex):", h)
assert (Cnv.fromhex(h) == Cnv.fromhex('3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532'))
b = Hash.file('abc.txt', Hash.Alg.SHA3_384)
print("Hash.file('abc.txt'):", Cnv.tohex(b))
assert (b == Cnv.fromhex(
'ec01498288516fc926459f58e2c6ad8df9b473cb0fc08c2596da7cf0e49be4b298d88cea927ac7f539f1edf228376d25'))
h = Hash.hex_from_file('abc.txt', Hash.Alg.SHA3_512)
print("Hash.hex_from_file('abc.txt'):", h)
assert (Cnv.fromhex(h) == Cnv.fromhex(
'b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0'))
def test_hmac():
print("\nTESTING Hmac...")
print("Test case 4 from RFC 2202 and RFC 4231")
key = Cnv.fromhex('0102030405060708090a0b0c0d0e0f10111213141516171819')
print("key: ", Cnv.tohex(key))
# data = 0xcd repeated 50 times
data = bytearray([0xcd] * 50)
print("data:", Cnv.tohex(data))
b = Hmac.data(data, key)
print("HMAC-SHA-1: ", Cnv.tohex(b))
assert (b == Cnv.fromhex('4c9007f4026250c6bc8414f9bf50c86c2d7235da'))
b = Hmac.data(data, key, Hmac.Alg.MD5)
print("HMAC-MD5: ", Cnv.tohex(b))
assert (b == Cnv.fromhex('697eaf0aca3a3aea3a75164746ffaa79'))
b = Hmac.data(data, key, Hmac.Alg.SHA256)
print("HMAC-SHA-256:", Cnv.tohex(b))
assert (b == Cnv.fromhex(
'82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b'))
h = Hmac.hex_from_data(data, key, Hmac.Alg.SHA256)
print("HMAC-SHA-256:", h)
assert (h == '82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b')
b = Hmac.data(data, key, Hmac.Alg.SHA512)
print("HMAC-SHA-512:", Cnv.tohex(b))
assert (b == Cnv.fromhex(
'b0ba465637458c6990e5a8c5f61d4af7 e576d97ff94b872de76f8050361ee3db a91ca5c11aa25eb4d679275cc5788063 a5f19741120c4f2de2adebeb10a298dd'))
print("Test case 7 from RFC 4231")
key = bytearray([0xaa] * 131)
print("key: ", Cnv.tohex(key).lower())
data = b"This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm."
print("data:", data)
b = Hmac.data(data, key, Hmac.Alg.SHA224)
print("HMAC-SHA-224:", Cnv.tohex(b))
assert (b == Cnv.fromhex(
'3a854166ac5d9f023f54d517d0b39dbd946770db9c2b95c9f6f565d1'))
# HMAC hex <-- hex
print("Test case 1 from RFC 2202 and RFC 4231")
keyhex = "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b" # (20 bytes)
datahex = "4869205468657265" # ("Hi There")
print("key: ", keyhex)
print("data:", datahex)
h = Hmac.hex_from_hex(datahex, keyhex)
print("HMAC-SHA-1:", h)
assert (h == "b617318655057264e28bc0b6fb378c8ef146be00")
h = Hmac.hex_from_hex(datahex, keyhex, Hmac.Alg.SHA256)
print("HMAC-SHA-256:", h)
assert (h == "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7")
def test_hmac_sha3():
print("\nTESTING Hmac(SHA-3)...")
print("NIST HMAC_SHA3-256.pdf Sample #1")
key = Cnv.fromhex('000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F')
print("key: ", Cnv.tohex(key))
data = b'Sample message for keylen<blocklen'
print("data:", data.decode())
b = Hmac.data(data, key, Hmac.Alg.SHA3_256)
print("HMAC-SHA-3-256:", Cnv.tohex(b))
assert (b == Cnv.fromhex('4fe8e202c4f058e8dddc23d8c34e467343e23555e24fc2f025d598f558f67205'))
print("NIST HMAC_SHA3-512.pdf Sample #3")
key = Cnv.fromhex("""000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F
202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F
404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F
606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F
8081828384858687""")
print("key: ", Cnv.tohex(key))
data = b'Sample message for keylen>blocklen'
print("data:", data.decode())
b = Hmac.data(data, key, Hmac.Alg.SHA3_512)
print("HMAC-SHA-3-512:", Cnv.tohex(b))
assert (b == Cnv.fromhex(
'5f464f5e5b7848e3885e49b2c385f0694985d0e38966242dc4a5fe3fea4b37d46b65ceced5dcf59438dd840bab22269f0ba7febdb9fcf74602a35666b2a32915'))
def test_wipe():
print("\nTESTING Wipe...")
print("Note that Wipe.data() just zeroizes the data, it does not change the length")
b = Cnv.fromhex('3a854166ac5d9f023f54d517d0b39dbd946770db9c2b95c9f6f565d1')
print("BEFORE b=", Cnv.tohex(b))
Wipe.data(b)
print("AFTER Wipe.data() b=", Cnv.tohex(b))
print("AFTER Wipe.data()", str(b))
print([c for c in b])
assert all([c == 0 for c in b])
# works with a bytes type but not with an immutable string type
s = b"a string"
print("BEFORE s='" + str(s) + "'")
print([c for c in s])
Wipe.data(s)
print("AFTER Wipe.data()", str(s))
print([c for c in s])
assert all([c == 0 for c in s])
# write a file containing some text
fname = 'tobedeleted.txt'
write_text_file(fname, 'Some secret text in this file.')
_dump_file(fname)
assert (os.path.isfile(fname))
Wipe.file(fname)
print("After Wipe.file(), isfile() returns", os.path.isfile(fname))
assert (not os.path.isfile(fname))
def test_asn1():
print("\nTESTING ASN.1...")
fname = "smallca.cer"
print("FILE:", fname)
t = Asn1.type(fname)
print("Asn1.type():", t)
dumpfile = 'asn1dump.txt'
Asn1.text_dump(dumpfile, fname, opts=Asn1.Opts.ADDLEVELS)
print("Asn1.text_dump():")
_print_file(dumpfile)
def test_ocsp():
print("\nTESTING Ocsp...")
# Create an OCSP request to check a code-signing certificate issued by the holder
# of certificate in the file `UTNUSERFirst-Object.cer`
issuercert = "UTNUSERFirst-Object.cer"
print("Issuer Cert=", issuercert)
certfile = "dims.cer"
print("Cert File to check=", certfile)
req = Ocsp.make_request(issuercert, certfile)
print("OCSPRequest=", req)
assert len(req) > 0
# We can analyze the ASN.1 data structure from the base64 string
_dump_and_print_asn1(req)
# Pass a hex serial number instead of filename
serialnum = "#x 00 FB C7 23 22 8C 8C 80 22 D8 85 92 23 DE E7 06 60"
print("Cert SerialNumber=", serialnum)
req1 = Ocsp.make_request(issuercert, serialnum)
print("OCSPRequest=", req1)
# These should be the same
assert (req1 == req)
# Now read a response
responsefile = "ocsp_response_ok_dims.dat"
print("ResponseFile=", responsefile)
resp = Ocsp.read_response(responsefile, issuercert)
print("OCSPResponse:", resp)
def test_ecc():
print("\nTESTING Ecc...")
pubkeyfile = "myeckeyp256.pub"
prikeyfile = "myeckeyp256.p8"
password = "password"
curvename = "P-256"
# Create a new pair of ECC keys, saved as DER-encoded files
n = Ecc.make_keys(pubkeyfile, prikeyfile, curvename, password)
assert (0 == n)
_dump_and_print_asn1(pubkeyfile)
print(pubkeyfile + ": " + Asn1.type(pubkeyfile))
print(prikeyfile + ": " + Asn1.type(prikeyfile))
# Read in private key to an internal key string
intpristr = Ecc.read_private_key(prikeyfile, password)
# This will be different each time, even for the same key
print(intpristr)
# But the key hash code will be the same
print("key_hash_code =", Ecc.key_hashcode(intpristr))
# Query this string for info
query = "keyBits"
r = Ecc.query_key(intpristr, query)
print("Ecc.query_key(" + query + ")=", r)
query = "curveName"
r = Ecc.query_key(intpristr, query)
print("Ecc.query_key(" + query + ")=", r)
query = "privateKey"
r = Ecc.query_key(intpristr, query)
print("Ecc.query_key(" + query + ")=", r)
# Read in a key from its hex representation
print("A NIST P-192 public key in X9.63 uncompressed format")
keyhex = "0496C248BE456192FA1380CCF615D171452F41FF31B92BA733524FD77168DEA4425A3EA8FD79B98DC7AFE83C86DCC39A96"
curvename = "prime192v1" # A synonym for "P-192"
print("KEYHEX:", keyhex)
print("CURVE: ", curvename)
intpubstr = Ecc.read_key_by_curve(keyhex, curvename)
print("keyBits=", Ecc.query_key(intpubstr, "keyBits"))
f = Ecc.query_key(intpubstr, "isPrivate")
print("isPrivate=", f)
assert (not f)
print("A Bitcoin private key in base58 form")
keyb58 = "6ACCbmy9qwiFcuVgvxNNwMPfoghobzznWrLs3v7t3RmN"
curvename = "secp256k1"
print("KEYB58:", keyb58)
print("CURVE: ", curvename)
intpristr = Ecc.read_key_by_curve(
Cnv.tohex(Cnv.frombase58(keyb58)), curvename)
print("keyBits=", Ecc.query_key(intpristr, "keyBits"))
f = Ecc.query_key(intpristr, "isPrivate")
print("isPrivate=", f)
assert (f)
print("key_hash_code =", Ecc.key_hashcode(intpristr))
print("Extract the public key in hex form from the internal private key string")
pubkey = Ecc.query_key(intpristr, 'publicKey')
print("publicKey=", pubkey)
assert pubkey == '04654bacc2fc7a3bde0f8eb95dc5aac9ba1df732255cf7f2eb7e1e8e6edbb1f4188ff3752ac4bdf1e3a31a488747745dddcbabd33a10c3b52d737c092851da13c0'
print("Extract the public key as an internal key string")
intpubstr = Ecc.publickey_from_private(intpristr)
print("intpubstr=", intpubstr)
print("key_hash_code =", Ecc.key_hashcode(intpubstr))
print("Query this internal public key string...")
query = "keybits"
print("Ecc.query_key(" + query + ")=", Ecc.query_key(intpubstr, query))
query = "curvename"
print("Ecc.query_key(" + query + ")=", Ecc.query_key(intpubstr, query))
query = "isPrivate"
print("Ecc.query_key(" + query + ")=", Ecc.query_key(intpubstr, query))
print("Save keys in various new file forms...")
# Note we must save from the internal key string forms
# Default unencrypted key files...
newkeyfile = 'myecpublic.key'
n = Ecc.save_key(newkeyfile, intpubstr)
# Show what type of file we made
print("File:", newkeyfile, "-->", Asn1.type(newkeyfile))
# and read it back in to check it's really OK...
s = Ecc.read_public_key(newkeyfile)
assert (Ecc.query_key(s, 'keyBits') == 256)
newkeyfile = 'myecprivate.key'
n = Ecc.save_key(newkeyfile, intpristr)
print("File:", newkeyfile, "-->", Asn1.type(newkeyfile))
s = Ecc.read_private_key(newkeyfile)
assert (Ecc.query_key(s, 'keyBits') == 256)
# Alternative PKCS#8 key type (unencrypted)
newkeyfile = 'myecprivate.p8'
n = Ecc.save_key(newkeyfile, intpristr,
keytype=Ecc.KeyType.PKCS8, fileformat=Ecc.Format.PEM)
print("File:", newkeyfile, "-->", Asn1.type(newkeyfile))
s = Ecc.read_private_key(newkeyfile)
assert (Ecc.query_key(s, 'keyBits') == 256)
# Encrypted private key (always PKCS#8)
newkeyfile = 'myecprivate_enc.p8'
n = Ecc.save_enc_key(newkeyfile, intpristr, 'password')
print("File:", newkeyfile, "-->", Asn1.type(newkeyfile))
s = Ecc.read_private_key(newkeyfile, 'password')
assert (Ecc.query_key(s, 'keyBits') == 256)
# with stronger encryption
newkeyfile = 'myecprivate_encx.p8'
n = Ecc.save_enc_key(newkeyfile, intpristr, 'password',
pbescheme=Ecc.PbeScheme.PBKDF2_AES256,
params="count=5999;prf=hmacWithSHA256;")
print("File:", newkeyfile, "-->", Asn1.type(newkeyfile))
s = Ecc.read_private_key(newkeyfile, 'password')
assert (Ecc.query_key(s, 'keyBits') == 256)
# Dump this
_dump_and_print_asn1(newkeyfile)
def test_ecc_brainpool():
print("\nTESTING ECC BRAINPOOL...")
pubkeyfile = "myeckeyBrainpool384.pub"
prikeyfile = "myeckeyBrainpool384.p8e"
password = "password"
curvename = "brainpoolP384r1"
# Create a new pair of ECC keys, saved as DER-encoded files with stronger encryption
n = Ecc.make_keys(pubkeyfile, prikeyfile, curvename, password,
Ecc.PbeScheme.PBKDF2_AES256, "count=8999;prf=hmacWithSha512", Ecc.Format.PEM)
assert (0 == n)
_dump_and_print_asn1(pubkeyfile)
print(pubkeyfile + ": " + Asn1.type(pubkeyfile))
print(prikeyfile + ": " + Asn1.type(prikeyfile))
# Read in private key to an internal key string
intpristr = Ecc.read_private_key(prikeyfile, password)
# This will be different each time, even for the same key
print(intpristr)
# But the key hash code will be the same
print("pri_key_hash_code =", Ecc.key_hashcode(intpristr))
print("pub_key_hash_code =", Ecc.key_hashcode(Ecc.read_public_key(pubkeyfile)))
# Query this string for info
query = "keyBits"
r = Ecc.query_key(intpristr, query)
print("Ecc.query_key(" + query + ")=", r)
query = "curveName"
r = Ecc.query_key(intpristr, query)
print("Ecc.query_key(" + query + ")=", r)
query = "privateKey"
r = Ecc.query_key(intpristr, query)
print("Ecc.query_key(" + query + ")=", r)
print("Sign 'abc' using ECDSA...")
msg = b'abc'
print("MSG =", Cnv.tohex(msg))
# Compute the signature value NB this will be different each time because we use a new key each time
sigval = Sig.sign_data(msg, intpristr, "", Sig.Alg.ECDSA_SHA384, Sig.Opts.DETERMINISTIC)
print("SIG =", sigval)
# Verify the signature
isok = Sig.data_is_verified(sigval, msg, pubkeyfile, Sig.Alg.ECDSA_SHA384)
print("Sig.data_is_verified returns ", isok)
def test_ecc_dh_shared_secret():
print("\nTEST ECC DIFFIE-HELLMAN SHARED SECRET...")
'''
Ref: CAVS 14.1 ECC CDH Primitive (SP800 - 56A Section 5.7.1.2) Test Information for "testecccdh"
https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-Validation-Program/documents/components/ecccdhtestvectors.zip
Extract:
----------------------------------------
[P-256]
COUNT = 0
QCAVSx = 700c48f77f56584c5cc632ca65640db91b6bacce3a4df6b42ce7cc838833d287
QCAVSy = db71e509e3fd9b060ddb20ba5c51dcc5948d46fbf640dfe0441782cab85fa4ac
dIUT = 7d7dc5f71eb29ddaf80d6214632eeae03d9058af1fb6d22ed80badb62bc1a534
QIUTx = ead218590119e8876b29146ff89ca61770c4edbbf97d38ce385ed281d8a6b230
QIUTy = 28af61281fd35e2fa7002523acc85a429cb06ee6648325389f59edfce1405141
ZIUT = 46fc62106420ff012e54a434fbdd2d25ccc5852060561e68040dd7778997bd7b
--------------------------------------
'''
# Read in private key (dIUT)
prikeystr = Ecc.read_key_by_curve("7d7dc5f71eb29ddaf80d6214632eeae03d9058af1fb6d22ed80badb62bc1a534",
Ecc.CurveName.P_256)
# Compose public key from QCAVSx+y in hex form
pubkeyhex = "04" + "700c48f77f56584c5cc632ca65640db91b6bacce3a4df6b42ce7cc838833d287" \
+ "db71e509e3fd9b060ddb20ba5c51dcc5948d46fbf640dfe0441782cab85fa4ac"
pubkeystr = Ecc.read_key_by_curve(pubkeyhex, Ecc.CurveName.P_256)
# Compute shared secret
zz = Ecc.dh_shared_secret(prikeystr, pubkeystr)
print("Computed DH shared secret =", Cnv.tohex(zz))
# Compare to expected result (ZIUT)
okhex = "46fc62106420ff012e54a434fbdd2d25ccc5852060561e68040dd7778997bd7b"
print("Expected DH shared secret =", okhex)
assert (Cnv.tohex(zz).lower() == okhex.lower())
def test_ecc_dh_shared_secret_x25519():
print("\nTEST X25519 ECDH DIFFIE-HELLMAN SHARED SECRET...")
'''
// Ref: RFC7748 Section 6.1
// https://tools.ietf.org/html/rfc7748#section-6.1
Test vector:
Alice's private key, a:
77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a
Alice's public key, X25519(a, 9):
8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a
Bob's private key, b:
5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb
Bob's public key, X25519(b, 9):
de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f
Their shared secret, K:
4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742
'''
okhex = "4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742"
# NOTE: for X25519 curve keys we must specify private or public (because they are both the same length)
# Read in Alice's private key
prikeystr = Ecc.read_key_by_curve("77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a",
Ecc.CurveName.X25519, ispublic=False)
# Read in Bob's public key
pubkeystr = Ecc.read_key_by_curve("de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f",
Ecc.CurveName.X25519, ispublic=True)
print("Our private key: ", Ecc.query_key(prikeystr, "privateKey"))
print("Their public key:", Ecc.query_key(pubkeystr, "publicKey"))
# Compute shared secret
zz = Ecc.dh_shared_secret(prikeystr, pubkeystr)
print("Computed DH shared secret =", Cnv.tohex(zz))
# Compare to expected result
print("Expected DH shared secret =", okhex)
assert (Cnv.tohex(zz).lower() == okhex.lower())
# OTHER WAY AROUND
# Read in Bobs's private key
prikeystr = Ecc.read_key_by_curve("5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb",
Ecc.CurveName.X25519, ispublic=False)
# Read in Alice's public key
pubkeystr = Ecc.read_key_by_curve("8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a",
Ecc.CurveName.X25519, ispublic=True)
print("Our private key: ", Ecc.query_key(prikeystr, "privateKey"))
print("Their public key:", Ecc.query_key(pubkeystr, "publicKey"))
# Compute shared secret
zz = Ecc.dh_shared_secret(prikeystr, pubkeystr)
print("Computed DH shared secret =", Cnv.tohex(zz))
# Compare to expected result
print("Expected DH shared secret =", okhex)
assert (Cnv.tohex(zz).lower() == okhex.lower())
def test_ecc_dh_shared_secret_x448():
print("\nTEST X448 ECDH DIFFIE-HELLMAN SHARED SECRET...")
'''
// Ref: RFC7748 Section 6.2
// https://tools.ietf.org/html/rfc7748#section-6.2
Test vector:
Alice's private key, a:
9a8f4925d1519f5775cf46b04b5800d4ee9ee8bae8bc5565d498c28d
d9c9baf574a9419744897391006382a6f127ab1d9ac2d8c0a598726b
Alice's public key, X448(a, 5):
9b08f7cc31b7e3e67d22d5aea121074a273bd2b83de09c63faa73d2c
22c5d9bbc836647241d953d40c5b12da88120d53177f80e532c41fa0
Bob's private key, b:
1c306a7ac2a0e2e0990b294470cba339e6453772b075811d8fad0d1d
6927c120bb5ee8972b0d3e21374c9c921b09d1b0366f10b65173992d
Bob's public key, X448(b, 5):
3eb7a829b0cd20f5bcfc0b599b6feccf6da4627107bdb0d4f345b430
27d8b972fc3e34fb4232a13ca706dcb57aec3dae07bdc1c67bf33609
Their shared secret, K:
07fff4181ac6cc95ec1c16a94a0f74d12da232ce40a77552281d282b
b60c0b56fd2464c335543936521c24403085d59a449a5037514a879d
'''
okhex = "07fff4181ac6cc95ec1c16a94a0f74d12da232ce40a77552281d282bb60c0b56fd2464c335543936521c24403085d59a449a5037514a879d"
# Read in Alice's private key
prikeystr = Ecc.read_key_by_curve(
"9a8f4925d1519f5775cf46b04b5800d4ee9ee8bae8bc5565d498c28dd9c9baf574a9419744897391006382a6f127ab1d9ac2d8c0a598726b",
Ecc.CurveName.X448, ispublic=False)
# Read in Bob's public key
pubkeystr = Ecc.read_key_by_curve(
"3eb7a829b0cd20f5bcfc0b599b6feccf6da4627107bdb0d4f345b43027d8b972fc3e34fb4232a13ca706dcb57aec3dae07bdc1c67bf33609",
Ecc.CurveName.X448, ispublic=True)
print("Our private key: ", Ecc.query_key(prikeystr, "privateKey"))
print("Their public key:", Ecc.query_key(pubkeystr, "publicKey"))
# Compute shared secret
zz = Ecc.dh_shared_secret(prikeystr, pubkeystr)
print("Computed DH shared secret =", Cnv.tohex(zz))
# Compare to expected result
print("Expected DH shared secret =", okhex)
assert (Cnv.tohex(zz).lower() == okhex.lower())
# OTHER WAY AROUND
# Read in Bobs's private key
prikeystr = Ecc.read_key_by_curve(
"1c306a7ac2a0e2e0990b294470cba339e6453772b075811d8fad0d1d6927c120bb5ee8972b0d3e21374c9c921b09d1b0366f10b65173992d",
Ecc.CurveName.X448, ispublic=False)
# Read in Alice's public key
pubkeystr = Ecc.read_key_by_curve(
"9b08f7cc31b7e3e67d22d5aea121074a273bd2b83de09c63faa73d2c22c5d9bbc836647241d953d40c5b12da88120d53177f80e532c41fa0",
Ecc.CurveName.X448, ispublic=True)
print("Our private key: ", Ecc.query_key(prikeystr, "privateKey"))
print("Their public key:", Ecc.query_key(pubkeystr, "publicKey"))
# Compute shared secret
zz = Ecc.dh_shared_secret(prikeystr, pubkeystr)
print("Computed DH shared secret =", Cnv.tohex(zz))
# Compare to expected result
print("Expected DH shared secret =", okhex)
assert (Cnv.tohex(zz).lower() == okhex.lower())
def test_pbe():
print("\nTESTING PASSWORD-BASED ENCRYPTION (PBE)...")
password = 'password'
salt = Cnv.fromhex('78 57 8E 5A 5D 63 CB 06')
count = 2048
print("password = '" + password + "'")
print("salt = 0x" + Cnv.tohex(salt))
print("count =", count)
dklen = 24
print("dklen =", dklen)
dk = Pbe.kdf2(dklen, password, salt, count)
print("dk =", Cnv.tohex(dk))
assert Cnv.tohex(dk) == "BFDE6BE94DF7E11DD409BCE20A0255EC327CB936FFE93643"
# Same params but derive a longer key (CAUTION: never use the same salt in
# practice)
dklen = 64
print("dklen =", dklen)
dk = Pbe.kdf2(dklen, password, salt, count)
print("dk =", Cnv.tohex(dk))
assert Cnv.tohex(dk) == \
"BFDE6BE94DF7E11DD409BCE20A0255EC327CB936FFE93643C4B150DEF77511224479994567F2E9B4E3BD0DF7AEDA3022B1F26051D81505C794F8940C04DF1144"
# Use different HMAC algorithms
dklen = 24
dk = Pbe.kdf2(dklen, password, salt, count, prfalg=Pbe.PrfAlg.HMAC_SHA1)
print("dk(HMAC-SHA-1) =", Cnv.tohex(dk))
assert Cnv.tohex(dk) == "BFDE6BE94DF7E11DD409BCE20A0255EC327CB936FFE93643"
dk = Pbe.kdf2(dklen, password, salt, count, prfalg=Pbe.PrfAlg.HMAC_SHA256)
print("dk(HMAC-SHA-256) =", Cnv.tohex(dk))
assert Cnv.tohex(dk) == "97B5A91D35AF542324881315C4F849E327C4707D1BC9D322"
dk = Pbe.kdf2(dklen, password, salt, count, prfalg=Pbe.PrfAlg.HMAC_SHA224)
print("dk(HMAC-SHA-224) =", Cnv.tohex(dk))
assert Cnv.tohex(dk) == "10CFFEDFB13503519969151E466F587028E0720B387F9AEF"
def test_pfx():
print("\nTESTING PFX (PKCS#12) FILE FUNCTIONS...")
pfxfile = "bob1.pfx"
certlist = "BobRSASignByCarl.cer"
prikeyfile = "BobPrivRSAEncrypt.p8e"
n = Pfx.make_file(pfxfile, certlist, prikeyfile, 'password', "Bob's ID")
assert (0 == n)
print("Created new PKCS#12 file:", pfxfile)
print("Asn1.Type(" + pfxfile + ") -->", Asn1.type(pfxfile))
print("Check signature is valid against password...")
isvalid = Pfx.sig_is_valid(pfxfile, 'password')
print("isvalid=", isvalid)
assert (isvalid)
print("Use the wrong password...")
isvalid = Pfx.sig_is_valid(pfxfile, 'passwordXXX')
print("isvalid=", isvalid)
assert (not isvalid)
print("Extract private key file from Pfx...")
newp8file = "NewBobPrivRsa.p8e"
n = Rsa.get_privatekey_from_pfx(newp8file, pfxfile)
assert (n > 0)
print("Created new PKCS#8 file:", newp8file)
print("Asn1.Type(" + newp8file + ") -->", Asn1.type(newp8file))
def test_pem():
print("\nTESTING PEM/BINARY FILE CONVERSIONS...")
binfile = "smallca.cer"
pemfile = "smallca.pem"
print("Create a PEM-format CERTIFICATE file from binary file...")
print("Binary file:", binfile)
n = Pem.from_binfile(pemfile, binfile, "CERTIFICATE", Pem.EOL.UNIX)
assert (0 == n)
print("Created file:", pemfile)
print("Check certificate thumbprints...")
thumb_bin = X509.cert_thumb(binfile)
thumb_pem = X509.cert_thumb(pemfile)
print("X509.cert_thumb(" + binfile + ")=" + thumb_bin)
print("X509.cert_thumb(" + pemfile + ")=" + thumb_pem)
assert (thumb_bin == thumb_pem)
print("Convert PEM to binary...")
binfile2 = "smallca-copy.bin"
n = Pem.to_binfile(binfile2, pemfile)
assert (0 == n)
print("Created file:", binfile2)
print("Binary files should be identical...")
hash_bin1 = Hash.hex_from_file(binfile)
hash_bin2 = Hash.hex_from_file(binfile2)
print("Hash.hex_from_file(" + binfile + ")=\t" + hash_bin1)
print("Hash.hex_from_file(" + binfile2 + ")=\t" + hash_bin2)
assert (hash_bin1 == hash_bin2)
# Note that the *hash* of the PEM file is not the same as the hash of the binary,
# but the X509.cert_thumb() is the same for both.
def test_cms_envdata():
print("\nTESTING CMS ENV-DATA...")
print("Creating an enveloped-data message for Bob and Carl, using file-->file mode")
# Create a file
mytext = 'This is some sample content.'
myfile = "mycontent.txt"
write_text_file(myfile, mytext)
envdatafile = 'cms2bobandcarl.p7m'
certlist = "BobRSASignByCarl.cer;CarlRSASelf.cer"
n = Cms.make_envdata(envdatafile, myfile, certlist)
print("Cms.make_envdata() returns " + str(n) + " (expected 2 = # of recipients)")
assert (n > 0)
_dump_and_print_asn1(envdatafile)
print("Asn1.type('" + envdatafile + "')-->" + Asn1.type(envdatafile))
# Query this CMS object file
fname = envdatafile
query = "recipientIssuerName"
res = Cms.query_envdata(envdatafile, query)
print("Cms.query_envdata(" + fname + ", " + query + "):", res)
query = "iv"
res = Cms.query_envdata(envdatafile, query)
print("Cms.query_envdata(" + fname + ", " + query + "):", res)
print("Bob reads the message, outputting to a new file")
outputfile = "bobsdata.txt"
# Bob reads in his private key to a secure "internal" key string
prikeystr = Rsa.read_private_key('BobPrivRSAEncrypt.p8e', 'password')
n = Cms.read_envdata_to_file(outputfile, envdatafile, prikeystr)
print("Cms.read_envdata_to_file() returns " + str(n) + " (expected 0)")
assert (0 == n)
_dump_file(outputfile)
# Check we got the same as we started
assert (read_text_file(outputfile) == mytext)
print("\nDo the same but using string-->file mode...")
print("DATA:", mytext)
envdatafile = 'cms2bobandcarl1.p7m'
n = Cms.make_envdata_from_string(envdatafile, mytext, certlist)
print("Cms.make_envdata_from_string() returns " + str(n) + " (expected 2 = # of recipients)")
assert (n > 0)
print("Asn1.type('" + envdatafile + "')-->" + Asn1.type(envdatafile))
s = Cms.read_envdata_to_string(envdatafile, prikeystr)
print(s)
print("\nDo the same but using bytes-->file mode...")
mydata = "Olá mundo".encode()
print("DATA:", mydata)
envdatafile = 'cms2bobandcarl2.p7m'
n = Cms.make_envdata_from_bytes(envdatafile, mydata, certlist)
print("Cms.make_envdata_from_string() returns " + str(n) + " (expected 2 = # of recipients)")
assert (n > 0)
print("Asn1.type('" + envdatafile + "')-->" + Asn1.type(envdatafile))
s = Cms.read_envdata_to_string(envdatafile, prikeystr)
print("Cms.read_envdata_to_string=", s)
b = Cms.read_envdata_to_bytes(envdatafile, prikeystr)
print("Cms.read_envdata_to_bytes=", b)
# clean up
prikeystr = None
def test_smime():
print("\nTESTING S/MIME...")
print("First create an enveloped-data message for Bob and Carl...")
# Create a file
mytext = 'This is some sample content.'
myfile = "mycontent.txt"
write_text_file(myfile, mytext)
envdatafile = 'cms2bobandcarl.p7m'
certlist = "BobRSASignByCarl.cer;CarlRSASelf.cer"
n = Cms.make_envdata(envdatafile, myfile, certlist)
print("Cms.make_envdata() returns " + str(n) + " (expected 2 = # of recipients)")
assert (n > 0)
print("Asn1.type('" + envdatafile + "')-->" + Asn1.type(envdatafile))
print("Now wrap in S/MIME headers...")
smimefile = 'cms2bobandcarl-smime-env.txt'
n = Smime.wrap(smimefile, envdatafile)
print("Smime.wrap() returns ", n, " (expected +ve)")
_dump_file(smimefile)
print("Query this S/MIME entity for info...")
query = "content-type"
r = Smime.query(smimefile, query)
print("Smime.query('%s')=[%s]" % (query, r))
query = "smime-type"
r = Smime.query(smimefile, query)
print("Smime.query('%s')=[%s]" % (query, r))
print("Extract the original CMS env-data object in base64")
extractedfile = 'cms2bobandcarl-extracted.txt'
n = Smime.extract(extractedfile, smimefile, Smime.Opts.ENCODE_BASE64)
print("Smime.extract() returns ", n, " (expected +ve)")
assert n > 0
_dump_file(extractedfile)
# Read base64 data into a string then analyze
s = read_text_file(extractedfile)
print("Asn1.type('" + extractedfile + "')-->" + Asn1.type(s))
def test_cms_sigdata():
print("\nTESTING CMS SIG-DATA...")
print("Create an signed-data message from Alice, using file-->file mode")
# Create a file
myfile = "mycontent.txt"
mytext = 'This is some sample content.'
write_text_file(myfile, mytext)
# Alice reads in her private key to a secure "internal" key string
prikeystr = Rsa.read_private_key('AlicePrivRSASign.p8e', 'password')
certlist = "AliceRSASignByCarl.cer"
sigdatafile = 'cms_signedbyalice.p7m'
n = Cms.make_sigdata(sigdatafile, myfile, certlist, prikeystr)
print("Cms.make_sigdata() returns " + str(n) + " (expected 0)")
assert (n == 0)
print("Asn1.type('" + sigdatafile + "')-->" + Asn1.type(sigdatafile))
print("\nQuery this CMS object file...")
fname = sigdatafile
query = "signatureAlgorithm"
res = Cms.query_sigdata(sigdatafile, query)
print("Cms.query_sigdata(" + fname + ", " + query + "):", res)
query = "CountOfSignerInfos"
res = Cms.query_sigdata(sigdatafile, query)
print("Cms.query_sigdata(" + fname + ", " + query + "):", res)
print("\nRead in the content from the signed-data file...")
outputfile = "alicesdata.txt"
n = Cms.read_sigdata_to_file(outputfile, sigdatafile)
print("Cms.read_sigdata_to_file() returns " + str(n) + " (expected 0)")
assert (0 == n)
_dump_file(outputfile)
print("\nVerify the signature in the sigdata file...")
isok = Cms.verify_sigdata(sigdatafile)
print("Cms.verify_sigdata() returns", isok)
assert isok
print("\nUse string-->file mode...")
print("DATA:", mytext)
sigdatafile1 = 'cms_signedbyalice1.p7m'
n = Cms.make_sigdata_from_string(sigdatafile1, mytext, certlist, prikeystr)
print("Cms.make_sigdata_from_string() returns " + str(n) + " (expected 0)")
assert (n == 0)
print("Asn1.type('" + sigdatafile1 + "')-->" + Asn1.type(sigdatafile1))
s = Cms.read_sigdata_to_string(sigdatafile)
print(s)
print("signed-data files should be identical...")
print("SHA1('" + sigdatafile + "')=\t" + Hash.hex_from_file(sigdatafile))
print("SHA1('" + sigdatafile1 + "')=\t" + Hash.hex_from_file(sigdatafile1))
assert (Hash.hex_from_file(sigdatafile) == Hash.hex_from_file(sigdatafile1))
print("\nUse bytes-->file mode...")
mydata = "Olá mundo".encode()
print("DATA:", mydata)
sigdatafile1 = 'cms_signedbyalice2.p7m'
n = Cms.make_sigdata_from_bytes(sigdatafile1, mydata, certlist, prikeystr)
print("Cms.make_sigdata_from_bytes() returns " + str(n) + " (expected 0)")
assert (n == 0)
print("Asn1.type('" + sigdatafile1 + "')-->" + Asn1.type(sigdatafile1))
b = Cms.read_sigdata_to_bytes(sigdatafile1)
print(b)
print("\nMake a 'detached signature' signed-data object using the message digest of the content...")
hexdigest = Hash.hex_from_string(mytext, Hash.Alg.SHA256)
print("SHA256('%s')=%s" % (mytext, hexdigest))
sigdatafile_det = 'cms_signedbyalice_det.p7m'
n = Cms.make_detached_sig(
sigdatafile_det, hexdigest, certlist, prikeystr, sigalg=Cms.SigAlg.RSA_PSS_SHA256)
print("Cms.make_detached_sig() returns " + str(n) + " (expected 0)")
assert (n == 0)
print("Verify the signature in the detached sigdata file against the digest value...")
print("First try verifying against the eContent (which is missing)...")
try:
isok = Cms.verify_sigdata(sigdatafile_det)
except PKIError as e:
print("Woops! PKIError:", e)
print("Now pass the digest we expect...")
isok = Cms.verify_sigdata(sigdatafile_det, hexdigest=hexdigest)
print("Cms.verify_sigdata(file,hexdigest) returns", isok)
assert isok
print("Query the signature and digest algorithms used in our signed-data object (expecting rsaPSS/sha256)")
query = "signatureAlgorithm"
s = Cms.query_sigdata(sigdatafile_det, query)
print(query + "=[" + s + "]")
query = "digestAlgorithm"
s = Cms.query_sigdata(sigdatafile_det, query)
print(query + "=[" + s + "]")
print("\nCreate signed-data from a pre-computed signature value...")
# Example 4.2 from [SMIME-EX]
# Data to be signed
datahex = ("54:68:69:73:20:69:73:20:73:6f:6d:65:20:73:61:6d"
"70:6c:65:20:63:6f:6e:74:65:6e:74:2e")
data = Cnv.fromhex(datahex)
print("DATA:", Cnv.tohex(data))
# Signature value generated by smartcard using rsa-sha1 (our default)
sighex = ("2F:23:82:D2:F3:09:5F:B8:0C:58:EB:4E:9D:BF:89:9A"
"81:E5:75:C4:91:3D:D3:D0:D5:7B:B6:D5:FE:94:A1:8A"
"AC:E3:C4:84:F5:CD:60:4E:27:95:F6:CF:00:86:76:75"
"3F:2B:F0:E7:D4:02:67:A7:F5:C7:8D:16:04:A5:B3:B5"
"E7:D9:32:F0:24:EF:E7:20:44:D5:9F:07:C5:53:24:FA"
"CE:01:1D:0F:17:13:A7:2A:95:9D:2B:E4:03:95:14:0B"
"E9:39:0D:BA:CE:6E:9C:9E:0C:E8:98:E6:55:13:D4:68"
"6F:D0:07:D7:A2:B1:62:4C:E3:8F:AF:FD:E0:D5:5D:C7")
sig = Cnv.fromhex(sighex)
print("SIG:", Cnv.tohex(sig))
sigdatafile2 = 'cms_signedbyalice2.p7m'
n = Cms.make_sigdata_from_sigvalue(sigdatafile2, sig, data, certlist)
print("Cms.make_sigdata_from_sigvalue() returns " + str(n) + " (expected 0)")
# Compare resulting file to expected `4.2.bin`
print("SHA1(outputfile)=", Hash.hex_from_file(sigdatafile2))
print("SHA1('4.2.bin' )=", Hash.hex_from_file('4.2.bin'))
assert (Hash.hex_from_file(sigdatafile2) == Hash.hex_from_file('4.2.bin'))
def test_cms_comprdata():
print("\nTESTING CMS COMPRESSED-DATA...")
print("Creating an compressed-data object...")
basefile = "sonnets.txt"
compfile = 'sonnets.p7z'
print("INPUT:", basefile, os.path.getsize(basefile), "bytes")
n = Cms.make_comprdata(compfile, basefile)
print("Cms.make_comprdata() returns " + str(n) + " (expected 0)")
assert (n == 0)
print("COMPR:", compfile, os.path.getsize(compfile), "bytes")
print("Asn1.type('" + compfile + "')-->" + Asn1.type(compfile))
print("Reading an compressed-data object...")
chkfile = "sonnets-unCompr.txt"
n = Cms.read_comprdata(chkfile, compfile)
print("Cms.read_comprdata() returns " + str(n) + " (expected +ve)")
assert (n > 0)
print("UNCPR:", chkfile, os.path.getsize(chkfile), "bytes")
# Compare base file to final uncompressed
print("SHA1(basefile)=", Hash.hex_from_file(basefile))
print("SHA1(uncmfile)=", Hash.hex_from_file(chkfile))
assert (Hash.hex_from_file(basefile) == Hash.hex_from_file(chkfile))
print("Read with no-inflate option...")
chkfile = "sonnets-noinflate.txt"
n = Cms.read_comprdata(chkfile, compfile, Cms.ComprDataOpts.NO_INFLATE)
assert (n > 0)
print("NOINF:", chkfile, os.path.getsize(chkfile), "bytes")
def test_sig_rsa():
print("\nTESTING SIG FUNCTIONS USING Rsa...")
print("Sign the string 'abc' using Alice's private RSA key...")
keyfile = "AlicePrivRSASign.p8e"
password = "password" # !!!
alg = Sig.Alg.RSA_SHA1
# Sign data
data = b"abc"
sig = Sig.sign_data(data, keyfile, password, alg)
print("sign_data: ", sig)
# Sign the digest value of the data
digest = Cnv.fromhex("a9993e364706816aba3e25717850c26c9cd0d89d")
sig1 = Sig.sign_digest(digest, keyfile, password, alg)
print("sign_digest:", sig1)
assert (sig1 == sig)
# Encode the signature differently
print("Different encodings...")
sig2 = Sig.sign_data(data, keyfile, password, alg,
encoding=Sig.Encoding.BASE64URL)
print("sign_data: ", sig2)
sig3 = Sig.sign_data(data, keyfile, password, alg,
encoding=Sig.Encoding.HEX)
print("sign_data: ", sig3)
print("Verify the signature over the data")
cert = "AliceRSASignByCarl.cer"
isok = Sig.data_is_verified(sig, data, cert, alg)
print("Sig.data_is_verified() returns", isok)
assert (isok)
print("Use the wrong cert...")
wrongcert = "BobRSASignByCarl.cer"
isok = Sig.data_is_verified(sig, data, wrongcert, alg)
print("Sig.data_is_verified() returns", isok, "(expected False)")
assert (not isok)
print("Verify the signature over the message digest value")
isok = Sig.digest_is_verified(sig, digest, cert, alg)
print("Sig.digest_is_verified() returns", isok)
assert (isok)
print("Sign a file containing 'abc' using Alice's private RSA key...")
datafile = "abc.txt"
write_text_file(datafile, 'abc')
sig = Sig.sign_file(datafile, keyfile, password, alg)
print("sign_file: ", sig)
# Verify it
isok = Sig.file_is_verified(sig, datafile, cert, alg)
print("Sig.file_is_verified() returns", isok)
assert (isok)
def test_sig_ecc():
print("\nTESTING SIG FUNCTIONS USING Ecc...")
# Ref: [RFC6979] "Deterministic Usage of the DSA and ECDSA"
# A.2.3. ECDSA, 192 Bits (Prime Field)
# Read in private key using (hex,curvename) form
keyhex = "6FAB034934E4C0FC9AE67F5B5659A9D7D1FEFD187EE09FD4"
curvename = Ecc.CurveName.P_192
print("KEYHEX:", keyhex)
print("CURVE:", curvename)
keystr = Ecc.read_key_by_curve(keyhex, curvename)
print("NBITS=", Ecc.query_key(keystr, "keyBits"))
# Sign data
alg = Sig.Alg.ECDSA_SHA1
data = b"test"
sig = Sig.sign_data(data, keystr, "", alg, opts=Sig.Opts.DETERMINISTIC, encoding=Sig.Encoding.HEX)
print("SIG:", sig)
print("Verify the signature over the data...")
# Derive the EC public key from the private key
pubkeystr = Ecc.publickey_from_private(keystr)
# And use it to verify the signature
isok = Sig.data_is_verified(sig, data, pubkeystr, alg)
print("Sig.data_is_verified() returns", isok)
assert (isok)
def test_x509_ecc():
print("\nTESTING X509 CERT FUNCTIONS USING Ecc...") # New in v11.3
# Use an EC key we made earlier
cakeyfile = 'ecprivkey.p8' # in pkiPythonTestFiles.zip
password = 'password'
cacert = 'myca_Ecc.cer'
dn = "O=My Company;OU=My Org;E=me@org.com;L=Perth;ST=WA;C=AU;CN=Test Example"
extns = "serialNumber=#x00F3ED4B1754C18AA5;notBefore=2017-09-19T08:09:06Z;notAfter=2027-09-17T08:09:06Z"
# Make a new self-signed certificate...
# (just for testing purposes we use the deterministic method for ECDSA, so we always get the same result)
print("About to create new certificate:", cacert)
r = X509.make_cert_self(cacert, cakeyfile, password, 0, 0, dn, extns, sigalg=X509.SigAlg.ECDSA_SHA256,
opts=X509.Opts.VERSION1 | X509.Opts.DETERMINISTIC)
assert (0 == r)
# Query this new cert
certname = cacert
print("serialNumber:", X509.query_cert(certname, "serialNumber"))
print("issuerName:", X509.query_cert(certname, "issuerName"))
print("signatureAlgorithm:", X509.query_cert(certname, "signatureAlgorithm"))
print("hashAlgorithm:", X509.query_cert(certname, "hashAlgorithm"))
print("subjectPublicKeyAlgorithm:", X509.query_cert(certname, "subjectPublicKeyAlgorithm"))
# Dump its details (new fn in v11.3)
dump = X509.text_dump_tostring(certname)
print("FILE:", certname)
print(dump)
# Verify this new certificate using itself
isok = X509.cert_is_verified(cacert, cacert)
print("X509.cert_is_verified({0}, {1}) returns {2}".format(cacert, cacert, isok))
assert (isok)
# Read in the EC public key value from the X.509 certificate (new in v11.3)
# (just to show we can!)
pubkey = Ecc.read_public_key(cacert)
assert (len(pubkey) > 0)
print("Public key size:", Ecc.query_key(pubkey, "keyBits"), "bits")
# Generate a new EC key pair for an end user
userprikeyfile = 'myuser_prikey.p8'
userpubkeyfile = 'myuser_pubkey.pub'
r = Ecc.make_keys(userpubkeyfile, userprikeyfile, Ecc.CurveName.P_224, "password")
print("Created new user key pair:", userprikeyfile, "&", userpubkeyfile)
assert (0 == r)
# Create a new end-user certificate using EC key we just made
usercert = 'myuser_Ecc.cer'
dn = "CN=Olá mundo;OU=Using ECC_P224"
print("About to create new certificate:", usercert)
r = X509.make_cert(usercert, cacert, userpubkeyfile, cakeyfile, password, 0x224, 5, dn,
sigalg=X509.SigAlg.ECDSA_SHA224, opts=X509.Opts.UTF8)
assert (0 == r)
# Query this new cert
certname = usercert
print("serialNumber:", X509.query_cert(certname, "serialNumber"))
print("issuerName:", X509.query_cert(certname, "issuerName"))
# User name is encoded in UTF-8: default is to display in hex
print("subjectName:", X509.query_cert(certname, "subjectName"))
# Display as latin-1 string properly in IDE
# -- No longer an issue with Python 3!!
# print("subjectName:", X509.query_cert(certname, "subjectName", X509.Opts.LATIN1).decode('iso-8859-1'))
print("signatureAlgorithm:", X509.query_cert(certname, "signatureAlgorithm"))
print("hashAlgorithm:", X509.query_cert(certname, "hashAlgorithm"))
print("subjectPublicKeyAlgorithm:", X509.query_cert(certname, "subjectPublicKeyAlgorithm"))
# Verify this new certificate using CA's cert
isok = X509.cert_is_verified(usercert, cacert)
print("X509.cert_is_verified({0}, {1}) returns {2}".format(usercert, cacert, isok))
assert (isok)
# Verify the path
certlist = usercert + ";" + cacert
isok = X509.cert_path_is_valid(certlist)
print("X509.cert_path_is_valid({0}) returns {1}".format(certlist, isok))
assert (isok)
def test_asn1_dumptostring():
print("\nTESTING ASN.1 TEXT DUMP TO STRING...") # New in v11.3
fname = r"C:\!Data\Crypto\X509\x509cat.Asn1.dat"
s = Asn1.text_dump_tostring(fname)
# File is large! Just dump the first part
print(s[:378])
def test_compress():
print("\nTEST ZLIB COMPRESSION....")
message = b"hello, hello, hello. This is a 'hello world' message for the world, repeat, for the world."
print("MSG:", message)
comprdata = Compr.compress(message)
print("Compressed = (0x)" + Cnv.tohex(comprdata))
print("Compressed %d bytes to %d" % (len(message), len(comprdata)))
# Now uncompresss (inflate)
uncomprdata = Compr.uncompress(comprdata)
print("Uncompressed = '" + str(uncomprdata) + "'")
assert (uncomprdata == message)
def test_aead():
print("\nTEST AES-GCM AUTHENTICATED ENCRYPTION....")
# GCM Test Case #03 (AES-128)
key = Cnv.fromhex("feffe9928665731c6d6a8f9467308308")
iv = Cnv.fromhex("cafebabefacedbaddecaf888")
pt = Cnv.fromhex(
"d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255")
okhex = "42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091473f59854d5c2af327cd64a62cf35abd2ba6fab4"
print("KY =", Cnv.tohex(key))
print("IV =", Cnv.tohex(iv))
print("PT =", Cnv.tohex(pt))
# Do the business
ct = Cipher.encrypt_aead(pt, key, iv, Cipher.AeadAlg.AES_128_GCM)
print("CT =", Cnv.tohex(ct))
print("OK =", okhex)
assert (okhex.lower() == Cnv.tohex(ct).lower())
# Decrypt, passing IV as an argument
dt = Cipher.decrypt_aead(ct, key, iv, Cipher.AeadAlg.AES_128_GCM)
print("DT =", Cnv.tohex(dt))
assert (Cnv.tohex(pt) == Cnv.tohex(dt))
print("Repeat but prepend IV to output..")
ct = Cipher.encrypt_aead(pt, key, iv, Cipher.AeadAlg.AES_128_GCM, opts=Cipher.Opts.PREFIXIV)
print("IV|CT =", Cnv.tohex(ct))
# Decrypt, IV is prepended to ciphertext
dt = Cipher.decrypt_aead(ct, key, None, Cipher.AeadAlg.AES_128_GCM, opts=Cipher.Opts.PREFIXIV)
print("DT =", Cnv.tohex(dt))
assert (Cnv.tohex(pt) == Cnv.tohex(dt))
def test_aead_chapoly():
print("\nTEST AEAD CHACHA20POLY1305....")
print("RFC8439 ChaCha20_Poly1305 Sunscreen test with AAD")
key = Cnv.fromhex("808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F")
iv = Cnv.fromhex("070000004041424344454647")
aad = Cnv.fromhex("50515253C0C1C2C3C4C5C6C7")
pt = Cnv.fromhex(
"4C616469657320616E642047656E746C656D656E206F662074686520636C617373206F66202739393A204966204920636F756C64206F6666657220796F75206F6E6C79206F6E652074697020666F7220746865206675747572652C2073756E73637265656E20776F756C642062652069742E")
okhex = "d31a8d34648e60db7b86afbc53ef7ec2a4aded51296e08fea9e2b5a736ee62d63dbea45e8ca9671282fafb69da92728b1a71de0a9e060b2905d6a5b67ecd3b3692ddbd7f2d778b8c9803aee328091b58fab324e4fad675945585808b4831d7bc3ff4def08e4b7a9de576d26586cec64b61161ae10b594f09e26a7e902ecbd0600691"
print("KY =", Cnv.tohex(key))
print("IV =", Cnv.tohex(iv))
print("AD =", Cnv.tohex(aad))
print("PT =", Cnv.tohex(pt))
# Do the business
ct = Cipher.encrypt_aead(pt, key, iv, Cipher.AeadAlg.CHACHA20_POLY1305, aad=aad)
print("CT =", Cnv.tohex(ct))
print("OK =", okhex)
assert (okhex.lower() == Cnv.tohex(ct).lower())
dt = Cipher.decrypt_aead(ct, key, iv, Cipher.AeadAlg.CHACHA20_POLY1305, aad=aad)
print("DT =", Cnv.tohex(dt))
print(f"DT ='{dt.decode()}'")
assert (Cnv.tohex(pt) == Cnv.tohex(dt))
# Again but prefix the IV to the ciphertext
print(f"Prefix the IV ({Cnv.tohex(iv)}) to the CT...")
ct = Cipher.encrypt_aead(pt, key, iv, Cipher.AeadAlg.CHACHA20_POLY1305, aad=aad, opts=Cipher.Opts.PREFIXIV)
print("CT =", Cnv.tohex(ct))
dt = Cipher.decrypt_aead(ct, key, iv, Cipher.AeadAlg.CHACHA20_POLY1305, aad=aad, opts=Cipher.Opts.PREFIXIV)
print("DT =", Cnv.tohex(dt))
assert (Cnv.tohex(pt) == Cnv.tohex(dt))
def test_readcertstring():
print("\nTEST READ CERT STRING FROM P7CHAIN AND Pfx....")
# Input is a P7 chain file in PEM format
# bob.p7b (contains 2 X.509 certs: BobRSA and CarlRSA)
strp7 = """-----BEGIN PKCS7-----
MIIERQYJKoZIhvcNAQcCoIIENjCCBDICAQExADALBgkqhkiG9w0BBwGgggQaMIICJzCCAZCgAwIB
AgIQRjRrx4AAVrwR024uzV1x0DANBgkqhkiG9w0BAQUFADASMRAwDgYDVQQDEwdDYXJsUlNBMB4X
DTk5MDkxOTAxMDkwMloXDTM5MTIzMTIzNTk1OVowETEPMA0GA1UEAxMGQm9iUlNBMIGfMA0GCSqG
SIb3DQEBAQUAA4GNADCBiQKBgQCp4WeYPznVX/Kgk0FepnmJhcg1XZqRW/sdAdoZcCYXD72lItA1
hW16mGYUQVzPt7cIOwnJkbgZaTdt+WUee9mpMySjfzu7r0YBhjY0MssHA1lS/IWLMQS4zBgIFEjm
Txz7XWDE4FwfU9N/U9hpAfEF+Hpw0b6Dxl84zxwsqmqn6wIDAQABo38wfTAMBgNVHRMBAf8EAjAA
MA4GA1UdDwEB/wQEAwIFIDAfBgNVHSMEGDAWgBTp4JAnrHggeprTTPJCN04irp44uzAdBgNVHQ4E
FgQU6PS4Z9izlqQq8xGqKdOVWoYWtCQwHQYDVR0RBBYwFIESQm9iUlNBQGV4YW1wbGUuY29tMA0G
CSqGSIb3DQEBBQUAA4GBAHuOZsXxED8QIEyIcat7QGshM/pKld6dDltrlCEFwPLhfirNnJOIh/uL
t359QWHh5NZt+eIEVWFFvGQnRMChvVl52R1kPCHWRbBdaDOS6qzxV+WBfZjmNZGjOd539OgcOync
f1EHl/M28FAK3Zvetl44ESv7V+qJba3JiNiPzyvTMIIB6zCCAVSgAwIBAgIQRjRrx4AAVrwR024u
n/JQIDANBgkqhkiG9w0BAQUFADASMRAwDgYDVQQDEwdDYXJsUlNBMB4XDTk5MDgxODA3MDAwMFoX
DTM5MTIzMTIzNTk1OVowEjEQMA4GA1UEAxMHQ2FybFJTQTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw
gYkCgYEA5Ev/GLgkV/R3/25ze5NxXLwzGpKSciPYQUbQzRE6BLOOr4KdvVEeF3rydiwrhjmnvdeN
GlPs5ADV6OyiNrHt4lDiMgmKP5+ZJY+4Tqu5fdWWZdoWoMW+Dq5EW+9e9Kcpy4LdrETpqpOUKQ74
GNbIV17ydsTyEWA4uRs8HZfJavECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E
BAMCAYYwHQYDVR0OBBYEFOngkCeseCB6mtNM8kI3TiKunji7MA0GCSqGSIb3DQEBBQUAA4GBALee
1ATT7Snk/4mJFS5M2wzwSA8yYe7EBOwSXS3/D2RZfgrD7Rj941ZAN6cHtfA4EmFQ7e/dP+MLuGGl
pJs85p6cVJq2ldbabDu1LUU1nUkBdvq5uTH5+WsSU6D1FGCbfco+8lNrsDdvreZ019v6WuoUQWNd
zb7IDsHaao1TNBgCMQA=
-----END PKCS7-----"""
# Get count of certs in P7 chain
ncerts = X509.get_cert_count_from_p7(strp7)
print("ncerts in P7 chain =", ncerts)
for i in range(1, ncerts + 1):
certstr = X509.read_cert_string_from_p7chain(strp7, i)
print("CER:", certstr[:80], "...", certstr[-10:])
subjectname = X509.query_cert(certstr, "subjectName")
print("subjectName:", subjectname)
# Input is a PFX file in PEM format
# bob.pfx (password="password")
strpfx = """-----BEGIN PKCS12-----
MIIGhAIBAzCCBkoGCSqGSIb3DQEHAaCCBjsEggY3MIIGMzCCAv8GCSqGSIb3DQEHBqCCAvAwggLsAgEAMIIC5QYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQYwDgQIawU
AVTFvAiECAggAgIICuNwEuFcRnZamZyMyIn+vH+wC5BVUtZAWNrlIqToezF7cYqt/18+HXB/46nllz+qUD3Dv9rS78MnPeAM47afFRTricHsiOpE+2eXf32lxduoF5+
CLS3S7TAhRUMp2Fh18LlukzK9lY67BGfU9Y3yCukTmwVXqe49dkj8y9JjVJhXnoc2c7eOk3o5RjXHFsAMHwirqdsESHstrDZYLMVGw5HnAamY7zQd8WUpIweAFaEDLJ
fyzqY1/LTL/txvZ9VQ/B/36HKyEpoIvuH6iOCBkebpJwWSkkffuVFbUfMLguMztL/sf+jE2NiuljSBJ9pTNsZziZWERb6CxZH0a2xkkBTciXM5Dl5efWL0GmBg+aJSI
yh+Gw5W8Q7gmnH6H9myszvW9uYv/epwCbIpHd0dRHPbL3fR4KGhFexq24tAG86tDqPKb6H6n0lSA+Oq46SwZ00xIFpVcFaO/8yVqf6+JRDGoZ55aAZF6OCi7R1GvI+6
pzz37pvP7SWfqVSuXCTNQq9uKw97SH5YftQ9hkELQ4vHCjFh4UJSBUCZgDtqR1uB/+44H5UpP8KvbETaOFJszMxsqXBMqc1uEODSNg+EHEx+yg7Bx1CcNrm+6rtThC4
9+ow18HDMxbn3lAw1ooblANvSzR4YTt68N/4dtwROOdXjwKzyg03qWK2sJaiH5LzbB5MMmrdAChb9dLoRKBN2LREob7KRKEs6v51IW1yq4UCwSmpP+RbchZwIoKVXx/
MYKjVqzGfZAgBRpXEq/KH/8R+ttFPKdab2GAEjd7hIOmetp5einQmK4C7JYE6Uyabf1IImtVhBw2dGU3GiM2zSIGqCx3bmYETZheMTAV9MMVUYe8gQeEpbXM4GAnwX0
wpS0aYapzGeA/62X2nFh21eRHVzUcf0miXVvyOy6a1vj6O6N5F1jVaCV3jCCAywGCSqGSIb3DQEHAaCCAx0EggMZMIIDFTCCAxEGCyqGSIb3DQEMCgECoIICpjCCAqI
wHAYKKoZIhvcNAQwBAzAOBAjw/dx4SlLcWwICCAAEggKALm91I8gYuPpRTCSn5pN4OQBLbI6jSW+9FGeNYvOy/+Pt3Oq0i15ZXZZez7dP8rdb0tmTCSZwVPIwtJRKxY
UNaTppUTWZhXhnmeTMtSZpFuKmo6UhW8lGUcg45sO5UKUtdH0/UgewaSUfV4L06vp4j7Fugwbp666seJJ/9vQwMAxoqj0blxNNmASAcW7yj/lA2/p4KuGlnGkv4MSW5
ViH7T24VeFXTzyFFR7UR1Nw9Blr5jdr7b2rZSdTj0GeHZ/L3FksFWJocl8PEEL4ZdVscbvO+l7vtbeBz0y9TDr/HUwt2tfqXgjckVVoJhmsczJXrG5Ai+brKnGQ7R5u
IpIsqd9O6EpG68VMMGA5iSKsLYtibieqom8mRO00sFiQharxONEdveY+3O98nG6xzHlaBdNbxVo38Y+4LK6Gc81dUWYwss3ajdiJWe0+TYQjMPF72eWctcQAoTxITpd
/j6rD7EmvLVyPIR46L4w6Gb/uz5G1T1UiLoh9luM1nRKKICyo2XllZDNO0msaub7DH1xzJzEy2OT9cwChqYfKKeWEE2BWL699fmq5RMCbIQVtE2bJDP8obu9j6HLskC
iZcJm6nC7IKS1pQ2BA/JJVKxC8ADuLOAOdicWquDd8MWL5a9HpXd5TtUlfiRecTw8IRozTLaoDVlhaYNGPzwkjL9zZ+Up5Uy6HHXMDb0aD0fgvMqdAspB1+Xlt2RgP6
CnEH2hwQqGFoA8TtijeS+DtdMy8BxJ7g1fiEH0+4UISl1vymjPI1MJCI1VlFLvpjZvKHluwjgp1SHk3tFRJLJ8a/eApvmscKXSlxcYz+5Bv8dxPGdhO/KOLQS7XZ4a8
VSg977WS1jFYMCMGCSqGSIb3DQEJFTEWBBRj8EbS3XBC5R/cJqUR73yB6mItizAxBgkqhkiG9w0BCRQxJB4iAEIAbwBiACcAcwAgAGYAcgBpAGUAbgBkAGwAeQAgAEk
ARDAxMCEwCQYFKw4DAhoFAAQUaHSMUJ415FfKGv3cZpwloKDmqgYECAreM3EkHVjCAgIIAA==
-----END PKCS12-----"""
certstr = X509.read_cert_string_from_pfx(strpfx, "password")
print("CER:", certstr[:80], "...", certstr[-10:])
subjectname = X509.query_cert(certstr, "subjectName")
print("subjectName:", subjectname)
# NEW IN [v12.3]
def test_cipher_prefix():
print("\nENCRYPT WITH PREFIXED IV xmlenc#aes128-cbc...")
plain = "<encryptme>hello world</encryptme>"
key = Cnv.fromhex("6162636465666768696A6B6C6D6E6F70")
iv = Rng.bytestring(Cipher.blockbytes(Cipher.Alg.AES128))
print("PT='", plain, "'", sep='')
pt = plain.encode()
print("HEX(PT)=", Cnv.tohex(pt), sep='')
print("KEY=", Cnv.tohex(key), sep='')
print("IV=", Cnv.tohex(iv), sep='')
# Encrypt and prepend IV before ciphertext
ct = Cipher.encrypt(pt, key, iv, "aes128/cbc", opts=Cipher.Opts.PREFIXIV)
print("IV|CT=", Cnv.tohex(ct), sep='')
# Encode in base64
ciphervalue = Cnv.tobase64(ct)
# Output in XML (NB will be different each time)
print("<CipherValue>{0}</CipherValue>".format(ciphervalue))
# ---------------
# PART 2 - decrypt
print("DECRYPTING...")
# Decode from base64
ct = Cnv.frombase64(ciphervalue)
print("IV|CT=", Cnv.tohex(ct), sep='')
# Decrypt. Note that IV is not specified when decrypting with a prefixed IV
dt = Cipher.decrypt(ct, key, None, "aes128/cbc", opts=Cipher.Opts.PREFIXIV)
# Display plaintext
print("DT=", Cnv.tohex(dt), sep='')
print("DT='", dt.decode(), "'", sep='')
assert (Cnv.tohex(pt) == Cnv.tohex(dt))
def test_x509_makecert_emptydn():
print("\nMAKE CERT WITH EMPTY DN:")
certname = "AliceRSA-emptyDN.cer"
issuercert = "CarlRSASelf.cer"
prikeyfile = "CarlPrivRSASign.p8e"
password = "password"
subjectpubkeyfile = "AlicePubRsa.pub"
dn = "$" # special flag for empty DN
extns = "iPAddress=192.168.15.1" # at least one field for subject alt name is required
keyusage = X509.KeyUsageFlags.DIGITALSIGNATURE | X509.KeyUsageFlags.NONREPUDIATION
# Create a new certificate for Alice signed by Carl valid for 2 years signed using RSA-SHA-256
# Subject's distinguished name will be empty, Subject alternative name will be automatically marked CRITICAL (denoted "[!]" in dump)
r = X509.make_cert(certname, issuercert, subjectpubkeyfile, prikeyfile, password, 0x1001, 2, dn, extns=extns,
sigalg=X509.SigAlg.RSA_SHA256, keyusage=keyusage)
assert (0 == r)
print("Created new X509 file '{0}'".format(certname))
_dump_and_print_x509(certname)
def test_x509_certrequest_emptydn_extkeyusage():
print("\nMAKE CERTIFICATE SIGNING REQUEST WITH EMPTY DN AND EXTENDED KEY USAGE:")
csrfile = "req_emptydn_extkeyusage.p10"
subjectprikeyfile = "AlicePrivRSASign.p8e"
password = "password"
dn = "$" # special flag for empty DN
# Use extensions parameter to add alt subject name and extended key usage flags
extns = "iPAddress=192.168.15.1;extKeyUsage=serverAuth,clientAuth,emailProtection,critical;"
# Create a CSR for Alice
# Subject's distinguished name is empty, extKeyUsage is marked CRITICAL (denoted "[!]" in dump)
r = X509.cert_request(csrfile, subjectprikeyfile, password, dn, extns=extns, sigalg=X509.SigAlg.RSA_SHA256)
assert (0 == r)
print("Created certificate request '{0}'".format(csrfile))
_dump_and_print_x509(csrfile)
certfile = "certfromcsr_emptydn_extkeyusage.cer"
issuercert = "CarlRSASelf.cer"
issuerprikeyfile = "CarlPrivRSASign.p8e"
issuerpassword = "password"
# Now use this PKCS#10 CSR to create an end-user X.509 certificate for Alice signed by Carl valid for 4 years
# Pass the csrfile as the subject public key file argument and leave the DN argument empty as a flag to use a CSR instead
r = X509.make_cert(certfile, issuercert, csrfile, issuerprikeyfile, issuerpassword, 0x10b, 4, "",
sigalg=X509.SigAlg.RSA_SHA256)
assert (0 == r)
print("Created end-user X.509 certificate '{0}'".format(certfile))
_dump_and_print_x509(certfile)
# Query the new certificate
query = "subjectName" # empty ''
s = X509.query_cert(certfile, query)
print("Query {0}='{1}'".format(query, s))
query = "subjectAltName"
s = X509.query_cert(certfile, query)
print("Query {0}='{1}'".format(query, s))
query = "extKeyUsageString"
s = X509.query_cert(certfile, query)
print("Query {0}='{1}'".format(query, s))
def test_read_x509_from_pfx_3des():
print("\nREAD IN CERT AS A STRING FROM PFX FILE USING 3DES ENCRYPTION...")
# PFX file from draft-dkg-lamps-samples-02 with cert encrypted using "stronger" 3DES
# Ref: IETF LAMPS WG https:#gitlab.com/dkg/lamps-samples
pfxfile = "bob-lamps.p12"
password = 'bob'
print("FILE:", pfxfile)
certstr = X509.read_cert_string_from_pfx(pfxfile, password)
assert (len(certstr) > 0)
print(certstr[:30], "...", certstr[-30:])
print("subjectName:", X509.query_cert(certstr, "subjectName"))
print("Asn1.type=", Asn1.type(certstr))
def test_pfx_makefile_3des():
print("\nCREATE A NEW PFX FILE USING 3DES TO ENCRYPT THE CERT:")
pfxfile = "bob-3des.pfx"
prikeyfile = "BobPrivRSAEncrypt.p8e"
certfile = "BobRSASignByCarl.cer"
password = "password"
# Use StrongCert option to encrypt cert using "stronger" 3DES instead of weak default 40-bit RC2.
r = Pfx.make_file(pfxfile, certfile, prikeyfile, password, "Old Bob", Pfx.Opts.STRONG_CERT)
assert (0 == r)
print("Created PKCS#12 key store file '{0}'".format(pfxfile))
# Now dump the ASN.1
# Note that certificate (in encryptedData) is encrypted with "pbeWithSHAAnd3-KeyTripleDES-CBC"
# (see line 275 (approx) of output)
_dump_and_print_asn1(pfxfile)
def test_rng_guid():
print("\nTEST RANDOM GUID STRINGS...")
for x in range(0, 5):
guid = Rng.guid()
print(guid)
def test_sig_signdata_ed25519():
print("\nSIGN DATA USING Ed25519...")
# Ref: [RFC8032] https://tools.ietf.org/html/rfc8032#section-7.1
# -----TEST SHA(abc)
# Read in private key from hex (NB need explicitly to identify as a private key)
prikey = Ecc.read_key_by_curve("833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42",
Ecc.CurveName.ED25519, Ecc.KeyType.PRIVATE_KEY)
print(f"Private key has {Ecc.query_key(prikey, 'keyBits')} bits")
print(f"ALGORITHM: {Ecc.query_key(prikey, 'curveName')}")
# Message is the 64-byte SHA-512 hash of "abc"
message = Cnv.fromhex(
"ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f")
# Compute signature value in hex
sig = Sig.sign_data(message, prikey, "", Sig.Alg.ED25519, encoding=Sig.Encoding.HEX)
print(f"SIGNATURE:\n{sig}")
# Check against known correct result
sigok = "dc2a4459e7369633a52b1bf277839a00201009a3efbf3ecb69bea2186c26b58909351fc9ac90b3ecfdfbc7c66431e0303dca179c138ac17ad9bef1177331a704"
assert (sig == sigok)
# Now verify using public key
pubkey = Ecc.read_key_by_curve("ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf",
Ecc.CurveName.ED25519, Ecc.KeyType.PUBLIC_KEY)
print(f"Public key has {Ecc.query_key(pubkey, 'keyBits')} bits")
ok = Sig.data_is_verified(sig, message, pubkey, Sig.Alg.ED25519)
print(f"Sig.data_is_verified() returns {ok}")
assert (ok)
def test_sig_signdata_ed448():
print("\nSIGN DATA USING Ed448...")
# Ref: [RFC8032] https://tools.ietf.org/html/rfc8032
# -----Blank
# Read in private key from hex (NB need explicitly to identify as a private key)
prikey = Ecc.read_key_by_curve(
"6c82a562cb808d10d632be89c8513ebf 6c929f34ddfa8c9f63c9960ef6e348a3 528c8a3fcc2f044e39a3fc5b94492f8f 032e7549a20098f95b",
Ecc.CurveName.ED448, Ecc.KeyType.PRIVATE_KEY)
print(f"Private key has {Ecc.query_key(prikey, 'keyBits')} bits")
print(f"ALGORITHM: {Ecc.query_key(prikey, 'curveName')}")
# Message is the empty string
message = Cnv.fromhex("")
# Compute signature value in hex
sig = Sig.sign_data(message, prikey, "", Sig.Alg.ED448, encoding=Sig.Encoding.HEX)
print(f"SIGNATURE:\n{sig}")
# Check against known correct result
sigok = "533a37f6bbe457251f023c0d88f976ae2dfb504a843e34d2074fd823d41a591f2b233f034f628281f2fd7a22ddd47d7828c59bd0a21bfd3980ff0d2028d4b18a9df63e006c5d1c2d345b925d8dc00b4104852db99ac5c7cdda8530a113a0f4dbb61149f05a7363268c71d95808ff2e652600"
assert (sig == sigok)
# Now verify using public key
pubkey = Ecc.read_key_by_curve(
"5fd7449b59b461fd2ce787ec616ad46a 1da1342485a70e1f8a0ea75d80e96778 edf124769b46c7061bd6783df1e50f6c d1fa1abeafe8256180",
Ecc.CurveName.ED448, Ecc.KeyType.PUBLIC_KEY)
print(f"Public key has {Ecc.query_key(pubkey, 'keyBits')} bits")
ok = Sig.data_is_verified(sig, message, pubkey, Sig.Alg.ED448)
print(f"Sig.data_is_verified() returns {ok}")
assert (ok)
def test_cms_makesigdata_ed25519():
print("\nCREATE A CMS SIGNED-DATA OBJECT USING Ed25519...")
outfile = "SignedData_Ed25519.p7m"
infile = "excontent.txt"
certfile = "Ed25519-ietf-selfsigned.cer" # Self-signed cert created using private Ed25519 key in [RFC8410]
prikeyfile = "edwards-ietf-ex.p8" # No password, from [RFC8410]
# Read in private key to internal key string (no password)
prikeystr = Ecc.read_private_key(prikeyfile, "")
print(prikeystr)
# Create the signed-data object using Ed25519 with signed attributes incl Algorithm Protection
opts = Cms.SigDataOpts.INCLUDE_ATTRS or Cms.SigDataOpts.ADD_ALGPROTECT
r = Cms.make_sigdata(outfile, infile, certfile, prikeystr, Cms.SigAlg.ED25519, opts=opts)
assert 0 == r
print(f"Created file '{outfile}'")
# Show ASN.1 dump of file
print(f"SIGNED-DATA:\n{Asn1.text_dump_tostring(outfile)}")
# Query the signed-data object
query = "digestAlgorithm"
s = Cms.query_sigdata(outfile, query)
print(f"Cms.query_sigdata({query})={s}")
query = "signatureAlgorithm"
s = Cms.query_sigdata(outfile, query)
print(f"Cms.query_sigdata({query})={s}")
query = "HASsignedAttributes"
s = Cms.query_sigdata(outfile, query)
print(f"Cms.query_sigdata({query})={s}")
query = "DigestOfSignedAttrs"
s = Cms.query_sigdata(outfile, query)
print(f"Cms.query_sigdata({query})={s}")
# Verify the signed-data
r = Cms.verify_sigdata(outfile)
print(f"Cms.verify_sigdata returns {r} (expecting True)")
assert r
# Read the signed-data content
s = Cms.read_sigdata_to_string(outfile)
print(f"signed-data content='{s}'")
assert len(s) > 0
def test_cms_makesigdata_ed448():
print("\nCREATE A CMS SIGNED-DATA OBJECT USING Ed448...")
outfile = "SignedData_Ed448.p7m"
infile = "excontent.txt"
certfile = "Ed448-selfsigned.cer" # Self-signed cert using Ed448
prikeyfile = "edkey448.p8" # No password
# Read in private key to internal key string (no password)
prikeystr = Ecc.read_private_key(prikeyfile, "")
print(prikeystr)
# Create the signed-data object using EdDSA with signed attributes incl Algorithm Protection
opts = Cms.SigDataOpts.INCLUDE_ATTRS | Cms.SigDataOpts.ADD_ALGPROTECT
r = Cms.make_sigdata(outfile, infile, certfile, prikeystr, Cms.SigAlg.ED448, opts=opts)
assert 0 == r
print(f"Created file '{outfile}'")
# Show ASN.1 dump of file
print(f"SIGNED-DATA:\n{Asn1.text_dump_tostring(outfile)}")
# Query the signed-data object
query = "digestAlgorithm"
s = Cms.query_sigdata(outfile, query)
print(f"Cms.query_sigdata({query})={s}")
query = "signatureAlgorithm"
s = Cms.query_sigdata(outfile, query)
print(f"Cms.query_sigdata({query})={s}")
query = "HASsignedAttributes"
s = Cms.query_sigdata(outfile, query)
print(f"Cms.query_sigdata({query})={s}")
query = "HASalgorithmProtection"
s = Cms.query_sigdata(outfile, query)
print(f"Cms.query_sigdata({query})={s}")
# Verify the signed-data
r = Cms.verify_sigdata(outfile)
print(f"Cms.verify_sigdata returns {r} (expecting True)")
assert r
# Read the signed-data content
s = Cms.read_sigdata_to_string(outfile)
print(f"signed-data content='{s}'")
assert len(s) > 0
def test_x509_makecertself_25519():
print("\nCREATE A SELF-SIGNED X.509 CERTIFICATE USING Ed25519...")
# Ref: [RFC8410] https://tools.ietf.org/html/rfc8410
# 1. Create a new self-*signed* certificate using the Ed25519 key in RFC8410
certname = "ietf-Ed25519-self.cer"
prikeyfile = "edwards-ietf.p8" # No password
dn = "CN=IETF Test Demo"
extns = "notBefore=2016-01-01;notAfter=2040-12-31"
keyusage = X509.KeyUsageFlags.DIGITALSIGNATURE | X509.KeyUsageFlags.KEYCERTSIGN | X509.KeyUsageFlags.CRLSIGN
r = X509.make_cert_self(certname, prikeyfile, "", 0x0ED25519, 0, dn, extns, keyusage, X509.SigAlg.ED25519,
X509.Opts.UTF8)
print(f"X509.make_cert_self returns {r} (expected 0)")
assert 0 == r
print(f"FILE: {certname}")
print(X509.text_dump_tostring(certname))
# Do a query on the cert
query = "signatureAlgorithm"
s = X509.query_cert(certname, query)
print(f"X509.query_sigdata({query})={s}")
assert len(s) > 0
# 2. Now create a self-*issued* cert using Ed25519 to sign an X25519 public key
# [RFC8410] 10.2. Example X25519 Certificate
# NB This is self-*issued* in that the public key is for an X25519 key intended for ECDH,
# but it is signed using an Ed25519 signature with a key also belonging to ones self.
# Read in X25519 public key from its hex value
# NB we *must* specify that it's a public key
pubkeystr = Ecc.read_key_by_curve("8520F0098930A754748B7DDCB43EF75A0DBF3A0D26381AF4EBA4A98EAA9B4E6A",
Ecc.CurveName.X25519, Ecc.KeyType.PUBLIC_KEY)
assert len(pubkeystr) > 0
# Set cert parameters to closely duplicate the cert given in RFC8410 (almost!)
dn = "CN=IETF Test Demo"
extns = "notBefore=2016-08-01T12:19:24;notAfter=2040-12-31T23:59:59;keyUsage=noncritical;serialNumber=#x5601474A2A8DC330;" + \
"subjectKeyIdentifier=9B1F5EEDED043385E4F7BC623C5975B90BC8BB3B"
keyusage = X509.KeyUsageFlags.KEYAGREEMENT
issuercert = certname # Use the self-signed cert we made above to issue this new cert
certname = "ietf-X25519-self-issued.cer"
r = X509.make_cert(certname, issuercert, pubkeystr, prikeyfile, "", 0, 0, dn, extns, keyusage, X509.SigAlg.ED25519,
X509.Opts.UTF8)
assert 0 == r
print(f"FILE: {certname}")
# Dump cert details
print(X509.text_dump_tostring(certname))
# Query the public key algorithm
query = "subjectPublicKeyAlgorithm"
s = X509.query_cert(certname, query)
print(f"X509.query_sigdata({query})={s}")
assert len(s) > 0
# Verify that this cert was signed by the one above
f = X509.cert_is_verified(certname, issuercert)
print(f"X509.cert_is_verified returns {f}")
assert f, "cert verification failed"
def test_cms_pseudo():
print("\nCREATE A SIGNED-DATA CMS OBJECT USING 'PSEUDO' PLACEHOLDER...")
# NB signature will be different each time because signingTime is different every time
pseudofile = "BasicSignByAlice_pseudo.p7m"
opts = Cms.SigDataOpts.PSEUDOSIG | Cms.SigDataOpts.ALT_ALGID | Cms.SigDataOpts.INCLUDE_ATTRS | Cms.SigDataOpts.ADD_SIGNTIME | Cms.SigDataOpts.ADD_SIGNINGCERT
# NB privkey not required with PSEUDO option
r = Cms.make_sigdata(pseudofile, "excontent.txt", "AliceRSASignByCarl.cer", "", Cms.SigAlg.RSA_SHA256, opts)
print(f"Cms.make_sigdata(PSEUDOSIG) returns {r} (expected 0)")
assert 0 == r
print(f"Created file {pseudofile}")
# Expecting bbbbbb... (this is *exactly* the correct length for the final signature)
print("signatureValue: " + Cms.query_sigdata(pseudofile, "signatureValue"))
# Check signing time (not required, but just to check, out of interest) NB UTC/GMT time
print("signingTime: " + Cms.query_sigdata(pseudofile, "signingTime"))
# Get digest value in hex - this is the digestValue over which the signature will be created.
dighex = Cms.query_sigdata(pseudofile, "DigestOfSignedAttrs")
print("DigestOfSignedAttrs: " + dighex)
# Convert to base64
digestvalue = Cnv.tobase64(Cnv.fromhex(dighex))
print("digestValue: " + digestvalue)
# Pass the digestValue in base64 encoding to the signing agency.
# They will return the signatureValue (signInfo) in base64 created over the digestValue using "your" private key.
# User: digestValue --> SigningAgency
# SigningAgency: signatureValue --> User
# OK, so we fiddle it here to compute the signatureValue ourselves using Alice's private key...
signaturevalue = Sig.sign_digest(Cnv.frombase64(digestvalue), "AlicePrivRSASign.p8e", "password",
Sig.Alg.RSA_SHA256)
print("signatureValue: " + signaturevalue)
# Now create a new signed-data file from the pseudo file and the received signature Value
signedfile = "BasicSignByAlice_signed_from_pseudo.p7m"
r = Cms.make_sigdata_from_pseudo(signedfile, pseudofile, Cnv.frombase64(signaturevalue))
print(f"Cms.make_sigdata_from_pseudo returns {r} (expected 0)")
assert 0 == r
print(f"Created file {signedfile}")
# Check the resulting file has a valid signature
isok = Cms.verify_sigdata(signedfile)
print(f"Cms.verify_sigdata returns {isok}")
assert isok
def test_rsa_readjwk():
print("\nREAD IN RSA KEY REPRESENTED AS JSON JWK...")
# RSA public key as a JSON string
# Ref: RFC 7517 JSON Web Key (JWK) Appendix A.1
json = '''
{"kty":"RSA",
"n": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw",
"e":"AQAB",
"alg":"RS256",
"kid":"2011-04-29"}
'''
print("JSON key=" + json)
publickey = Rsa.read_public_key(json)
assert len(publickey) > 0
# Display some key properties
print("RSA key size =", Rsa.key_bits(publickey))
# Expecting 57F6BA24
keyhashcode = Rsa.key_hashcode(publickey)
print("KeyHashCode =", keyhashcode)
assert keyhashcode == "57F6BA24"
def test_hash_length():
print("\nTEST HASH LENGTH...")
print("Hash.length(SHA-1) =", Hash.length(Hash.Alg.SHA1))
print("Hash.length(SHA-256) =", Hash.length(Hash.Alg.SHA256))
print("Hash.length(SHA-512) =", Hash.length(Hash.Alg.SHA512))
print("Hash.length(RMD160) =", Hash.length(Hash.Alg.RMD160))
def test_kdf():
print("\nTEST KEY DERIVATION FUNCTIONS...")
# ansx963_2001.rsp CAVS 12.0 'ANS X9.63-2001' information for sample
nbytes = 128 // 8
zz = Cnv.fromhex("96c05619d56c328ab95fe84b18264b08725b85e33fd34f08")
okhex = "443024c3dae66b95e6f5670601558f71"
kek = Kdf.bytes(nbytes, zz, Kdf.KdfAlg.X963, Kdf.HashAlg.SHA256)
print("KEK=", Cnv.tohex(kek))
print("OK =", okhex)
assert (Cnv.tohex(kek).lower() == okhex)
# [RFC 5869] A.1. Test Case 1 Basic test case with SHA-256
nbytes = 42
zz = Cnv.fromhex("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b")
info = Cnv.fromhex("f0f1f2f3f4f5f6f7f8f9")
okhex = "3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865"
kek = Kdf.bytes(nbytes, zz, Kdf.KdfAlg.HKDF, Kdf.HashAlg.SHA256, info, "salt=000102030405060708090a0b0c")
print("KEK=", Cnv.tohex(kek))
print("OK =", okhex)
assert (Cnv.tohex(kek).lower() == okhex)
# [RFC 5869] A.3. Test with SHA-256 and zero-length salt/info
nbytes = 42
zz = Cnv.fromhex("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b") # (22 octets)
okhex = "8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d9d201395faa4b61a96c8"
kek = Kdf.bytes(nbytes, zz, Kdf.KdfAlg.HKDF, Kdf.HashAlg.SHA256)
print("KEK=", Cnv.tohex(kek))
print("OK =", okhex)
assert (Cnv.tohex(kek).lower() == okhex)
# Test Kdf.for_cms
zz = Cnv.fromhex("160E3F5588C6FB4E9CEE8BC3C1C5000AB86396468C3D1CAEC0CB6E21536B5513")
okhex = "04d616c654cdf62bb186a5a088b60fb5"
kek = Kdf.for_cms(zz, Kdf.KeyWrapAlg.AES128_WRAP, Kdf.KdfAlg.X963, Kdf.HashAlg.SHA1)
print("KEK=", Cnv.tohex(kek))
print("OK =", okhex)
assert (Cnv.tohex(kek).lower() == okhex)
def test_prf():
print("\nTEST PRF FUNCTIONS...")
# `KMAC_samples.pdf` "Secure Hashing - KMAC-Samples" 2017-02-27
# Sample #1
# "standard" KMAC output length KMAC128 => 256 bits, no custom string
nbytes = 256 // 8
msg = Cnv.fromhex("00010203")
key = Cnv.fromhex("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F")
okhex = "E5780B0D3EA6F7D3A429C5706AA43A00FADBD7D49628839E3187243F456EE14E"
kmac = Prf.bytes(nbytes, msg, key, Prf.Alg.KMAC128)
print("KMAC=", Cnv.tohex(kmac))
print("OK =", okhex)
assert Cnv.tohex(kmac).upper() == okhex, "KMAC failed"
# "standard" KMAC output length KMAC256 => 512 bits, no custom string
# Sample #6
nbytes = 512 // 8
# Length of data is 1600 bits
msg = Cnv.fromhex("""000102030405060708090A0B0C0D0E0F
101112131415161718191A1B1C1D1E1F
202122232425262728292A2B2C2D2E2F
303132333435363738393A3B3C3D3E3F
404142434445464748494A4B4C4D4E4F
505152535455565758595A5B5C5D5E5F
606162636465666768696A6B6C6D6E6F
707172737475767778797A7B7C7D7E7F
808182838485868788898A8B8C8D8E8F
909192939495969798999A9B9C9D9E9F
A0A1A2A3A4A5A6A7A8A9AAABACADAEAF
B0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF
C0C1C2C3C4C5C6C7""")
key = Cnv.fromhex("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F")
okhex = "75358CF39E41494E949707927CEE0AF20A3FF553904C86B08F21CC414BCFD691589D27CF5E15369CBBFF8B9A4C2EB17800855D0235FF635DA82533EC6B759B69"
kmac = Prf.bytes(nbytes, msg, key, Prf.Alg.KMAC256)
print("KMAC=", Cnv.tohex(kmac))
print("OK =", okhex)
assert Cnv.tohex(kmac).upper() == okhex, "KMAC failed"
# Sample #2
# Same as Sample #1 except with custom string
nbytes = 256 // 8
msg = Cnv.fromhex("00010203")
key = Cnv.fromhex("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F")
custom = "My Tagged Application"
okhex = "3B1FBA963CD8B0B59E8C1A6D71888B7143651AF8BA0A7070C0979E2811324AA5"
kmac = Prf.bytes(nbytes, msg, key, Prf.Alg.KMAC128, custom)
print("KMAC=", Cnv.tohex(kmac))
print("OK =", okhex)
assert Cnv.tohex(kmac).upper() == okhex, "KMAC failed"
# Request a lot of output (> single KECCAK block)
nbytes = 1600 // 8
msg = Cnv.fromhex("00010203")
key = Cnv.fromhex("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F")
okhex = """38158A1CAE4E1A25D85F2031246ADE69
7B3292FEF88B0923A59A02D1D53B7046
53EE7242662A10796BA20779D300D52D
7432018741233D587252D31DC48BDB82
33285D4A4ACD65848509B051A448D873
649228B6626E5EF817C7AF2DEDC91F12
0F8CA535A1EE301FAE8186FDEDE5A761
81A472A32CFAD1DDD1391E162F124D4A
7572AD8A20076601BCF81E4B0391F3E9
5AEFFA708C33C1217C96BE6A4F02FBBC
2D3B3B6FFAEB5BFD3BE4A2E02B75993F
CC04DA6FAC4BFCB2A9F05792A1A5CC80
CA34186243EFDB31"""
okhex = okhex.replace("\n", "")
kmac = Prf.bytes(nbytes, msg, key, Prf.Alg.KMAC128)
print("KMAC=", Cnv.tohex(kmac))
print("OK =", okhex)
assert Cnv.tohex(kmac).upper() == okhex, "KMAC failed"
def test_xof():
print("\nTEST XOF FUNCTIONS...")
# Ref: "SHA-3 XOF Test Vectors for Byte-Oriented Output"
# File `SHAKE256VariableOut.rsp` COUNT = 1244
nbytes = 2000 // 8
msg = Cnv.fromhex("6ae23f058f0f2264a18cd609acc26dd4dbc00f5c3ee9e13ecaea2bb5a2f0bb6b")
okhex = """b9b92544fb25cfe4ec6fe437d8da2bbe
00f7bdaface3de97b8775a44d753c3ad
ca3f7c6f183cc8647e229070439aa953
9ae1f8f13470c9d3527fffdeef6c94f9
f0520ff0c1ba8b16e16014e1af43ac6d
94cb7929188cce9d7b02f81a2746f52b
a16988e5f6d93298d778dfe05ea0ef25
6ae3728643ce3e29c794a0370e9ca6a8
bf3e7a41e86770676ac106f7ae79e670
27ce7b7b38efe27d253a52b5cb54d6eb
4367a87736ed48cb45ef27f42683da14
0ed3295dfc575d3ea38cfc2a3697cc92
864305407369b4abac054e497378dd9f
d0c4b352ea3185ce1178b3dc1599df69
db29259d4735320c8e7d33e8226620c9
a1d22761f1d35bdff79a"""
okhex = okhex.replace("\n", "")
xof = Xof.bytes(nbytes, msg, Xof.Alg.SHAKE256)
print("OUT=", Cnv.tohex(xof))
print("OK =", okhex)
assert (Cnv.tohex(xof).lower() == okhex)
# Using MGF1-SHA-256
# From SPHINCS+ test vectors r.3
nbytes = 34
msg = Cnv.fromhex("3b5c056af3ebba70d4c805380420585562b32410a778f558ff951252407647e3")
okhex = "5b7eb772aecf04c74af07d9d9c1c1f8d3a90dcda00d5bab1dc28daecdc86eb87611e"
xof = Xof.bytes(nbytes, msg, Xof.Alg.MGF1_SHA256)
print("OUT=", Cnv.tohex(xof))
print("OK =", okhex)
assert Cnv.tohex(xof).lower() == okhex, "XOF failed"
# Test other MGF1's
nbytes = 24
msg = Cnv.fromhex("012345ff")
okhex = "242fb2e7a338ae07e580047f82b7acff83a41ec5d8ff9bab"
xof = Xof.bytes(nbytes, msg, Xof.Alg.MGF1_SHA1)
print("OUT=", Cnv.tohex(xof))
print("OK =", okhex)
assert Cnv.tohex(xof).lower() == okhex, "XOF failed"
nbytes = 32
msg = Cnv.fromhex("012345ff")
okhex = "6855a6ab4f421ecb99857d31c4aa836bf3d4916ee8a71a168d3f4665f2d7b74c"
xof = Xof.bytes(nbytes, msg, Xof.Alg.MGF1_SHA512)
print("OUT=", Cnv.tohex(xof))
print("OK =", okhex)
assert Cnv.tohex(xof).lower() == okhex, "XOF failed"
def test_hkpe_labeled():
print("\nTESTING HPKE LABELED{EXTRACT|EXPAND}...")
print("RFC 9180 Appendix A.1 DHKEM(X25519, HKDF-SHA256), HKDF-SHA256, AES-128-GCM")
print('prk = LabeledExtract("", "dkp_prk", ikm)')
extracted = Hpke.labeled_extract(None, "dkp_prk",
Cnv.fromhex("7268600d403fce431561aef583ee1613527cff655c1343f29812e66706df3234"),
Hpke.CurveName.X25519)
print("prk:", Cnv.tohex(extracted))
assert Cnv.tohex(
extracted).upper() == "7B8BFE1D6F3D0CB45C585E133299C64AC998BF46CAF2DC13BA874F23413EC23A", "labeled_extract failed"
print("psk_id_hash = LabeledExtract('', 'psk_id_hash', '')")
extracted = Hpke.labeled_extract(None, "psk_id_hash",
None, Hpke.CurveName.X25519, Hpke.AeadAlg.AES_128_GCM)
print("psk_id_hash:", Cnv.tohex(extracted))
assert Cnv.tohex(
extracted).lower() == "725611c9d98c07c03f60095cd32d400d8347d45ed67097bbad50fc56da742d07", "labeled_extract failed"
print("key = LabeledExpand(secret, 'key', key_schedule_context, Nk)")
nk = 16
key = Hpke.labeled_expand(nk, Cnv.fromhex("12fff91991e93b48de37e7daddb52981084bd8aa64289c3788471d9a9712f397"),
"key",
Cnv.fromhex(
"00725611c9d98c07c03f60095cd32d400d8347d45ed67097bbad50fc56da742d07cb6cffde367bb0565ba28bb02c90744a20f5ef37f30523526106f637abb05449"),
Hpke.CurveName.X25519, Hpke.AeadAlg.AES_128_GCM)
print("key:", Cnv.tohex(key))
assert Cnv.tohex(key).lower() == "4531685d41d65f03dc48f6b8302c05b0", "labeled_expand failed"
def test_hkpe_derive_private_key():
print("\nTESTING HPKE DERIVEPRIVATEKEY...")
print("RFC9180 A.1. DHKEM(X25519, HKDF-SHA256)")
ikmhex = "7268600d403fce431561aef583ee1613527cff655c1343f29812e66706df3234"
skokhex = "52c4a758a802cd8b936eceea314432798d5baf2d7e9235dc084ab1b9cfa2f736"
pkokhex = "37fda3567bdbd628e88668c3c8d7e97d1d1253b6d4ea6d44c150f741f1bf4431"
# A. Derive private key in hex format
print("ikmE:", ikmhex)
skhex = Hpke.derive_private_key(Cnv.fromhex(ikmhex), Hpke.CurveName.X25519, Hpke.OutputOpts.KEYASHEX)
print("skEm:", skhex)
assert skhex.lower() == skokhex, "HPKE derived key does not match test vector"
# B. Derive key in ephemeral internal private key format (NB different each time)
prikeystr = Hpke.derive_private_key(Cnv.fromhex(ikmhex), Hpke.CurveName.X25519)
print("prikeystr:", prikeystr)
print("curveName:", Ecc.query_key(prikeystr, "curveName"))
# C. Get public key in hex format from internal key string
pkhex = Ecc.query_key(prikeystr, "publicKey")
print("pkEm:", pkhex)
assert pkhex.lower() == pkokhex, "Public key does not match test vector"
print("RFC9180 A.6. DHKEM(P-521, HKDF-SHA512)")
ikmhex = "7f06ab8215105fc46aceeb2e3dc5028b44364f960426eb0d8e4026c2f8b5d7e7a986688f1591abf5ab753c357a5d6f0440414b4ed4ede71317772ac98d9239f70904"
skokhex = "014784c692da35df6ecde98ee43ac425dbdd0969c0c72b42f2e708ab9d535415a8569bdacfcc0a114c85b8e3f26acf4d68115f8c91a66178cdbd03b7bcc5291e374b"
pkokhex = "040138b385ca16bb0d5fa0c0665fbbd7e69e3ee29f63991d3e9b5fa740aab8900aaeed46ed73a49055758425a0ce36507c54b29cc5b85a5cee6bae0cf1c21f2731ece2013dc3fb7c8d21654bb161b463962ca19e8c654ff24c94dd2898de12051f1ed0692237fb02b2f8d1dc1c73e9b366b529eb436e98a996ee522aef863dd5739d2f29b0"
# A. Derive private key in hex format
print("ikmE:", ikmhex)
skhex = Hpke.derive_private_key(Cnv.fromhex(ikmhex), Hpke.CurveName.P_521, Hpke.OutputOpts.KEYASHEX)
print("skEm:", skhex)
assert skhex.lower() == skokhex, "HPKE derived key does not match test vector"
# B. Derive key in ephemeral internal private key format (NB different each time)
prikeystr = Hpke.derive_private_key(Cnv.fromhex(ikmhex), Hpke.CurveName.P_521)
print("prikeystr:", prikeystr)
print("curveName:", Ecc.query_key(prikeystr, "curveName"))
# C. Get public key in hex format from internal key string
pkhex = Ecc.query_key(prikeystr, "publicKey")
print("pkEm:", pkhex)
assert pkhex.lower() == pkokhex, "Public key does not match test vector"
def test_cms_makeenvdata_ecdh():
print("\nMAKE ENVELOPED-DATA OBJECTS USING ECDH KARI...")
# Create an enveloped CMS object to Dana (using ecdh) and Alice (using RSA)
fname = "dana_alice_all_defaults.p7m"
certlist = "lamps-dana.encrypt.crt;lamps-alice.encrypt.crt"
msg = "This is some sample content."
n = Cms.make_envdata_from_string(fname, msg, certlist, Cipher.Alg.AES128)
print("Cms.make_envdata_from_string returns", n, " (expecting 2)")
assert n > 0
print("FILE:", fname)
# Query the enveloped-data file
query = "contentEncryptionAlgorithm"
s = Cms.query_envdata(fname, query)
print(f"{query}='{s}'")
query = "recipientInfoType"
s = Cms.query_envdata(fname, query)
print(f"{query}='{s}'")
query = "recipientInfoType/2"
s = Cms.query_envdata(fname, query)
print(f"{query}='{s}'")
query = "keyEncryptionAlgorithm"
s = Cms.query_envdata(fname, query)
print(f"{query}='{s}'")
query = "keyEncryptionAlgorithm/2"
s = Cms.query_envdata(fname, query)
print(f"{query}='{s}'")
# Read back from CMS enveloped-data object using private keys
print("Read CMS using Alice's RSA private key:")
prikeyalice = Rsa.read_private_key("lamps-alice.decrypt.p8.pem", "")
s = Cms.read_envdata_to_string(fname, prikeyalice, "lamps-alice.encrypt.crt")
print("MSG =", s)
assert (len(s) > 0)
print("Read CMS using Dana's ECC X25519 private key:")
prikeydana = Ecc.read_private_key("lamps-dana.decrypt.p8.pem", "")
s = Cms.read_envdata_to_string(fname, prikeydana, "lamps-dana.encrypt.crt")
print("MSG =", s)
assert (len(s) > 0)
def test_x509_makecert_internal_x25519():
print("\nCREATE A NEW CERTIFICATE USING INTERNAL KEY STRINGS WITH X25519...")
certname = "new-lamps-dana.encrypt.cer"
issuercert = "lamps-ca.ed25519.crt"
prikeyfile = "lamps-ca.ed25519.p8"
pubkeyfile = "lamps-dana.encrypt.crt"
dn = "O=IETF;OU=LAMPS WG;CN=Dana Hopper"
# sMIMECapabilities = ECDH with HKDF using SHA-256; uses AES-128 key wrap
extns = "serialNumber=#x0E4B0A36A9EFBA9C9A3B68248E521DC0DEF3A7;notBefore=2020-12-15T21:35:44;notAfter=2052-12-15T21:35:44;extKeyUsage=emailProtection;" \
+ "keyUsage=keyAgreement;sMIMECapabilities=301A060B2A864886F70D0109100313300B0609608648016503040105;" \
+ "certificatePolicies=2.16.840.1.101.3.2.1.48.1;rfc822Name=dana@smime.example;subjectKeyIdentifier=9ddf4dd405ef9aec6086bc276d04e9ce5adc8fa4;"
# Read in private and public keys to internal key strings
prikeystr = Ecc.read_private_key(prikeyfile, "")
print("prikeystr=", prikeystr)
print("PRI: keyBits=", Ecc.query_key(prikeystr, "keyBits"), ", curveName =", Ecc.query_key(prikeystr, "curveName"),
", keyHashCode=", Ecc.key_hashcode(prikeystr))
assert (len(prikeystr) > 0)
pubkeystr = Ecc.read_public_key(pubkeyfile)
print("PUB: keyBits=", Ecc.query_key(pubkeystr, "keyBits"), ", curveName =", Ecc.query_key(pubkeystr, "curveName"),
", keyHashCode=", Ecc.key_hashcode(pubkeystr))
assert (len(pubkeystr) > 0)
print("dn='" + dn + "'")
print("extns='" + extns + "'")
# Create the new certificate
try:
r = X509.make_cert(certname, issuercert, pubkeystr, prikeystr, "", distname=dn, extns=extns,
sigalg=X509.SigAlg.ED25519, opts=X509.Opts.AUTHKEYID)
print("X509.make_cert returns", r)
except PKIError as e:
print("Woops! PKIError:", e)
# print(Asn1.text_dump_tostring(certname))
print("FILE:", certname)
query = "subjectPublicKeyAlgorithm"
print(query + "='" + X509.query_cert(certname, query) + "'")
query = "signatureAlgorithm"
print(query + "='" + X509.query_cert(certname, query) + "'")
print(X509.text_dump_tostring(certname))
def test_cms_envdata_auth():
print("\nAUTHENTICATED-ENVELOPED-DATA OBJECTS...")
# Create an authenticated-enveloped CMS object to Bob using Bob's X.509 certificate
fname = "cms2bob_auth.p7m"
fnamecert = "BobRSASignByCarl.cer"
s = "This is some sample content."
n = Cms.make_envdata_from_string(fname, s, fnamecert, Cipher.Alg.AES128, Cms.KeyEncrAlg.RSA_PKCS1V1_5,
0, Cms.EnvDataOpts.AUTHENTICATED, count=13)
print("Cms.make_envdata_from_string returns", n)
assert (n == 1)
print(Asn1.text_dump_tostring(fname))
def test_cms_make_envdata_auth_chapoly():
print("\nAUTHENTICATED-ENVELOPED-DATA USING CHACHA20POLY1305...")
filein = "excontent.txt"
cmsfile = "cms2bob_auth_chapoly.p7m"
certfile = "lamps-bob.crt"
keyfile = "lamps-bob.p8" # Unencrypted
n = Cms.make_envdata(cmsfile, filein, certfile, Cms.ContentEncrAlg.CHACHA20_POLY1305)
assert n == 1 # Expecting one recipient
print("Created file:", cmsfile)
print(Asn1.type(cmsfile))
print("contentEncryptionAlgorithm:", Cms.query_envdata(cmsfile, "contentEncryptionAlgorithm"))
print("keyEncryptionAlgorithm:", Cms.query_envdata(cmsfile, "keyEncryptionAlgorithm"))
# print(Asn1.text_dump_tostring(cmsfile))
# Now try and read it
prikeystr = Rsa.read_private_key(keyfile)
decstr = Cms.read_envdata_to_string(cmsfile, prikeystr)
assert len(decstr) > 0
print(f"DEC: '{decstr}'")
# Now use X25519
print("\nUsing X25519...")
cmsfile = "cms2carlos_auth_chapoly_X25519.p7m"
certfile = "lamps-carlos.encrypt.cer"
keyfile = "lamps-carlos.decrypt.p8" # Unencrypted
n = Cms.make_envdata(cmsfile, filein, certfile, Cms.ContentEncrAlg.CHACHA20_POLY1305, kdfalg=Kdf.KdfAlg.HKDF)
assert n == 1 # Expecting one recipient
print("Created file:", cmsfile)
print(Asn1.type(cmsfile))
print("contentEncryptionAlgorithm:", Cms.query_envdata(cmsfile, "contentEncryptionAlgorithm"))
print("keyEncryptionAlgorithm:", Cms.query_envdata(cmsfile, "keyEncryptionAlgorithm"))
print("originatorKeyAlgorithm:", Cms.query_envdata(cmsfile, "originatorKeyAlgorithm"))
# print(Asn1.text_dump_tostring(cmsfile))
# Now try and read it
prikeystr = Ecc.read_private_key(keyfile)
decstr = Cms.read_envdata_to_string(cmsfile, prikeystr)
assert len(decstr) > 0
print(f"DEC: '{decstr}'")
print("\nUsing X448...")
cmsfile = "cms2alice_auth_chapoly_X448.p7m"
certfile = "X448-alice-self-issued.cer"
keyfile = "X448-alice-self.p8" # Unencrypted
n = Cms.make_envdata(cmsfile, filein, certfile, Cms.ContentEncrAlg.CHACHA20_POLY1305, hashalg=Hash.Alg.SHA512,
kdfalg=Kdf.KdfAlg.HKDF)
assert n == 1 # Expecting one recipient
print("Created file:", cmsfile)
print(Asn1.type(cmsfile))
print("keyEncryptionAlgorithm:", Cms.query_envdata(cmsfile, "keyEncryptionAlgorithm"))
print("originatorKeyAlgorithm:", Cms.query_envdata(cmsfile, "originatorKeyAlgorithm"))
# print(Asn1.text_dump_tostring(cmsfile))
# Now try and read it
prikeystr = Ecc.read_private_key(keyfile)
decstr = Cms.read_envdata_to_string(cmsfile, prikeystr)
assert len(decstr) > 0
print(f"DEC: '{decstr}'")
def test_cms_envdata_examples():
print("\nENVELOPED-DATA EXAMPLES USED IN DOCS...")
print("Create an enveloped CMS object (ktri type) to Bob using Bob's RSA key..")
n = Cms.make_envdata("cms2bob_aes128.p7m", "excontent.txt", "BobRSASignByCarl.cer", Cipher.Alg.AES128,
Cms.KeyEncrAlg.RSA_OAEP)
print("Cms.make_envdata returns", n)
assert (n == 1)
fname = "cms2bob_aes128.p7m"
print("FILE:", fname)
query = "recipientInfoType"
print("%s=%s" % (query, Cms.query_envdata(fname, query)))
query = "contentEncryptionAlgorithm"
print("%s=%s" % (query, Cms.query_envdata(fname, query)))
print("Same but using authenticated encryption and creating an authEnvelopedData object..")
n = Cms.make_envdata("cms2bob_aes128auth.p7m", "excontent.txt", "BobRSASignByCarl.cer", Cms.ContentEncrAlg.AES_128_GCM,
Cms.KeyEncrAlg.RSA_OAEP)
assert (n == 1)
fname = "cms2bob_aes128auth.p7m"
print("FILE:", fname)
query = "recipientInfoType"
print("%s=%s" % (query, Cms.query_envdata(fname, query)))
query = "contentEncryptionAlgorithm"
print("%s=%s" % (query, Cms.query_envdata(fname, query)))
print("Create an enveloped CMS object (kari type) to Dana using Dana's ECC key..")
n = Cms.make_envdata("cms2dana_hkdf.p7m", "excontent.txt", "lamps-dana.encrypt.crt", Cipher.Alg.AES256,
hashalg=Hash.Alg.SHA256, kdfalg=Kdf.KdfAlg.HKDF,
keywrapalg=Kdf.KeyWrapAlg.AES256_WRAP)
print("Cms.make_envdata returns", n)
assert (n == 1)
fname = "cms2dana_hkdf.p7m"
print("FILE:", fname)
query = "recipientInfoType"
print("%s=%s" % (query, Cms.query_envdata(fname, query)))
query = "contentEncryptionAlgorithm"
print("%s=%s" % (query, Cms.query_envdata(fname, query)))
print(
"Create an enveloped CMS object (kekri type) using a previously distributed symmetric key-encryption key (KEK)..")
n = Cms.make_envdata("cms_envdata_kekri.p7m", "excontent.txt", "type=@kekri,keyid=ourcommonkey",
Cipher.Alg.AES256, hashalg=Hash.Alg.SHA256,
keywrapalg=Kdf.KeyWrapAlg.AES128_WRAP, keyString="#x0123456789ABCDEFF0E1D2C3B4A59687")
print("Cms.make_envdata returns", n)
assert (n == 1)
fname = "cms_envdata_kekri.p7m"
print("FILE:", fname)
query = "recipientInfoType"
print("%s=%s" % (query, Cms.query_envdata(fname, query)))
query = "contentEncryptionAlgorithm"
print("%s=%s" % (query, Cms.query_envdata(fname, query)))
query = "keyid"
print("%s=%s" % (query, Cms.query_envdata(fname, query)))
print("Create an enveloped CMS object (pwri type) using password-based key management..")
n = Cms.make_envdata("cms_envdata_pwri.p7m", "excontent.txt", "type=@pwri", Cipher.Alg.AES192,
keyString="password12345")
print("Cms.make_envdata returns", n)
assert (n == 1)
fname = "cms_envdata_pwri.p7m"
print("FILE:", fname)
query = "recipientInfoType"
print("%s=%s" % (query, Cms.query_envdata(fname, query)))
query = "contentEncryptionAlgorithm"
print("%s=%s" % (query, Cms.query_envdata(fname, query)))
print("\nNow read in the enveloped-data objects we made above...")
prikeystr = Rsa.read_private_key("BobPrivRSAEncrypt.p8e", "password")
assert (len(prikeystr) > 0)
fname = "cms2bob_aes128.p7m"
print("FILE:", fname)
s = Cms.read_envdata_to_string(fname, prikeystr)
print("MSG='%s'" % s)
assert (len(s) > 0)
fname = "cms2bob_aes128auth.p7m"
print("FILE:", fname)
s = Cms.read_envdata_to_string(fname, prikeystr)
print("MSG='%s'" % s)
assert (len(s) > 0)
prikeystr = Ecc.read_private_key("lamps-dana.decrypt.p8.pem", "")
assert (len(prikeystr) > 0)
fname = "cms2dana_hkdf.p7m"
print("FILE:", fname)
s = Cms.read_envdata_to_string(fname, prikeystr)
print("MSG='%s'" % s)
assert (len(s) > 0)
fname = "cms_envdata_kekri.p7m"
print("FILE:", fname)
s = Cms.read_envdata_to_string(fname, "#x0123456789ABCDEFF0E1D2C3B4A59687")
print("MSG='%s'" % s)
assert (len(s) > 0)
fname = "cms_envdata_pwri.p7m"
print("FILE:", fname)
s = Cms.read_envdata_to_string(fname, "password12345")
print("MSG='%s'" % s)
assert (len(s) > 0)
def test_cnv_shortpathname():
print("\nGET SHORT NAME PATH...")
shortname = Cnv.shortpathname("你好.txt")
print("shortname='%s'" % shortname)
exists = os.path.exists(shortname) # Fixed [2023-04-19]
print("File '" + shortname + "' " + "EXISTS" if exists else "does not exists")
assert (exists)
shortname = Cnv.shortpathname("File with a long name and spaces hello there all good yes thanks.txt")
print("shortname='%s'" % shortname)
exists = os.path.exists(shortname) # Fixed [2023-04-19]
print("File '" + shortname + "' " + "EXISTS" if exists else "does not exists")
assert (exists)
def test_gen_format_error_message():
print("\nTEST FORMAT ERROR MESSAGE...")
# Try and read missing file
try:
s = Asn1.type("missing.file")
except PKIError as e:
print(e)
# ERROR CODE 1: Cannot open input file (OPEN_ERROR): Unable to open file 'missing.file'
# Attempt to create signed data but pass name of missing certificate file
privkey = Rsa.read_private_key('AlicePrivRSASign.p8e', 'password')
try:
r = Cms.make_sigdata('sigdata.p7m', 'excontent.txt', 'missing.file', privkey)
print("Cms.make_sigdata succeeded returning ", r) # Shouldn't happen
except PKIError as e:
print(e)
# ERROR CODE 21: No match found (NO_MATCH_ERROR): (1) Cannot open input file (OPEN_ERROR):
# Private key does not match any certificate in list
def test_rsa_read_public_key_csr():
print("\nREAD PUBLIC KEY FROM CSR...")
# Create a new CSR for LAMPS WG alice
csrfile = "lamps-alice-csr.pem"
keyfile = "lamps-alice.p8" # No password
dn = "O=IETF;OU=LAMPS WG;CN=Alice Lovelace;"
extns = "keyUsage=digitalSignature,nonRepudiation;extKeyUsage=emailProtection"
r = X509.cert_request(csrfile, keyfile, "", dn, extns, X509.SigAlg.RSA_SHA256)
print(f"X509.cert_request created file '{csrfile}'")
# Dump details of CSR we just made...
print(X509.text_dump_tostring(csrfile, X509.Opts.LDAP))
# New in [v20.7]: Read in public key from this CSR file to an internal key string
keystr = Rsa.read_public_key(csrfile)
print("Keysize=" + str(Rsa.key_bits(keystr)) + " bits, HashCode=0x" + Rsa.key_hashcode(keystr))
# Keysize=2048 bits, HashCode=0xCA0B84DA
def test_x509_make_cert_448():
print("\nMAKE X.509 CERT USING CURVE448:")
# 1. Create a self-signed certificate using the Ed448 key
prikeyfile = "edkey448.p8"
certfile = "Ed448-self.cer"
dn = "CN=example.com"
extns = "notBefore=2023-01-01;notAfter=2040-12-31;"
# Digital Signature, Certificate Signing, [Off-line CRL Signing], CRL Signing
# keyusage = X509.KeyUsageFlags.DIGITALSIGNATURE | X509.KeyUsageFlags.KEYCERTSIGN | X509.KeyUsageFlags.CRLSIGN
extns += "keyUsage=digitalSignature,keyCertSign,cRLSign;"
r = X509.make_cert_self(certfile, prikeyfile, "", 0x0ED448, 0, dn, extns, sigalg=X509.SigAlg.ED448,
opts=X509.Opts.UTF8)
print("Created self-signed X.509 certificate:", certfile)
print(X509.text_dump_tostring(certfile, X509.Opts.LDAP))
print("issuerName:", X509.query_cert(certfile, "issuerName"))
print("subjectName:", X509.query_cert(certfile, "subjectName"))
print("subjectPublicKeyAlgorithm:", X509.query_cert(certfile, "subjectPublicKeyAlgorithm"))
print("signatureAlgorithm:", X509.query_cert(certfile, "signatureAlgorithm"))
# 2. Now create a self-*issued* cert using Ed448 to sign an X448 public key
print("\nAbout to create a *self-issued* cert using Ed448 to sign an X448 public key...")
# Read in the public key from its hex value
pubkeystr = Ecc.read_key_by_curve(
"9b08f7cc31b7e3e67d22d5aea121074a273bd2b83de09c63faa73d2c22c5d9bbc836647241d953d40c5b12da88120d53177f80e532c41fa0",
Ecc.CurveName.X448, ispublic=True)
assert len(pubkeystr) > 0
dn = "CN=Alice X448;O=example.com"
extns = "notBefore=2023-07-01T12:19:24;notAfter=2040-12-31T23:59:58;keyUsage=noncritical;serialNumber=#x5601474A2A8DC330;" \
+ "subjectKeyIdentifier=DEADBEEFCAFEBABE"
keyusage = X509.KeyUsageFlags.KEYAGREEMENT
issuercert = certfile # Created above
certfile = "X448-self-issued.cer"
# Create self-issued cert containing Alice's X448 public key but signed by Ed448 cert
r = X509.make_cert(certfile, issuercert, pubkeystr, prikeyfile, "", 0, 0, dn, extns, keyusage,
X509.SigAlg.ED448, opts=X509.Opts.UTF8)
print("Created self-issued X.509 certificate:", certfile)
# print(X509.text_dump_tostring(certfile, X509.Opts.LDAP))
print("issuerName:", X509.query_cert(certfile, "issuerName"))
print("subjectName:", X509.query_cert(certfile, "subjectName"))
print("subjectPublicKeyAlgorithm:", X509.query_cert(certfile, "subjectPublicKeyAlgorithm"))
print("signatureAlgorithm:", X509.query_cert(certfile, "signatureAlgorithm"))
# Verify that self-issued cert was signed by issuer
print("Verify the certificate against its issuer...")
isok = X509.cert_is_verified(certfile, issuercert)
print("X509.cert_is_verified returns", isok)
assert isok
def test_scrypt():
print("\nTESTING SCRYPT PASSWORD-BASED KEY DERIVATION FUNCTION...")
# Use SCRYPT examples from RFC7914
dk = Pbe.scrypt(64, b'password', b'NaCl', 1024, 8, 16)
print("dk(SCRYPT)=", Cnv.tohex(dk))
assert Cnv.tohex(dk) == 'FDBABE1C9D3472007856E7190D01E9FE7C6AD7CBC8237830E77376634B373162' \
+ '2EAF30D92E22A3886FF109279D9830DAC727AFB94A83EE6D8360CBDFA2CC0640'
# Pass empty string for both password and salt with (N=16, r=1, p=1)
dk = Pbe.scrypt(64, b'', b'', 16, 1, 1)
print("dk(SCRYPT)=", Cnv.tohex(dk))
assert Cnv.tohex(dk) == '77D6576238657B203B19CA42C18A0497F16B4844E3074AE8DFDFFA3FEDE21442' \
+ 'FCD0069DED0948F8326A753A0FC81F17E8D3E0FB2E0D3628CF35E20C38D18906'
def test_ecc_make_keys_448():
print("\nTESTING MAKE KEYS FOR ED448 and X448...")
pubkeyfile = "myed448.pub"
prikeyfile = "myed448.p8e"
pwd = "password"
n = Ecc.make_keys(pubkeyfile, prikeyfile, Ecc.CurveName.ED448, pwd, pbescheme=Ecc.PbeScheme.PBKDF2_AES256)
assert (0 == n)
_dump_and_print_asn1(pubkeyfile)
print(pubkeyfile + ": " + Asn1.type(pubkeyfile))
print(prikeyfile + ": " + Asn1.type(prikeyfile))
# Read in private key as internal key string
skstr = Ecc.read_private_key(prikeyfile, pwd)
print("sk curve =", Ecc.query_key(skstr, "curveName"), "keyhashcode =", Ecc.key_hashcode(skstr))
pkstr = Ecc.read_public_key(pubkeyfile)
print("pk curve =", Ecc.query_key(pkstr, "curveName"), "keyhashcode =", Ecc.key_hashcode(pkstr))
pubkeyfile = "myX448.pub"
prikeyfile = "myX448.p8e"
pwd = "password"
n = Ecc.make_keys(pubkeyfile, prikeyfile, Ecc.CurveName.X448, pwd, pbescheme=Ecc.PbeScheme.PBKDF2_AES256)
assert (0 == n)
_dump_and_print_asn1(pubkeyfile)
print(pubkeyfile + ": " + Asn1.type(pubkeyfile))
print(prikeyfile + ": " + Asn1.type(prikeyfile))
# Read in private key as internal key string
skstr = Ecc.read_private_key(prikeyfile, pwd)
print("sk curve =", Ecc.query_key(skstr, "curveName"), "keyhashcode =", Ecc.key_hashcode(skstr))
pkstr = Ecc.read_public_key(pubkeyfile)
print("pk curve =", Ecc.query_key(pkstr, "curveName"), "keyhashcode =", Ecc.key_hashcode(pkstr))
def test_ecc_readbycurve_448():
print("\nTESTING READBYCURVE FOR ED448 and X448...")
prikeystr = Ecc.read_key_by_curve(
"c4eab05d357007c632f3dbb48489924d 552b08fe0c353a0d4a1f00acda2c463a fbea67c5e8d2877c5e3bc397a659949e f8021e954e0a12274e",
Ecc.CurveName.ED448, ispublic=False)
assert len(prikeystr) > 0
print("CURVE: ", Ecc.query_key(prikeystr, "curveName"))
print("KeyHashCode:", Ecc.key_hashcode(prikeystr))
print("SK: ", Ecc.query_key(prikeystr, "privateKey"))
print("PK: ", Ecc.query_key(prikeystr, "publicKey"))
# Read in corresponding public key
pubkeystr = Ecc.read_key_by_curve(
"43ba28f430cdff456ae531545f7ecd0ac834a55d9358c0372bfa0c6c6798c0866aea01eb00742802b8438ea4cb82169c235160627b4c3a9480",
Ecc.CurveName.ED448, ispublic=True)
assert len(pubkeystr) > 0
print("CURVE: ", Ecc.query_key(pubkeystr, "curveName"))
print("KeyHashCode:", Ecc.key_hashcode(pubkeystr))
# Again for ECDH X448 key
prikeystr = Ecc.read_key_by_curve(
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
Ecc.CurveName.X448, ispublic=False)
assert len(prikeystr) > 0
print("CURVE: ", Ecc.query_key(prikeystr, "curveName"))
print("KeyHashCode:", Ecc.key_hashcode(prikeystr))
print("SK: ", Ecc.query_key(prikeystr, "privateKey"))
print("PK: ", Ecc.query_key(prikeystr, "publicKey"))
# Read in corresponding public key
pubkeystr = Ecc.read_key_by_curve(
"172837c1ef0bf5d890af8dcee6bda1ad1970c167e893dd46054795693a11397580fe732f2b50bd9fc1d7596c62fd5c4d5df403e94ad8c507",
Ecc.CurveName.X448, ispublic=True)
assert len(pubkeystr) > 0
print("CURVE: ", Ecc.query_key(pubkeystr, "curveName"))
print("KeyHashCode:", Ecc.key_hashcode(pubkeystr))
def test_ecc_savekeys_448():
print("\nTESTING SAVEKEYS FOR CURVE448...")
# Read in private key from hex representation
prikeystr = Ecc.read_key_by_curve(
"9a8f4925d1519f5775cf46b04b5800d4ee9ee8bae8bc5565d498c28dd9c9baf574a9419744897391006382a6f127ab1d9ac2d8c0a598726b",
Ecc.CurveName.X448, ispublic=False)
assert len(prikeystr) > 0
print("CURVE: ", Ecc.query_key(prikeystr, "curveName"))
print("KeyHashCode:", Ecc.key_hashcode(prikeystr))
print("SK: ", Ecc.query_key(prikeystr, "privateKey"))
print("PK: ", Ecc.query_key(prikeystr, "publicKey"))
# Save to unencrypted PKCS8 v2 file (OneAsymmetricKey)
# [v22.0] by default now includes the public key as well
fname = "keypri_X448.p8"
r = Ecc.save_key(fname, prikeystr)
print(f"Created key file '{fname}'")
print(Asn1.type(fname))
print(Asn1.text_dump_tostring(fname))
# Check we can read the private key
prikeystr = Ecc.read_private_key(fname)
assert len(prikeystr) > 0
print("KeyHashCode:", Ecc.key_hashcode(prikeystr))
print("Is a Private Key" if Ecc.query_key(prikeystr, "isPrivate") else "Is a Public Key")
# Check we can read the public key
pubkeystr = Ecc.read_public_key(fname)
assert len(pubkeystr) > 0
print("KeyHashCode:", Ecc.key_hashcode(pubkeystr))
print("Is a Private Key" if Ecc.query_key(pubkeystr, "isPrivate") else "Is a Public Key")
# Now save in legacy v1 PKCS8 without public key
fname = "keypri_X448_legacy.p8"
r = Ecc.save_key(fname, prikeystr, keytype=Ecc.KeyType.LEGACY)
print(f"Created key file '{fname}'")
print(Asn1.type(fname))
print(Asn1.text_dump_tostring(fname))
def test_pfx_makefile_double():
print("\nTESTING MAKE PFX LIKE PARAGUAY CA'S DO...")
epkfile = "sifen-emisor.p8e"
certfile = "sifen-emisor.cer"
pwd = "12345678a"
pfxfile = "sifen-emisor.p12"
# Make a PFX like Paraguay SET CA's (unencrypted cert + double-encrypted key)
n = Pfx.make_file(pfxfile, certfile, epkfile, pwd, "EMPRESA DE AUTOBUSES",
Pfx.Opts.DOUBLE_ENCRYPT | Pfx.Opts.PLAIN_CERT)
assert (0 == n)
print("Created new PKCS#12 file:", pfxfile)
print("Asn1.Type(" + pfxfile + ") -->", Asn1.type(pfxfile))
# print(Asn1.text_dump_tostring(pfxfile))
# Make sure we can read both the private key and certificate
prikeystr = Rsa.read_private_key(pfxfile, pwd)
assert len(prikeystr) > 0
print("Key size =", Rsa.key_bits(prikeystr))
certstr = X509.read_cert_string_from_pfx(pfxfile, pwd)
assert len(certstr) > 0
print("Cert subject =", X509.query_cert(certstr, "subjectName", opts=X509.Opts.LDAP))
def test_aead_TOREMOVE():
pwd = "abcdef"
salt = Cnv.fromhex("DEADBEEFCAFEBABE01020304")
key = Pbe.kdf2(16, pwd, salt, 2048, Pbe.PrfAlg.HMAC_SHA256)
print(Cnv.tohex(key))
##key = Pbe.kdf2(16, "", salt, 2048, Pbe.PrfAlg.HMAC_SHA256)
##print(Cnv.tohex(key))
iv = Cnv.fromhex("4d4395e80a90b8065f56bb65")
ct = Cnv.fromhex(
"864c7e9287136ac1bdae0549121a989d1ab7067a2d6c6d1670433d98708663889069446a06daafe1904733a6bfa6ceb3c9a4bcb73833affc6f071ad45f7aabd4781eac21ed308082604217084e2c426ab7711cd2dfaad1c3031843f6e530d75ec37e8a80827b18a7f113183f6bc855d64bb004ba2368077d01db7e8539122bfecf895e34c26f09b0af54919ed6cc74d40f460fa4e5aae289bf5155098cc18a5e4cc0b048fd1b0ad06e0230031b3d642eab5d205b6284e7f70576ab2497450b3e543f527f596f5ff53b750e865e2fa0248cdd05e2b2c8c5348d52f96fa616294cee69de14f4fa9e00203d8e9ef9003ec6b27f37550b8c7ed4dfe989e5d2545602c5472ebbc986f171a3d91bd0b124a087e7622fcbe02a730b7c0d9c17b7a919dfa578a700cf4b1a727979c49431015e1e6ef0058eca07dc64ace5a1c9654d9f80a4378a719cc99c25091920e1a00e2fb5f0ae0c2350faf53d391aaf9f6faef6bcc8251029bc79b3167c58c6b8659b39edab2166ce12d0aa24271245c4e525b24e2e05703508d541e85bee75ad22e9fa71802b1d3d477cd8f62a1d5bc3cce7314a2b5c02decb0c517b5c1d19fab85c0f2b2002c13c4cd6233c46cb5ffba3ed973ee09e95f4ffce9998649df6eb91d7effbd55bb1d2a722f5b20e5f2edfe119a30b37b472685314615706afc685526dbe8bb35b262ae6e605befa926662cff131eda7263cd3586b3667dc303c8e9cbf39a534068faed83213d73fc14218cf95d53eb235ce72c3c263a2c6e80c41e56e5401382a55dfe204cf199d773563198fbf406696d6b1f071889240f1f77746b4742e1ed2db209b48d45425a1900efb0cdcc29d321ee8aab8637e3ccabf51f0c887a0c53ae7e150738a949cccf6355ed55f48182c2f3391cde0563e91c964a0048317ff9212de29bba6c0138c6cf3b98cf2f9aedb41ae9a4c7592b5bbb4a726bce29f4431789c68364d009ea7bf36b231d34d3b1dc7242f63a4dd2d5fb35ae9f32dc9d4fcad6953d724a3885b17aca34e42b065864826b3cc05e2e3d727f3a31ba94218345ab3303f5a540d486cf8dc7bf19d9f17641453e11bab07fb52cb69a96edb5f48849107cf38d81629462f588b76b9428663f404f16a7aea508fd7fda43b83198b68851d58089c98644b203313551fcc2898248eb5809c19269458ce36052c2ff155158188d2680fc98e54c22e19b9217a9ffd7a5114da4f9e32289c7183bff2d66bac9397999e21b767a58cf2ce6f65f77be5ae7cddbfe3e167015e047321245d93231324576cb50e68466a72b45aa4ab3e7b8fed6d44f4d9b847662664959316b07888de4b925141927d8d1b2257b3f72f82012e6419181e79cafb5c228638e9a369527114f34d977530a13630afce99d9c15d57d62899fffd780be2f238106051223e61ded57a2fba261b7c80b023e4cf619a654069b77791144cb32f99f8d63991f9d4e9200637fef9c914c3e57b88dda7a3da939c2cf2e8edc6ea29337c93301bcdea04bb7205f4f7d9489dc47ee7c2e24be3be33637923cc01c52d3a1219d92a357b53cb3cf8452a9d44b80b07efd88560c3d95d10652734382e9195b8774d321e6ff2670180630d641d0ea47f145f29d2b737e8005f8ccbac4319ed9719e28464c4f8882ecf3201386ad049fa03f118076e57f5ba1af616a1caf1ac57603501d529864a6de7a37c63858cfc5b63d2dfc4834de830c38e3ef67f44ae47633370c4118706f065a87c4833fbd39ad29ab7962d88a3353e1032493a0df552c79a3eac111df5b9fccef2ee18f8074f50740c477551337ddc91c5c1c1f7fc2c6b8f4b3e7c8b540524494e84c9d2a674ae44c543b45e172f8153d477de2724ef49dd7f1197761de5f7866540dd01dd2e28210fbd80fae7c3b064c46879fd40fd35e61a6de4db4c9072c2e79b2dda6b218ef8f39958b0673851a1f0e30fb5989afa39bb85ee4ace7c7e52c8ae74dbbaae3d370967ab726959cc990c962682505e69471f8af00071164d6b64f41250141c0608e4b9e8d4bcafc549d7adffb6e799895d67203ba52c9ff0c752914a7ce45c8225ea0925f9401166f48a4b5ce6d0dd303d1d70b2cbcd58509f0a000fdeb80e18d1c0b2cb2b646e438a93bf8f8d6b1b3d94bc967ea218a633954ed70bbf32f109f02106bcae86a256f8a7193ba7614aa4164803cf1b2383a061bec55dc99cd3873be80a67e1ab6a1c4cbc1551aa54436d7156806c1397b7151921ab80447ba7cfc8f58f0d2244b8f8555dea6d70bcd50353d966611b9cad0c8781581e562c823333f810406260a4b5aa706c500ebd453a6f800646be14a9e109630776c7cc7e5e33b1eed87a922d1b56769188c0e3cf4d3b9ebd75c893f0424654a5bdf465465e52ddcb8705cfe3c7c5c7a881f8cd956eba972a76cadb06d4663b4158e697121d3ab91aab156f54e721aaa247cbc8e5eb7aac5a0546fb7c58d25c60f8e8dc3750aebc8bada3f89b734b2bc7a95cffcc028d2d4e2ac30de8f7fc3b3ff7bae6b90ba7b619e66c7444551086b4e7121b7f399c33a72d755f57605a71b6529dbe3a4d01521a299ff3afc936683e55254cf42eca283a8eebdc98c0a9a5b7e98a0efdf939969cb9dcfdca2f139048e77f838d1101a0ba4d469187b77499e622d60c09a54ad197075f18ec2ef0b4244229f4c9e0b10050dc391de78dba817e93e11bc0b7fabe9c02fd7c1a114e01e675b4bf0e36ba5c25ad1ba86d200ff97396f52cb220fc244d3ecff1c7e2b17d7023d5a4ba9cca522bb2181e4c0fed8a38ea12da425acda4ee5dda6af8f11d231a334c2c83df02cdb7034cd5528574071a255e0fc356acd1fdb9afdea309a1952c05c0e1ca4db93eae60a8aefceb55a089592b79")
tag = Cnv.fromhex("fb87df7d7df8b00451fb01fdc3e792db")
print(Cnv.tohex(ct + tag))
pt = Cipher.decrypt_aead(ct + tag, key, iv, Cipher.AeadAlg.AES_128_GCM)
print(Cnv.tohex(pt))
# Explicity call this function to test the Pwd dialog class
# Note this does not begin with `test_` because we don't want it firing in py.test
def do_pwd():
print("\nTESTING PWD DIALOG...")
pwd = Pwd.prompt()
print("[" + pwd + "]")
pwd = Pwd.prompt("Demo of Pwd.prompt()", "Type secret phrase:")
print("[" + pwd + "]")
def quick_version():
print("\nDETAILS OF CORE DLL...")
print("DLL Version=" + str(Gen.version())
+ " [" + Gen.core_platform() + "] Lic="
+ Gen.licence_type()
+ " Compiled=["
+ Gen.compile_time() + "]")
print("[" + Gen.module_name() + "]" + " (" + Gen.module_info() + ")")
def main():
do_all = True
for arg in sys.argv:
global delete_tmp_dir
if (arg == 'nodelete'):
delete_tmp_dir = False
elif (arg == 'some'):
do_all = False
setup_temp_dir()
# DO THE TESTS - EITHER SOME OR ALL
if (do_all):
test_version()
test_error_lookup()
test_cnv()
test_cnv_utf8()
test_cipher()
test_cipher_block()
test_cipher_file()
test_cipher_keywrap()
test_cipher_pad()
test_rsa_makekeys()
test_rsa_errors()
test_rsa_savekeys()
test_rsa_sign()
test_rsa_encrypt()
test_rng()
test_hash()
test_hmac()
test_x509_generate()
test_x509_analyze()
test_x509_validate()
test_x509_extract()
test_wipe()
test_asn1()
test_ocsp()
test_ecc()
test_pbe()
test_pfx()
test_pem()
test_cms_envdata()
test_cms_sigdata()
test_cms_comprdata()
test_smime()
test_sig_rsa()
test_sig_ecc()
test_x509_ecc()
test_asn1_dumptostring()
test_compress()
test_aead()
test_readcertstring()
test_cipher_prefix()
test_x509_makecert_emptydn()
test_x509_certrequest_emptydn_extkeyusage()
test_read_x509_from_pfx_3des()
test_pfx_makefile_3des()
test_rng_guid()
test_ecc_dh_shared_secret()
test_ecc_dh_shared_secret_x25519()
test_cipher_hex()
test_sig_signdata_ed25519()
test_cms_makesigdata_ed25519()
test_x509_makecertself_25519()
test_cms_pseudo()
test_rsa_readjwk()
test_ecc_brainpool()
test_hash_length()
test_kdf()
test_cms_makeenvdata_ecdh()
test_x509_makecert_internal_x25519()
test_cms_envdata_auth()
test_cms_envdata_examples()
test_cnv_shortpathname()
test_gen_format_error_message()
test_cipher_gcm()
test_rsa_read_public_key_csr()
test_hash_sha3()
test_hmac_sha3()
test_prf()
test_xof()
test_scrypt()
test_pfx_makefile_double()
test_ecc_make_keys_448()
test_ecc_readbycurve_448()
test_ecc_savekeys_448()
test_ecc_dh_shared_secret_x448()
test_x509_make_cert_448()
test_sig_signdata_ed448()
test_cms_makesigdata_ed448()
test_hkpe_labeled()
test_hkpe_derive_private_key()
test_aead_chapoly()
test_cms_make_envdata_auth_chapoly()
test_rng_initialize_ex()
else: # just do some tests: comment out as necessary
test_version()
# test_error_lookup()
# test_cnv()
# test_cnv_utf8()
# test_cipher()
# test_cipher_block()
# test_cipher_file()
# test_cipher_keywrap()
# test_cipher_pad()
# test_rsa_makekeys()
# test_rsa_errors()
# test_rsa_savekeys()
# test_rsa_sign()
# test_rsa_encrypt()
test_rng()
# test_hash()
# test_hmac()
# test_x509_generate()
# test_x509_analyze()
# test_x509_validate()
# test_x509_extract()
# test_wipe()
# test_asn1()
# test_ocsp()
# test_ecc()
# test_pbe()
# test_pfx()
# test_pem()
# test_cms_envdata()
# test_cms_sigdata()
# test_cms_comprdata()
# test_smime()
# test_sig_rsa()
# test_sig_ecc()
# test_x509_ecc()
# test_asn1_dumptostring()
# test_compress()
# test_aead()
# test_readcertstring()
# test_cipher_prefix()
# test_x509_makecert_emptydn()
# test_x509_certrequest_emptydn_extkeyusage()
# test_read_x509_from_pfx_3des()
# test_pfx_makefile_3des()
test_rng_guid()
# test_ecc_dh_shared_secret()
# test_ecc_dh_shared_secret_x25519()
# test_cipher_hex()
# test_sig_signdata_ed25519()
# test_cms_makesigdata_ed25519()
# test_x509_makecertself_25519()
# test_cms_pseudo()
# test_rsa_readjwk()
# test_ecc_brainpool()
# New in [v20.5]
# test_hash_length()
# test_kdf()
# test_cms_makeenvdata_ecdh()
# test_x509_makecert_internal_x25519()
# # New in [v20.6]
# test_cms_envdata_auth()
# test_cms_envdata_examples()
# # New in [v21.0]
# test_cnv_shortpathname()
# test_gen_format_error_message()
# test_cipher_gcm()
# test_rsa_read_public_key_csr()
# test_x509_make_cert_ex()
# test_hash_sha3()
# test_hmac_sha3()
# test_prf()
# test_xof()
# # New in [v22.0]
# test_scrypt()
# test_pfx_makefile_double()
# test_ecc_make_keys_448()
# test_ecc_readbycurve_448()
# test_ecc_savekeys_448()
# test_ecc_dh_shared_secret_x448()
# test_x509_make_cert_448()
# test_sig_signdata_ed448()
# test_cms_makesigdata_ed448()
# test_hkpe_labeled()
# test_hkpe_derive_private_key()
# test_aead_chapoly()
# test_cms_make_envdata_auth_chapoly()
# # New in [v22.1]
test_rng_initialize_ex()
# Uncomment the next line to test the Pwd dialog procedure
# Do not do in py.test (unless you want to interact!)
# ## do_pwd()
# Uncomment the next line to test the Rng dialog procedure
# Do not do in py.test (unless you want to interact!)
# ##do_rng_prompt()
reset_start_dir()
quick_version()
print("__version__=", pki.__version__)
print("ALL DONE.")
if __name__ == "__main__":
main()