#! python3
# -*- coding: utf-8 -*-

"""Some tests for ``crsysapi.py`` the Python interface to CryptoSys API"""

# test_crsysapi.py: version 6.22.1
# $Date: 2024-01-05 13:53:00 $

# ************************** LICENSE *****************************************
# Copyright (C) 2023-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.
# For a copy, see <http://opensource.org/licenses/MIT>
# ****************************************************************************

import crsysapi
import os
import sys
import pytest
import shutil
from glob import iglob

_MIN_API_VERSION = 62201

print("crsysapi version =", crsysapi.__version__)
# Show some info about the core native DLL
print("API core version =", crsysapi.Gen.version())
print("module_name =", crsysapi.Gen.module_name())
print("compile_time =", crsysapi.Gen.compile_time())
print("platform =", crsysapi.Gen.core_platform())
print("licence_type =", crsysapi.Gen.licence_type())
print("module_info =", crsysapi.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 crsysapi.Gen.version() < _MIN_API_VERSION:
    raise Exception('Require API version ' +
                    str(_MIN_API_VERSION) + ' or greater')

# GLOBAL VARS
# Remember CWD where we started
start_dir = os.getcwd()
# We use a subdir `work` for our temp files
work_dir = os.path.join(start_dir, "work")


def setup_work_dir():
    if not os.path.isdir(work_dir):
        os.mkdir(work_dir)
    # Set CWD here
    os.chdir(work_dir)
    print("Working in directory:", os.getcwd())


def reset_start_dir():
    if not os.path.isdir(start_dir):
        return
    if (work_dir == start_dir):
        return
    os.chdir(start_dir)
    print("")
    # print("CWD:", os.getcwd())


# JIGGERY_POKERY FOR py.test
@pytest.fixture(scope="module", autouse=True)
def divider_module(request):
    print("\n   --- module %s() start ---" % request.module.__name__)
    setup_work_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(work_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(crsysapi.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 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_error_lookup():
    print("\nLOOKUP SOME ERROR CODES...")
    for n in range(13):
        s = crsysapi.Gen.error_lookup(n)
        if (len(s) > 0):
            print("error_lookup(" + str(n) + ")=" + s)


def test_cnv():
    print("\nTEST CNV FUNCTIONS...")

    # hex --> bytes --> base64
    b = crsysapi.Cnv.fromhex("FE DC BA 98 76 54 32 10")
    print("b=0x" + crsysapi.Cnv.tohex(b))
    print("b64(b)=" + crsysapi.Cnv.tobase64(b))
    assert(crsysapi.Cnv.tobase64(b) == "/ty6mHZUMhA=")

    # base64 --> bytes --> hex --> base64
    b = crsysapi.Cnv.frombase64("/ty6mHZUMhA=")
    print("b=0x" + crsysapi.Cnv.tohex(b))
    assert(crsysapi.Cnv.tohex(b) == "FEDCBA9876543210")
    print("b64(b)=" + crsysapi.Cnv.tobase64(b))
    assert(crsysapi.Cnv.tobase64(b) == "/ty6mHZUMhA=")


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 = crsysapi.Cipher.encrypt(pt, key, iv, algstr)
    print(crsysapi.Cnv.tohex(ct))
    b = bytearray.fromhex("5468697320736F6D652073616D706520636F6E74656E742E")
    print(b)
    assert(ct == bytearray.fromhex(
        "D76FD1178FBD02F84231F5C1D2A2F74A4159482964F675248254223DAF9AF8E4"))
    p1 = crsysapi.Cipher.decrypt(ct, key, iv, algstr)
    print(p1)
    assert(p1 == pt)

    print("Use default ECB mode (IV is ignored)")
    ct = crsysapi.Cipher.encrypt(pt, key, alg=crsysapi.Cipher.Alg.TDEA)
    print(crsysapi.Cnv.tohex(ct))
    p1 = crsysapi.Cipher.decrypt(ct, key, alg=crsysapi.Cipher.Alg.TDEA)
    print(p1)
    assert(p1 == pt)

    ct = crsysapi.Cipher.encrypt(pt, key, iv, mode=crsysapi.Cipher.Mode.CBC,
                        alg=crsysapi.Cipher.Alg.TDEA)
    print(crsysapi.Cnv.tohex(ct))
    p1 = crsysapi.Cipher.decrypt(ct, key, iv, mode=crsysapi.Cipher.Mode.CBC,
                        alg=crsysapi.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 = crsysapi.Cipher.encrypt(pt, key, iv, algstr)
    print(crsysapi.Cnv.tohex(ct))
    assert(ct == bytearray.fromhex(
        "C3153108A8DD340C0BCB1DFE8D25D2320EE0E66BD2BB4A313FB75C5638E9E17753C7E8DF5975A36677355F5C6584228B"))
    # Now decrypt using flags instead of alg string
    p1 = crsysapi.Cipher.decrypt(ct, key, iv, alg=crsysapi.Cipher.Alg.AES128,
                        mode=crsysapi.Cipher.Mode.CBC, pad=crsysapi.Cipher.Pad.PKCS5)
    print("P':", p1)
    assert(p1 == pt)

    algstr = "Aes128/ECB/OneAndZeroes"
    print(algstr)
    ct = crsysapi.Cipher.encrypt(pt, key, algmodepad=algstr)
    print("CT:", crsysapi.Cnv.tohex(ct))
    p1 = crsysapi.Cipher.decrypt(ct, key, algmodepad="Aes128/ECB/NoPad")
    print("Pn:", crsysapi.Cnv.tohex(p1))
    p1 = crsysapi.Cipher.decrypt(ct, key, algmodepad=algstr)
    print("P':", crsysapi.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 = crsysapi.Cipher.encrypt_hex(pthex, keyhex, ivhex, algstr)
    print("CT:", cthex)
    print("OK:", okhex)
    assert cthex == okhex, "crsysapi.Cipher.encrypt_hex failed"
    print("About to decrypt...")
    # Decrypt using flags instead of alg string
    p1hex = crsysapi.Cipher.decrypt_hex(cthex, keyhex, ivhex, alg=crsysapi.Cipher.Alg.TDEA, mode=crsysapi.Cipher.Mode.CBC, pad=crsysapi.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 = crsysapi.Cipher.encrypt_hex(pthex, keyhex, ivhex, algstr, opts=crsysapi.Cipher.Opts.PREFIXIV)
    print("CT:", cthex)
    print("OK:", okhex)
    assert cthex == okhex, "crsysapi.Cipher.encrypt_hex failed"
    # Decrypt using flags instead of alg string - this time we don't need the IV argument
    p1hex = crsysapi.Cipher.decrypt_hex(cthex, keyhex, None, alg=crsysapi.Cipher.Alg.AES128, mode=crsysapi.Cipher.Mode.CBC, pad=crsysapi.Cipher.Pad.ONEANDZEROES, opts=crsysapi.Cipher.Opts.PREFIXIV)
    print("P':", p1hex)
    assert(p1hex == pthex)

    # Test in ECB mode
    # SP 800-38A F.1.3 ECB-AES192.Encrypt
    keyhex = "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"
    pthex = "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51" \
            + "30c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710"
    okhex = "bd334f1d6e45f25ff712a214571fa5cc974104846d0ad3ad7734ecb3ecee4eef" \
            + "ef7afd2270e2e60adce0ba2face6444e9a4b41ba738d6c72fb16691603c18e0e"
    print("PT:", pthex)
    cthex = crsysapi.Cipher.encrypt_hex(pthex, keyhex, algmodepad="Aes192-ECB-Nopad").lower()
    print("CT:", cthex)
    print("OK:", okhex)
    assert cthex == okhex, "crsysapi.Cipher.encrypt_hex failed"
    p1hex = crsysapi.Cipher.decrypt_hex(cthex, keyhex, alg=crsysapi.Cipher.Alg.AES192, pad=crsysapi.Cipher.Pad.NOPAD).lower()
    print("P':", p1hex)
    assert(p1hex == pthex)


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 = crsysapi.Cnv.fromhex("fedcba9876543210fedcba9876543210")
    iv = crsysapi.Rng.bytestring(crsysapi.Cipher.blockbytes(crsysapi.Cipher.Alg.AES128))
    print("IV:", crsysapi.Cnv.tohex(iv))
    file_ct = "hello.aes128.enc.dat"
    n = crsysapi.Cipher.file_encrypt(file_ct, file_pt, key, iv, "aes128-ctr", opts=crsysapi.Cipher.Opts.PREFIXIV)
    assert(n == 0)
    print(file_ct + ":",)
    _print_file_hex(file_ct)

    file_chk = "hello.aes128.chk.txt"
    n = crsysapi.Cipher.file_decrypt(file_chk, file_ct, key, iv, "aes128-ctr", opts=crsysapi.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_pad():
    print("\nTEST CIPHER PAD....")

    data = crsysapi.Cnv.fromhex('FFFFFFFFFF')
    print("Input data :", crsysapi.Cnv.tohex(data))
    padded = crsysapi.Cipher.pad(data, crsysapi.Cipher.Alg.TDEA)
    print("Padded data:", crsysapi.Cnv.tohex(padded))
    unpadded = crsysapi.Cipher.unpad(padded, crsysapi.Cipher.Alg.TDEA)
    print("Unpadded   :", crsysapi.Cnv.tohex(unpadded))
    padded = crsysapi.Cipher.pad(data, crsysapi.Cipher.Alg.TDEA,
                        crsysapi.Cipher.Pad.ONEANDZEROES)
    print("Padded data:", crsysapi.Cnv.tohex(padded))
    unpadded = crsysapi.Cipher.unpad(padded, crsysapi.Cipher.Alg.TDEA,
                            crsysapi.Cipher.Pad.ONEANDZEROES)
    print("Unpadded   :", crsysapi.Cnv.tohex(unpadded))

    # Pad the empty string
    data = crsysapi.Cnv.fromhex('')
    print("Input data :", crsysapi.Cnv.tohex(data))
    padded = crsysapi.Cipher.pad(data, crsysapi.Cipher.Alg.AES128)
    print("Padded data:", crsysapi.Cnv.tohex(padded))
    unpadded = crsysapi.Cipher.unpad(padded, crsysapi.Cipher.Alg.AES128)
    print("Unpadded   :", crsysapi.Cnv.tohex(unpadded))
    # Pass data as hex strings
    datahex = 'aaaaaa'
    print("Input data :", datahex)
    paddedhex = crsysapi.Cipher.pad_hex(datahex, crsysapi.Cipher.Alg.TDEA)
    print("Padded data:", paddedhex)
    unpaddedhex = crsysapi.Cipher.unpad_hex(paddedhex, crsysapi.Cipher.Alg.TDEA)
    print("Unpadded   :", unpaddedhex)
    paddedhex = crsysapi.Cipher.pad_hex(
        datahex, crsysapi.Cipher.Alg.TDEA, crsysapi.Cipher.Pad.ONEANDZEROES)
    print("Padded data:", paddedhex)
    unpaddedhex = crsysapi.Cipher.unpad_hex(
        paddedhex, crsysapi.Cipher.Alg.TDEA, crsysapi.Cipher.Pad.ONEANDZEROES)
    print("Unpadded   :", unpaddedhex)


def test_cipher_block():
    print("\nTEST CIPHER FUNCTIONS WITH EXACT BLOCK LENGTHS...")
    key = crsysapi.Cnv.fromhex("0123456789ABCDEFF0E1D2C3B4A59687")
    iv = crsysapi.Cnv.fromhex("FEDCBA9876543210FEDCBA9876543210")
    print("KY:", crsysapi.Cnv.tohex(key))
    print("IV:", crsysapi.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:", crsysapi.Cnv.tohex(pt))
    okhex = "C3153108A8DD340C0BCB1DFE8D25D2320EE0E66BD2BB4A313FB75C5638E9E177"
    ct = crsysapi.Cipher.encrypt_block(
        pt, key, iv, alg=crsysapi.Cipher.Alg.AES128, mode=crsysapi.Cipher.Mode.CBC)
    print("CT:", crsysapi.Cnv.tohex(ct))
    print("OK:", okhex)
    assert(okhex.upper() == crsysapi.Cnv.tohex(ct))
    p1 = crsysapi.Cipher.decrypt_block(
        ct, key, iv, alg=crsysapi.Cipher.Alg.AES128, mode=crsysapi.Cipher.Mode.CBC)
    print("P1:", crsysapi.Cnv.tohex(p1))
    print("P1:", p1)

    # Using defaults (TDEA/ECB)
    key = crsysapi.Rng.bytestring(crsysapi.Cipher.keybytes(crsysapi.Cipher.Alg.TDEA))
    print("KY:", crsysapi.Cnv.tohex(key))
    ct = crsysapi.Cipher.encrypt_block(pt, key)
    print("CT:", crsysapi.Cnv.tohex(ct))
    p1 = crsysapi.Cipher.decrypt_block(ct, key)
    print("P1:", crsysapi.Cnv.tohex(p1))
    print("P1:", p1)


def test_blowfish():
    print("\nTEST BLOWFISH CIPHER...")
    key = crsysapi.Cnv.fromhex("0123456789ABCDEFF0E1D2C3B4A59687")
    iv = crsysapi.Cnv.fromhex("FEDCBA9876543210")
    print("KY:", crsysapi.Cnv.tohex(key))
    print("IV:", crsysapi.Cnv.tohex(iv))
    pt = crsysapi.Cnv.fromhex("37363534333231204E6F77206973207468652074696D6520666F722000000000")
    print("PT:", crsysapi.Cnv.tohex(pt))
    okhex = "6B77B4D63006DEE605B156E27403979358DEB9E7154616D959F1652BD5FF92CC"
    ct = crsysapi.Blowfish.encrypt_block(pt, key, "CBC", iv)
    print("CT:", crsysapi.Cnv.tohex(ct))
    print("OK:", okhex)
    assert(okhex.upper() == crsysapi.Cnv.tohex(ct))
    p1 = crsysapi.Blowfish.decrypt_block(ct, key, "CBC", iv)
    print("P1:", crsysapi.Cnv.tohex(p1))
    print("P1:", bytes(p1))
    assert(p1 == pt)

    # Using default ECB mode
    key = crsysapi.Cnv.fromhex("FEDCBA9876543210")
    print("KY:", crsysapi.Cnv.tohex(key))
    pt = crsysapi.Cnv.fromhex("0123456789ABCDEF0123456789ABCDEF")
    print("PT:", crsysapi.Cnv.tohex(pt))
    okhex = "0ACEAB0FC6A0A28D0ACEAB0FC6A0A28D"
    ct = crsysapi.Blowfish.encrypt_block(pt, key)
    print("CT:", crsysapi.Cnv.tohex(ct))
    print("OK:", okhex)
    assert(okhex.upper() == crsysapi.Cnv.tohex(ct))
    p1 = crsysapi.Blowfish.decrypt_block(ct, key)
    print("P1:", crsysapi.Cnv.tohex(p1))
    assert(p1 == pt)


def test_aead():
    print("\nTEST AEAD ENCRYPTION....")

    # GCM Test Case #03 (AES-128)
    key = crsysapi.Cnv.fromhex("feffe9928665731c6d6a8f9467308308")
    iv = crsysapi.Cnv.fromhex("cafebabefacedbaddecaf888")
    pt = crsysapi.Cnv.fromhex("d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255")
    okhex = "42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091473f59854d5c2af327cd64a62cf35abd2ba6fab4"
    print("KY =", crsysapi.Cnv.tohex(key))
    print("IV =", crsysapi.Cnv.tohex(iv))
    print("PT =", crsysapi.Cnv.tohex(pt))
    # Do the business
    ct = crsysapi.Aead.encrypt_with_tag(pt, key, iv, crsysapi.Aead.AeadAlg.AES_128_GCM)
    print("CT =", crsysapi.Cnv.tohex(ct))
    print("OK =", okhex)
    assert (okhex.lower() == crsysapi.Cnv.tohex(ct).lower())

    # Decrypt, passing IV as an argument
    dt = crsysapi.Aead.decrypt_with_tag(ct, key, iv, crsysapi.Aead.AeadAlg.AES_128_GCM)
    print("DT =", crsysapi.Cnv.tohex(dt))
    assert (crsysapi.Cnv.tohex(pt) == crsysapi.Cnv.tohex(dt))

    print("Repeat but prepend IV to output..")
    ct = crsysapi.Aead.encrypt_with_tag(pt, key, iv, crsysapi.Aead.AeadAlg.AES_128_GCM, opts=crsysapi.Aead.Opts.PREFIXIV)
    print("IV|CT =", crsysapi.Cnv.tohex(ct))
    # Decrypt, IV is prepended to ciphertext
    dt = crsysapi.Aead.decrypt_with_tag(ct, key, None, crsysapi.Aead.AeadAlg.AES_128_GCM, opts=crsysapi.Aead.Opts.PREFIXIV)
    print("DT =", crsysapi.Cnv.tohex(dt))
    assert (crsysapi.Cnv.tohex(pt) == crsysapi.Cnv.tohex(dt))

    print("RFC7739 ChaCha20_Poly1305 Sunscreen test with AAD")
    key = crsysapi.Cnv.fromhex("808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F")
    iv = crsysapi.Cnv.fromhex("070000004041424344454647")
    aad = crsysapi.Cnv.fromhex("50515253C0C1C2C3C4C5C6C7")
    pt = crsysapi.Cnv.fromhex("4C616469657320616E642047656E746C656D656E206F662074686520636C617373206F66202739393A204966204920636F756C64206F6666657220796F75206F6E6C79206F6E652074697020666F7220746865206675747572652C2073756E73637265656E20776F756C642062652069742E")
    okhex = "d31a8d34648e60db7b86afbc53ef7ec2a4aded51296e08fea9e2b5a736ee62d63dbea45e8ca9671282fafb69da92728b1a71de0a9e060b2905d6a5b67ecd3b3692ddbd7f2d778b8c9803aee328091b58fab324e4fad675945585808b4831d7bc3ff4def08e4b7a9de576d26586cec64b61161ae10b594f09e26a7e902ecbd0600691"
    print("KY =", crsysapi.Cnv.tohex(key))
    print("IV =", crsysapi.Cnv.tohex(iv))
    print("AD =", crsysapi.Cnv.tohex(aad))
    print("PT =", crsysapi.Cnv.tohex(pt))
    # Do the business
    ct = crsysapi.Aead.encrypt_with_tag(pt, key, iv, crsysapi.Aead.AeadAlg.CHACHA20_POLY1305, aad=aad)
    print("CT =", crsysapi.Cnv.tohex(ct))
    print("OK =", okhex)
    assert (okhex.lower() == crsysapi.Cnv.tohex(ct).lower())
    dt = crsysapi.Aead.decrypt_with_tag(ct, key, iv, crsysapi.Aead.AeadAlg.CHACHA20_POLY1305, aad=aad)
    print("DT =", crsysapi.Cnv.tohex(dt))
    print(f"DT ='{dt}'")
    assert (crsysapi.Cnv.tohex(pt) == crsysapi.Cnv.tohex(dt))


def test_crc():
    print("\nTEST CRC FUNCTIONS...")

    crc = crsysapi.Crc.bytes(b"123456789")
    print(f"crc={crc}=0x{crc:08x}")
    crc = 0
    fname = "1-9.txt"
    write_text_file(fname, "123456789")
    crc = crsysapi.Crc.file(fname)
    print(f"crc={crc}=0x{crc:08x}")


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 = crsysapi.Rng.initialize(seedfile)
    assert(0 == n)
    print('crsysapi.Rng.initialize() returns', n, ". Contents of seed file:")
    sd = read_binary_file(seedfile)
    print(crsysapi.Cnv.tohex(sd))
    assert(len(sd) == crsysapi.Rng.SEED_BYTES)

    print("5 random byte arrays")
    for i in range(5):
        b = crsysapi.Rng.bytestring((i + 2) * 2)
        print(crsysapi.Cnv.tohex(b).lower())

    print("5 random numbers in the range [-1 million, +1 million]")
    for i in range(5):
        r = crsysapi.Rng.number(-1000000, 1000000)
        print(r)
        assert(-1000000 <= r <= 1000000)

    print("5 random octet values")
    s = ""  # fudge to do in one line
    for i in range(5):
        r = crsysapi.Rng.octet()
        assert(0 <= r <= 255)
        s += str(r) + " "
    print(s)

    # Update seedfile
    n = crsysapi.Rng.update_seedfile(seedfile)
    assert(0 == n)
    print('crsysapi.Rng.update_seedfile() returns', n, ". Contents of seed file:")
    sd = read_binary_file(seedfile)
    print(textwrap(crsysapi.Cnv.tohex(sd)))
    assert(len(sd) == crsysapi.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 = crsysapi.Rng.test_drbgvs(2048, "da740cbc36057a8e282ae717fe7dfbb245e9e5d49908a0119c5dbcf0a1f2d5ab", "46561ff612217ba3ff91baa06d4b5440",
        "fc227293523ecb5b1e28c87863626627d958acc558a672b148ce19e2abd2dde4", "b7998998eaf9e5d34e64ff7f03de765b31f407899d20535573e670c1b402c26a",
        "1d61d4d8a41c3254b92104fd555adae0569d1835bb52657ec7fbba0fe03579c5", "b9ed8e35ad018a375b61189c8d365b00507cb1b4510d21cac212356b5bbaa8b2",
        "2089d49d63e0c4df58879d0cb1ba998e5b3d1a7786b785e7cf13ca5ea5e33cfd")
    ok = "5b70f3e4da95264233efbab155b828d4e231b67cc92757feca407cc9615a6608" + \
        "71cb07ad1a2e9a99412feda8ee34dc9c57fa08d3f8225b30d29887d20907d123" + \
        "30fffd14d1697ba0756d37491b0a8814106e46c8677d49d9157109c402ad0c24" + \
        "7a2f50cd5d99e538c850b906937a05dbb8888d984bc77f6ca00b0e3bc97b16d6" + \
        "d25814a54aa12143afddd8b2263690565d545f4137e593bb3ca88a37b0aadf79" + \
        "726b95c61906257e6dc47acd5b6b7e4b534243b13c16ad5a0a1163c0099fce43" + \
        "f428cd27c3e6463cf5e9a9621f4b3d0b3d4654316f4707675df39278d5783823" + \
        "049477dcce8c57fdbd576711c91301e9bd6bb0d3e72dc46d480ed8f61fd63811"

    print("crsysapi.Rng.test_drbgvs returns:")
    print(textwrap(s))
    print("Expected:\n", ok[:64], ' ... ', ok[-32:], sep='')
    assert(s == ok)


# 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 = crsysapi.Rng.make_seedfile('newseed.dat', strength=crsysapi.Rng.Strength.BITS_128)
    print("crsysapi.Rng.make_seedfile returns", n)

    b = crsysapi.Rng.bytes_with_prompt(32, crsysapi.Rng.Strength.BITS_192, "Type random keys until done")
    print("crsysapi.Rng.bytes_with_prompt:", crsysapi.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 = crsysapi.Cnv.tohex(b'abc')
    print("'abc' in hex:", abc_hex)

    # Use default SHA-1 algorithm
    print("Using default SHA-1...")
    b = crsysapi.Hash.data(b'abc')
    print("crsysapi.Hash.data('abc'):", crsysapi.Cnv.tohex(b))
    h = crsysapi.Hash.hex_from_data(b'abc')
    print("crsysapi.Hash.hex_from_data('abc'):", h)
    h = crsysapi.Hash.hex_from_data(bytearray.fromhex('616263'))
    print("crsysapi.Hash.hex_from_data('abc'):", h)
    h = crsysapi.Hash.hex_from_hex(abc_hex)
    print("crsysapi.Hash.hex_from_hex(abc_hex):", h)
    b = crsysapi.Hash.file('abc.txt')
    print("crsysapi.Hash.file('abc.txt'):", crsysapi.Cnv.tohex(b))
    h = crsysapi.Hash.hex_from_file('abc.txt')
    print("crsysapi.Hash.hex_from_file('abc.txt'):", h)

    print("Using SHA-256...")
    b = crsysapi.Hash.data(b'abc', crsysapi.Hash.Alg.SHA256)
    print("crsysapi.Hash.data('abc'):", crsysapi.Cnv.tohex(b))
    h = crsysapi.Hash.hex_from_hex(abc_hex, crsysapi.Hash.Alg.SHA256)
    print("crsysapi.Hash.hex_from_hex(abc_hex):", h)
    b = crsysapi.Hash.file('abc.txt', crsysapi.Hash.Alg.SHA256)
    print("crsysapi.Hash.file('abc.txt'):", crsysapi.Cnv.tohex(b))
    h = crsysapi.Hash.hex_from_file('abc.txt', crsysapi.Hash.Alg.SHA256)
    print("crsysapi.Hash.hex_from_file('abc.txt'):", h)

    # write a file containing the 3 bytes 'abc'
    write_text_file('abc.txt', 'abc')
    _dump_file('abc.txt')
    abc_hex = crsysapi.Cnv.tohex(b'abc')
    print("'abc' in hex:", abc_hex)

    b = crsysapi.Hash.data(b'abc', crsysapi.Hash.Alg.SHA3_224)
    print("crsysapi.Hash.data('abc'):", crsysapi.Cnv.tohex(b))
    assert(b == crsysapi.Cnv.fromhex('e642824c3f8cf24ad09234ee7d3c766fc9a3a5168d0c94ad73b46fdf'))
    h = crsysapi.Hash.hex_from_hex(abc_hex, crsysapi.Hash.Alg.SHA3_256)
    print("crsysapi.Hash.hex_from_hex(abc_hex):", h)
    assert(crsysapi.Cnv.fromhex(h) == crsysapi.Cnv.fromhex('3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532'))
    b = crsysapi.Hash.file('abc.txt', crsysapi.Hash.Alg.SHA3_384)
    print("crsysapi.Hash.file('abc.txt'):", crsysapi.Cnv.tohex(b))
    assert(b == crsysapi.Cnv.fromhex('ec01498288516fc926459f58e2c6ad8df9b473cb0fc08c2596da7cf0e49be4b298d88cea927ac7f539f1edf228376d25'))
    h = crsysapi.Hash.hex_from_file('abc.txt', crsysapi.Hash.Alg.SHA3_512)
    print("crsysapi.Hash.hex_from_file('abc.txt'):", h)
    assert(crsysapi.Cnv.fromhex(h) == crsysapi.Cnv.fromhex('b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0'))


def test_hash_bits():
    print("\nTESTING HASH BITS...")
    h = crsysapi.Hash.hex_from_bits(crsysapi.Cnv.fromhex("5180"), 9, crsysapi.Hash.Alg.SHA1)
    print("Input bits (9) = 0101 0001 1")
    print("hex_from_bits(SHA-1) =", h)
    assert(crsysapi.Cnv.fromhex(h) == crsysapi.Cnv.fromhex('0f582fa68b71ecdf1dcfc4946019cf5a18225bd2'))
    # Ref: SHAVS-SHA3 CAVS 19.0 "SHA3-256 ShortMsg"
    h = crsysapi.Hash.hex_from_bits(crsysapi.Cnv.fromhex("2590A0"), 22, crsysapi.Hash.Alg.SHA3_256)
    print("Input bits (22) = 1001 0110 0100 0010 1000 00")
    print("hex_from_bits(SHA-3-256) =", h)
    assert(crsysapi.Cnv.fromhex(h) == crsysapi.Cnv.fromhex('d5863d4b1ff41551c92a9e08c52177e32376c9bd100c611c607db840096eb22f'))


def test_hash_length():
    print("\nTEST HASH LENGTH...")
    print("Hash.length(SHA-1) =", crsysapi.Hash.length(crsysapi.Hash.Alg.SHA1))
    print("Hash.length(SHA-256) =", crsysapi.Hash.length(crsysapi.Hash.Alg.SHA256))
    print("Hash.length(SHA-384) =", crsysapi.Hash.length(crsysapi.Hash.Alg.SHA384))
    print("Hash.length(SHA-512) =", crsysapi.Hash.length(crsysapi.Hash.Alg.SHA512))
    print("Hash.length(RMD160) =", crsysapi.Hash.length(crsysapi.Hash.Alg.RMD160))
    print("Hash.length(ASCON-HASH) =", crsysapi.Hash.length(crsysapi.Hash.Alg.ASCON_HASH))


def test_mac():
    print("\nTESTING MAC...")
    print("Test case 4 from RFC 2202 and RFC 4231")
    key = crsysapi.Cnv.fromhex('0102030405060708090a0b0c0d0e0f10111213141516171819')
    print("key: ", crsysapi.Cnv.tohex(key))
    # data = 0xcd repeated 50 times
    data = bytearray([0xcd] * 50)
    print("data:", crsysapi.Cnv.tohex(data))

    b = crsysapi.Mac.data(data, key)
    print("HMAC-SHA-1:  ", crsysapi.Cnv.tohex(b))
    assert(b == crsysapi.Cnv.fromhex('4c9007f4026250c6bc8414f9bf50c86c2d7235da'))

    b = crsysapi.Mac.data(data, key, crsysapi.Mac.Alg.HMAC_MD5)
    print("HMAC-MD5:    ", crsysapi.Cnv.tohex(b))
    assert(b == crsysapi.Cnv.fromhex('697eaf0aca3a3aea3a75164746ffaa79'))

    b = crsysapi.Mac.data(data, key, crsysapi.Mac.Alg.HMAC_SHA256)
    print("HMAC-SHA-256:", crsysapi.Cnv.tohex(b))
    assert(b == crsysapi.Cnv.fromhex(
        '82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b'))

    h = crsysapi.Mac.hex_from_data(data, key, crsysapi.Mac.Alg.HMAC_SHA256)
    print("HMAC-SHA-256:", h)
    assert(h == '82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b')

    b = crsysapi.Mac.data(data, key, crsysapi.Mac.Alg.HMAC_SHA512)
    print("HMAC-SHA-512:", crsysapi.Cnv.tohex(b))
    assert(b == crsysapi.Cnv.fromhex(
        'b0ba465637458c6990e5a8c5f61d4af7 e576d97ff94b872de76f8050361ee3db a91ca5c11aa25eb4d679275cc5788063 a5f19741120c4f2de2adebeb10a298dd'))

    print("Test case 7 from RFC 4231")
    key = bytearray([0xaa] * 131)
    print("key: ", crsysapi.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 = crsysapi.Mac.data(data, key, crsysapi.Mac.Alg.HMAC_SHA224)
    print("HMAC-SHA-224:", crsysapi.Cnv.tohex(b))
    assert(b == crsysapi.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 = crsysapi.Mac.hex_from_hex(datahex, keyhex)
    print("HMAC-SHA-1:", h)
    assert(h == "b617318655057264e28bc0b6fb378c8ef146be00")
    h = crsysapi.Mac.hex_from_hex(datahex, keyhex, crsysapi.Mac.Alg.HMAC_SHA256)
    print("HMAC-SHA-256:", h)
    assert(h == "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7")
    # HMAC hex <-- string
    h = crsysapi.Mac.hex_from_string("Hi There", crsysapi.Cnv.fromhex(keyhex), crsysapi.Mac.Alg.HMAC_SHA1)
    print("HMAC-SHA-1:", h)

    print("\nTESTING Mac(SHA-3)...")
    print("NIST HMAC_SHA3-256.pdf Sample #1")
    key = crsysapi.Cnv.fromhex('000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F')
    print("key: ", crsysapi.Cnv.tohex(key))
    data = b'Sample message for keylen<blocklen'
    print("data:", data.decode())
    b = crsysapi.Mac.data(data, key, crsysapi.Mac.Alg.HMAC_SHA3_256)
    print("HMAC-SHA-3-256:", crsysapi.Cnv.tohex(b))
    assert(b == crsysapi.Cnv.fromhex('4fe8e202c4f058e8dddc23d8c34e467343e23555e24fc2f025d598f558f67205'))

    print("NIST HMAC_SHA3-512.pdf Sample #3")
    key = crsysapi.Cnv.fromhex("""000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F
202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F
404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F
606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F
8081828384858687""")
    print("key: ", crsysapi.Cnv.tohex(key))
    data = b'Sample message for keylen>blocklen'
    print("data:", data.decode())
    b = crsysapi.Mac.data(data, key, crsysapi.Mac.Alg.HMAC_SHA3_512)
    print("HMAC-SHA-3-512:", crsysapi.Cnv.tohex(b))
    assert(b == crsysapi.Cnv.fromhex('5f464f5e5b7848e3885e49b2c385f0694985d0e38966242dc4a5fe3fea4b37d46b65ceced5dcf59438dd840bab22269f0ba7febdb9fcf74602a35666b2a32915'))

    print("CMAC tests from SP800-38B...")
    # CMAC-AES-128 on the empty string
    keyhex = "2b7e151628aed2a6abf7158809cf4f3c"
    datahex = ""
    h = crsysapi.Mac.hex_from_hex(datahex, keyhex, crsysapi.Mac.Alg.CMAC_AES128)
    print("CMAC-AES-128(K128, '')=", h)
    assert(h == "bb1d6929e95937287fa37d129b756746")
    # CMAC_AES-256 on Example 12: Mlen = 512
    keyhex = "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"
    datahex = "6bc1bee22e409f96e93d7e117393172a" + \
        "ae2d8a571e03ac9c9eb76fac45af8e51" + \
        "30c81c46a35ce411e5fbc1191a0a52ef" + \
        "f69f2445df4f9b17ad2b417be66c3710"
    h = crsysapi.Mac.hex_from_hex(datahex, keyhex, crsysapi.Mac.Alg.CMAC_AES256)
    print("CMAC-AES-256(K256, M512)=", h)
    assert(h == "e1992190549f6ed5696a2c056c315410")

    # POLY1305 AUTHENTICATION ALGORITHM
    # Ref: Test vector from `RFC 7539` section 2.5.2
    print("Poly1305 tests...")

    keyhex = "85d6be7857556d337f4452fe42d506a80103808afb0db2fd4abff6af4149f51b"
    datahex = crsysapi.Cnv.tohex(b"Cryptographic Forum Research Group")
    print(f"key={keyhex}")
    print(f"msg='{crsysapi.Cnv.fromhex(datahex).decode()}'")
    h = crsysapi.Mac.hex_from_hex(datahex, keyhex, crsysapi.Mac.Alg.MAC_POLY1305)
    print(f"POLY1305={h}")
    assert(h == "a8061dc1305136c6c22b8baf0c0127a9")

    # KMAC
    # Ref: `KMAC_samples.pdf` "Secure Hashing - KMAC-Samples" 2017-02-27
    print("KMAC tests...")
    keyhex = "404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F"
    datahex = "00010203"
    h = crsysapi.Mac.hex_from_hex(datahex, keyhex, crsysapi.Mac.Alg.KMAC_128)
    print("KMAC128=", h)
    assert(h == "e5780b0d3ea6f7d3a429c5706aa43a00fadbd7d49628839e3187243f456ee14e")

    keyhex = "404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F"
    datahex = "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7"
    h = crsysapi.Mac.hex_from_hex(datahex, keyhex, crsysapi.Mac.Alg.KMAC_256)
    print("KMAC256=", h)
    assert(h == "75358cf39e41494e949707927cee0af20a3ff553904c86b08f21cc414bcfd691589d27cf5e15369cbbff8b9a4c2eb17800855d0235ff635da82533ec6b759b69")


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 = crsysapi.Cnv.fromhex("00010203")
    key = crsysapi.Cnv.fromhex("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F")
    okhex = "E5780B0D3EA6F7D3A429C5706AA43A00FADBD7D49628839E3187243F456EE14E"
    kmac = crsysapi.Prf.bytes(nbytes, msg, key, crsysapi.Prf.Alg.KMAC128)
    print("KMAC=", crsysapi.Cnv.tohex(kmac))
    print("OK  =", okhex)
    assert crsysapi.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 = crsysapi.Cnv.fromhex("""000102030405060708090A0B0C0D0E0F
101112131415161718191A1B1C1D1E1F
202122232425262728292A2B2C2D2E2F
303132333435363738393A3B3C3D3E3F
404142434445464748494A4B4C4D4E4F
505152535455565758595A5B5C5D5E5F
606162636465666768696A6B6C6D6E6F
707172737475767778797A7B7C7D7E7F
808182838485868788898A8B8C8D8E8F
909192939495969798999A9B9C9D9E9F
A0A1A2A3A4A5A6A7A8A9AAABACADAEAF
B0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF
C0C1C2C3C4C5C6C7""")
    key = crsysapi.Cnv.fromhex("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F")
    okhex = "75358CF39E41494E949707927CEE0AF20A3FF553904C86B08F21CC414BCFD691589D27CF5E15369CBBFF8B9A4C2EB17800855D0235FF635DA82533EC6B759B69"
    kmac = crsysapi.Prf.bytes(nbytes, msg, key, crsysapi.Prf.Alg.KMAC256)
    print("KMAC=", crsysapi.Cnv.tohex(kmac))
    print("OK  =", okhex)
    assert crsysapi.Cnv.tohex(kmac).upper() == okhex, "KMAC failed"

    # Sample #2
    # Same as Sample #1 except with custom string
    nbytes = 256 // 8
    msg = crsysapi.Cnv.fromhex("00010203")
    key = crsysapi.Cnv.fromhex("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F")
    custom = "My Tagged Application"
    okhex = "3B1FBA963CD8B0B59E8C1A6D71888B7143651AF8BA0A7070C0979E2811324AA5"
    kmac = crsysapi.Prf.bytes(nbytes, msg, key, crsysapi.Prf.Alg.KMAC128, custom)
    print("KMAC=", crsysapi.Cnv.tohex(kmac))
    print("OK  =", okhex)
    assert crsysapi.Cnv.tohex(kmac).upper() == okhex, "KMAC failed"

    # Request a lot of output (> single KECCAK block)
    nbytes = 1600 // 8
    msg = crsysapi.Cnv.fromhex("00010203")
    key = crsysapi.Cnv.fromhex("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F")
    okhex = """38158A1CAE4E1A25D85F2031246ADE69
7B3292FEF88B0923A59A02D1D53B7046
53EE7242662A10796BA20779D300D52D
7432018741233D587252D31DC48BDB82
33285D4A4ACD65848509B051A448D873
649228B6626E5EF817C7AF2DEDC91F12
0F8CA535A1EE301FAE8186FDEDE5A761
81A472A32CFAD1DDD1391E162F124D4A
7572AD8A20076601BCF81E4B0391F3E9
5AEFFA708C33C1217C96BE6A4F02FBBC
2D3B3B6FFAEB5BFD3BE4A2E02B75993F
CC04DA6FAC4BFCB2A9F05792A1A5CC80
CA34186243EFDB31"""
    okhex = okhex.replace("\n", "")
    kmac = crsysapi.Prf.bytes(nbytes, msg, key, crsysapi.Prf.Alg.KMAC128)
    print("KMAC=", crsysapi.Cnv.tohex(kmac))
    print("OK  =", okhex)
    assert crsysapi.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 = crsysapi.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 = crsysapi.Xof.bytes(nbytes, msg, crsysapi.Xof.Alg.SHAKE256)
    print("OUT=", crsysapi.Cnv.tohex(xof))
    print("OK =", okhex)
    assert(crsysapi.Cnv.tohex(xof).lower() == okhex)

# TODO: add MGF-1


def test_compress():
    print("\nTEST COMPRESSION....")
    print("Using zlib...")
    message = b"hello, hello, hello. This is a 'hello world' message for the world, repeat, for the world."
    print("MSG:", message)
    comprdata = crsysapi.Compr.compress(message)
    print("Compressed = (0x)" + crsysapi.Cnv.tohex(comprdata))
    print(f"Compressed {len(message)} bytes to {len(comprdata)}")
    # Now uncompresss (inflate)
    uncomprdata = crsysapi.Compr.uncompress(comprdata)
    print("Uncompressed = '" + str(uncomprdata) + "'")
    assert (uncomprdata == message)
    print("Using Zstandard...")
    comprdata = crsysapi.Compr.compress(message, crsysapi.Compr.Alg.ZSTD)
    print("Compressed = (0x)" + crsysapi.Cnv.tohex(comprdata))
    print(f"Compressed {len(message)} bytes to {len(comprdata)}")
    # Now uncompresss (inflate)
    uncomprdata = crsysapi.Compr.uncompress(comprdata, crsysapi.Compr.Alg.ZSTD)
    print("Uncompressed = '" + str(uncomprdata) + "'")
    assert (uncomprdata == message)


def test_pbe():
    print("\nTESTING PASSWORD-BASED ENCRYPTION (PBE)...")
    password = 'password'
    salt = crsysapi.Cnv.fromhex('78 57 8E 5A 5D 63 CB 06')
    count = 2048
    print("password = '" + password + "'")
    print("salt = 0x" + crsysapi.Cnv.tohex(salt))
    print("count =", count)

    dklen = 24
    print("dklen =", dklen)
    dk = crsysapi.Pbe.kdf2(dklen, password, salt, count)
    print("dk =", crsysapi.Cnv.tohex(dk))
    assert crsysapi.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 = crsysapi.Pbe.kdf2(dklen, password, salt, count)
    print("dk =", crsysapi.Cnv.tohex(dk))
    assert crsysapi.Cnv.tohex(dk) == \
        "BFDE6BE94DF7E11DD409BCE20A0255EC327CB936FFE93643C4B150DEF77511224479994567F2E9B4E3BD0DF7AEDA3022B1F26051D81505C794F8940C04DF1144"

    # Use different HMAC algorithms
    dklen = 24
    dk = crsysapi.Pbe.kdf2(dklen, password, salt, count, prfalg=crsysapi.Pbe.PrfAlg.HMAC_SHA1)
    print("dk(HMAC-SHA-1)   =", crsysapi.Cnv.tohex(dk))
    assert crsysapi.Cnv.tohex(dk) == "BFDE6BE94DF7E11DD409BCE20A0255EC327CB936FFE93643"
    dk = crsysapi.Pbe.kdf2(dklen, password, salt, count, prfalg=crsysapi.Pbe.PrfAlg.HMAC_SHA256)
    print("dk(HMAC-SHA-256) =", crsysapi.Cnv.tohex(dk))
    assert crsysapi.Cnv.tohex(dk) == "97B5A91D35AF542324881315C4F849E327C4707D1BC9D322"
    dk = crsysapi.Pbe.kdf2(dklen, password, salt, count, prfalg=crsysapi.Pbe.PrfAlg.HMAC_SHA224)
    print("dk(HMAC-SHA-224) =", crsysapi.Cnv.tohex(dk))
    assert crsysapi.Cnv.tohex(dk) == "10CFFEDFB13503519969151E466F587028E0720B387F9AEF"

    # Use SCRYPT examples from RFC7914
    dk = crsysapi.Pbe.scrypt(64, b'password', b'NaCl', 1024, 8, 16)
    print("dk(SCRYPT)=", crsysapi.Cnv.tohex(dk))
    assert crsysapi.Cnv.tohex(dk)== 'FDBABE1C9D3472007856E7190D01E9FE7C6AD7CBC8237830E77376634B373162' \
            + '2EAF30D92E22A3886FF109279D9830DAC727AFB94A83EE6D8360CBDFA2CC0640'
    # Pass empty string for both password and salt with (N=16, r=1, p=1)
    dk = crsysapi.Pbe.scrypt(64, b'', b'', 16, 1, 1)
    print("dk(SCRYPT)=", crsysapi.Cnv.tohex(dk))
    assert crsysapi.Cnv.tohex(dk)== '77D6576238657B203B19CA42C18A0497F16B4844E3074AE8DFDFFA3FEDE21442' \
            + 'FCD0069DED0948F8326A753A0FC81F17E8D3E0FB2E0D3628CF35E20C38D18906'


def test_wipe():
    print("\nTESTING Wipe...")

    print("Note that Wipe.data() just zeroizes the data, it does not change the length")

    b = crsysapi.Cnv.fromhex('3a854166ac5d9f023f54d517d0b39dbd946770db9c2b95c9f6f565d1')
    print("BEFORE b=", crsysapi.Cnv.tohex(b))
    crsysapi.Wipe.data(b)
    print("AFTER Wipe.data() b=", crsysapi.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])
    crsysapi.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))
    crsysapi.Wipe.file(fname)
    print("After Wipe.file(), isfile() returns",  os.path.isfile(fname))
    assert(not os.path.isfile(fname))


def test_cipherstream():
    print("\nTESTING CipherStream...")
    print("Using ARCFOUR...")
    key = crsysapi.Cnv.fromhex("0123456789abcdef")
    pt = crsysapi.Cnv.fromhex("0123456789abcdef")
    okhex = "75b7878099e0c596"
    print("KY =", crsysapi.Cnv.tohex(key))
    print("PT =", crsysapi.Cnv.tohex(pt))
    # Do the business
    ct = crsysapi.CipherStream.bytes(pt, key, None, crsysapi.CipherStream.Alg.ARCFOUR)
    print("CT =", crsysapi.Cnv.tohex(ct))
    print("OK =", okhex)
    assert (okhex.lower() == crsysapi.Cnv.tohex(ct).lower())
    # Repeat to decrypt
    dt = crsysapi.CipherStream.bytes(ct, key, None, crsysapi.CipherStream.Alg.ARCFOUR)
    print("DT =", crsysapi.Cnv.tohex(dt))
    assert (pt == dt)
    # Create and encrypt a file
    ptfile = "arcfour.dat"
    encfile = "arcfour.enc"
    write_binary_file(ptfile, crsysapi.Cnv.fromhex("0123456789abcdef"))
    r = crsysapi.CipherStream.file(encfile, ptfile, key, b'', crsysapi.CipherStream.Alg.ARCFOUR)
    print("CipherStream.file returns ", r, "(expected 0)")
    ct = read_binary_file(encfile)
    print("CT =", crsysapi.Cnv.tohex(ct))
    print("OK =", okhex)

    print("Using Salsa20...")
    # Set 6, vector#  0:
    key = crsysapi.Cnv.fromhex("0053A6F94C9FF24598EB3E91E4378ADD")
    iv = crsysapi.Cnv.fromhex("0D74DB42A91077DE")
    pt = b'\x00' * 64
    okhex = "05E1E7BEB697D999656BF37C1B978806735D0B903A6007BD329927EFBE1B0E2A8137C1AE291493AA83A821755BEE0B06CD14855A67E46703EBF8F3114B584CBA"
    print("KY =", crsysapi.Cnv.tohex(key))
    print("IV =", crsysapi.Cnv.tohex(iv))
    print("PT =", crsysapi.Cnv.tohex(pt))
    # Do the business
    ct = crsysapi.CipherStream.bytes(pt, key, iv, crsysapi.CipherStream.Alg.SALSA20)
    print("CT =", crsysapi.Cnv.tohex(ct))
    print("OK =", okhex)
    assert (okhex.lower() == crsysapi.Cnv.tohex(ct).lower())
    # Repeat to decrypt
    dt = crsysapi.CipherStream.bytes(ct, key, iv, crsysapi.CipherStream.Alg.SALSA20)
    print("DT =", crsysapi.Cnv.tohex(dt))
    assert (pt == dt)

    print("Using ChaCha20 with counter=1...")
    key = crsysapi.Cnv.fromhex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f")
    iv = crsysapi.Cnv.fromhex("000000000000004a00000000")
    pt = b"Ladies and Gentlemen of the class of '99: If I could offer you only one tip for the future, sunscreen would be it."
    okhex = "6E2E359A2568F98041BA0728DD0D6981E97E7AEC1D4360C20A27AFCCFD9FAE0BF91B65C5524733AB8F593DABCD62B3571639D624E65152AB8F530C359F0861D807CA0DBF500D6A6156A38E088A22B65E52BC514D16CCF806818CE91AB77937365AF90BBF74A35BE6B40B8EEDF2785E42874D"
    print("KY =", crsysapi.Cnv.tohex(key))
    print("IV =", crsysapi.Cnv.tohex(iv))
    print("PT =", crsysapi.Cnv.tohex(pt))
    print(f"PT = {pt}")
    # Do the business
    ct = crsysapi.CipherStream.bytes(pt, key, iv, crsysapi.CipherStream.Alg.CHACHA20, counter=1)
    print("CT =", crsysapi.Cnv.tohex(ct))
    print("OK =", okhex)
    assert (okhex.lower() == crsysapi.Cnv.tohex(ct).lower())
    # Repeat to decrypt
    dt = crsysapi.CipherStream.bytes(ct, key, iv, crsysapi.CipherStream.Alg.CHACHA20, counter=1)
    print("DT =", crsysapi.Cnv.tohex(dt))
    assert (pt == dt)


def test_keywrap():
    print("\nTESTING CipherKeyWrap...")
    keydata = crsysapi.Cnv.fromhex("00112233 44556677 8899aabb ccddeeff")
    kek = crsysapi.Cnv.fromhex("c17a44e8 e28d7d64 81d1ddd5 0a3b8914")
    print("KD          =", crsysapi.Cnv.tohex(keydata))
    print("KEK         =", crsysapi.Cnv.tohex(kek))
    wk = crsysapi.Cipher.key_wrap(keydata, kek, crsysapi.Cipher.Alg.AES128)
    print("WK(AES-128) =", crsysapi.Cnv.tohex(wk))
    print("OK          =", "503D75C73630A7B02ECF51B9B29B907749310B77B0B2E054")
    # Reverse
    kd = crsysapi.Cipher.key_unwrap(wk, kek, crsysapi.Cipher.Alg.AES128)
    print("KD'         =", crsysapi.Cnv.tohex(kd))

    keydata = crsysapi.Cnv.fromhex("8cbedec4 8d063e1b a46be8e3 69a9c398 d8e30ee5 42bc347c 4f30e928 ddd7db49")
    kek = crsysapi.Cnv.fromhex("9e84ee99 e6a84b50 c76cd414 a2d2ec05 8af41bfe 4bf3715b f894c8da 1cd445f6")
    print("KD          =", crsysapi.Cnv.tohex(keydata))
    print("KEK         =", crsysapi.Cnv.tohex(kek))
    wk = crsysapi.Cipher.key_wrap(keydata, kek, crsysapi.Cipher.Alg.AES256)
    print("WK(AES-256) =", crsysapi.Cnv.tohex(wk))
    print("OK          =", "EAFB901F82B98D37F17497063DE3E5EC7246AB57200AE73EDDDDF24AA403DAFA0C5AE151D1746FA4")
    # Reverse
    kd = crsysapi.Cipher.key_unwrap(wk, kek, crsysapi.Cipher.Alg.AES256)
    print("KD'         =", crsysapi.Cnv.tohex(kd))

    keydata = crsysapi.Cnv.fromhex("84E7F2D878F89FCCCD2D5EBAFC56DAF73300F27EF771CD68")
    kek = crsysapi.Cnv.fromhex("8AD8274E56F467738EDD83D4394E5E29AF7C4089E4F8D9F4")
    print("KD          =", crsysapi.Cnv.tohex(keydata))
    print("KEK         =", crsysapi.Cnv.tohex(kek))
    wk = crsysapi.Cipher.key_wrap(keydata, kek, crsysapi.Cipher.Alg.TDEA)
    print("WK(3DES)    =", crsysapi.Cnv.tohex(wk))
    # NOTE: output for Triple DES key wrap is different each time
    # Reverse
    kd = crsysapi.Cipher.key_unwrap(wk, kek, crsysapi.Cipher.Alg.TDEA)
    print("KD'         =", crsysapi.Cnv.tohex(kd))


def test_ascon_aead():
    print("\nTEST ASCON AEAD...")
    # Ref: ascon128v12/LWC_AEAD_KAT_128_128.txt, Count = 303
    key = crsysapi.Cnv.fromhex("000102030405060708090A0B0C0D0E0F")
    nonce = crsysapi.Cnv.fromhex("000102030405060708090A0B0C0D0E0F")
    pt = crsysapi.Cnv.fromhex("000102030405060708")
    ad = crsysapi.Cnv.fromhex("0001020304")
    print("K =", crsysapi.Cnv.tohex(key))
    print("N =", crsysapi.Cnv.tohex(nonce))
    print("P =", crsysapi.Cnv.tohex(pt))
    print("A =", crsysapi.Cnv.tohex(ad))

    ct = crsysapi.Aead.encrypt_with_tag(pt, key, nonce, crsysapi.Aead.AeadAlg.AEAD_ASCON_128, aad=ad)
    print("C =", crsysapi.Cnv.tohex(ct))
    assert(crsysapi.Cnv.tohex(ct) == "0E6A8B0CA517F53D3D375623AC11C852FF0A98098CCB7429F2")
    # Check decrypted text
    dt = crsysapi.Aead.decrypt_with_tag(ct, key, nonce, crsysapi.Aead.AeadAlg.AEAD_ASCON_128, aad=ad)
    print("D =", crsysapi.Cnv.tohex(dt))
    assert(crsysapi.Cnv.tohex(dt) == crsysapi.Cnv.tohex(pt))
    # Same but prepending iv (nonce) to ciphertext
    ct = crsysapi.Aead.encrypt_with_tag(pt, key, nonce, crsysapi.Aead.AeadAlg.AEAD_ASCON_128, aad=ad, opts=crsysapi.Aead.Opts.PREFIXIV)
    print("C =", crsysapi.Cnv.tohex(ct))
    dt = crsysapi.Aead.decrypt_with_tag(ct, key, nonce, crsysapi.Aead.AeadAlg.AEAD_ASCON_128, aad=ad, opts=crsysapi.Aead.Opts.PREFIXIV)
    print("D =", crsysapi.Cnv.tohex(dt))
    assert(crsysapi.Cnv.tohex(dt) == crsysapi.Cnv.tohex(pt))

    # Use ASCON-128A with no AAD on empty string
    # Ref: ascon128av12/LWC_AEAD_KAT_128_128.txt, Count = 1
    pt = crsysapi.Cnv.fromhex("")  # Empty string
    print("P =", crsysapi.Cnv.tohex(pt))
    ct = crsysapi.Aead.encrypt_with_tag(pt, key, nonce, crsysapi.Aead.AeadAlg.AEAD_ASCON_128A)
    print("C =", crsysapi.Cnv.tohex(ct))
    assert(crsysapi.Cnv.tohex(ct) == "7A834E6F09210957067B10FD831F0078")
    dt = crsysapi.Aead.decrypt_with_tag(ct, key, nonce, crsysapi.Aead.AeadAlg.AEAD_ASCON_128A)
    print("D =", crsysapi.Cnv.tohex(dt))
    assert(crsysapi.Cnv.tohex(dt) == crsysapi.Cnv.tohex(pt))


def test_ascon_hash():
    print("\nTEST ASCON HASH...")
    # Ref: asconhashv12/LWC_HASH_KAT_256.txt; Count = 513
    msg = crsysapi.Cnv.fromhex("""000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627
28292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F
505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F7071727374757677
78797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F
A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7
C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF
F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF000102030405060708090A0B0C0D0E0F1011121314151617
18191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F
404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F6061626364656667
68696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F
909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7
B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF
E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF""")
    digest = crsysapi.Hash.data(msg, crsysapi.Hash.Alg.ASCON_HASH)
    print("MD =", crsysapi.Cnv.tohex(digest))
    assert(crsysapi.Cnv.tohex(digest) == "7039284FA1CB4C798250B1A62E2378718040E10F206527BFCEB2FF3887884484")
    # Ref: asconhashav12/LWC_HASH_KAT_256.txt; Count = 1
    # ASCON-HASHA of empty string
    digesthex = crsysapi.Hash.hex_from_string("", crsysapi.Hash.Alg.ASCON_HASHA).upper()
    print("MD =", digesthex)
    assert(digesthex == "AECD027026D0675F9DE7A8AD8CCF512DB64B1EDCF0B20C388A0C7CC617AAA2C4")
    # Compute digest of file - ah! cannot use ASCON for files
    print("<<EXPECTING AN ERROR HERE...")
    print("Cannot hash file using ASCON:")
    try:
        write_binary_file("ascon_data.dat", msg);
        digest = crsysapi.Hash.file("ascon_data.dat", crsysapi.Hash.Alg.ASCON_HASH)
        print("MD =", crsysapi.Cnv.tohex(digest))
    except Exception as e:
        print("\t", e)
    print(">>")


def test_ascon_xof():
    print("\nTEST ASCON XOF...")
    # Ref: asconxofv12/LWC_HASH_KAT_256.txt, Count = 17
    msg = crsysapi.Cnv.fromhex("000102030405060708090A0B0C0D0E0F")
    md = crsysapi.Xof.bytes(32, msg, crsysapi.Xof.Alg.ASCON_XOF)
    print("MD =", crsysapi.Cnv.tohex(md))
    assert(crsysapi.Cnv.tohex(md) == "C861A89CFB1335F278C96CF7FFC9753C290CBE1A4E186D2923B496BB4EA5E519")
    # Repeat but ask for more or fewer bytes in output
    md = crsysapi.Xof.bytes(20, msg, crsysapi.Xof.Alg.ASCON_XOF)
    print("MD =", crsysapi.Cnv.tohex(md))
    md = crsysapi.Xof.bytes(40, msg, crsysapi.Xof.Alg.ASCON_XOF)
    print("MD =", crsysapi.Cnv.tohex(md))
    # ASCON-XOFA of empty string
    # Ref: asconxofav12/LWC_HASH_KAT_256.txt, Count = 1
    md = crsysapi.Xof.bytes(32, b"", crsysapi.Xof.Alg.ASCON_XOFA)
    print("MD =", crsysapi.Cnv.tohex(md))
    assert(crsysapi.Cnv.tohex(md) == "7C10DFFD6BB03BE262D72FBE1B0F530013C6C4EADAABDE278D6F29D579E3908D")
    md = crsysapi.Xof.bytes(20, b"", crsysapi.Xof.Alg.ASCON_XOFA)
    print("MD =", crsysapi.Cnv.tohex(md))
    md = crsysapi.Xof.bytes(40, b"", crsysapi.Xof.Alg.ASCON_XOFA)
    print("MD =", crsysapi.Cnv.tohex(md))


def test_xof_mgf1():
    print("\nTEST XOF MGF1...")
    msg = crsysapi.Cnv.fromhex("012345ff")
    md = crsysapi.Xof.bytes(24, msg, crsysapi.Xof.Alg.MGF1_SHA1)
    print("MD(mgf1_sha1) =", crsysapi.Cnv.tohex(md))
    assert(crsysapi.Cnv.tohex(md) == "242FB2E7A338AE07E580047F82B7ACFF83A41EC5D8FF9BAB")
    # MGF1-SHA-1 of empty string
    md = crsysapi.Xof.bytes(24, b'', crsysapi.Xof.Alg.MGF1_SHA1)
    print("MD(mgf1_sha1) =", crsysapi.Cnv.tohex(md))
    assert(crsysapi.Cnv.tohex(md) == "9069CA78E7450A285173431B3E52C5C25299E473479E04F3")
    # Example from SPHINCS+ submission October 2020
    msg = crsysapi.Cnv.fromhex("3b5c056af3ebba70d4c805380420585562b32410a778f558ff951252407647e3")
    md = crsysapi.Xof.bytes(34, msg, crsysapi.Xof.Alg.MGF1_SHA256)
    print("MD(mgf1_sha256) =", crsysapi.Cnv.tohex(md))
    assert(crsysapi.Cnv.tohex(md) == "5B7EB772AECF04C74AF07D9D9C1C1F8D3A90DCDA00D5BAB1DC28DAECDC86EB87611E")
    md = crsysapi.Xof.bytes(34, msg, crsysapi.Xof.Alg.MGF1_SHA512)
    print("MD(mgf1_sha512) =", crsysapi.Cnv.tohex(md))


def test_shortpathname():
    print("\nTEST SHORTNAMEPATH...")
    fname = "你好.txt"
    write_text_file(fname, "你好")
    print("filename =", fname)
    shortname = crsysapi.Cnv.shortpathname(fname)
    print("shortname=", shortname)
    # Create an empty file with Unicode name for encrypted output
    file_ct = "你好加密.enc"
    write_text_file(file_ct, "")
    key = crsysapi.Cnv.fromhex("fedcba9876543210fedcba9876543210")
    iv = crsysapi.Rng.bytestring(crsysapi.Cipher.blockbytes(crsysapi.Cipher.Alg.AES128))
    # Get shortname for output file
    shortname_ct = crsysapi.Cnv.shortpathname(file_ct)
    print("shortname_ct=", shortname_ct)
    # Carry out file encryption using shortpath names
    n = crsysapi.Cipher.file_encrypt(shortname_ct, shortname, key, iv, "aes128-ctr", opts=crsysapi.Cipher.Opts.PREFIXIV)
    assert(n == 0)
    # Note we can use the Unicode name with pure Python functions,
    # but we must use the shortpathname when calling cryptosyspki functions.
    print(file_ct + ":",)
    _print_file_hex(file_ct)

    file_chk = "nihao.aes128.chk.txt"
    # Use shortpathname for filein argument
    n = crsysapi.Cipher.file_decrypt(file_chk, shortname_ct, key, None, "aes128-ctr", opts=crsysapi.Cipher.Opts.PREFIXIV)
    assert(n == 0)
    print(file_chk + ":",)
    _print_file(file_chk)
    # check files are equal
    assert(read_binary_file(fname) == read_binary_file(file_chk))


def test_rng_initialize_ex():
    print("\nTESTING RNG_INITIALIZE_EX...")
    n = crsysapi.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
    # NB this is a demonstration; you would not do this under normal circumstances.
    n = crsysapi.Rng.initialize_ex(crsysapi.Rng.Opts.NO_INTEL_DRNG)
    print(f"Rng.initialize_ex(NO_INTEL_DRNG) returns {n} (expected -214)")
    # Check again, should now be off
    n = crsysapi.Rng.initialize_ex()
    print(f"Rng.initialize_ex returns {n} (expected -214)")


def quick_version():
    print("\nDETAILS OF CORE DLL...")
    print("DLL Version=" + str(crsysapi.Gen.version())
          + " [" + crsysapi.Gen.core_platform() + "] Lic="
          + crsysapi.Gen.licence_type()
          + " Compiled=["
          + crsysapi.Gen.compile_time() + "]")
    print("[" + crsysapi.Gen.module_info() + "]")
    print("[" + crsysapi.Gen.module_name() + "]")


def main():
    # Act on any arguments in command line
    do_all = True
    for arg in sys.argv:
        if (arg == 'some'):
            do_all = False
    setup_work_dir()

    # DO THE TESTS - EITHER SOME OR ALL
    if (do_all):
        print("DOING ALL TESTS...")
        test_error_lookup()
        test_cnv()
        test_cipher()
        test_cipher_hex()
        test_cipher_file()
        test_cipher_block()
        test_cipher_pad()
        test_crc()
        test_rng()
        test_hash()
        test_hash_bits()
        test_hash_length()
        test_mac()
        test_prf()
        test_xof()
        test_wipe()
        test_compress()
        test_blowfish()
        test_pbe()
        test_aead()
        test_cipherstream()
        test_keywrap()
        test_ascon_aead()
        test_ascon_hash()
        test_ascon_xof()
        test_xof_mgf1()
        test_shortpathname()
        test_rng_initialize_ex()

    else:   # just do some tests: comment out as necessary
        print("DOING SOME TESTS...")
        # test_error_lookup()
        # test_cnv()
        # test_cipher()
        # test_cipher_hex()
        # test_cipher_block()
        # test_cipher_file()
        # test_cipher_pad()
        # test_crc()
        # test_rng()
        # test_hash()
        # test_hash_length()
        # test_hash_bits()
        # test_mac()
        # test_prf()
        # test_xof()
        # test_wipe()
        # test_compress()
        # test_blowfish()
        # test_pbe()
        # test_aead()
        # test_cipherstream()
        # test_keywrap()
        # test_ascon_aead()
        # test_ascon_hash()
        # test_ascon_xof()
        # test_xof_mgf1()
        # test_shortpathname()
        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_rng_prompt()
    reset_start_dir()
    quick_version()
    print("crsysapi.__version__=", crsysapi.__version__)
    print("ALL DONE.")


if __name__ == "__main__":
    main()