Attribute VB_Name = "TestPKI"
' $Id: TestPKI.bas $

'****************************** LICENSE ***********************************
' * Copyright (C) 2001-23 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>
' *   Last updated:
' *   $Date: 2022-01-01 03:31:00 $
' *   $Version: 21.0.0 $
'****************************************************************************
'
' Some tests using the CryptoSys PKI VB6/VBA wrapper interface.

Option Explicit
Option Base 0

Public Const MIN_VERSION As Long = 210000

Public Sub DoAllTests()
    Dim n As Long
    Dim isok As Boolean
    
    Debug.Print ("INTERROGATE THE CORE DICRPKI DLL...")
    n = pkiVersion()
    Debug.Print "Version=" & n
    If n < MIN_VERSION Then
        MsgBox "Require diCrPKI v" & MIN_VERSION & " or higher", vbCritical
        Exit Sub
    End If
    Debug.Print "ModuleName=" & pkiModuleName()
    Debug.Print "CWD=" & CurDir
     
    Call test_aead
    Call test_asn1TextDumpToString
    Call test_asn1Type
    Call test_cipherDecryptAEAD
    Call test_cipherDecryptBytes
    Call test_cipherDecryptHex
    Call test_cipherEncryptAEAD
    Call test_cipherEncryptBytes
    Call test_cipherEncryptHex
    Call test_cipherKeyWrap
    Call test_cmsGetSigDataDigest
    Call test_cmsMakeSigData_pss
    Call test_cmsMakeSigDataFromSigValue
    Call test_cmsQueryEnvData
    Call test_cmsQuerySigData
    Call test_cmsReadEnvDataToBytes
    Call test_cmsReadSigDataToBytes
    Call test_cnvBase58FromBytes
    Call test_cnvByteEncoding
    Call test_cnvBytesLen
    Call test_cnvNumToBytes
    Call test_cnvReverseBytes
    Call test_cnvUTF8BytesFromLatin1
    Call test_comprCompress
    Call test_eccDHSharedSecret
    Call test_eccReadKey
    Call test_eccReadPrivateKey
    Call test_eccMakeKeys
    Call test_encrypt_empty
    Call test_hash_empty
    Call test_hash_utf8
    Call test_hashHexFromHex
    Call test_hmac_empty
    Call test_hmacBytes
    Call test_ocspMakeRequest
    Call test_ocspReadResponse
    Call test_padBytesBlock
    Call test_padHexBlock
    Call test_pbeKdf2
    Call test_pbeKdf2Hex
    Call test_pkiCompileTime
    Call test_pkiLastError
    Call test_rngBytes
    Call test_rngGuid
    Call test_rsaEncodeMsg
    Call test_rsaEncrypt
    Call test_rsaKeys
    Call test_rsaKeyValue
    Call test_rsaPublicKeyFromPrivate
    Call test_rsaRawPrivate
    Call test_rsaReadAnyPrivateKey
    Call test_rsaReadAnyPublicKey
    Call test_rsaToXMLString
    Call test_sigSignData
    Call test_sigSignFile
    Call test_smimeQuery
    Call test_unpadHex
    Call test_wipeBytes
    Call test_wipeString
    Call test_x509QueryCert
    Call test_x509ReadStringFromFile
    ' New in [v20.5]
    Call test_hashLength
    Call test_kdfBytes
    Call test_kdfForCms
    Call test_cmsEnvData_ecdh
    Call test_x509MakeCert_X25519
    Call test_pfxMakeFile_AES256
    Call test_cmsMakeSigData_X25519
    ' New in [v20.6]
    Call test_cmsEnvData_adv
    ' New in [v21.0]
    Call test_errFormatErrorMessage
    Call test_cipher_GCM
    Call test_rsaReadPublicKey_CSR
    Call test_x509MakeCert_Ex
    Call test_hash_sha3
    Call test_hmac_sha3
    Call test_prfBytes
    Call test_xofBytes
    
    Debug.Print "ALL DONE."
End Sub

Public Sub test_cnvBytesLen()
    Dim ab() As Byte
    Debug.Print cnvBytesLen(ab) ' Expecting 0
    ReDim ab(10)    ' NB actually 11 elements (0..10)
    Debug.Print cnvBytesLen(ab) ' 11
    ab = vbNullString   ' Set as empty array
    Debug.Print cnvBytesLen(ab) ' 0
End Sub

Public Sub test_pkiLastError()
    Dim s As String
    ' Valid function call, no error
    s = hashHexFromHex("616263", PKI_HASH_SHA1)
    Debug.Print "SHA1('abc')=" & s
    ' No error, so expecting empty string
    Debug.Print "LastError='" & pkiLastError() & "'"
    ' Force an error
    s = rsaFromXMLString("BADSTRING")
    Debug.Print "rsaFromXMLString(ERROR) returns '" & s & "'"
    Debug.Print "LastError='" & pkiLastError() & "'"
End Sub

Public Sub test_pkiErrorLookup()
    Dim nErrCode As Long
    For nErrCode = 1 To 11
        Debug.Print nErrCode & " = " & pkiErrorLookup(nErrCode)
    Next
End Sub

Public Sub test_aead()
    Dim key() As Byte
    Dim iv() As Byte
    Dim pt() As Byte
    Dim ct() As Byte
    Dim strOK As String
    
    ' GCM Test Case #03 (AES-128)
    key = cnvBytesFromHexStr("feffe9928665731c6d6a8f9467308308")
    iv = cnvBytesFromHexStr("cafebabefacedbaddecaf888")
    ct = cnvBytesFromHexStr("42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091473f59854d5c2af327cd64a62cf35abd2ba6fab4")
    strOK = "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255"
    Debug.Print "KY=" & cnvHexStrFromBytes(key)
    Debug.Print "IV=" & cnvHexStrFromBytes(iv)
    Debug.Print "CT=" & cnvHexStrFromBytes(ct)
    
    ' Must dimension any optional empty byte array
    Dim lpAAD() As Byte
    
    pt = cipherDecryptAEAD(ct, key, iv, lpAAD, PKI_AEAD_AES_128_GCM)
    Debug.Print "PT=" & cnvHexStrFromBytes(pt)
    
End Sub

Public Sub test_cipherEncryptAEAD()
    Dim key() As Byte
    Dim iv() As Byte
    Dim pt() As Byte
    Dim ct() As Byte
    Dim lpDummy() As Byte
    ' GCM Test Case #03 (AES-128)
    key = cnvBytesFromHexStr("feffe9928665731c6d6a8f9467308308")
    iv = cnvBytesFromHexStr("cafebabefacedbaddecaf888")
    pt = cnvBytesFromHexStr("d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255")
    ct = cipherEncryptAEAD(pt, key, iv, lpDummy, PKI_AEAD_AES_128_GCM Or PKI_IV_PREFIX)
    Debug.Print "IV|CT=" & cnvHexStrFromBytes(ct)
    Debug.Print "OK=   " & _
        "CAFEBABEFACEDBADDECAF888" & _
    "42831EC2217774244B7221B784D0D49CE3AA212F2C02A4E035C17E2329ACA12E21D514B25466931C7D8F6A5AAC84AA051BA30B396A0AAC973D58E091473F59854D5C2AF327CD64A62CF35ABD2BA6FAB4"
    
End Sub

Public Sub test_x509QueryCert()
    Debug.Print x509TextDumpToString("AliceRSASignByCarl.cer")
    Debug.Print x509QueryCert("AliceRSASignByCarl.cer", "subjectName")
    'Debug.Print asn1TextDumpToString("AliceRSASignByCarl.cer")
    ' Certificate with non-ASCII Spanish characters
    Debug.Print "Default: " & x509QueryCert("alicia.cer", "issuerName")
    Debug.Print "LATIN1:  " & x509QueryCert("alicia.cer", "issuerName", PKI_X509_LATIN1)
    Debug.Print "UTF8:    " & x509QueryCert("alicia.cer", "issuerName", PKI_X509_UTF8)
    Debug.Print "LDAP:    " & x509QueryCert("alicia.cer", "issuerName", PKI_X509_LDAP)
    ' Certificate with Chinese characters
    Debug.Print "Default: " & x509QueryCert("myca-chinadavid.cer", "subjectName")
    Debug.Print "LDAP:    " & x509QueryCert("myca-chinadavid.cer", "subjectName", PKI_X509_LDAP)
End Sub

Public Sub test_eccReadKey()
    Dim curveName As String
    Dim alicePrivateKeyHex As String
    Dim ourPrivateKey As String
 
    curveName = "X25519"
    alicePrivateKeyHex = "77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a"
    
    ' The new short way with a wrapper function
    ourPrivateKey = eccReadKeyByCurve(alicePrivateKeyHex, curveName, PKI_ECC_PRIVATE_KEY)
    Debug.Assert Len(ourPrivateKey) > 0
    Debug.Print "Key curve=" & eccQueryKey(ourPrivateKey, "curveName", 0) & " keyBits=" & eccQueryKey(ourPrivateKey, "keyBits", 0)
End Sub

Public Sub test_eccReadPrivateKey()
    Dim strIntKey As String
    
    ' Read in public key from file
    strIntKey = eccReadPublicKey("myeckeyp256.pub")
    Debug.Assert Len(strIntKey) > 0
    Debug.Print "Key curve=" & eccQueryKey(strIntKey, "curveName", 0) & " keyBits=" & _
        eccQueryKey(strIntKey, "keyBits", 0) & _
        " and is a " & _
        IIf(eccQueryKey(strIntKey, "isPrivate") = "1", "Private", "Public") & " key"
    Debug.Print eccQueryKey(strIntKey, "publicKey")
    Debug.Print "KeyHashCode=0x" & Hex(eccKeyHashCode(strIntKey))
    
    ' Read in private key from file
    strIntKey = eccReadPrivateKey("myeckeyp256.p8", "password")
    Debug.Assert Len(strIntKey) > 0
    Debug.Print "Key curve=" & eccQueryKey(strIntKey, "curveName", 0) & " keyBits=" & _
        eccQueryKey(strIntKey, "keyBits", 0) & _
        " and is a " & _
        IIf(eccQueryKey(strIntKey, "isPrivate") = "1", "Private", "Public") & " key"
    Debug.Print eccQueryKey(strIntKey, "publicKey")
    Debug.Print "KeyHashCode=0x" & Hex(eccKeyHashCode(strIntKey))
    
    ' Derive public key from private key
    strIntKey = eccPublicKeyFromPrivate(strIntKey)
    Debug.Assert Len(strIntKey) > 0
    Debug.Print "Key curve=" & eccQueryKey(strIntKey, "curveName", 0) & " keyBits=" & _
        eccQueryKey(strIntKey, "keyBits", 0) & _
        " and is a " & _
        IIf(eccQueryKey(strIntKey, "isPrivate") = "1", "Private", "Public") & " key"
    Debug.Print eccQueryKey(strIntKey, "publicKey")
    Debug.Print "KeyHashCode=0x" & Hex(eccKeyHashCode(strIntKey))

End Sub

Public Sub test_eccMakeKeys()
    Dim r As Long
    Dim strIntKey As String
    
    ' Generate brainpool key pair
    r = eccMakeKeys("myeccBP256r1.pub", "myeccBP256r1.p8e", "brainpoolP256r1", "password1", "count=6000;prf=hmacWithSHA256", PKI_PBE_PBKDF2_AES128 Or PKI_KEY_FORMAT_PEM)
    Debug.Print " returns " & r & " (expected 0)"
    ' Read in key to internal string
    strIntKey = eccReadPrivateKey("myeccBP256r1.p8e", "password1")
    Debug.Print "curveName=" & eccQueryKey(strIntKey, "curveName")
    Debug.Print "keyBits=" & eccQueryKey(strIntKey, "keyBits")
 
End Sub

Public Sub test_eccDHSharedSecret()
    Dim strCurveName As String
    Dim ourPrivateKey As String
    Dim theirPublicKey As String
    Dim lpZZ() As Byte
    
    ' Ref: RFC7748 Section 6.1
    Const alicePrivateKeyHex As String = "77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a"
    Const alicePublicKeyHex As String = "8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a"
    Const bobPrivateKeyHex As String = "5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb"
    Const bobPublicKeyHex As String = "de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f"
    
    strCurveName = "X25519"
    ' 1. Alice's private + Bob's public
    ourPrivateKey = eccReadKeyByCurve(alicePrivateKeyHex, strCurveName, PKI_ECC_PRIVATE_KEY)
    Debug.Print "Our key has " & eccQueryKey(ourPrivateKey, "keyBits") & " bits and is a " & _
        IIf(eccQueryKey(ourPrivateKey, "isPrivate") = "1", "Private", "Public") & " key"
    theirPublicKey = eccReadKeyByCurve(bobPublicKeyHex, strCurveName, PKI_ECC_PUBLIC_KEY)
    Debug.Print "Their key has " & eccQueryKey(theirPublicKey, "keyBits") & " bits and is a " & _
        IIf(eccQueryKey(theirPublicKey, "isPrivate") = "1", "Private", "Public") & " key"
    ' Compute shared secret
    lpZZ = eccDHSharedSecret(ourPrivateKey, theirPublicKey)
    Debug.Print "ZZ=" & cnvHexStrFromBytes(lpZZ)
    Debug.Print "OK=4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742"
    
    ' 2. Bob's private + Alice's public
    ourPrivateKey = eccReadKeyByCurve(bobPrivateKeyHex, strCurveName, PKI_ECC_PRIVATE_KEY)
    Debug.Print "Our key has " & eccQueryKey(ourPrivateKey, "keyBits") & " bits and is a " & _
        IIf(eccQueryKey(ourPrivateKey, "isPrivate") = "1", "Private", "Public") & " key"
    theirPublicKey = eccReadKeyByCurve(alicePublicKeyHex, strCurveName, PKI_ECC_PUBLIC_KEY)
    Debug.Print "Their key has " & eccQueryKey(theirPublicKey, "keyBits") & " bits and is a " & _
        IIf(eccQueryKey(theirPublicKey, "isPrivate") = "1", "Private", "Public") & " key"
    ' Compute shared secret
    lpZZ = eccDHSharedSecret(ourPrivateKey, theirPublicKey)
    Debug.Print "ZZ=" & cnvHexStrFromBytes(lpZZ)
    Debug.Print "OK=4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742"

End Sub

Public Sub test_hashHexFromHex()
    Dim strDigest As String
    Dim lpMessage() As Byte
    Dim lpDigest() As Byte
    
    ' Hex <-- Hex
    strDigest = hashHexFromHex("616263", PKI_HASH_SHA256)   ' "abc" in hex
    Debug.Print strDigest
    lpMessage = StrConv("abc", vbFromUnicode)   ' "abc" in a byte array
    ' Hex <-- Bytes
    strDigest = hashHexFromBytes(lpMessage, PKI_HASH_SHA256)
    Debug.Print strDigest
    ' Bytes <-- Bytes
    lpDigest = hashBytes(lpMessage, PKI_HASH_SHA256)
    Debug.Print cnvHexStrFromBytes(lpDigest)
    ' Hex <-- File
    strDigest = hashHexFromFile("abc.txt", PKI_HASH_SHA256) ' "abc" in a text file
    Debug.Print strDigest
    ' Bytes <-- File
    lpDigest = hashFile("abc.txt", PKI_HASH_SHA256)
    Debug.Print cnvHexStrFromBytes(lpDigest)
    
    Debug.Print "OK=" & "BA7816BF8F01CFEA414140DE5DAE2223B00361A396177A9CB410FF61F20015AD"
    
End Sub

Public Sub test_hash_empty()
    Dim strDigest As String
    Dim lpMessage() As Byte
    Dim lpDigest() As Byte
    lpDigest = hashBytes(lpMessage, PKI_HASH_SHA256)
    Debug.Print cnvHexStrFromBytes(lpDigest)
    lpDigest = hashBytes(lpMessage, PKI_HASH_SHA256)
    Debug.Print cnvHexStrFromBytes(lpDigest)
    strDigest = hashHexFromBytes(lpMessage, PKI_HASH_SHA256)
    Debug.Print strDigest
    strDigest = hashHexFromBytes(lpMessage, PKI_HASH_SHA512)
    Debug.Print strDigest
    strDigest = hashHexFromBytes(lpMessage, PKI_HASH_SHA512)
    Debug.Print strDigest
    
End Sub

Public Sub test_hmac_empty()
    Dim strDigest As String
    Dim lpMessage() As Byte
    Dim lpDigest() As Byte
    Dim lpKey() As Byte
    lpKey = cnvBytesFromHexStr("0102030405060708090a0b0c0d0e0f10111213141516171819")
    lpDigest = hmacBytes(lpMessage, lpKey, PKI_HASH_SHA256)
    Debug.Print cnvHexStrFromBytes(lpDigest)
    lpDigest = hmacBytes(lpMessage, lpKey, PKI_HASH_SHA256)
    Debug.Print cnvHexStrFromBytes(lpDigest)
    strDigest = hmacHexFromBytes(lpMessage, lpKey, PKI_HASH_SHA256)
    Debug.Print strDigest
    strDigest = hmacHexFromBytes(lpMessage, lpKey, PKI_HASH_SHA512)
    Debug.Print strDigest
    strDigest = hmacHexFromBytes(lpMessage, lpKey, PKI_HASH_SHA512)
    Debug.Print strDigest
    
End Sub

Public Sub test_encrypt_empty()
    Dim lpKey() As Byte
    Dim lpIV() As Byte
    Dim lpPlain() As Byte
    Dim lpCipher() As Byte
    ' Empty key = NBG
    lpCipher = cipherEncryptBytes(lpPlain, lpKey, lpIV, "Aes128/ECB", 0)
    Debug.Print "CT=" & cnvHexStrFromBytes(lpCipher)
    Debug.Print pkiGetLastError() & ": " & pkiGetLastError()
    lpKey = cnvBytesFromHexStr("0123456789ABCDEFF0E1D2C3B4A59687")
    lpCipher = cipherEncryptBytes(lpPlain, lpKey, lpIV, "Aes128/ECB", 0)
    Debug.Print "CT=" & cnvHexStrFromBytes(lpCipher)
    lpCipher = cipherEncryptBytes(lpPlain, lpKey, lpIV, "Aes128/ECB", 0)
    Debug.Print "CT=" & cnvHexStrFromBytes(lpCipher)
End Sub

Public Sub test_cipherEncryptHex()
    Dim strKeyHex As String
    Dim strIvHex As String
    Dim strPlainHex As String
    Dim strCipherHex As String
    strKeyHex = "0123456789ABCDEFF0E1D2C3B4A59687"
    strIvHex = "FEDCBA9876543210FEDCBA9876543210"
    strPlainHex = "4E6F77206973207468652074696D6520666F7220616C6C20676F6F64206D656E20746F"
    
    ' Get encrypted output directly in hex
    strCipherHex = cipherEncryptHex(strPlainHex, strKeyHex, strIvHex, "Aes128/CBC/OneAndZeroes", 0)
    Debug.Print strCipherHex
   
    ' Same again with bytes
    Dim lpKey() As Byte
    Dim lpIV() As Byte
    Dim lpPlain() As Byte
    Dim lpCipher() As Byte
    lpPlain = StrConv("Now is the time for all good men to", vbFromUnicode)
    lpKey = cnvBytesFromHexStr("0123456789ABCDEFF0E1D2C3B4A59687")
    lpIV = cnvBytesFromHexStr("FEDCBA9876543210FEDCBA9876543210")
    ' Get encrypted output
    lpCipher = cipherEncryptBytes(lpPlain, lpKey, lpIV, "Aes128/CBC/OneAndZeroes", 0)
    Debug.Print cnvHexStrFromBytes(lpCipher)
    
    ' Same again using ECB mode with default PKCS#5 padding
    ' To pass an empty byte array for IV, create a dummy zero-length array
    Dim lpDummy() As Byte
    lpCipher = cipherEncryptBytes(lpPlain, lpKey, lpDummy, "Aes128/ECB", 0)
    Debug.Print cnvHexStrFromBytes(lpCipher)
    
    ' Same again with hex using ECB mode with default PKCS#5 padding
    ' To pass a "null" IV in hex, just use the empty string
    strCipherHex = cipherEncryptHex(strPlainHex, strKeyHex, "", "Aes128/ECB", 0)
    Debug.Print strCipherHex
    
    ' Or vbNullString
    strCipherHex = cipherEncryptHex(strPlainHex, strKeyHex, vbNullString, "Aes128/ECB", 0)
    Debug.Print strCipherHex
    
End Sub

Public Sub test_cipherDecryptHex()
    Dim strKeyHex As String
    Dim strIvHex As String
    Dim strPlainHex As String
    Dim strCipherHex As String
    strKeyHex = "0123456789ABCDEFF0E1D2C3B4A59687"
    strIvHex = "FEDCBA9876543210FEDCBA9876543210"
    strCipherHex = "C3153108A8DD340C0BCB1DFE8D25D2320EE0E66BD2BB4A313FB75C5638E9E1771D4CDA34FBFB7E74B321F9A2CF4EA61B"
    strPlainHex = cipherDecryptHex(strCipherHex, strKeyHex, strIvHex, "Aes128/CBC/OneAndZeroes")
    Debug.Print "PT=" & strPlainHex
    Debug.Print "PT='" & cnvStringFromHexStr(strPlainHex) & "'"
    

End Sub


Public Sub test_cipherEncryptBytes()
    Dim key() As Byte
    Dim iv() As Byte
    Dim pt() As Byte
    Dim ct() As Byte
    Dim dt() As Byte
    Dim algstr As String
    
    ' PART 1
    algstr = "Aes128/CBC/OneAndZeroes"
    Debug.Print algstr
    key = cnvBytesFromHexStr("0123456789ABCDEFF0E1D2C3B4A59687")
    iv = cnvBytesFromHexStr("FEDCBA9876543210FEDCBA9876543210")
    ' "Now is the time for all good men to"
    pt = cnvBytesFromHexStr("4E6F77206973207468652074696D6520666F7220616C6C20676F6F64206D656E20746F")
    
    ct = cipherEncryptBytes(pt, key, iv, algstr, 0)
    Debug.Print "CT=" & cnvHexStrFromBytes(ct)
    Debug.Print "OK=C3153108A8DD340C0BCB1DFE8D25D2320EE0E66BD2BB4A313FB75C5638E9E1771D4CDA34FBFB7E74B321F9A2CF4EA61B"

    dt = cipherDecryptBytes(ct, key, iv, algstr, 0)
    Debug.Print "dt='" & StrConv(dt, vbUnicode) & "'"
    
    ' PART 2 - Use CTR mode and prefix the IV in the output
    algstr = "Aes128/CTR"
    Debug.Print algstr & " + PREFIX"
    ct = cipherEncryptBytes(pt, key, iv, algstr, PKI_IV_PREFIX)
    Debug.Print "CT=" & cnvHexStrFromBytes(ct)
    dt = cipherDecryptBytes(ct, key, iv, algstr, PKI_IV_PREFIX)
    Debug.Print "dt='" & StrConv(dt, vbUnicode) & "'"
    
    ' PART 3 - Use ECB mode and note we use a dummy empty byte array for the IV
    Dim dummy() As Byte
    algstr = "Aes128/ECB"
    Debug.Print algstr
    ct = cipherEncryptBytes(pt, key, dummy, algstr, 0)
    Debug.Print "CT=" & cnvHexStrFromBytes(ct)
    dt = cipherDecryptBytes(ct, key, dummy, algstr, 0)
    Debug.Print "dt='" & StrConv(dt, vbUnicode) & "'"
    
End Sub

Public Sub test_cipherDecryptBytes()
    Dim key() As Byte
    Dim iv() As Byte
    Dim ct() As Byte
    Dim ok() As Byte
    Dim dt() As Byte
    key = cnvBytesFromHexStr("0123456789ABCDEFF0E1D2C3B4A59687")
    iv = cnvBytesFromHexStr("FEDCBA9876543210FEDCBA9876543210")
    ct = cnvBytesFromHexStr("C3153108A8DD340C0BCB1DFE8D25D2320EE0E66BD2BB4A313FB75C5638E9E1771D4CDA34FBFB7E74B321F9A2CF4EA61B")
    ' Decrypt
    dt = cipherDecryptBytes(ct, key, iv, "Aes128/CBC/OneAndZeroes")
    Debug.Print ("DT=" & cnvHexStrFromBytes(dt))
    Debug.Print ("DT='" & StrConv(dt, vbUnicode) + "'")

End Sub

Public Sub test_padBytesBlock()
    Dim lpInput() As Byte
    Dim lpBlock() As Byte
    Dim lpUnpadded() As Byte
    lpInput = cnvBytesFromHexStr("FDFDFDFDFD")
    Debug.Print "Input data =  0x" & cnvHexStrFromBytes(lpInput)
    lpBlock = padBytesBlock(lpInput, 8, 0)
    Debug.Print "Padded data = 0x" & cnvHexStrFromBytes(lpBlock)
    ' Unpad
    lpUnpadded = padUnpadBytes(lpBlock, 8, 0)
    Debug.Print "Unpadded data = 0x" & cnvHexStrFromBytes(lpUnpadded)
    
    ' Special corner case - output is the empty string
    lpBlock = cnvBytesFromHexStr("0808080808080808")
    Debug.Print "Padded data = 0x" & cnvHexStrFromBytes(lpBlock)
    lpUnpadded = padUnpadBytes(lpBlock, 8, 0)
    Debug.Print "Unpadded data = 0x" & cnvHexStrFromBytes(lpUnpadded)
End Sub

Public Sub test_padHexBlock()
    Dim strInputHex As String
    Dim strOutputHex As String
    strInputHex = "FDFDFD"
    Debug.Print "Hex input  =" & strInputHex
    
    strOutputHex = padHexBlock(strInputHex, 8, 0)
    Debug.Print "Padded data=" & strOutputHex
    Debug.Print "Unpadded   =" & padUnpadHex(strOutputHex, 8, 0)
    
    strOutputHex = padHexBlock(strInputHex, 8, PKI_PAD_1ZERO)
    Debug.Print "Padded data=" & strOutputHex
    Debug.Print "Unpadded   =" & padUnpadHex(strOutputHex, 8, PKI_PAD_1ZERO)
    
    strOutputHex = padHexBlock(strInputHex, 8, PKI_PAD_AX923)
    Debug.Print "Padded data=" & strOutputHex
    Debug.Print "Unpadded   =" & padUnpadHex(strOutputHex, 8, PKI_PAD_AX923)
    
End Sub

Public Sub test_unpadHex()
    Dim strInputHex As String
    Dim strOutputHex As String
    strInputHex = "FFFFFFFFFF030303"
    Debug.Print "Hex input  =" & strInputHex
    strOutputHex = padUnpadHex(strInputHex, PKI_BLK_TDEA_BYTES, 0)
    Debug.Print "Unpadded   =" & strOutputHex
    ' Output is empty string
    strInputHex = "0808080808080808"
    Debug.Print "Hex input  =" & strInputHex
    strOutputHex = padUnpadHex(strInputHex, PKI_BLK_TDEA_BYTES, 0)
    Debug.Print "Unpadded   =" & strOutputHex
    ' Bad input data results in the same data being returned
    strInputHex = "FFFFFFFFFFFFFFFF"
    Debug.Print "Hex input  =" & strInputHex
    strOutputHex = padUnpadHex(strInputHex, PKI_BLK_TDEA_BYTES, 0)
    Debug.Print "Unpadded   =" & strOutputHex
    If Len(strOutputHex) = Len(strInputHex) Then
        Debug.Print "DECRYPTION ERROR"
    End If
    Debug.Assert Len(strOutputHex) = Len(strInputHex)
End Sub

Public Sub test_rngBytes()
    Dim i As Integer
    For i = 1 To 10
        Debug.Print cnvHexStrFromBytes(rngBytes(32))
    Next
End Sub

Public Sub test_rngGuid()
    Dim i As Integer
    For i = 1 To 5
        Debug.Print rngGuid()
    Next
End Sub

Public Sub test_asn1TextDumpToString()
    Dim strInput As String
    Dim strOutput As String
    strInput = "MAQwAgUA"
    Debug.Print "Input: " & strInput
    strOutput = asn1TextDumpToString(strInput)
    Debug.Print strOutput
    Debug.Print asn1TextDumpToString(strInput, PKI_ASN1_NOCOMMENTS)
    
End Sub

Public Sub test_asn1Type()
    Debug.Print asn1Type("AliceRSASignByCarl.cer", 0)
    Debug.Print asn1Type("BobPrivRSAEncrypt.p8e", 0)
    Debug.Print asn1Type("bad.file", 0)
End Sub

Public Sub test_cipherDecryptAEAD()
    Dim key() As Byte
    Dim iv() As Byte
    Dim pt() As Byte
    Dim ct() As Byte
    Dim strOK As String
    
    ' GCM Test Case #03 (AES-128)
    key = cnvBytesFromHexStr("feffe9928665731c6d6a8f9467308308")
    iv = cnvBytesFromHexStr("cafebabefacedbaddecaf888")
    ct = cnvBytesFromHexStr("42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091473f59854d5c2af327cd64a62cf35abd2ba6fab4")
    strOK = "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255"
    Dim lpAAD() As Byte ' Declare empty array for NULL input
    pt = cipherDecryptAEAD(ct, key, iv, lpAAD, PKI_AEAD_AES_128_GCM)
    Debug.Print "PT=" & cnvHexStrFromBytes(pt)
    Debug.Print "OK=" & strOK

End Sub

Public Sub test_smimeQuery()
    Dim strFileIn As String
    Dim strQuery As String
    
    strFileIn = "cmsalice2bob-smime-env.txt"
    Debug.Print "FILE: " & strFileIn
    strQuery = "content-type"
    Debug.Print strQuery & "=" & smimeQuery(strFileIn, strQuery, 0)
    strQuery = "smime-type"
    Debug.Print strQuery & "=" & smimeQuery(strFileIn, strQuery, 0)
    strQuery = "encoding"
    Debug.Print strQuery & "=" & smimeQuery(strFileIn, strQuery, 0)
    strQuery = "filename"
    Debug.Print strQuery & "=" & smimeQuery(strFileIn, strQuery, 0)
End Sub

Public Sub test_rsaToXMLString()
    Dim strPrivateKey As String
    strPrivateKey = rsaReadPrivateKey("AlicePrivRSASign.p8e", "password")
    Debug.Print rsaToXMLString(strPrivateKey, 0)
    Debug.Print rsaToXMLString(strPrivateKey, PKI_XML_EXCLPRIVATE Or PKI_XML_HEXBINARY)
    Debug.Print rsaToXMLStringEx(strPrivateKey, "ds", PKI_XML_EXCLPRIVATE)
    ' Now derive internal private key string from XML
    Dim strXML As String
    Dim strKey As String
    strXML = rsaToXMLString(strPrivateKey)
    strKey = rsaFromXMLString(strXML)
    Debug.Print "Key length = " & rsaKeyBits(strKey) & " bits"
    Debug.Print "Key length in bytes = " & rsaKeyBytes(strKey) & " bytes"
End Sub

Public Sub test_rsaEncrypt()
    Dim strPubKeyFile As String
    Dim lpMsg() As Byte
    Dim lpEnc() As Byte
    Dim strPriKeyFile As String
    Dim lpDec() As Byte
    
    ' Message to be encrypted:
    lpMsg = cnvBytesFromHexStr("6628194e12073db03ba94cda9ef9532397d50dba79b987004afefe34")
    Debug.Print "MSG=" & cnvHexStrFromBytes(lpMsg)
    
    ' Use RSA-OEAP with SHA-256
    strPubKeyFile = "rsa-oaep-1.pub"
    lpEnc = rsaEncrypt(lpMsg, strPubKeyFile, PKI_EME_OAEP + PKI_HASH_SHA256)
    ' NB different each time...
    Debug.Print "ENC=" & cnvHexStrFromBytes(lpEnc)
    strPriKeyFile = "rsa-oaep-1.p8"
    lpDec = rsaDecrypt(lpEnc, strPriKeyFile, "", PKI_EME_OAEP + PKI_HASH_SHA256)
    Debug.Print "DEC=" & cnvHexStrFromBytes(lpDec)

    strPubKeyFile = "rsa-oaep-1.pub"
    ' Set seed to fixed value for debugging....
    lpEnc = rsaEncrypt(lpMsg, strPubKeyFile, PKI_EME_OAEP, "seed=18b776ea21069d69776a33e96bad48e1dda0a5ef")
    Debug.Print "ENC=" & cnvHexStrFromBytes(lpEnc)
    Debug.Print "OK =354fe67b4a126d5d35fe36c777791a3f7ba13def484e2d3908aff722fad468fb" _
        & "21696de95d0be911c2d3174f8afcc201035f7b6d8e69402de5451618c21a535f" _
        & "a9d7bfc5b8dd9fc243f8cf927db31322d6e881eaa91a996170e657a05a266426" _
        & "d98c88003f8477c1227094a0d9fa1e8c4024309ce1ecccb5210035d47ac72e8a"
    ' Decrypt
    strPriKeyFile = "rsa-oaep-1.p8"
    lpDec = rsaDecrypt(lpEnc, strPriKeyFile, "", PKI_EME_OAEP)
    Debug.Print "DEC=" & cnvHexStrFromBytes(lpDec)

End Sub

Public Sub test_cnvUTF8BytesFromLatin1()
    Dim strData As String
    Dim lpDataUTF8() As Byte
    strData = "abcóéíáñ"
    Debug.Print "Latin-1 string='" & strData & "'"
    Debug.Print " (" & Len(strData) & " characters)"
    lpDataUTF8 = cnvUTF8BytesFromLatin1(strData)
    Debug.Print "UTF-8=(0x)" & cnvHexStrFromBytes(lpDataUTF8)
    Debug.Print " (" & cnvBytesLen(lpDataUTF8) & " bytes)"
    Debug.Print "cnvCheckUTF8Bytes returns " & cnvCheckUTF8Bytes(lpDataUTF8) & " (expected 2)"
    ' And back to a string
    Dim strLatin1 As String
    strLatin1 = cnvLatin1FromUTF8Bytes(lpDataUTF8)
    Debug.Print "Back to string='" & strLatin1 & "'"
End Sub

Public Sub test_cmsReadEnvDataToBytes()
    Dim strPrivateKey As String
    Dim lpData() As Byte
    Dim strData As String
    
    ' Read in private key to internal key string
    strPrivateKey = rsaReadPrivateKey("BobPrivRSAEncrypt.p8e", "password")
    Debug.Assert Len(strPrivateKey) > 0
    
    ' 1. Decrypted content is UTF-8 encoded
    lpData = cmsReadEnvDataToBytes("cmsalice2bob_utf8.p7m", "", strPrivateKey, 0)
    Debug.Assert cnvBytesLen(lpData) > 0
    Debug.Print "HEX(PT)=" & cnvHexStrFromBytes(lpData)
    ' Convert from UTF-8-encoded bytes to VB Unicode string
    strData = cnvLatin1FromUTF8Bytes(lpData)
    Debug.Print "PT=" & strData
    
    ' 2. Decrypted content is plain ANSI string
    strData = cmsReadEnvDataToString("cms2bobandcarl.p7m", "", strPrivateKey, 0)
    Debug.Print "PT=" & strData
    
    ' Clean up
    strPrivateKey = wipeString(strPrivateKey)
    
End Sub

Public Sub test_cmsQueryEnvData()
    Dim strQuery As String
    Dim strOutput As String
    Dim strEnvDataFile As String
    
    strEnvDataFile = "5.1.bin"
    Debug.Print "FILE: " & strEnvDataFile
    strQuery = "keyEncryptionAlgorithm"
    strOutput = cmsQueryEnvData(strEnvDataFile, strQuery, 0)
    Debug.Print strQuery & " ==> " & strOutput
    strQuery = "contentEncryptionAlgorithm"
    strOutput = cmsQueryEnvData(strEnvDataFile, strQuery, 0)
    Debug.Print strQuery & " ==> " & strOutput
    strQuery = "sizeofEncryptedContent"
    strOutput = cmsQueryEnvData(strEnvDataFile, strQuery, 0)
    Debug.Print strQuery & " ==> " & strOutput
    
End Sub

Public Sub test_pkiCompileTime()
    Debug.Print pkiCompileTime()
    Debug.Print pkiModuleInfo()
    Debug.Print pkiModuleName()
    Debug.Print pkiPlatform()
    
End Sub

Public Sub test_cipherKeyWrap()
    Dim lpWK() As Byte
    Dim lpKeyData() As Byte
    Dim lpKEK() As Byte
    
    lpKeyData = cnvBytesFromHexStr("00112233 44556677 8899aabb ccddeeff")
    lpKEK = cnvBytesFromHexStr("c17a44e8 e28d7d64 81d1ddd5 0a3b8914")
    ' NB Specific nonzero option required in nOptions
    lpWK = cipherKeyWrap(lpKeyData, lpKEK, PKI_BC_AES128)
    Debug.Print "WK=" & cnvHexStrFromBytes(lpWK)
    Debug.Print "OK=503D75C73630A7B02ECF51B9B29B907749310B77B0B2E054"
    
    ' Now unwrap the KEK
    Dim lpKeyUnwrapped() As Byte
    lpKeyUnwrapped = cipherKeyUnwrap(lpWK, lpKEK, PKI_BC_AES128)
    Debug.Print "KY=" & cnvHexStrFromBytes(lpKeyUnwrapped)
    Debug.Print "OK=00112233445566778899AABBCCDDEEFF"

End Sub

Public Sub test_comprCompress()
    Dim strPlain As String
    Dim lpToCompress() As Byte
    Dim lpCompressed() As Byte
    Dim lpUncompressed() As Byte
    strPlain = "hello, hello, hello. This is a 'hello world' message " & _
        "for the world, repeat, for the world."
    lpToCompress = StrConv(strPlain, vbFromUnicode)
    lpCompressed = comprCompress(lpToCompress)
    Debug.Print "OK=        " & "789CCB48CDC9C9D751C840A2F4144232328B15802851411D2CA2509E5F9493A2AE909B5A5C9C989EAA90965FA45092910A11D651284A2D484D2CD14115D6030086D11F4E"
    Debug.Print "COMPRESSED=" & cnvHexStrFromBytes(lpCompressed)
    lpUncompressed = comprUncompress(lpCompressed)
    Debug.Print "'" & StrConv(lpUncompressed, vbUnicode); "'"
    
End Sub

Public Sub test_hmacBytes()
    Dim lpData() As Byte
    Dim lpKey() As Byte
    Dim lpDigest() As Byte
    Dim strDigest As String
    
    ' Test case 4 from RFC 2202 and RFC 4231
    lpKey = cnvBytesFromHexStr("0102030405060708090a0b0c0d0e0f10111213141516171819")
    ' data = 0xcd repeated 50 times
    lpData = cnvBytesFromHexStr("cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd" & _
        "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd")
    ' Bytes <-- Bytes
    lpDigest = hmacBytes(lpData, lpKey, PKI_HASH_SHA256)
    Debug.Print "HMAC-SHA-256=" & cnvHexStrFromBytes(lpDigest)
    Debug.Print "CORRECT     =82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b"
    ' Hex <-- Bytes
    strDigest = hmacHexFromBytes(lpData, lpKey, PKI_HASH_SHA256)
    Debug.Print "HMAC-SHA-256=" & strDigest
    
    ' Hex <-- Hex
    ' Test case 1 from RFC 2202 and RFC 4231
    ' Data = "Hi There"
    strDigest = hmacHexFromHex("4869205468657265", "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", PKI_HASH_SHA256)
    Debug.Print "HMAC-SHA-256=" & strDigest
    Debug.Print "CORRECT     =b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7"
    
End Sub

Public Sub test_hmac_sha3()
    Dim lpData() As Byte
    Dim lpKey() As Byte
    Dim lpDigest() As Byte
    Dim strDigest As String
    Dim strKeyHex As String
    
    ' NIST HMAC_SHA3-256.pdf Sample #1
    lpKey = cnvBytesFromHexStr("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F")
    lpData = StrConv("Sample message for keylen<blocklen", vbFromUnicode)
    ' Bytes <-- Bytes
    lpDigest = hmacBytes(lpData, lpKey, PKI_HASH_SHA3_256)
    Debug.Print "HMAC-SHA3-256=" & cnvHexStrFromBytes(lpDigest)
    Debug.Print "CORRECT      =4fe8e202c4f058e8dddc23d8c34e467343e23555e24fc2f025d598f558f67205"
    ' Hex <-- Bytes
    strDigest = hmacHexFromBytes(lpData, lpKey, PKI_HASH_SHA3_256)
    Debug.Print "HMAC-SHA3-256=" & strDigest
    
    ' Hex <-- Hex
    ' NIST HMAC_SHA3-224.pdf Sample #3
    ' Data = "Sample message for keylen>blocklen"
    strKeyHex = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" & _
        "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f" & _
        "404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f" & _
        "606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f" & _
        "808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f" & _
        "a0a1a2a3a4a5a6a7a8a9aaab"
    strDigest = hmacHexFromHex("53616d706c65206d65737361676520666f72206b65796c656e3e626c6f636b6c656e", strKeyHex, PKI_HASH_SHA3_224)
    Debug.Print "HMAC-SHA3-224=" & strDigest
    Debug.Print "CORRECT      =078695eecc227c636ad31d063a15dd05a7e819a66ec6d8de1e193e59"
    
End Sub

Public Sub test_cmsGetSigDataDigest()
    Dim strHexDigest As String
    Dim strData As String
    Const strCmsFile As String = "4.2.bin"
    
    ' Extract the digest value
    strHexDigest = cmsGetSigDataDigest(strCmsFile, "")
    Debug.Print "extracted digest=[" & strHexDigest & "]"
    ' Extract content from signed-data file
    strData = cmsReadSigDataToString(strCmsFile)
    Debug.Print "content='" & strData & "'"
    ' Compute digest value over the content
    Debug.Print "computed digest =[" & hashHexFromBytes(StrConv(strData, vbFromUnicode), PKI_HASH_SHA1) & "]"
    
End Sub

Public Sub test_cmsMakeSigData_pss()
    Dim strPriKey As String
    Dim lpData() As Byte
    Dim strCmsFile As String
    Dim r As Long
    Dim strQuery As String
    Dim s As String
    
    ' Read in private key to internal key string
    strPriKey = rsaReadPrivateKey("User_RSA_2048.p8e", "password")
    Debug.Assert Len(strPriKey) > 0
    Debug.Print "Private key is " & RSA_KeyBits(strPriKey) & " bits"
    ' Get input data in a byte array
    lpData = StrConv("This is some sample content.", vbFromUnicode)
    ' Make signed-data file
    strCmsFile = "SignedData_PSS_384.p7m"
    r = cmsMakeSigDataFromBytes(strCmsFile, lpData, "User_RSA_2048.cer", strPriKey, PKI_SIG_RSA_PSS_SHA384 Or PKI_CMS_INCLUDE_ATTRS)
    Debug.Print "cmsMakeSigDataFromBytes returns " & r & " (expecting 0)"
    Debug.Assert 0 = r
    ' Query the resulting file
    Debug.Print asn1Type(strCmsFile)
    strQuery = "signatureAlgorithm"
    s = cmsQuerySigData(strCmsFile, strQuery)
    Debug.Print strQuery & "='" & s & "'"
    strQuery = "digestAlgorithm"
    s = cmsQuerySigData(strCmsFile, strQuery)
    Debug.Print strQuery & "='" & s & "'"
    ' Validate it
    r = CMS_VerifySigData(strCmsFile, "", "", 0)
    Debug.Print "CMS_VerifySigData returns " & r & " (expecting 0)"
    Debug.Assert 0 = r
    
End Sub

Public Sub test_cmsMakeSigDataFromSigValue()
    Dim strDataHex As String
    Dim strSigHex As String
    Dim strCertFile As String
    Dim strCmsFile As String
    Dim r As Long
    
    ' Data to be signed in hex format (punctuation will be removed)
    strDataHex = "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"
    ' The signature (generated by the smart card) is:
    strSigHex = "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"
    strCertFile = "AliceRSASignByCarl.cer"
    strCmsFile = "BasicSignByAliceExternal.p7m"
    ' Create the signed-data file
    r = cmsMakeSigDataFromSigValue(strCmsFile, cnvFromHex(strSigHex), cnvFromHex(strDataHex), strCertFile, PKI_SIG_RSA_SHA1)
    Debug.Print "cmsMakeSigDataFromSigValue returns " & r & " (expected 0)"
    Debug.Print asn1Type(strCmsFile)
End Sub

Public Sub test_cmsQuerySigData()
    Dim strCmsFile As String
    Dim strQuery As String
    Dim strOutput As String
    
    strCmsFile = "4.6.bin"
    Debug.Print "FILE: " & strCmsFile
    strQuery = "version"
    strOutput = cmsQuerySigData(strCmsFile, strQuery)
    Debug.Print strQuery & " ==> [" & strOutput & "]"
    strQuery = "digestAlgorithm"
    strOutput = cmsQuerySigData(strCmsFile, strQuery)
    Debug.Print strQuery & " ==> [" & strOutput & "]"
    
    strCmsFile = "4.7.bin"
    Debug.Print "FILE: " & strCmsFile
    strQuery = "version"
    strOutput = cmsQuerySigData(strCmsFile, strQuery)
    Debug.Print strQuery & " ==> [" & strOutput & "]"
    strQuery = "signatureAlgorithm"
    strOutput = cmsQuerySigData(strCmsFile, strQuery)
    Debug.Print strQuery & " ==> [" & strOutput & "]"

    strCmsFile = "BasicSignByAlice_attr.bin"
    Debug.Print "FILE: " & strCmsFile
    strQuery = "signingTime"
    strOutput = cmsQuerySigData(strCmsFile, strQuery)
    Debug.Print strQuery & " ==> [" & strOutput & "]"

End Sub

Public Sub test_cmsReadSigDataToBytes()
    Dim lpData() As Byte
    Dim strData As String
    
    ' Read UTF-8 encoded data from signed-data CMS object
    lpData = cmsReadSigDataToBytes("basicsignedbyalice_utf8.p7m")
    Debug.Assert cnvBytesLen(lpData) > 0
    Debug.Print "HEX(CONTENT)=" & cnvHexStrFromBytes(lpData)
    ' Convert from UTF-8-encoded bytes to VB Unicode string
    strData = cnvLatin1FromUTF8Bytes(lpData)
    Debug.Print "CONTENT='" & strData & "'"

End Sub

Public Sub test_cnvBase58FromBytes()
    Dim lpData() As Byte
    Dim strBase58 As String
    
    lpData = cnvBytesFromHexStr("00010966776006953D5567439E5E39F86A0D273BEED61967F6")
    strBase58 = cnvBase58FromBytes(lpData)
    Debug.Print strBase58
    ' Decode base58 string to byte array
    lpData = cnvBase58ToBytes(strBase58)
    Debug.Print cnvHexStrFromBytes(lpData)
    strBase58 = "DiManagement"
    Debug.Print "INPUT: " & strBase58
    lpData = cnvBase58ToBytes(strBase58)
    Debug.Print cnvHexStrFromBytes(lpData)
       
End Sub

Public Sub test_cnvByteEncoding()
    Dim lpLatin1() As Byte
    Dim lpUTF8() As Byte
    ' Set up a byte array with the following 4 characters encoded in Latin-1
    '  U+0061 LATIN SMALL LETTER A
    '  U+00E9 LATIN SMALL LETTER E WITH ACUTE
    '  U+00F1 LATIN SMALL LETTER N WITH TILDE
    '  U+0062 LATIN SMALL LETTER B
    lpLatin1 = cnvBytesFromHexStr("61E9F162")
    Debug.Print "Latin-1=" & cnvHexStrFromBytes(lpLatin1) & " (" & cnvBytesLen(lpLatin1) & " bytes)"
    lpUTF8 = cnvByteEncoding(lpLatin1, PKI_CNV_UTF8_FROM_LATIN1)
    Debug.Print "UTF-8  =" & cnvHexStrFromBytes(lpUTF8) & " (" & cnvBytesLen(lpUTF8) & " bytes)"
    ' And back again the other way...
    lpLatin1 = cnvByteEncoding(lpUTF8, PKI_CNV_LATIN1_FROM_UTF8)
    Debug.Print "Latin-1=" & cnvHexStrFromBytes(lpLatin1) & " (" & cnvBytesLen(lpLatin1) & " bytes)"

End Sub

Public Sub test_cnvNumToBytes()
    Dim lpData() As Byte
    Dim nBytes As Long
    Dim nNumber As Long
    
    nNumber = &HDEADBEEF
    Debug.Print "INPUT=0x" & Hex(nNumber) & " (" & nNumber & ")"
    ' Default big-endian order
    lpData = cnvNumToBytes(nNumber)
    Debug.Print "cnvNumToBytes(BE)=" & cnvHexStrFromBytes(lpData)
    ' Little-endian order
    lpData = cnvNumToBytes(nNumber, PKI_CNV_LITTLE_ENDIAN)
    Debug.Print "cnvNumToBytes(LE)=" & cnvHexStrFromBytes(lpData)
    
End Sub

Public Sub test_cnvReverseBytes()
    Debug.Print cnvToHex(cnvReverseBytes(cnvFromHex("DEADBEEF")))
    ' EFBEADDE
End Sub

Public Sub test_pbeKdf2()
    Dim lpDK() As Byte
    Dim strPassword As String
    Dim lpSalt() As Byte
    Dim nCount As Long
    strPassword = "password"
    lpSalt = cnvBytesFromHexStr("78 57 8E 5A 5D 63 CB 06")
    nCount = 2048
    lpDK = pbeKdf2(24, StrConv(strPassword, vbFromUnicode), lpSalt, nCount)
    Debug.Print "Derived key = " & cnvHexStrFromBytes(lpDK)
    Debug.Print "Correct key = BFDE6BE94DF7E11DD409BCE20A0255EC327CB936FFE93643"
    
    lpDK = pbeKdf2(24, StrConv(strPassword, vbFromUnicode), lpSalt, nCount, PKI_HASH_SHA256)
    Debug.Print "Derived key {HMAC-SHA-256} = " & cnvHexStrFromBytes(lpDK)
    Debug.Print "Correct key {HMAC-SHA-256} = 97B5A91D35AF542324881315C4F849E327C4707D1BC9D322"
End Sub

Public Sub test_pbeKdf2Hex()
    Dim strDK As String
    Dim strPassword As String
    Dim strSaltHex As String
    Dim nCount As Long
    strPassword = "password"
    strSaltHex = "78578E5A5D63CB06"
    nCount = 2048
    strDK = pbeKdf2Hex(24, strPassword, strSaltHex, nCount)
    Debug.Print "Derived key = " & strDK
    Debug.Print "Correct key = BFDE6BE94DF7E11DD409BCE20A0255EC327CB936FFE93643"
End Sub

Public Sub test_ocspMakeRequest()
    Dim strOcsp As String
    strOcsp = ocspMakeRequest("UTNUSERFirst-Object.cer", "dims.cer", PKI_HASH_SHA1)
    Debug.Print strOcsp
    ' Pass serial number instead of filename
    strOcsp = ocspMakeRequest("UTNUSERFirst-Object.cer", "#x 00 FB C7 23 22 8C 8C 80 22 D8 85 92 23 DE E7 06 60", PKI_HASH_SHA1)
    Debug.Print strOcsp
End Sub

Public Sub test_ocspReadResponse()
    Dim strBuf As String
    strBuf = ocspReadResponse("ocsp_response_ok_dims.dat", "UTNUSERFirst-Object.cer")
    Debug.Print strBuf
End Sub

Public Sub test_rsaKeys()
    Dim r As Long
    Dim strIntKeyStr As String
    Dim strKeyFile As String
    Dim nPriHashCode As Long
    Dim nPubHashCode As Long
    Dim strASN1 As String
    ' Make a pair of 512-bit keys (just a demo for speed, too short in practice)
    Debug.Print "About to create an RSA key pair..."
    r = rsaMakeKeys("myrsa512.pub", "myrsa512.p8e", "password", 512)
    Debug.Print "rsaMakeKeys returns " & r
    Debug.Assert r = 0
    ' Display the type of ASN.1 files we created
    Debug.Print asn1Type("myrsa512.pub")
    Debug.Print asn1Type("myrsa512.p8e")
    ' Read in the private key to an internal key string
    strIntKeyStr = rsaReadPrivateKey("myrsa512.p8e", "password")
    Debug.Assert Len(strIntKeyStr) > 0
    Debug.Print "Private key size=" & RSA_KeyBits(strIntKeyStr) & " bits"
    nPriHashCode = RSA_KeyHashCode(strIntKeyStr)
    Debug.Print "KeyHashCode=0x" & Hex(nPriHashCode)
    ' Save with stronger encryption
    strKeyFile = "myrsa512ex.p8e"
    r = rsaSaveEncKey(strKeyFile, strIntKeyStr, "password1", "count=6666;prf=hmacWithSHA384", PKI_PBE_PBKDF2_AES192)
    Debug.Assert r = 0
    ' Show ASN.1 dump
    strASN1 = asn1TextDumpToString(strKeyFile)
    Debug.Print strASN1
    ' Expected to contain certain strings consistent with arguments above
    Debug.Assert InStr(strASN1, "hmacWithSHA384")
    Debug.Assert InStr(strASN1, "--6666")
    Debug.Assert InStr(strASN1, "aes192-CBC")
    
    Debug.Print asn1Type(strKeyFile)
    ' Save in unencrypted form
    strKeyFile = "myrsa512.p8"
    r = rsaSaveKey(strKeyFile, strIntKeyStr)
    Debug.Assert r = 0
    Debug.Print asn1Type(strKeyFile)
    ' Save in SSL unencrypted form
    strKeyFile = "myrsa512.key"
    r = rsaSaveKey(strKeyFile, strIntKeyStr, PKI_KEY_FORMAT_SSL)
    Debug.Assert r = 0
    Debug.Print asn1Type(strKeyFile)
    
    ' Read in the public key to an internal key string
    strIntKeyStr = rsaReadPublicKey("myrsa512.pub")
    Debug.Assert Len(strIntKeyStr) > 0
    Debug.Print "Key size=" & RSA_KeyBits(strIntKeyStr) & " bits"
    nPubHashCode = RSA_KeyHashCode(strIntKeyStr)
    Debug.Print "KeyHashCode=0x" & Hex(nPubHashCode)
    ' The two hashcodes should be equal
    Debug.Assert nPubHashCode = nPriHashCode
    
    ' Save in PEM form
    strKeyFile = "myrsa512.pem"
    r = rsaSaveKey(strKeyFile, strIntKeyStr, PKI_KEY_FORMAT_PEM)
    Debug.Assert r = 0
    Debug.Print asn1Type(strKeyFile)
    ' Save in SSL form
    strKeyFile = "myrsa512ssl.pem"
    r = rsaSaveKey(strKeyFile, strIntKeyStr, PKI_KEY_FORMAT_SSL)
    Debug.Assert r = 0
    Debug.Print asn1Type(strKeyFile)
    
End Sub

Public Sub test_rsaKeyValue()
    Dim strKeyString As String
    Dim strFieldName As String
    Dim strValue As String
    
    strKeyString = rsaReadPublicKey("AliceRSASignByCarl.cer")
    strFieldName = "Modulus"
    strValue = rsaKeyValue(strKeyString, strFieldName)
    Debug.Print strFieldName & "=" & strValue
    strFieldName = "Exponent"
    strValue = rsaKeyValue(strKeyString, strFieldName)
    Debug.Print strFieldName & "=" & strValue
End Sub

Public Sub test_rsaPublicKeyFromPrivate()
    Dim strPrivateKey As String
    Dim strPublicKey As String
    ' Read in private key to internal string
    strPrivateKey = rsaReadPrivateKey("BobPrivRSAEncrypt.p8e", "password")
    Debug.Assert Len(strPrivateKey) > 0
    Debug.Print "Private key length = " & rsaKeyBits(strPrivateKey) & " bits"
    Debug.Print "KeyHashCode=0x" & Hex(RSA_KeyHashCode(strPrivateKey))
    ' Convert to public key string
    strPublicKey = rsaPublicKeyFromPrivate(strPrivateKey)
    Debug.Print "Public key length = " & rsaKeyBits(strPublicKey) & " bits"
    Debug.Print "KeyHashCode=0x" & Hex(RSA_KeyHashCode(strPublicKey))
End Sub

Public Sub test_rsaRawPrivate()
    Dim strPrivateKey As String
    Dim pt() As Byte
    Dim ct() As Byte
    strPrivateKey = rsaReadPrivateKey("rsa508.p8e", "password")
    Debug.Assert Len(strPrivateKey) > 0
    pt = cnvBytesFromHexStr("0001ffffffffffffffffffffffffffff" & _
        "ffffffffffffffffffffffffff003020" & _
        "300c06082a864886f70d020205000410" & _
        "dca9ecf1c15c1bd266aff9c8799365cd")
    ct = rsaRawPrivate(pt, strPrivateKey)
    Debug.Print "CT=" & cnvHexStrFromBytes(ct)
    
    Dim strPublicKey As String
    Dim dt() As Byte
    strPublicKey = rsaReadPublicKey("Rsa508.pub")
    Debug.Assert Len(strPublicKey) > 0
    dt = rsaRawPublic(ct, strPublicKey)
    Debug.Print "DT=" & cnvHexStrFromBytes(dt)
End Sub

Public Sub test_rsaReadAnyPrivateKey()
    Dim strIntKey As String
    
    strIntKey = rsaReadAnyPrivateKey("AlicePrivRSASign.p8e", "password")
    Debug.Print strIntKey
    Debug.Print "KeyHashCode=0x" & Hex(RSA_KeyHashCode(strIntKey))
    ' Unencrypted key
    strIntKey = rsaReadAnyPrivateKey("AlicePrivRSASign.pri", "")
    Debug.Print strIntKey
    Debug.Print "KeyHashCode=0x" & Hex(RSA_KeyHashCode(strIntKey))
    ' Key in XML form
    strIntKey = rsaReadAnyPrivateKey("alice-pri.xml", "")
    Debug.Print strIntKey
    Debug.Print "KeyHashCode=0x" & Hex(RSA_KeyHashCode(strIntKey))
   
End Sub

Public Sub test_rsaReadAnyPublicKey()
    Dim strIntKey As String
    
    strIntKey = rsaReadAnyPublicKey("AlicePubRSA.pub")
    Debug.Print strIntKey
    Debug.Print "KeyHashCode=0x" & Hex(RSA_KeyHashCode(strIntKey))
    ' X.509 certificate
    strIntKey = rsaReadAnyPublicKey("AliceRSASignByCarl.cer")
    Debug.Print strIntKey
    Debug.Print "KeyHashCode=0x" & Hex(RSA_KeyHashCode(strIntKey))
    ' Key in XML form
    strIntKey = rsaReadAnyPublicKey("alice-pub.xml")
    Debug.Print strIntKey
    Debug.Print "KeyHashCode=0x" & Hex(RSA_KeyHashCode(strIntKey))
   
End Sub

Public Sub test_x509ReadStringFromFile()
    Dim strCertString As String
    strCertString = x509ReadStringFromFile("AliceRSASignByCarl.cer")
    Debug.Print strCertString
    Debug.Print "CertThumb=" & x509CertThumb(strCertString)
    strCertString = x509ReadCertStringFromP7Chain("alice_bob_carl_certs.p7c", 3)
    Debug.Print strCertString
    Debug.Print "CertThumb=" & x509CertThumb(strCertString)
    Debug.Print "HashIssuerAndSN=" & x509HashIssuerAndSN(strCertString, PKI_HASH_SHA256)
   
    'Invalid index
    strCertString = x509ReadCertStringFromP7Chain("alice_bob_carl_certs.p7c", 0)
    Debug.Print "[" & strCertString & "]"
    
    strCertString = x509ReadCertStringFromPFX("alice.p12", "password")
    Debug.Print strCertString
    Debug.Print "CertThumb=" & x509CertThumb(strCertString)
    Debug.Print "HashIssuerAndSN=" & x509HashIssuerAndSN(strCertString)
    
    Dim strP7File As String
    Dim nIndex As Long
    Dim nCerts As Long
    strP7File = "alice_bob_carl_certs.p7c"
    ' Call core fn with zero index to find count
    nCerts = X509_ReadCertStringFromP7Chain("", 0, strP7File, 0, 0)
    Debug.Print "nCerts=" & nCerts
    For nIndex = 1 To nCerts
        strCertString = x509ReadCertStringFromP7Chain(strP7File, nIndex)
        Debug.Print "subjectName: " & x509QueryCert(strCertString, "subjectName")
    Next
    
End Sub

Public Sub test_rsaEncodeMsg()
    Dim lpData() As Byte
    Dim lpBlock() As Byte
    Dim lpDecoded() As Byte
    Dim nBlockLen As Long
    nBlockLen = 512 \ 8
    
    lpData = cnvBytesFromHexStr("DEADBEEF")
    
    lpBlock = rsaEncodeMsg(nBlockLen, lpData, PKI_EME_PKCSV1_5)
    Debug.Print cnvHexStrFromBytes(lpBlock)
    lpDecoded = rsaDecodeMsg(lpBlock, PKI_EME_PKCSV1_5)
    Debug.Print "DECODED=" & cnvHexStrFromBytes(lpDecoded)
    
    lpBlock = rsaEncodeMsg(nBlockLen, lpData, PKI_EME_OAEP)
    Debug.Print cnvHexStrFromBytes(lpBlock)
    lpDecoded = rsaDecodeMsg(lpBlock, PKI_EME_OAEP)
    Debug.Print "DECODED=" & cnvHexStrFromBytes(lpDecoded)
   
    lpBlock = rsaEncodeMsg(nBlockLen, lpData, PKI_EMSIG_PKCSV1_5 Or PKI_HASH_SHA256)
    Debug.Print cnvHexStrFromBytes(lpBlock)
    lpDecoded = rsaDecodeMsg(lpBlock, PKI_EMSIG_PKCSV1_5)
    Debug.Print "DECODED=" & cnvHexStrFromBytes(lpDecoded)
    
    Debug.Print "DIGEST =" & hashHexFromBytes(lpData, PKI_HASH_SHA256)
End Sub

Public Sub test_sigSignData()
    Dim lpData() As Byte
    Dim strSig As String
    lpData = StrConv("abc", vbFromUnicode)
    strSig = sigSignData(lpData, "AlicePrivRSASign.p8e", "password", "sha1WithRSAEncryption")
    Debug.Print "SIG=" & strSig
    Debug.Print "OK =" & "YK1aePtKQDDsVCyJdM0V9VOE6DZVTO3Z ... AmHH6QIsDZ8R8="
    ' Now verify the signature using Alice's certificate
    Dim r As Long
    r = sigVerifyData(strSig, lpData, "AliceRSASignByCarl.cer", "sha1WithRSAEncryption")
    Debug.Print "sigVerifyData returns " & r & " (expected 0)"
End Sub

Public Sub test_sigSignFile()
    Dim strSig As String
    strSig = sigSignFile("abc.txt", "AlicePrivRSASign.p8e", "password", "", PKI_SIG_SHA256RSA)
    Debug.Print "SIG=" & strSig
    Debug.Print "OK =" & "tLy6hJadL4w9JI/A/qLCG0V...peD1VHSzgu/qirjOaA="
End Sub

Public Sub test_hash_utf8()
    Dim strData As String
    Dim strDigest As String
    ' Our original string data
    strData = "Estándares de Electrónica de México para mañana"
    ' Compute SHA-1 hash over UTF-8 encoded byte array
    strDigest = hashHexFromBytes(cnvUTF8BytesFromLatin1(strData), PKI_HASH_SHA1)
    Debug.Print "Digest=" & strDigest
    Debug.Print "OK =   " & "3eeb1871c14cd03af6d586850e3058fa80cbbe51"
End Sub

Public Sub test_wipeString()
    Dim strData As String
    strData = "my deepest secrets"
    strData = wipeString(strData)
    Debug.Print "AFTER: '" & strData & "'"
End Sub

Public Sub test_wipeBytes()
    Dim lpData() As Byte
    lpData = cnvFromHex("DEADBEEF")
    Debug.Print "BEFORE: 0x(" & cnvToHex(lpData) & ")" ' BEFORE: 0x(DEADBEEF)
    Call wipeBytes(lpData)
    Debug.Print "AFTER: 0x(" & cnvToHex(lpData) & ")" ' AFTER: 0x()
End Sub

Public Sub test_hashLength()
    Debug.Print hashLength(PKI_HASH_SHA512) ' 64
    Debug.Print hashLength(PKI_HASH_BTC160) ' 20
End Sub

Public Sub test_kdfBytes()
    Dim lpKEK() As Byte
    Dim lpZZ() As Byte
    Dim lpInfo() As Byte

    ' ansx963_2001.rsp CAVS 12.0 'ANS X9.63-2001' information for sample
    lpZZ = cnvFromHex("96c05619d56c328ab95fe84b18264b08725b85e33fd34f08")
    lpKEK = kdfBytes(128 \ 8, lpZZ, lpInfo, PKI_HASH_SHA256)
    Debug.Print "KEK = " & cnvToHex(lpKEK)
    Debug.Print "OK  = 443024c3dae66b95e6f5670601558f71"
    
    ' [RFC 5869] A.1.  Test Case 1 Basic test case with SHA-256
    lpZZ = cnvFromHex("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b")
    lpInfo = cnvFromHex("f0f1f2f3f4f5f6f7f8f9")
    lpKEK = kdfBytes(42, lpZZ, lpInfo, PKI_KDF_HKDF Or PKI_HASH_SHA256, "salt=000102030405060708090a0b0c")
    Debug.Print "KEK = " & cnvToHex(lpKEK)
    Debug.Print "OK  = 3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865"
End Sub

Public Sub test_kdfForCms()
    Dim lpKEK() As Byte
    Dim lpZZ() As Byte
    Dim lpUkm() As Byte

    lpZZ = cnvFromHex("160E3F5588C6FB4E9CEE8BC3C1C5000AB86396468C3D1CAEC0CB6E21536B5513")
    lpKEK = kdfForCms(lpZZ, lpUkm, PKI_KWRAP_AES128 Or PKI_KDF_X963 Or PKI_HASH_SHA1)
    Debug.Print "KEK = " & cnvToHex(lpKEK)
    Debug.Print "OK  = 04D616C654CDF62BB186A5A088B60FB5"
    
    lpUkm = cnvFromHex("616263")    ' "abc"
    lpKEK = kdfForCms(lpZZ, lpUkm, PKI_KWRAP_AES256 Or PKI_KDF_HKDF Or PKI_HASH_SHA256)
    Debug.Print "KEK = " & cnvToHex(lpKEK)
    Debug.Print "OK  = 1D06D6FD5C1EBFB33CAD875E6B99781D3D750875F573C9093CECBFBA6937ACC5"
End Sub

Public Sub test_cmsEnvData_ecdh()
    ' Create an enveloped CMS object to Dana (using ecdh) and Alice (using RSA)
    Dim strMsg As String
    Dim strCertList As String
    Dim strCmsFile As String
    Dim nRet As Long
    Dim strQuery As String
    Dim strPriKeyAlice As String
    Dim strPriKeyDana As String
    Dim strOut As String
    Dim strCertFile As String
    Dim abMsg() As Byte
    
    strCertList = "lamps-dana.encrypt.crt;lamps-alice.encrypt.crt"
    strMsg = "This is some sample content."
    
    '  Create an enveloped CMS object to Dana (using ecdh) and Alice (using RSA)
    strCmsFile = "dana_alice_all_defaults.p7m"
    nRet = cmsMakeEnvDataFromString(strCmsFile, strMsg, strCertList)
    Debug.Print "cmsMakeEnvDataFromString returns " & nRet & " (expecting 2)"
    Debug.Print "FILE: " & strCmsFile
    strQuery = "contentEncryptionAlgorithm"
    Debug.Print "QueryEnvData('" & strQuery & "')=" & cmsQueryEnvData(strCmsFile, strQuery)
    strQuery = "recipientInfoType"
    Debug.Print "QueryEnvData('" & strQuery & "')=" & cmsQueryEnvData(strCmsFile, strQuery)
    strQuery = "keyEncryptionAlgorithm"
    Debug.Print "QueryEnvData('" & strQuery & "')=" & cmsQueryEnvData(strCmsFile, strQuery)
    strQuery = "recipientInfoType/2"
    Debug.Print "QueryEnvData('" & strQuery & "')=" & cmsQueryEnvData(strCmsFile, strQuery)
    strQuery = "keyEncryptionAlgorithm/2"
    Debug.Print "QueryEnvData('" & strQuery & "')=" & cmsQueryEnvData(strCmsFile, strQuery)
    
    ' Read in Alice's RSA and Dana's ECC private key (unencrypted)
    strPriKeyAlice = rsaReadPrivateKey("lamps-alice.decrypt.p8.pem", "")
    Debug.Assert Len(strPriKeyAlice) > 0
    strPriKeyDana = eccReadPrivateKey("lamps-dana.decrypt.p8.pem", "")
    Debug.Assert Len(strPriKeyDana) > 0
    
    ' Read CMS enveloped-data using Alice's RSA key
    strCertFile = "lamps-alice.encrypt.crt"
    strOut = cmsReadEnvDataToString(strCmsFile, strCertFile, strPriKeyAlice)
    Debug.Assert (Len(strOut) > 0)
    Debug.Print "MSG=" & strOut
    
    ' Read CMS enveloped-data using Dana's ECC key
    strCertFile = "lamps-dana.encrypt.crt"
    strOut = cmsReadEnvDataToString(strCmsFile, strCertFile, strPriKeyDana)
    Debug.Assert (Len(strOut) > 0)
    Debug.Print "MSG=" & strOut
       
    ' Create enveloped CMS object using RSA-OAEP but defaults for ECDH
    strCmsFile = "dana_alice_oaep_ecc_defaults.p7m"
    nRet = cmsMakeEnvDataFromString(strCmsFile, strMsg, strCertList, "", PKI_BC_AES128 Or PKI_KT_RSAES_OAEP Or PKI_MGF_MGF1SHA1 Or PKI_HASH_SHA256)
    Debug.Print "cmsMakeEnvDataFromString returns " & nRet & " (expecting 2)"
    Debug.Print "FILE: " & strCmsFile
    strQuery = "contentEncryptionAlgorithm"
    Debug.Print "QueryEnvData('" & strQuery & "')=" & cmsQueryEnvData(strCmsFile, strQuery)
    strQuery = "recipientInfoType"
    Debug.Print "QueryEnvData('" & strQuery & "')=" & cmsQueryEnvData(strCmsFile, strQuery)
    strQuery = "keyEncryptionAlgorithm"
    Debug.Print "QueryEnvData('" & strQuery & "')=" & cmsQueryEnvData(strCmsFile, strQuery)
    strQuery = "recipientInfoType/2"
    Debug.Print "QueryEnvData('" & strQuery & "')=" & cmsQueryEnvData(strCmsFile, strQuery)
    strQuery = "keyEncryptionAlgorithm/2"
    Debug.Print "QueryEnvData('" & strQuery & "')=" & cmsQueryEnvData(strCmsFile, strQuery)
    
    ' Read CMS enveloped-data using Alice's RSA key
    strCertFile = "lamps-alice.encrypt.crt"
    strOut = cmsReadEnvDataToString(strCmsFile, strCertFile, strPriKeyAlice)
    Debug.Assert (Len(strOut) > 0)
    Debug.Print "MSG=" & strOut
    
    ' Read CMS enveloped-data using Dana's ECC key
    strCertFile = "lamps-dana.encrypt.crt"
    strOut = cmsReadEnvDataToString(strCmsFile, strCertFile, strPriKeyDana)
    Debug.Assert (Len(strOut) > 0)
    Debug.Print "MSG=" & strOut

    ' Use specific ECDH parameters
    strCmsFile = "dana_alice_hkdf.p7m"
    strCertList = "lamps-dana.encrypt.crt"
    abMsg = StrConv(strMsg, vbFromUnicode)
    nRet = cmsMakeEnvDataFromBytes(strCmsFile, abMsg, strCertList, "", PKI_BC_AES256 Or PKI_HASH_SHA256 Or PKI_KDF_HKDF Or PKI_KWRAP_AES256)
    Debug.Print "cmsMakeEnvDataFromString returns " & nRet & " (expecting 1)"
    Debug.Print "FILE: " & strCmsFile
    strQuery = "keyEncryptionAlgorithm"
    Debug.Print "QueryEnvData('" & strQuery & "')=" & cmsQueryEnvData(strCmsFile, strQuery)
    strQuery = "keyWrapAlgorithm"
    Debug.Print "QueryEnvData('" & strQuery & "')=" & cmsQueryEnvData(strCmsFile, strQuery)

    ' Read CMS enveloped-data using Dana's ECC key
    strCertFile = "lamps-dana.encrypt.crt"
    strOut = cmsReadEnvDataToString(strCmsFile, strCertFile, strPriKeyDana)
    Debug.Assert (Len(strOut) > 0)
    Debug.Print "MSG=" & strOut

End Sub

Public Sub test_x509MakeCert_X25519()
    Dim strCertName As String
    Dim strIssuercert As String
    Dim strPriKeyFile As String
    Dim strPubKeyFile As String
    Dim strPriKeyStr As String
    Dim strPubKeyStr As String
    Dim strDn As String
    Dim strExtns As String
    Dim r As Long
    
    strCertName = "new-lamps-dana.encrypt.cer"
    strIssuercert = "lamps-ca.ed25519.crt"
    strPriKeyFile = "lamps-ca.ed25519.p8"     ' No password
    strPubKeyFile = "lamps-dana.encrypt.crt"  ' We get the public key from the cert we are trying to reproduce!
    strDn = "O=IETF;OU=LAMPS WG;CN=Dana Hopper"
    strExtns = "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
    strPriKeyStr = eccReadPrivateKey(strPriKeyFile, "")
    Debug.Assert Len(strPriKeyStr) > 0
    Debug.Print "curveName=" & eccQueryKey(strPriKeyStr, "curvename")
    strPubKeyStr = eccReadPublicKey(strPubKeyFile)
    Debug.Assert Len(strPubKeyStr) > 0
    Debug.Print "curveName=" & eccQueryKey(strPubKeyStr, "curvename")
    
    ' Create the new certificate using internal keystrings for public and private keys
    r = X509_MakeCert(strCertName, strIssuercert, strPubKeyStr, strPriKeyStr, 0, 0, strDn, strExtns, 0, "", PKI_SIG_ED25519 Or PKI_X509_AUTHKEYID)
    Debug.Print "X509_MakeCert returns " & r & " (expecting 0)"
    Debug.Assert r = 0
    ' Dump details of new cert
    Debug.Print "FILE: " & strCertName
    Debug.Print (x509TextDumpToString(strCertName))
    
    ' For comparison, dump details of original lamps cert
    Debug.Print "FILE: " & strPubKeyFile
    Debug.Print (x509TextDumpToString(strPubKeyFile))
    ' NOTE: the *content* of the original certificate is the same as the newly created one
    ' _BUT_ the *order* of extension fields is different, so the thumbprints and signatures will not match.
    ' AFAWK there is no accepted order for extensions in an X.509 certificate.
   
End Sub

Public Sub test_pfxMakeFile_AES256()
    Dim strPfxFile As String
    Dim strPlainKeyFile As String
    Dim strKeyFile As String
    Dim strCertFile As String
    Dim strPassword As String
    Dim strKeyStr As String
    Dim strCertStr As String
    Dim strThumb As String
    Dim r As Long
    
    strPfxFile = "bob-aes256.pfx"
    strPlainKeyFile = "lamps-bob.p8.pem"
    strKeyFile = "lamps-bob.p8e"
    strCertFile = "lamps-bob.crt"
    strPassword = "password"
    
    ' Read in unencrypted key file then save as encrypted
    ' (We need an encrypted key file to make the PFX)
    strKeyStr = rsaReadPrivateKey(strPlainKeyFile, "")
    Debug.Assert Len(strKeyStr) > 0
    r = rsaSaveEncKey(strKeyFile, strKeyStr, strPassword, "", PKI_PBE_PBKDF2_AES128)
    Debug.Print "rsaSaveEncKey returns " & r & " (expecting 0)"
    Debug.Assert 0 = r
    
    ' Make a PFX file using AES256-SHA256
    r = PFX_MakeFile(strPfxFile, strCertFile, strKeyFile, strPassword, "Bob's friendly AES256 ID", PKI_PFX_AES256_SHA256)
    Debug.Print "PFX_MakeFile returns " & r & " (expecting 0)"
    Debug.Assert 0 = r
    Debug.Print "Created file: " & strPfxFile
    
    ' Verify the PFX file's signature
    r = PFX_VerifySig(strPfxFile, strPassword, 0)
    Debug.Print "PFX_VerifySig returns " & r & " (expecting 0)"
    Debug.Assert 0 = r
    
    ' Extract the certifcate from the PFX file we just made
    strCertStr = x509ReadCertStringFromPFX(strPfxFile, strPassword)
    Debug.Print "CERT=" & strCertStr
    
    ' Show the subject name
    Debug.Print "subjectName='" & x509QueryCert(strCertStr, "subjectName") & "'"
    ' Check thumbprint
    strThumb = x509CertThumb(strCertStr)
    Debug.Print "SHA1(CER)=" & strThumb
    Debug.Assert strThumb = "119cf5ff83dca26642cf3f2bb556241ccade75ec"
    
End Sub

Public Sub test_cmsMakeSigData_X25519()
    Dim strSigDataFile As String
    Dim strCertFile As String
    Dim lpData() As Byte
    Dim strPrivateKey As String
    Dim strQuery As String
    Dim r As Long
        
    ' Input contains two non-ASCII characters:
    '   U+00CD Latin capital letter I with acute, encodes as (0x) C3 8D
    '   U+00F1 Latin small letter N with tilde, encodes as (0x) C3 B1
    ' Convert Unicode string to UTF-8-encoded byte array to be signed
    lpData = cnvUTF8BytesFromLatin1("<doc><name c='es'>Íñigo</name></doc>")
    Debug.Print "HEX(data to be signed)=" & cnvToHex(lpData)
    ' Read in Dana's ED25519 private key
    strPrivateKey = eccReadPrivateKey("lamps-dana.p8.pem", "")
    strCertFile = "lamps-dana.crt"
    
    ' Create a CMS signed-data object
    strSigDataFile = "signeddata-utf8-dana.p7m"
    r = cmsMakeSigDataFromBytes(strSigDataFile, lpData, strCertFile, strPrivateKey, PKI_SIG_ED25519 Or PKI_CMS_INCLUDE_ATTRS Or PKI_CMS_ADD_SIGNINGCERT)
    
    Debug.Print "cmsMakeSigDataFromBytes returns " & r & " (expected 0)"
    Debug.Assert 0 = r
    Debug.Print "FILE: " & strSigDataFile
    ' Query the signed-data object
    strQuery = "signatureAlgorithm"
    Debug.Print "QuerySigData('" & strQuery & "')=" & cmsQuerySigData(strSigDataFile, strQuery)
    strQuery = "signingCertHash"
    Debug.Print "QuerySigData('" & strQuery & "')=" & cmsQuerySigData(strSigDataFile, strQuery)
    ' Check thumbprint of cert, this should match the signingCertHash
    Debug.Print "CertThumb=" & x509CertThumb(strCertFile)
    ' Read back the signed data
    lpData = cmsReadSigDataToBytes(strSigDataFile)
    Debug.Print "HEX(recovered content)=" & cnvToHex(lpData)
     
End Sub

Public Sub test_cmsEnvData_adv()
    Dim n As Long
    
    ' Create an enveloped CMS object (ktri type) to Bob using Bob's RSA key...
    n = cmsMakeEnvData("cms2bob_aes128.p7m", "excontent.txt", "BobRSASignByCarl.cer", "", PKI_BC_AES128 Or PKI_KT_RSAES_OAEP)
    Debug.Print "cmsMakeEnvData returns " & n & " (expecting 1)"
    Debug.Assert 1 = n
    ' Same but using authenticated encryption and creating an authEnvelopedData object...
    n = cmsMakeEnvData("cms2bob_aes128auth.p7m", "excontent.txt", "BobRSASignByCarl.cer", "", PKI_AEAD_AES_128_GCM Or PKI_KT_RSAES_OAEP)
    Debug.Print "cmsMakeEnvData returns " & n & " (expecting 1)"
    Debug.Assert 1 = n
    ' Create an enveloped CMS object (kari type) to Dana using Dana's ECC key...
    n = cmsMakeEnvData("cms2dana_hkdf.p7m", "excontent.txt", "lamps-dana.encrypt.crt", "", PKI_BC_AES256 Or PKI_HASH_SHA256 Or PKI_KDF_HKDF Or PKI_KWRAP_AES256)
    Debug.Print "cmsMakeEnvData returns " & n & " (expecting 1)"
    Debug.Assert 1 = n
    ' Create an enveloped CMS object (kekri type) using a previously distributed symmetric key-encryption key (KEK)...
    n = cmsMakeEnvData("cms_envdata_kekri.p7m", "excontent.txt", "type=@kekri,keyid=ourcommonkey", "#x0123456789ABCDEFF0E1D2C3B4A59687", PKI_BC_AES256 Or PKI_HASH_SHA256 Or PKI_KWRAP_AES128)
    Debug.Print "cmsMakeEnvData returns " & n & " (expecting 1)"
    Debug.Assert 1 = n
    ' Create an enveloped CMS object (pwri type) using password-based key management...
    n = cmsMakeEnvData("cms_envdata_pwri.p7m", "excontent.txt", "type=@pwri", "password12345", PKI_BC_AES192)
    Debug.Print "cmsMakeEnvData returns " & n & " (expecting 1)"
    Debug.Assert 1 = n
    
End Sub

Public Sub test_errFormatErrorMessage()
    Dim s As String
    Dim r As Long
    
    ' Clear any existing errors
    Call pkiVersion

    Debug.Print errFormatErrorMessage(11)
    Debug.Print errFormatErrorMessage(11, "User message!")
    ' Try and read missing file
    s = asn1Type("missing.file")
    Debug.Print errFormatErrorMessage()
    r = cmsMakeEnvData("not-to-be-made.p7m", "missing.file", "")
    Debug.Print errFormatErrorMessage(r)
    ' Try to create a signed-data object but passing a missing cert file
    Dim privkey As String
    privkey = rsaReadPrivateKey("AlicePrivRSASign.p8e", "password")
    r = CMS_MakeSigData("not-to-be-made.p7m", "excontent.txt", "missing.cer", privkey, 0)
    Debug.Print errFormatErrorMessage(r, "User/expected error")
       
End Sub

Public Sub test_cipher_GCM()
    Debug.Print "Testing cipher GCM..."
    Dim fileIn As String
    Dim fileEnc As String
    Dim fileChk As String
    Dim r As Long
    Dim key() As Byte
    Dim iv() As Byte
    
    key = cnvFromHex("2B7E151628AED2A6ABF7158809CF4F3C")
    ' NB Require exact 12-byte IV for GCM
    iv = cnvFromHex("000102030405060708090A0B")
    
    Debug.Print "Encrypt a file using AES-GCM..."
    fileIn = "excontent.txt"
    fileEnc = "excontent-gcm-enc.dat"
    fileChk = "abc-gcm-chk.dat"
    
    ' Encrypt the file
    Debug.Print "About to encrypt file '" & fileIn & "' of length " & FileLen(fileIn)
    r = cipherFileEncrypt(fileEnc, fileIn, key, iv, "aes128-gcm", PKI_IV_PREFIX)
    Debug.Print "cipherFileEncrypt(GCM) returns " & r & " (expecting 0)"
    Debug.Assert r = 0
    Debug.Print "Created file '" & fileEnc & "' of length " & FileLen(fileEnc) _
        & " (expected " & FileLen(fileIn) & "+12+16=" & FileLen(fileIn) + 12 + 16 & ")"
    
    ' Decrypt the file - IV is already at start of file so pass null iv argument
    iv = vbNullString   ' Set IV to be an empty byte array
    Debug.Print "About to decrypt file '" & fileEnc
    r = cipherFileDecrypt(fileChk, fileEnc, key, iv, "aes128-gcm", PKI_IV_PREFIX)
    Debug.Print "cipherFileDecrypt(GCM) returns " & r & " (expecting 0)"
    Debug.Assert r = 0
    Debug.Print "Created file '" & fileChk & "' of length " & FileLen(fileChk)
    
    ' Check decrypted file is the same as original
    Debug.Assert hashHexFromFile(fileIn, PKI_HASH_SHA1) = hashHexFromFile(fileChk, PKI_HASH_SHA1)
    
    Debug.Print "Encrypt using AES-GCM with hex-encoded parameters..."
    ' Same as EncryptAEAD except without AAD and with hex-encoded arguments
    Dim pthex As String
    Dim cthex As String
    Dim dthex As String
    Dim keyHex As String
    Dim ivhex As String
    
    keyHex = "2B7E151628AED2A6ABF7158809CF4F3C"
    ivhex = "000102030405060708090A0B"
    pthex = cnvHexStrFromString("This is some sample content.")
    Debug.Print "PT=" & pthex
    cthex = cipherEncryptHex(pthex, keyHex, ivhex, "aes128-gcm")
    Debug.Print "CT=" & cthex
    ' CT=0FA752259801FD6293B779E382FAD5FA7B5664D62EB63AA66064E189024C709ED4D580FB5E04E001C2D8DF97
    dthex = cipherDecryptHex(cthex, keyHex, ivhex, "aes128-gcm")
    Debug.Print "DT=" & dthex
    Debug.Assert Len(dthex) > 0
    Debug.Print "DT='" & cnvStringFromHexStr(dthex) & "'"
    ' Check decrypted hex is equal to original
    Debug.Assert UCase(dthex) = UCase(pthex)

End Sub

Public Sub test_rsaReadPublicKey_CSR()
    Dim csrfile As String
    Dim keyfile As String
    Dim dn As String
    Dim extns As String
    Dim keystr As String
    Dim r As Long
    
    ' 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_CertRequest(csrfile, keyfile, dn, extns, "", PKI_SIG_SHA256RSA)
    Debug.Print "X509_CertRequest returns " & r & " (expecting 0)"
    ' Dump details of CSR we just made...
    Debug.Print x509TextDumpToString(csrfile, PKI_X509_LDAP)
    
    ' Read in public key from this CSR file  to an internal key string
    ' (New in [v20.7])
    keystr = rsaReadPublicKey(csrfile)
    Debug.Print "Keysize=" & rsaKeyBits(keystr) & " bits, HashCode=0x" & Hex(RSA_KeyHashCode(keystr))
    ' EXPECTED: Keysize=2048 bits, HashCode=0xCA0B84DA

End Sub

Public Sub test_x509MakeCert_Ex()
    Dim r As Long
    Dim certname As String
    Dim keyfile As String
    Dim dn As String
    Dim extns As String
    Dim serialNum As Long
    Dim s As String
    
    certname = "myca-newattributes2022.cer"
    keyfile = "lamps-ca.rsa.p8"     ' No password
    
    dn = "C=DE;dnQualifier='distinguisher';initials='E.M.';pseudonym='Super Muster';generationQualifier='3rd.';CN=Erika Mustermann"
    extns = "keyUsage=digitalSignature,nonRepudiation;extKeyUsage=emailProtection;rfc822Name=erika@example.com;cRLDistributionPoints=http://dodgycert.example.com/evca.crl;"
    serialNum = &H88C
    
    r = X509_MakeCertSelf(certname, keyfile, serialNum, 10, dn, extns, 0, "", PKI_SIG_SHA256RSA)
    Debug.Print "X509_MakeCertSelf returns " & r & " (expecting 0)"
    Debug.Assert r = 0
    ' Dump details of cert we just made...
    Debug.Print x509TextDumpToString(certname, PKI_X509_LDAP)

    ' Query the certificate
    s = x509QueryCert(certname, "cRLDistributionPointsURI")
    Debug.Print "cRLDistributionPointsURI='" & s & "'"

End Sub

Public Sub test_prfBytes()
    Dim lpPrf() As Byte
    Dim lpMsg() As Byte
    Dim lpKey() As Byte
    lpKey = cnvFromHex("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F")
    lpMsg = cnvFromHex("00010203")
    ' "Standard" KMAC output length KMAC128 => 256 bits, no custom string
    lpPrf = prfBytes(256 \ 8, lpMsg, lpKey, PKI_KMAC_128)
    Debug.Print "KMAC=" & cnvToHex(lpPrf)
    Debug.Print "OK  =E5780B0D3EA6F7D3A429C5706AA43A00FADBD7D49628839E3187243F456EE14E"
    
    ' Same with custom string
    ' NB order of parameters (szCustom <=> nOptions).
    lpPrf = prfBytes(256 \ 8, lpMsg, lpKey, PKI_KMAC_128, "My Tagged Application")
    Debug.Print "KMAC=" & cnvToHex(lpPrf)
    Debug.Print "OK  =3B1FBA963CD8B0B59E8C1A6D71888B7143651AF8BA0A7070C0979E2811324AA5"
    
    ' Use KMAC256 with 1600-bit message and "standard" 512-bit output
    lpKey = cnvFromHex("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F")
    Dim strMsg As String
    strMsg = "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F3031" _
        & "32333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F60616263" _
        & "6465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495" _
        & "969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7"
    lpMsg = cnvFromHex(strMsg)
    lpPrf = prfBytes(512 \ 8, lpMsg, lpKey, PKI_KMAC_256)
    Debug.Print "KMAC=" & cnvToHex(lpPrf)
    Debug.Print "OK  =75358CF39E41494E949707927CEE0AF20A3FF553904C86B08F21CC414BCFD691589D27CF5E15369CBBFF8B9A4C2EB17800855D0235FF635DA82533EC6B759B69"

    
End Sub

Public Sub test_xofBytes()
    Dim lpMessage() As Byte
    Dim lpOut() As Byte
    lpMessage = cnvFromHex("6ae23f058f0f2264a18cd609acc26dd4dbc00f5c3ee9e13ecaea2bb5a2f0bb6b")
    ' Output 2000 bits
    lpOut = xofBytes(2000 \ 8, lpMessage, PKI_XOF_SHAKE256)
    Debug.Print "OUT=" & cnvToHex(lpOut)
    Debug.Print "OK =" & "b9b92544fb25cf...f1d35bdff79a"
    ' MGF1-SHA-256
    lpMessage = cnvFromHex("3b5c056af3ebba70d4c805380420585562b32410a778f558ff951252407647e3")
    Debug.Print cnvToHex(lpMessage)
    lpOut = xofBytes(34, lpMessage, PKI_XOF_MGF1_SHA256)
    Debug.Print "OUT=" & cnvToHex(lpOut)
    Debug.Print "OK =" & "5b7eb772aecf04c74af07d9d9c1c1f8d3a90dcda00d5bab1dc28daecdc86eb87611e"
    
End Sub

Public Sub test_hash_sha3()
    Dim lpMessage() As Byte
    lpMessage = StrConv("abc", vbFromUnicode)
    Debug.Print "lpMessage=" & cnvHexStrFromBytes(lpMessage)
    
    Debug.Print "OK:" & vbCrLf & "3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532"
    Debug.Print hashHexFromBytes(lpMessage, PKI_HASH_SHA3_256)
    Debug.Print hashHexFromHex("616263", PKI_HASH_SHA3_256)
    Debug.Print hashHexFromFile("abc.txt", PKI_HASH_SHA3_256)
    Debug.Print cnvHexStrFromBytes(hashBytes(lpMessage, PKI_HASH_SHA3_256))
    Debug.Print cnvHexStrFromBytes(hashFile("abc.txt", PKI_HASH_SHA3_256))
    ' Test other algs
    Debug.Print hashHexFromBytes(lpMessage, PKI_HASH_SHA3_224)
    Debug.Print hashHexFromHex("616263", PKI_HASH_SHA3_256)
    Debug.Print hashHexFromFile("abc.txt", PKI_HASH_SHA3_384)
    Debug.Print cnvHexStrFromBytes(hashBytes(lpMessage, PKI_HASH_SHA3_512))
    
End Sub