Imports System
Imports System.Diagnostics
Imports System.Reflection
Imports System.IO
Imports System.Text
Imports CryptoSysPKI
' $Id: TestPKIcsharp.vb $
' * Last updated:
' * $Date: 2023-01-01 03:41:00 $
' * $Version: 21.0.0 $
'
' Some tests using the CryptoSysPKI .NET interface.
' *
' * Requires `CryptoSys PKI` to be installed on your system: available from <https://cryptosys.net/pki/>.
' * Add a reference to `diCrSysPKINet.dll` installed in `C:\Program Files (x86)\CryptoSysPKI\DotNet`,
' * or include the C# source code module `CryptoSysPKI.cs` directly in your project.
' *
' * Test files are in `pkiDotNetTestFiles.zip`. These must be in the CWD.
' *
' * This is a Console Application written for target .NET Framework 4.0 and above.
' * Please report any bugs to <https://cryptosys.net/contact>.
'
'****************************** LICENSE ***********************************
' * Copyright (C) 2005-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>
'****************************************************************************
'
' [2015-03] Re-organised into modular form
' [2017-07] Changed license on this code to MIT
' [2019-03] Updated to avoid deprecated Cms.Options
' [2021-10] Requires .NET 4.0
' NOTE: Requires certain files to exist in the current working directory
' * (by default, the same directory as the executable).
' * See `arrFileNames` below - these files are in `pkiDotNetTestFiles.zip`
'
' Ported from C# to VB.NET using icsharpcode.net's SharpDevelop.
Namespace TestPKIExamples
''' <summary>
''' Test examples for CryptoSysPKI interface
''' </summary>
Class TestPKIExamples
Private Const MIN_PKI_VERSION As Integer = 200700
' Test files required to exist in the current working directory:
' Unencrypted version
' Encrypted, password="password"
Private Shared arrFileNames As String() = New String() {"alice-lamps.crt", "alice-lamps.p12", "AlicePrivRSASign.p8e", "AlicePubRSA.pub", "AliceRSASignByCarl.cer", "bob.p7b", _
"bob-lamps.crt", "bob-lamps.p12", "BobPrivRSAEncrypt.p8e", "BobRSASignByCarl.cer", "CarlPrivRSASign.p8e", "CarlRSASelf.cer", _
"dims.cer", "ocsp_response_ok_dims.dat", "rfc3280bis_cert1.cer", "rfc3280bis_cert2.cer", "rfc3280bis_CRL.crl", "smallca.cer", _
"sonnets.txt", "UTNUSERFirst-Object.cer", "AliceRSAPSS.p8", "AliceRSAPSS.p8e", "AliceRSAPssSignByCarl.cer", "BobRSAPSS.p8e", _
"BobRSAPssSignByCarl.cer", "CarlRSAPssSelf.cer", "CA_ECC_P256.p8e", "CA_ECC_P256.pub", "CA_RSA_2048.p8e", "CA_RSA_2048.pub", _
"excontent.txt", "rsa-oaep-1.p8", "rsa-oaep-1.pub", "User_ECC_P256.p8e", "User_ECC_P256.pub", "User_RSA_2048.p8e", _
"User_RSA_2048.pub", "User_RSA_2048.cer", "User2_ECC_P256.p8e", "User2_ECC_P256.pub", "User2_RSA_2048.p8e", "User2_RSA_2048.pub", _
"edwards-ietf.p8", "edwards-ietf-ex.p8", "Ed25519-ietf-selfsigned.cer", "lamps-alice.crt", "lamps-alice.p8", "lamps-alice.encrypt.crt", _
"lamps-alice.decrypt.p8.pem", "lamps-dana.encrypt.crt", "lamps-dana.decrypt.p8.pem", "lamps-ca.ed25519.crt", "lamps-ca.ed25519.p8", "lamps-bob.p8.pem", _
"lamps-bob.crt", "lamps-ca.rsa.p8", "File with a long name and spaces hello there all good yes thanks.txt", "你好.txt"}
' Name of file with zipped test files
Friend Shared zippedTestFiles As String = "pkiDotNetTestFiles.zip"
' Global vars set by command-line args
Private Shared doPrompt As Boolean = False
Private Shared doBigFile As Boolean = False
''' <summary>
''' The main entry point for the application.
''' </summary>
<STAThread> _
Public Shared Sub Main(args As String())
Dim origdir As String
' To store CWD before changed to temp
' Make sure minimum required version of CryptoSys PKI is installed...
Console.WriteLine("PKI Version is " & General.Version())
If General.Version() < MIN_PKI_VERSION Then
Console.WriteLine("FATAL ERROR: Require PKI version " & MIN_PKI_VERSION & " or later.")
Return
End If
Console.WriteLine("NET version is {0}", General.NetVersion())
' Handle command-line arguments
' * [some] just do some tests (default = do all)
' * [prompt] prompt for keystrokes and passwords
' * [bigfile] do operations on big files
' * [askdelete] ask to delete the temp directory when finished (default=delete automatically)
'
Dim doSome As Boolean = False
Dim askDelete As Boolean = False
' These are global
doPrompt = False
doBigFile = False
For iarg As Integer = 0 To args.Length - 1
If args(iarg) = "some" Then
doSome = True
End If
If args(iarg) = "prompt" Then
doPrompt = True
End If
If args(iarg) = "askdelete" Then
askDelete = True
End If
If args(iarg) = "bigfile" Then
doBigFile = True
End If
Next
' Check required files exist and setup temp directory
origdir = SetupTestFilesAndDirectory(arrFileNames)
If origdir Is Nothing Then
Return
End If
'*************
' DO THE TESTS
'*************
If doSome Then
' Use "some" in the command line
' Do some tests - comment these out as required
Console.WriteLine("DOING SOME TESTS...")
'test_General();
'test_Tdea();
'test_Rsa();
'test_Rsa_XML();
'test_X509();
'test_Pfx();
'test_CRL();
'test_OCSP();
'test_CMS(doBigFile);
'test_CMS_EnvData();
'test_CMS_SMIME_Chain();
'test_Hash();
'test_Hmac();
'test_Prompt(doPrompt);
'test_Wipe();
'test_Rng(doPrompt);
'test_Cipher();
'test_Cipher_Hex();
'test_CipherPad();
'test_KeyWrap();
'test_Rsa_Keys();
'test_Rsa_X509_Stronger();
'test_Autack();
'test_PEM();
'test_Padding();
'test_Cnv_hex();
'test_Cnv_base64();
'test_Cnv_other();
'test_Cnv_base58();
'test_Pbkdf2();
'test_Sig();
'test_Sig_Vars();
'test_Asn1();
'test_Byte_Utils();
'test_Ecc_MakeKeys();
'test_Ecc_KeyByCurve();
'test_Ecc_SaveKey();
'test_Ecc_MakeReadSaveKeys();
'test_Sig_Ecc();
'test_Sig_Ecc_det();
'test_Sig_Ecc_btc();
'test_Cipher_File();
'test_Cipher_Size();
'test_CMS_SigData_PSS();
'test_Compress();
'test_Cms_Data_Bytes();
'test_ReadJWK();
'test_Rng_Guid();
'test_Cipher_Encrypt_Prefix();
'test_X509_MakeCert_EmptyDN();
'test_X509_CertRequest_EmptyDN_extKeyUsage();
'test_X509_ReadCertStringFromPFX_3des();
'test_PFX_MakeFile_3DES();
'test_CMS_MakeSigData_signingcert();
' Tests copied from TestPKIcsharpV12.cs
'test_ReadRSA_ECCKeys();
'test_MakeCerts_ECDSA();
'test_MakeCerts_PSS();
'test_SIG_VerifyData_PSS();
'test_RSA_EncryptDecrypt();
'test_SIG_SignData_PSS();
'test_SIG_SignData_ECDSA();
'test_RSA_ToXMLStringEx();
'test_MakeSignedEnveloped_PSS_OAEP();
'test_PFX_MakeFile_PSS();
'test_CIPHER_EncryptAEAD();
'test_X509_ReadCertFromP7Chain();
'test_X509_ReadCertFromPFX();
' New in [v20.0]
'test_CIPHER_EncryptHex();
'test_RSA_XML_withprefixes();
'test_ECC_DHSharedSecret();
'test_ECC_DHSharedSecret_25519();
'test_SIG_SignData_Ed25519();
'test_X509_MakeCertSelf_Ed25519();
'test_CMS_MakeSigData_Ed25519();
' New in [v20.2]
'test_General_FormatErrorMessage();
' New in [v20.3]
'test_RSA_SaveEncKey();
' New in [v20.4]
'test_ECC_Brainpool();
' New in [v20.5]
'test_HASH_Length();
'test_KDF_Bytes();
'test_KDF_ForCms();
'test_CMS_EnvData_ecdh();
'test_X509_MakeCert_Internal_X25519();
'test_PFX_MakeFile_AES256();
' New in [v20.6]
'test_CMS_EnvData_auth();
'test_CMS_EnvData_pwri();
'test_CMS_EnvData_kekri();
'test_CMS_EnvData_examples();
' New in [v21.0]
'test_Hash_SHA3();
'test_Hmac_SHA3();
'test_Xof();
'test_Prf();
'test_CIPHER_File_GCM();
'test_RSA_ReadPublicKey_CSR();
'test_X509_MakeCert_Ex();
'test_CNV_ShortNamePath();
'test_CNV_ShortNamePath_EncryptFile();
test_CMS_MakeSigData_PSS()
Else
' Do all the test modules (default)
DoAllTests()
End If
' FINALLY, DISPLAY QUICK INFO ABOUT THE CORE DLL
Console.WriteLine(vbLf & "DETAILS OF CORE DLL...")
Console.WriteLine("DLL Version={0} [{1}] Lic={2} Compiled=[{3}] ", General.Version(), General.Platform(), General.LicenceType(), General.CompileTime())
Console.WriteLine("[{0}] NetVersion={1}", General.ModuleName(), General.NetVersion())
'********************************************
Console.WriteLine(vbLf & "ALL TESTS COMPLETED.")
' Put CWD back to original and offer to remove the test dir
RestoreDirectory(origdir, askDelete)
End Sub
Private Shared Sub DoAllTests()
Console.WriteLine("DOING ALL TESTS...")
test_General()
test_Tdea()
test_Rsa()
test_Rsa_XML()
test_X509()
test_Pfx()
test_CRL()
test_OCSP()
test_CMS(doBigFile)
test_CMS_EnvData()
test_CMS_SMIME_Chain()
test_Hash()
test_Hmac()
test_Prompt(doPrompt)
test_Wipe()
test_Rng(doPrompt)
test_Cipher()
test_Cipher_Hex()
test_CipherPad()
test_KeyWrap()
test_Rsa_Keys()
test_Rsa_X509_Stronger()
test_Autack()
test_PEM()
test_Padding()
test_Cnv_hex()
test_Cnv_base64()
test_Cnv_other()
test_Cnv_base58()
test_Pbkdf2()
test_Sig()
test_Sig_Vars()
test_Asn1()
test_Byte_Utils()
test_Ecc_MakeKeys()
test_Ecc_KeyByCurve()
test_Ecc_SaveKey()
test_Ecc_MakeReadSaveKeys()
test_Sig_Ecc()
test_Sig_Ecc_det()
test_Sig_Ecc_btc()
test_Cipher_File()
test_Cipher_Size()
test_Compress()
test_Cms_Data_Bytes()
test_ReadJWK()
test_Rng_Guid()
test_Cipher_Encrypt_Prefix()
test_X509_MakeCert_EmptyDN()
test_X509_CertRequest_EmptyDN_extKeyUsage()
test_X509_ReadCertStringFromPFX_3des()
test_PFX_MakeFile_3DES()
test_CMS_MakeSigData_signingcert()
' Tests from TestPKIcsharpV12.cs
test_ReadRSA_ECCKeys()
test_MakeCerts_ECDSA()
test_MakeCerts_PSS()
test_SIG_VerifyData_PSS()
test_RSA_EncryptDecrypt()
test_SIG_SignData_PSS()
test_SIG_SignData_ECDSA()
test_RSA_ToXMLStringEx()
test_CMS_MakeSigData_PSS()
test_MakeSignedEnveloped_PSS_OAEP()
test_PFX_MakeFile_PSS()
test_CIPHER_EncryptAEAD()
test_X509_ReadCertFromP7Chain()
test_X509_ReadCertFromPFX()
test_CIPHER_EncryptHex()
test_RSA_XML_withprefixes()
test_ECC_DHSharedSecret()
test_ECC_DHSharedSecret_25519()
test_SIG_SignData_Ed25519()
test_X509_MakeCertSelf_Ed25519()
test_CMS_MakeSigData_Ed25519()
test_General_FormatErrorMessage()
test_RSA_SaveEncKey()
test_ECC_Brainpool()
test_HASH_Length()
test_KDF_Bytes()
test_KDF_ForCms()
test_CMS_EnvData_ecdh()
test_X509_MakeCert_Internal_X25519()
test_PFX_MakeFile_AES256()
test_CMS_EnvData_auth()
test_CMS_EnvData_pwri()
test_CMS_EnvData_kekri()
test_CMS_EnvData_examples()
test_Hash_SHA3()
test_Hmac_SHA3()
test_Xof()
test_Prf()
test_CIPHER_File_GCM()
test_RSA_ReadPublicKey_CSR()
test_CNV_ShortNamePath()
test_X509_MakeCert_Ex()
test_CNV_ShortNamePath_EncryptFile()
End Sub
'********************
' THE TEST MODULES...
'********************
Private Shared Sub test_General()
Dim n As Integer
Dim ch As Char
Dim s As String
'****************
' GENERAL TESTS *
'****************
Console.WriteLine(vbLf & "GENERAL FUNCTIONS:")
n = CryptoSysPKI.General.Version()
Console.WriteLine("Version={0}", n)
ch = CryptoSysPKI.General.LicenceType()
Console.WriteLine("LicenceType={0}", ch)
s = CryptoSysPKI.General.ModuleName()
Console.WriteLine("ModuleName={0}", s)
s = CryptoSysPKI.General.ModuleInfo()
Console.WriteLine("ModuleInfo={0}", s)
s = CryptoSysPKI.General.CompileTime()
Console.WriteLine("CompileTime={0}", s)
s = General.Platform()
Console.WriteLine("Platform={0}", s)
s = CryptoSysPKI.General.LastError()
Console.WriteLine("LastError='{0}' (expecting empty)", s)
n = CryptoSysPKI.General.PowerUpTests()
Console.WriteLine("PowerUpTests={0} (expecting 0)", n)
End Sub
Private Shared Sub test_Tdea()
'*******************************************
' TDEA (Triple DES, 3DES) ENCRYPTION TESTS *
'*******************************************
Dim s As String
Dim n As Integer
Dim b As Byte()
Dim keyhex As String, plainStr As String, cipherStr As String, ivhex As String, okhex As String
Dim arrPlain As Byte()
Dim arrCipher As Byte()
Dim arrKey As Byte()
Dim arrIV As Byte()
Dim excontent As String, fnameData As String, fnameEnc As String, fnameCheck As String
Console.WriteLine(vbLf & "TESTING TRIPLE DES:")
keyhex = "010101010101010101010101010101010101010101010101"
plainStr = "8000000000000000"
cipherStr = "95F8A5E5DD31D900"
' Encrypt in ECB mode using hex strings
s = Tdea.Encrypt(plainStr, keyhex, Mode.ECB, Nothing)
Console.WriteLine("KY={0}", keyhex)
Console.WriteLine("PT={0}", plainStr)
Console.WriteLine("CT={0}", s)
Console.WriteLine("OK={0}", cipherStr)
Debug.Assert([String].Compare(s, cipherStr, True) = 0, "Tdea.HexECB failed")
' Decrypt
s = Tdea.Decrypt(cipherStr, keyhex, Mode.ECB, Nothing)
Console.WriteLine("P'={0}", s)
Console.WriteLine("OK={0}", plainStr)
Debug.Assert([String].Compare(s, plainStr, True) = 0, "Tdea.HexECB failed")
' Ditto using byte arrays
arrPlain = Cnv.FromHex(plainStr)
arrCipher = Cnv.FromHex(cipherStr)
arrKey = Cnv.FromHex(keyhex)
b = Tdea.Encrypt(arrPlain, arrKey, Mode.ECB, Nothing)
Console.WriteLine("CT={0}", Cnv.ToHex(b))
b = Tdea.Decrypt(arrCipher, arrKey, Mode.ECB, Nothing)
Console.WriteLine("P'={0}", Cnv.ToHex(b))
' Encrypt in CBC mode using hex strings
keyhex = "737C791F25EAD0E04629254352F7DC6291E5CB26917ADA32"
ivhex = "B36B6BFB6231084E"
plainStr = "5468697320736F6D652073616D706520636F6E74656E742E0808080808080808"
cipherStr = "d76fd1178fbd02f84231f5c1d2a2f74a4159482964f675248254223daf9af8e4"
s = Tdea.Encrypt(plainStr, keyhex, Mode.CBC, ivhex)
Console.WriteLine("KY={0}", keyhex)
Console.WriteLine("IV={0}", ivhex)
Console.WriteLine("PT={0}", plainStr)
Console.WriteLine("CT={0}", s)
Console.WriteLine("OK={0}", cipherStr)
Debug.Assert([String].Compare(s, cipherStr, True) = 0, "Tdea.Encrypt{Hex,CBC} failed")
' Decrypt
s = Tdea.Decrypt(cipherStr, keyhex, Mode.CBC, ivhex)
Console.WriteLine("P'={0}", s)
Console.WriteLine("OK={0}", plainStr)
Debug.Assert([String].Compare(s, plainStr, True) = 0, "Tdea.Decrypt{Hex,CBC} failed")
' Ditto using byte arrays
arrPlain = Cnv.FromHex(plainStr)
arrCipher = Cnv.FromHex(cipherStr)
arrKey = Cnv.FromHex(keyhex)
arrIV = Cnv.FromHex(ivhex)
b = Tdea.Encrypt(arrPlain, arrKey, Mode.CBC, arrIV)
Console.WriteLine("CT={0}", Cnv.ToHex(b))
b = Tdea.Decrypt(arrCipher, arrKey, Mode.CBC, arrIV)
Console.WriteLine("P'={0}", Cnv.ToHex(b))
Debug.Assert([String].Compare(arrPlain.ToString(), b.ToString()) = 0, "Tdea.BytesCBC failed")
' Create a test text file
excontent = "This is some sample content."
fnameData = "excontent.txt"
File.WriteAllText(fnameData, excontent)
' Encrypt a file
keyhex = "fedcba98765432100123456789abcdeffedcba9876543210"
fnameEnc = "excontent.tdea.enc.dat"
okhex = "DD1E1FA430AE6BE1D3B83245F7A5B17C4BF03688238778E95F2CCD05AF1A8F44"
n = Tdea.FileEncrypt(fnameEnc, fnameData, keyhex, Mode.ECB, Nothing)
If 0 = n Then
Console.WriteLine("Tdea.File created encrypted file '{0}'", fnameEnc)
Else
Console.WriteLine("Tdea.File returned error code {0}", n)
End If
Debug.Assert(0 = n, "Tdea.File failed.")
' Check we got what we should
b = File.ReadAllBytes(fnameEnc)
Console.WriteLine("CT={0}", Cnv.ToHex(b))
Debug.Assert([String].Compare(Cnv.ToHex(b), okhex, True) = 0, "Tdea.FileEncrypt failed")
' Decrypt it using byte format of key instead of hex
fnameCheck = "excontent.tdea.chk.txt"
b = Cnv.FromHex(keyhex)
n = Tdea.FileDecrypt(fnameCheck, fnameEnc, b, Mode.ECB, Nothing)
If 0 = n Then
Console.WriteLine("Tdea.File decrypted to file '{0}'", fnameCheck)
' Show contents of file
s = File.ReadAllText(fnameCheck)
Debug.Assert([String].Compare(s, excontent) = 0, "Decrypted file data does not match")
Else
Console.WriteLine("Tdea.File returned error code {0}", n)
End If
Debug.Assert(0 = n, "Tdea.File failed.")
End Sub
Private Shared Sub test_Rsa()
'************
' RSA TESTS *
'************
Dim s As String
Dim n As Integer, nblock As Integer
Dim b As Byte()
Dim isok As Boolean
Dim msg As Byte()
Dim bcheck As Byte()
Dim sbPrivateKey As StringBuilder
Dim sbPublicKey As StringBuilder
Dim fnameOutput As String, fname As String
Dim strCheck As String
Console.WriteLine(vbLf & "RSA FUNCTION TESTS:")
' Read the public key from the recipient's X.509 certificate
sbPublicKey = Rsa.ReadPublicKey("AliceRSASignByCarl.cer")
Console.WriteLine("PublicKey={0}", sbPublicKey.ToString())
Console.WriteLine("PublicKeyBits={0}", Rsa.KeyBits(sbPublicKey.ToString()))
Console.WriteLine("PublicKeyBytes={0}", Rsa.KeyBytes(sbPublicKey.ToString()))
' A message to transmit in byte format
msg = System.Text.Encoding.[Default].GetBytes("Hello world!")
' Make an RSA data block of same length in bytes as key
' using EME-PKCS1-v1_5 encoding
nblock = Rsa.KeyBytes(sbPublicKey.ToString())
' [old, deprecated way:] b = Rsa.EncodeMsg(nblock, msg, Rsa.EncodeFor.Encryption);
' [New way in v2.9:]
b = Rsa.EncodeMsgForEncryption(nblock, msg, Rsa.EME.PKCSv1_5)
Console.WriteLine("BLK={0}", Cnv.ToHex(b))
' Encrypt with RSA public key
b = Rsa.RawPublic(b, sbPublicKey.ToString())
Console.WriteLine("ENC={0}", Cnv.ToHex(b))
' Read in the private key from the encrypted key file
sbPrivateKey = Rsa.ReadPrivateKey("AlicePrivRSASign.p8e", "password")
Console.WriteLine("PrivateKey={0}", sbPrivateKey.ToString())
Console.WriteLine("PrivateKeyBits={0}", Rsa.KeyBits(sbPrivateKey.ToString()))
Console.WriteLine("PrivateKeyBytes={0}", Rsa.KeyBytes(sbPrivateKey.ToString()))
' Decrypt with private key
b = Rsa.RawPrivate(b, sbPrivateKey.ToString())
Console.WriteLine("DEC={0}", Cnv.ToHex(b))
' Extract the message from the encryption block
' [old, deprecated way:] b = Rsa.DecodeMsg(b, Rsa.EncodeFor.Encryption);
' [New way in v2.9:]
b = Rsa.DecodeMsgForEncryption(b, Rsa.EME.PKCSv1_5)
Console.WriteLine("MSG={0}", Cnv.ToHex(b))
' Convert back to a string
s = System.Text.Encoding.[Default].GetString(b)
Console.WriteLine("MSG={0}", s)
' Now use to do RSA digital signing
' A message to sign in byte format
msg = System.Text.Encoding.[Default].GetBytes("abc")
' Make an RSA data block of same length in bytes as key
' using EMSA-PKCS1-v1_5 encoding with SHA-1
nblock = Rsa.KeyBytes(sbPrivateKey.ToString())
' [old, deprecated way:] b = Rsa.EncodeMsg(nblock, msg, Rsa.EncodeFor.Signature);
' [New way in v2.9:]
b = Rsa.EncodeMsgForSignature(nblock, msg, HashAlgorithm.Sha1)
Console.WriteLine("BLK={0}", Cnv.ToHex(b))
' Sign with RSA private key
b = Rsa.RawPrivate(b, sbPrivateKey.ToString())
Console.WriteLine("SIG={0}", Cnv.ToHex(b))
' Transmit the message + SIG block to recipient...
' Decrypt to verify with RSA public key
b = Rsa.RawPublic(b, sbPublicKey.ToString())
Console.WriteLine("VER={0}", Cnv.ToHex(b))
' Create an independent Encoded block from message
' [old, deprecated way:] bcheck = Rsa.EncodeMsg(nblock, msg, Rsa.EncodeFor.Signature);
' [New way in v2.9:]
bcheck = Rsa.EncodeMsgForSignature(nblock, msg, HashAlgorithm.Sha1)
' And compare to see if they are the same
' (mmm, C# doesn't have a memcmp function, so we need our own function)
If ByteArraysEqual(bcheck, b) Then
Console.WriteLine("OK, verification OK")
Else
Console.WriteLine("ERROR: verification failed")
End If
Debug.Assert(ByteArraysEqual(bcheck, b), "Verification failed")
' Test Encode & Decode functions directly
Console.WriteLine("Testing RSA Encoding methods...")
Console.WriteLine("EME-PKCS1-V1_5 method")
msg = Cnv.FromHex("deadbeef")
'b = Rsa.EncodeMsg(64, msg, Rsa.EncodeFor.Encryption);
b = Rsa.EncodeMsgForEncryption(64, msg, Rsa.EME.PKCSv1_5)
Console.WriteLine("MSG={0}", Cnv.ToHex(msg))
Console.WriteLine("EME={0}", Cnv.ToHex(b))
'bcheck = Rsa.DecodeMsg(b, Rsa.EncodeFor.Encryption);
bcheck = Rsa.DecodeMsgForEncryption(b, Rsa.EME.PKCSv1_5)
Console.WriteLine("MSG={0}", Cnv.ToHex(bcheck))
Debug.Assert(ByteArraysEqual(bcheck, msg), "EME-PKCSv1_5 Decoding failed")
' Again using OAEP algorithm instead of default
Console.WriteLine("EME-OAEP method")
msg = Cnv.FromHex("deadbeef")
'b = Rsa.EncodeMsg(64, msg, Rsa.EncodeFor.Encryption_OAEP);
b = Rsa.EncodeMsgForEncryption(64, msg, Rsa.EME.OAEP)
Console.WriteLine("MSG={0}", Cnv.ToHex(msg))
Console.WriteLine("EME={0}", Cnv.ToHex(b))
'bcheck = Rsa.DecodeMsg(b, Rsa.EncodeFor.Encryption_OAEP);
bcheck = Rsa.DecodeMsgForEncryption(b, Rsa.EME.OAEP)
Console.WriteLine("MSG={0}", Cnv.ToHex(bcheck))
Debug.Assert(ByteArraysEqual(bcheck, msg), "EME-OAEP Decoding failed")
' Ditto for signature
Console.WriteLine("EME-PKCS1-V1_5 method for signature")
msg = System.Text.Encoding.[Default].GetBytes("abc")
'b = Rsa.EncodeMsg(64, msg, Rsa.EncodeFor.Signature);
b = Rsa.EncodeMsgForSignature(64, msg, HashAlgorithm.Sha1)
Console.WriteLine("MSG={0}", Cnv.ToHex(msg))
Console.WriteLine("EMSA={0}", Cnv.ToHex(b))
'bcheck = Rsa.DecodeMsg(b, Rsa.EncodeFor.Signature);
' Note we can only ever extract the *digest* out of an EMSA block, not the original message
bcheck = Rsa.DecodeDigestForSignature(b)
Console.WriteLine("MD={0}", Cnv.ToHex(bcheck))
' We expect the value of SHA-1("abc")
Debug.Assert(ByteArraysEqual(bcheck, Cnv.FromHex("A9993E364706816ABA3E25717850C26C9CD0D89D")))
' Check our valid keys
n = Rsa.CheckKey(sbPrivateKey.ToString())
Console.WriteLine("Rsa.CheckKey returns {0} for private key (expecting 0)", n)
n = Rsa.CheckKey(sbPublicKey.ToString())
Console.WriteLine("Rsa.CheckKey returns {0} for public key (expecting 1)", n)
' and try something non-valid
Console.WriteLine("Try an invalid key string...")
n = Rsa.CheckKey("Some garbage in a string")
Console.WriteLine("Rsa.CheckKey returns {0} (expecting -ve error code) {1};{2}", n, General.ErrorLookup(n), General.LastError())
' Create a PKCS-12 file containing Alice's private key
' Updated [v3.8] Default is now with "standard" encrypted cert
fname = "alice.pfx"
n = Pfx.MakeFile(fname, "AliceRSASignByCarl.cer", "AlicePrivRSASign.p8e", "password", "Alice's Key", Pfx.Options.[Default])
Console.WriteLine("Pfx.MakeFile returns {0} (expected 0)", n)
Debug.Assert(0 = n, "Failed to create PFX file")
' Verify that we saved it OK
isok = Pfx.SignatureIsValid(fname, "password")
Console.WriteLine("Signature in {0} is {1}", fname, (If(isok, "OK", "INVALID")))
Debug.Assert(isok, "PFX signature is invalid")
' Extract the encrypted private key from the PKCS12 file into a new PKCS-8 file
fnameOutput = "alice_epk_from_pfx.bin"
n = Rsa.GetPrivateKeyFromPFX(fnameOutput, fname)
Console.WriteLine("Rsa.GetPrivateKeyFromPFX returns {0} (expected +ve)", n)
Debug.Assert(n > 0, "Failed to extract private key from PFX file")
' Check we got the same private key as we had before
sbPrivateKey = Rsa.ReadPrivateKey(fnameOutput, "password")
strCheck = sbPrivateKey.ToString()
sbPrivateKey = Rsa.ReadPrivateKey("AlicePrivRSASign.p8e", "password")
' Use the KeyHashCode - don't try and compare internal strings directly
Debug.Assert(Rsa.KeyHashCode(strCheck) = Rsa.KeyHashCode(sbPrivateKey.ToString()), "Private keys don't match")
' Save private key in unencrypted format compatible with OpenSSL
fname = "AlicePriInfo_ssl.txt"
n = Rsa.SavePrivateKeyInfo(fname, sbPrivateKey.ToString(), Rsa.Format.SSL)
Console.WriteLine("Rsa.SavePrivateKeyInfo returns {0} (expected 0)", n)
Debug.Assert(0 = n, "Failed to create unencrypted private key file")
' Check we can read it and that it's the same as before
strCheck = sbPrivateKey.ToString()
s = Rsa.ReadPrivateKey(fname, "").ToString()
' Use the HashCode of the internal strings
Console.WriteLine("Rsa.KeyHashCode(old)={0,8:X}", Rsa.KeyHashCode(strCheck))
Console.WriteLine("Rsa.KeyHashCode(new)={0,8:X}", Rsa.KeyHashCode(s))
Debug.Assert(Rsa.KeyHashCode(strCheck) = Rsa.KeyHashCode(s), "Private keys don't match")
' Read the private key directly from the PFX file [new in v3.8]
fname = "alice.pfx"
sbPrivateKey = Rsa.ReadPrivateKey(fname, "password")
Console.WriteLine("Rsa.ReadPrivateKeyFromPFX returns a string {0} characters long", sbPrivateKey.ToString().Length)
Debug.Assert(sbPrivateKey.ToString().Length > 0, "Rsa.ReadPrivateKeyFromPFX failed")
Console.WriteLine("Rsa.KeyHashCode={0,8:X}", Rsa.KeyHashCode(sbPrivateKey.ToString()))
' Convert this to a public key string [new in v3.8]
sbPublicKey = Rsa.PublicKeyFromPrivate(sbPrivateKey)
Console.WriteLine("Rsa.PublicKeyFromPrivate returns a string {0} characters long", sbPublicKey.ToString().Length)
Debug.Assert(sbPublicKey.ToString().Length > 0, "Rsa.PublicKeyFromPrivate failed")
Console.WriteLine("Rsa.KeyHashCode={0,8:X}", Rsa.KeyHashCode(sbPublicKey.ToString()))
Debug.Assert(Rsa.KeyHashCode(sbPublicKey.ToString()) = Rsa.KeyHashCode(sbPrivateKey.ToString()), "Public and private keys don't match")
' Now save the public key in PEM format
fname = "pubkey_check.txt"
n = Rsa.SavePublicKey(fname, sbPublicKey.ToString(), Rsa.Format.PEM)
Console.WriteLine("Rsa.SavePublicKey returns {0} (expected 0)", n)
Debug.Assert(0 = n, "Failed to create public key file")
' And check we can read it and it is the same
strCheck = sbPublicKey.ToString()
s = Rsa.ReadPublicKey(fname).ToString()
' Use the HashCode of the internal strings
Console.WriteLine("Rsa.KeyHashCode(old)={0,8:X}", Rsa.KeyHashCode(strCheck))
Console.WriteLine("Rsa.KeyHashCode(new)={0,8:X}", Rsa.KeyHashCode(s))
Debug.Assert(Rsa.KeyHashCode(strCheck) = Rsa.KeyHashCode(s), "Public keys don't match")
' NOTE: [v3.0] This comparison of internal strings will no longer work.
' Debug.Assert(strCheck == s, "Public keys don't match");
' Show that a private and public key string are matched
' Read in the private key from the encrypted key file
sbPrivateKey = Rsa.ReadPrivateKey("AlicePrivRSASign.p8e", "password")
Debug.Assert(sbPrivateKey.Length > 0, "Failed to read in private key")
' Read the public key from the recipient's X.509 certificate
sbPublicKey = Rsa.ReadPublicKey("AliceRSASignByCarl.cer")
Debug.Assert(sbPublicKey.Length > 0, "Failed to read in public key")
n = Rsa.KeyMatch(sbPrivateKey.ToString(), sbPublicKey.ToString())
Console.WriteLine("Rsa.KeyMatch(PRIV_alice,PUB_alice) returned {0} (expected 0)", n)
Debug.Assert(n = 0, "Rsa.KeyMatch failed")
' Try a pair that are not matched: use Alice's private key and Bob's public
sbPublicKey = Rsa.ReadPublicKey("BobRSASignByCarl.cer")
n = Rsa.KeyMatch(sbPrivateKey.ToString(), sbPublicKey.ToString())
Console.WriteLine("Rsa.KeyMatch(PRIV_alice,PUB_bob) returned {0} [{1}] (expected -ve)", n, General.ErrorLookup(n))
Debug.Assert(n <> 0, "Rsa.KeyMatch failed")
End Sub
Private Shared Sub test_Rsa_XML()
'*********************
' RSA TESTS WITH XML *
'*********************
Dim s As String
Dim sbPrivateKey As StringBuilder
Dim fldName As String
Dim xmlkey As String
Console.WriteLine(vbLf & "RSA TESTS WITH XML:")
' Read in the private key from the encrypted key file
sbPrivateKey = Rsa.ReadPrivateKey("AlicePrivRSASign.p8e", "password")
' Export private key to XML format as <RSAKeyPair>
s = Rsa.ToXMLString(sbPrivateKey.ToString(), 0)
Console.WriteLine("Private key in XML format:" & vbLf & "{0}", s)
' Export key to XML format using <RSAKeyValue> instead of correct <RSAKeyPair>
' and add "ds" prefix.
s = Rsa.ToXMLString(sbPrivateKey.ToString(), "ds", Rsa.XmlOptions.ForceRSAKeyValue)
Console.WriteLine("Private key in XML format, .NET style tag name, plus ds: prefix:" & vbLf & "{0}", s)
' Export just the public key to XML format
s = Rsa.ToXMLString(sbPrivateKey.ToString(), Rsa.XmlOptions.ExcludePrivateParams)
Console.WriteLine("Public key in XML format extracted from private key:" & vbLf & "{0}", s)
' Test re-import from XML (NB just the public here)
xmlkey = s
s = Rsa.FromXMLString(xmlkey)
' NB the internal strings are always different even for the same key
Console.WriteLine("Internal key (always different):" & vbLf & "{0}", s)
' Show we can read this new internal (public) key
Console.WriteLine("Key bits={0}, KeyHashCode=0x{1:X8}", Rsa.KeyBits(s), Rsa.KeyHashCode(s))
Debug.Assert(Rsa.KeyBits(s) > 0)
' Try and import a private key from a public XML key (should fail)
s = Rsa.FromXMLString(xmlkey, Rsa.XmlOptions.RequirePrivate)
Console.WriteLine("Rsa.FromXMLString(xmlkey, Rsa.XmlOptions.RequirePrivate) returns '{0}' (expecting empty string)", s)
Console.WriteLine("ErrorCode={0}, LastError()='{1}'", General.ErrorCode(), General.LastError())
Debug.Assert(s.Length = 0)
' Use Rsa.KeyValue to get base64 values for XML <RSAKeyValue> node
Console.WriteLine("Use Rsa.KeyValue()...")
fldName = "Modulus"
s = Rsa.KeyValue(sbPrivateKey.ToString(), fldName)
Console.WriteLine("{0}={1}", fldName, s)
Debug.Assert(s.Length > 0)
fldName = "Exponent"
s = Rsa.KeyValue(sbPrivateKey.ToString(), fldName)
Console.WriteLine("{0}={1}", fldName, s)
Debug.Assert(s.Length > 0)
' Read in a private key when we know only (n,e,d)
xmlkey = "<RSAKeyPair>" & "<Modulus EncodingType='hexBinary'>E08973398DD8F5F5E88776397F4EB005BB5383DE0FB7ABDC7DC775290D052E6D12DFA68626D4D26FAA5829FC97ECFA82510F3080BEB1509E4644F12CBBD832CFC6686F07D9B060ACBEEE34096A13F5F7050593DF5EBA3556D961FF197FC981E6F86CEA874070EFAC6D2C749F2DFA553AB9997702A648528C4EF357385774575F</Modulus>" & "<Exponent EncodingType='hexBinary'>010001</Exponent>" & "<D EncodingType='hexBinary'>A403C327477634346CA686B57949014B2E8AD2C862B2C7D748096A8B91F736F275D6E8CD15906027314735644D95CD6763CEB49F56AC2F376E1CEE0EBF282DF439906F34D86E085BD5656AD841F313D72D395EFE33CBFF29E4030B3D05A28FB7F18EA27637B07957D32F2BDE8706227D04665EC91BAF8B1AC3EC9144AB7F21</D>" & "</RSAKeyPair>"
Console.WriteLine("Private key in XML hexbinary format with only (n,e,d) parameters:" & vbLf & "{0}", xmlkey)
s = Rsa.FromXMLString(xmlkey)
Debug.Assert(s.Length > 0)
' Show we can read this new internal key - hashcode should be same as previous
Console.WriteLine("Key bits={0}, KeyHashCode=0x{1:X8}", Rsa.KeyBits(s), Rsa.KeyHashCode(s))
Debug.Assert(Rsa.KeyBits(s) > 0)
End Sub
Private Shared Sub test_Pfx()
'***************************
' PFX/PKCS-12 FILE FUNCTIONS
'***************************
Dim n As Integer
Dim fname As String
Dim s As String
Dim fnameInput As String, fnameCert As String, fnameP7 As String
Dim password As String
Console.WriteLine(vbLf & "TEST PFX/PKCS-12 FILE FUNCTIONS:")
' Create a PKCS-12 file containing Alice's private key
fname = "alice.pfx"
n = Pfx.MakeFile(fname, "AliceRSASignByCarl.cer", "AlicePrivRSASign.p8e", "password", "Alice's Key", Pfx.Options.[Default])
Console.WriteLine("Pfx.MakeFile returns {0} (expected 0)", n)
Debug.Assert(0 = n, "Failed to create PFX file")
' Create a PKCS-12 file excluding Alice's private key; i.e. just the cert
' and with the cert unencrypted (.PlainCert option)
fname = "alice-nokey.pfx"
n = Pfx.MakeFile(fname, "AliceRSASignByCarl.cer", "", "", "Alice's Cert", Pfx.Options.PlainCert)
Console.WriteLine("Pfx.MakeFile (no key) returns {0} (expected 0)", n)
Debug.Assert(0 = n, "Failed to create PFX file (no key)")
' Extract the certificate from a PKCS-12 PFX file
fnameInput = "alice.pfx"
fnameCert = "alice_fromPFX.cer"
n = X509.GetCertFromPFX(fnameCert, fnameInput, "password")
Console.WriteLine("X509.GetCertFromPFX returns {0} (expected +ve).", n)
Debug.Assert(n > 0, "Failed to extract certificate from PFX file")
' Get type name of ASN.1 object
s = Asn1.Type(fnameCert)
Console.WriteLine("{0} is a '{1}'", fnameCert, s)
' Check it is an X.509 cert by getting its subject
s = X509.CertSubjectName(fnameCert, "")
Console.WriteLine("{0} has subject {1}.", fnameCert, s)
' And again from a PKCS-12 file with just a certificate
fnameInput = "alice-nokey.pfx"
fnameCert = "alice_fromPFX-nokey.cer"
n = X509.GetCertFromPFX(fnameCert, fnameInput, "password")
Console.WriteLine("X509.GetCertFromPFX returns {0} (expected +ve).", n)
Debug.Assert(n > 0, "Failed to extract certificate from PFX file")
' Check it is an X.509 cert by getting its subject
s = X509.CertSubjectName(fnameCert, "")
Console.WriteLine("{0} has subject {1}.", fnameCert, s)
' Make a PFX file with three certificates
fname = "bob-3certsEnc.pfx"
password = "password"
n = Pfx.MakeFile(fname, "BobRSASignByCarl.cer;CarlRSASelf.cer;AliceRSASignByCarl.cer", "BobPrivRSAEncrypt.p8e", password, "Bob's friendly 3-cert ID", 0)
Console.WriteLine("Pfx.MakeFile(3-certs) returns {0} (expected 0)", n)
Debug.Assert(0 = n, "Failed to create PFX file")
Console.WriteLine("Created file '{0}'", fname)
Debug.Assert(Pfx.SignatureIsValid(fname, password))
' Extract all the certificate from a PKCS-12 PFX file as a PKCS-7 certificate chain file
fnameInput = "bob-3certsEnc.pfx"
fnameP7 = "p7ChainfromPFX.p7c"
n = X509.GetP7ChainFromPFX(fnameP7, fnameInput, "password")
Console.WriteLine("X509.GetP7ChainFromPFX returns {0} (expected +ve).", n)
Debug.Assert(n > 0, "Failed to extract p7c from PFX file")
' Get type name of ASN.1 object
s = Asn1.Type(fnameP7)
Console.WriteLine("{0} is a '{1}'", fnameP7, s)
' How many certs in it?
'n = X509.GetCertFromP7Chain("", fnameP7, 0);
' New method in [v12.2]
n = X509.GetCertCountInP7Chain(fnameP7)
Console.WriteLine("{0} contains {1} certificates (expected 3)", fnameP7, n)
Debug.Assert(n = 3, "Wrong number of certs in P7 file")
End Sub
Private Shared Sub test_Rsa_Keys()
'***************************************
' ADVANCED PRIVATE KEY SAVING OPTIONS
' --- OVERLOAD for Rsa.SaveEncPrivateKey
'***************************************
Dim n As Integer
Dim fname As String
Dim s As String
Dim sbPrivateKey As StringBuilder
Dim sbKeyCheck As StringBuilder
Console.WriteLine(vbLf & "TEST RSA SAVE ENCRYPTED PRIVATE KEY OPTIONS:")
' Read in a known private key from its encrypted key file
Console.WriteLine("Read in a private key...")
sbPrivateKey = Rsa.ReadPrivateKey("AlicePrivRSASign.p8e", "password")
Console.WriteLine("PrivateKeyBits={0}", Rsa.KeyBits(sbPrivateKey.ToString()))
Console.WriteLine("PrivateKeyBytes={0}", Rsa.KeyBytes(sbPrivateKey.ToString()))
Console.WriteLine("KeyHashCode={0,8:X}", Rsa.KeyHashCode(sbPrivateKey.ToString()))
' Save with some new options, then check we can read
fname = "alice_rsa_aes128sha1_epk.bin"
n = Rsa.SaveEncPrivateKey(fname, sbPrivateKey.ToString(), 3000, "password", CipherAlgorithm.Aes128, HashAlgorithm.Sha1, _
Rsa.Format.[Default])
Console.WriteLine("Rsa.SaveEncPrivateKey returns {0} (expected 0)", n)
Debug.Assert(n = 0, "Rsa.SaveEncPrivateKey failed")
Console.WriteLine("Created private key file {0}", fname)
sbKeyCheck = Rsa.ReadPrivateKey(fname, "password")
Console.WriteLine("KeyHashCode={0,8:X}", Rsa.KeyHashCode(sbKeyCheck.ToString()))
Debug.Assert(Rsa.KeyHashCode(sbKeyCheck.ToString()) = Rsa.KeyHashCode(sbPrivateKey.ToString()), "KeyHashCodes do not match")
fname = "alice_rsa_aes192sha256_epk.bin"
n = Rsa.SaveEncPrivateKey(fname, sbPrivateKey.ToString(), 3000, "password", CipherAlgorithm.Aes192, HashAlgorithm.Sha256, _
Rsa.Format.[Default])
Console.WriteLine("Rsa.SaveEncPrivateKey returns {0} (expected 0)", n)
Debug.Assert(n = 0, "Rsa.SaveEncPrivateKey failed")
Console.WriteLine("Created private key file {0}", fname)
sbKeyCheck = Rsa.ReadPrivateKey(fname, "password")
Console.WriteLine("KeyHashCode={0,8:X}", Rsa.KeyHashCode(sbKeyCheck.ToString()))
Debug.Assert(Rsa.KeyHashCode(sbKeyCheck.ToString()) = Rsa.KeyHashCode(sbPrivateKey.ToString()), "KeyHashCodes do not match")
fname = "alice_rsa_aes256sha512_epk.pem.txt"
n = Rsa.SaveEncPrivateKey(fname, sbPrivateKey.ToString(), 3000, "password", CipherAlgorithm.Aes192, HashAlgorithm.Sha256, _
Rsa.Format.PEM)
Console.WriteLine("Rsa.SaveEncPrivateKey returns {0} (expected 0)", n)
Debug.Assert(n = 0, "Rsa.SaveEncPrivateKey failed")
Console.WriteLine("Created private key file {0}", fname)
sbKeyCheck = Rsa.ReadPrivateKey(fname, "password")
Console.WriteLine("KeyHashCode={0,8:X}", Rsa.KeyHashCode(sbKeyCheck.ToString()))
Debug.Assert(Rsa.KeyHashCode(sbKeyCheck.ToString()) = Rsa.KeyHashCode(sbPrivateKey.ToString()), "KeyHashCodes do not match")
' Read private key from a string instead of a file
Console.WriteLine("Reading key from a PEM string...")
s = "-----BEGIN ENCRYPTED PRIVATE KEY-----" & "MIICojAcBgoqhkiG9w0BDAEDMA4ECHPQz6NdAmoFAgIH0ASCAoBKn9KXr+dm" & "Vtc0ZhEog7t3Prs4rJazwUsXExU78ePLMquxLi/cPmqtyjb472r6XUOa9J/v" & "g2gYHlJ7D7FfAdTdVbHmXWfZzdIqI+AKZmrMoIfSVSSrI8mLDXLDgJVm2Gxa" & "r/YJ154L4fwqWjj0b06v8nTrXTp7G3ZSxjmXc3auf8tS1RatpDuSn027jBGt" & "Pg2CGPjeSomOU7Efd89R+gryW3RfXaMEv1TtGmdS+szxN4TAzgFTzjzE7qJ2" & "+WL09hBRxSyi5JybbxblrO5zDbGJD8rq4kGawWUj4PYDpOkxQYQyK/cALEvv" & "EipLeWvk03CadKER3EcpL7wQT3N5wJGNx7GR3efkO7lO/VfGf6kYFsJ8Qt94" & "vBlgq84abgSD+rlRX03re/NLJQ00Qxl3bDrkSiRoXSfBiOeVzBVTsh03Sj4B" & "V0v2KLENsMXr40rMqTGfKD3V+FyYUehWEkEl3NrIVpBSJir+g4H3tl76SdNe" & "mq/cTtQP+EY8fpC3I46dyDXFat3wQfubw+E5nGfv7xp6vRVRRolpZx7DpuB/" & "z1tzO3uP0vJ0pjATriO/ZAVs6UrXx+DJ6XsfrAVt0jpW5Ngr8rm2EiD3/1T9" & "7q1dELJ7GzCY1dG99XVjt9ZXb7cI8zsPpT/gzQJLfeLe3U5Mdw0hKZLfPCex" & "0urs3ytK0XNu+jZAYeSaysG8/rHJaH74WOgJ8gnSPY4QtWsu6+3qBErS2jbq" & "7E2jRvBKWICVd1yiQCDq/c6s9LeYhNhZsmcWxuX9b4lG9f1LHZy0djhIYi4x" & "IpcEfjkTH+7zUOkMQ+fXZHtSEVFt9L2Ci49jB8YReqbfOuDFzzwsk3xxfL2h" & "ZoRK" & "-----END ENCRYPTED PRIVATE KEY-----"
sbKeyCheck = Rsa.ReadPrivateKey(s, "password")
Console.WriteLine("Private key is " & Rsa.KeyBits(sbKeyCheck.ToString()) & " bits long")
Console.WriteLine("KeyHashCode={0,8:X}", Rsa.KeyHashCode(sbKeyCheck.ToString()))
Wipe.[String](sbKeyCheck)
End Sub
Private Shared Sub test_Rsa_X509_Stronger()
Dim n As Integer
Dim fname As String
Dim i As Integer, k As Integer
Dim sbPrivateKey As StringBuilder
Dim sbPublicKey As StringBuilder
Dim pubkeyFile As String, prikeyFile As String
Dim s As String
Dim fnameCert As String
Dim issuerCert As String
Dim distname As String
Dim query As String
Dim certList As String
Dim cert1 As String, cert2 As String
Console.WriteLine(vbLf & "STRONGER RSA KEY ENCRYPTION:")
' Read in Carl's key
fname = "CarlPrivRSASign.p8e"
Console.WriteLine("Reading private key file {0}", fname)
sbPrivateKey = Rsa.ReadPrivateKey(fname, "password")
Debug.Assert(sbPrivateKey.ToString().Length > 0, "Unable to read Carl's private key")
k = Rsa.KeyHashCode(sbPrivateKey.ToString())
Console.WriteLine("Existing KeyHashCode= {0,8:X}", k)
' Now save again in a new file but using stronger encryption
' (pity about the strength of the password!)
fname = "Carl_aes256sha256.p8e.txt"
n = Rsa.SaveEncPrivateKey(fname, sbPrivateKey.ToString(), 3000, "password", CipherAlgorithm.Aes256, HashAlgorithm.Sha256, _
Rsa.Format.PEM)
Wipe.[String](sbPrivateKey)
Debug.Assert(0 = n, "Rsa.SaveEncPrivateKey failed")
Console.WriteLine("Created new encrypted private key file '{0}'", fname)
' Check we can read in the new format
sbPrivateKey = Rsa.ReadPrivateKey(fname, "password")
Debug.Assert(sbPrivateKey.ToString().Length > 0, "Unable to read Carl's private key")
Console.WriteLine("Key length={0} bits", Rsa.KeyBits(sbPrivateKey.ToString()))
Console.WriteLine("Recreated KeyHashCode={0,8:X}", Rsa.KeyHashCode(sbPrivateKey.ToString()))
Debug.Assert(k = Rsa.KeyHashCode(sbPrivateKey.ToString()), "KeyHashCodes do not match")
Wipe.[String](sbPrivateKey)
Console.WriteLine("GENERATE NEW RSA KEY PAIR WITH STRONGER ENCRYPTION:")
' Generate another new RSA key using stronger encryption algorithm for private key
pubkeyFile = "test_tdea_pub.bin"
prikeyFile = "test_tdea_epk.bin"
n = Rsa.MakeKeys(pubkeyFile, prikeyFile, "password", 512, pbes := Rsa.PbeOptions.Pbe_Pbkdf2_des_EDE3_CBC, paramString := "count=3000")
Console.WriteLine("Rsa.MakeKeys returned {0}", n)
Debug.Assert(n = 0, "Failed to create RSA key pair")
Console.WriteLine("Created public/private key pair OK")
' And check the key pair we just made
sbPublicKey = Rsa.ReadPublicKey(pubkeyFile)
sbPrivateKey = Rsa.ReadPrivateKey(prikeyFile, "password")
Console.WriteLine("Key length={0} bits", Rsa.KeyBits(sbPublicKey.ToString()))
Console.WriteLine("Key length={0} bytes", Rsa.KeyBytes(sbPrivateKey.ToString()))
n = Rsa.KeyMatch(sbPrivateKey.ToString(), sbPublicKey.ToString())
Console.WriteLine("Rsa.KeyMatch returns {0} (expecting 0)", n)
Debug.Assert(0 = n, "Rsa.KeyMatch failed.")
Console.WriteLine("GENERATE NEW RSA KEY PAIR WITH STRONGER ENCRYPTION:")
' Generate another new RSA key using stronger encryption algorithm for private key
' CAUTION: we make this quite small (only 768 bits) for speed in testing;
' this is too small for real use!
pubkeyFile = "carol_pub.pem.txt"
prikeyFile = "carol_epk.pem.txt"
n = Rsa.MakeKeys(pubkeyFile, prikeyFile, "password", 768, Rsa.PublicExponent.Exp_EQ_65537, Rsa.PbeOptions.Pbe_Pbkdf2_aes128_CBC, _
"count=3000;prf=hmacWithSHA224", Rsa.Format.PEM, True)
Console.WriteLine("Rsa.MakeKeys returned {0}", n)
Debug.Assert(n = 0, "Failed to create RSA key pair")
Console.WriteLine("Created public/private key pair OK")
' And check the key pair we just made
sbPublicKey = Rsa.ReadPublicKey(pubkeyFile)
sbPrivateKey = Rsa.ReadPrivateKey(prikeyFile, "password")
Console.WriteLine("Key length={0} bits", Rsa.KeyBits(sbPublicKey.ToString()))
Console.WriteLine("Key length={0} bytes", Rsa.KeyBytes(sbPrivateKey.ToString()))
n = Rsa.KeyMatch(sbPrivateKey.ToString(), sbPublicKey.ToString())
Console.WriteLine("Rsa.KeyMatch returns {0} (expecting 0)", n)
Debug.Assert(0 = n, "Rsa.KeyMatch failed.")
Console.WriteLine(vbLf & "STRONGER X.509 SIGNATURE ALGORITHMS:")
' Create a new self-signed CA certificate for Carol, using PEM-style key we made above
issuerCert = "carolSelf_384.cer"
distname = "CN=Carol;O=Test"
Console.WriteLine("Creating new self-signed X.509 cert '{0}' for '{1}'" & " signed by private key in '{2}'", issuerCert, distname, prikeyFile)
n = X509.MakeCertSelf(issuerCert, prikeyFile, &H1, 10, distname, "", _
X509.KeyUsageOptions.KeyCertSign Or X509.KeyUsageOptions.DigitalSignature Or X509.KeyUsageOptions.CrlSign Or X509.KeyUsageOptions.DataEncipherment, "password", SigAlgorithm.Rsa_Sha384, X509.CertOptions.[Default])
Debug.Assert(0 = n, "X509.MakeCertSelf failed.")
Console.WriteLine("Created self-signed X.509 cert '{0}'", issuerCert)
' Query the new certificate
query = "signatureAlgorithm"
s = X509.QueryCert(issuerCert, query)
Console.WriteLine("{0}='{1}'", query, s)
query = "subjectName"
s = X509.QueryCert(issuerCert, query)
Console.WriteLine("{0}='{1}'", query, s)
query = "serialNumber"
s = X509.QueryCert(issuerCert, query)
Console.WriteLine("{0}='{1}'", query, s)
query = "subjectName"
s = X509.QueryCert(issuerCert, query)
Console.WriteLine("{0}='{1}'", query, s)
' Get the key usage flags
k = X509.KeyUsageFlags(issuerCert)
' (Note silly efforts required to get leading zeroes displayed in X format)
Console.WriteLine("KeyUsage={0}", k.ToString("X").PadLeft(8, "0"C))
' Now let's create an X.509 certificate for Bob with a stronger signature algorithm
' To do that we need the issuer's encrypted private key file (which we just made)
' and the subject's public key file (which we don't have). So, for this example,
' we'll just create a new public key file from the key in Bob's existing certificate
' and use the same KeyUsage flags from the existing certificate
' (just because it's easier for testing).
k = X509.KeyUsageFlags("BobRSASignByCarl.cer")
Console.WriteLine("Bob's key usage flags are {0}", k.ToString("X").PadLeft(8, "0"C))
sbPublicKey = Rsa.ReadPublicKey("BobRSASignByCarl.cer")
Debug.Assert(sbPublicKey.ToString().Length > 0, "Unable to read Bob's public key from certificate")
pubkeyFile = "Bob_pubkey.dat"
' And we'll save the public key in SSL format, just for fun :-)
n = Rsa.SavePublicKey(pubkeyFile, sbPublicKey.ToString(), Rsa.Format.SSL)
Debug.Assert(0 = n, "Rsa.SavePublicKey failed.")
' Make the new certificate, using the new key files
distname = "CN=Bob"
fnameCert = "BobByCarol_256.cer"
Console.WriteLine("Creating new X.509 cert '{0}' for '{1}' using public key in '{2}'" & " signed by private key in '{3}'", fnameCert, distname, pubkeyFile, prikeyFile)
n = X509.MakeCert(fnameCert, issuerCert, pubkeyFile, prikeyFile, &H256, 9, _
distname, "", CType(k, X509.KeyUsageOptions), "password", SigAlgorithm.Rsa_Sha256, 0)
Debug.Assert(0 = n, "X509.MakeCert failed.")
Console.WriteLine("Created X.509 cert '{0}'", fnameCert)
' Query the new certificate
query = "signatureAlgorithm"
s = X509.QueryCert(fnameCert, query)
Console.WriteLine("{0}='{1}'", query, s)
query = "issuerName"
s = X509.QueryCert(fnameCert, query)
Console.WriteLine("{0}='{1}'", query, s)
query = "serialNumber"
s = X509.QueryCert(fnameCert, query)
Console.WriteLine("{0}='{1}'", query, s)
query = "subjectName"
s = X509.QueryCert(fnameCert, query)
Console.WriteLine("{0}='{1}'", query, s)
' And verify the issuer
n = X509.VerifyCert(fnameCert, issuerCert)
Console.WriteLine("X509.VerifyCert returns {0} (expecting 0)", n)
Debug.Assert(0 = n, "X509.VerifyCert failed.")
' OK, as tricky as we can think of...
Console.WriteLine(vbLf & "MAKE ENVELOPED-DATA USING PEM-STYLE STRINGS FOR CERTS:")
' First, we'll re-save a couple of X.509 certificates in PEM format,
' then we'll read these PEM files (which are text) into strings.
fname = "CarolSelf_384.cer"
s = X509.ReadStringFromFile(fname)
fname = fname & ".pem.txt"
n = X509.SaveFileFromString(fname, s, True)
Console.WriteLine("Created {0}", fname)
cert1 = File.ReadAllText(fname)
fname = "BobByCarol_256.cer"
s = X509.ReadStringFromFile(fname)
fname = fname & ".pem.txt"
n = X509.SaveFileFromString(fname, s, True)
Console.WriteLine("Created {0}", fname)
cert2 = File.ReadAllText(fname)
' Create an enveloped-data object for Carol and Bob using the PEM cert strings we just read
certList = cert1 & ";" & cert2
fname = "cms2carol_bob.p7m"
s = "Hello all. Here is a secret message."
Console.WriteLine("About to create enveloped-data file '{0}'", fname)
n = Cms.MakeEnvDataFromString(fname, s, certList, CipherAlgorithm.Aes128, Cms.KeyEncrAlgorithm.Rsa_Pkcs1v1_5, 0, _
0)
' Expecting 2 = number of valid recipients
Console.WriteLine("Cms.MakeEnvDataFromString returns {0} (expecting 2)", n)
Debug.Assert(2 = n, "Cms.MakeEnvDataFromString failed.")
' Check the details in the new CMS file
query = "contentEncryptionAlgorithm"
s = Cms.QueryEnvData(fname, query)
Console.WriteLine("{0}='{1}'", query, s)
query = "countOfRecipientInfos"
s = Cms.QueryEnvData(fname, query)
Console.WriteLine("{0}='{1}'", query, s)
' NB always returns a string, so convert to an integer
n = Convert.ToInt32(s)
' Loop through all recipients
For i = 1 To n
Console.WriteLine("For recipient {0}:", i)
query = [String].Concat("recipientIssuerName", "/", i)
s = Cms.QueryEnvData(fname, query)
Console.WriteLine("{0}='{1}'", query, s)
query = [String].Concat("recipientSerialNumber", "/", i)
s = Cms.QueryEnvData(fname, query)
Console.WriteLine("{0}='{1}'", query, s)
Next
' Carol reads in her encrypted private key data to a string
' (NB this is not the same as an "internal" key string)
' (We're just reading in the file to a string so you can see how to read a string directly!)
Console.WriteLine("Reading file '{0}'", prikeyFile)
s = File.ReadAllText(prikeyFile)
' so instead of using the filename, we can read this string instead
sbPrivateKey = Rsa.ReadPrivateKey(s, "password")
Debug.Assert(sbPrivateKey.Length > 0, "Rsa.ReadPrivateKey failed.")
Console.WriteLine("Key length={0} bits", Rsa.KeyBits(sbPrivateKey.ToString()))
' Now we have the private key as an internal string (actually StringBuilder)
' Carol can read the message sent to her in the enveloped-data file
s = Cms.ReadEnvDataToString(fname, "", sbPrivateKey.ToString())
Debug.Assert(s.Length > 0, "Cms.ReadEnvDataToString failed.")
Console.WriteLine("Msg='{0}'", s)
' Clean up
Wipe.[String](sbPrivateKey)
End Sub
Private Shared Sub test_X509()
'*************
' X509 TESTS *
'*************
Dim s As String
Dim i As Integer, n As Integer, r As Integer
Dim isok As Boolean
Dim sbPublicKey As StringBuilder
Dim fnameCheck As String
Dim fnameInput As String, fnameCert As String, fname As String
Dim issuerCert As String
Dim hexDigest As String
Dim strCheck As String, certBase64 As String, distname As String
Dim query As String
Dim certList As String, certFile As String, csrFile As String
Dim extns As String, dn As String, password As String
Dim pubkeyFile As String, prikeyFile As String
Console.WriteLine(vbLf & "X509 TESTS:")
' Generate a fresh RSA key which we'll use later
pubkeyFile = "mykey_pub.bin"
prikeyFile = "mykey_epk.bin"
n = Rsa.MakeKeys(pubkeyFile, prikeyFile, "password", 512)
Console.WriteLine("Rsa.MakeKeys returned {0}", n)
Debug.Assert(n = 0, "Failed to create RSA key pair")
Console.WriteLine("Created public/private key pair OK")
' create a new self-signed certificate (Issue No 1) using keys we just created
fnameCert = "myCAcert.cer"
n = X509.MakeCertSelf(fnameCert, prikeyFile, 1, 5, "CN=Me;C=AU", "myemail@here.com", _
X509.KeyUsageOptions.DigitalSignature Or X509.KeyUsageOptions.KeyCertSign, "password", SigAlgorithm.Rsa_Sha1, X509.CertOptions.FormatPem)
Console.WriteLine("X509.MakeCertSelf returned {0}", n)
' create a new certificate for me (Issue No 101) as issued by Carl
fnameCert = "mycert.cer"
issuerCert = "CarlRSASelf.cer"
prikeyFile = "CarlPrivRSASign.p8e"
n = X509.MakeCert(fnameCert, issuerCert, pubkeyFile, prikeyFile, 101, 2, _
"CN=Me;C=US;O=MyOrg", "", 0, "password", SigAlgorithm.Rsa_Md5, X509.CertOptions.VersionOne)
Console.WriteLine("X509.MakeCert returned {0}", n)
' Verify our two new certificates
n = X509.VerifyCert(fnameCert, issuerCert)
If 0 = n Then
Console.WriteLine("OK, {0} was issued by {1}.", fnameCert, issuerCert)
Else
Console.WriteLine("ERROR: {0} was NOT issued by {1}.", fnameCert, issuerCert)
End If
fnameCert = "myCAcert.cer"
issuerCert = "myCAcert.cer"
n = X509.VerifyCert(fnameCert, issuerCert)
If 0 = n Then
Console.WriteLine("OK, {0} was issued by {1}.", fnameCert, issuerCert)
Else
Console.WriteLine("ERROR: {0} was NOT issued by {1}.", fnameCert, issuerCert)
End If
' Get subject name from cert
s = X509.CertSubjectName(fnameCert, "")
Console.WriteLine("{0} has subject {1}.", fnameCert, s)
' and again
fnameCert = "mycert.cer"
s = X509.CertSubjectName(fnameCert, "|")
Console.WriteLine("{0} has subject {1}.", fnameCert, s)
' Get SHA-1 "thumbprint" (i.e. hash digest) of cert file
s = X509.CertThumb(fnameCert, HashAlgorithm.Sha1)
Console.WriteLine("{0} has SHA-1 Thumbprint {1}" & vbLf & vbTab & "--Go on, use CERTMGR and check!", fnameCert, s)
' Verify a known certificate is still valid
fnameCert = "CarlRSASelf.cer"
Console.WriteLine("For certificate '{0}':", fnameCert)
s = X509.CertIssuedOn(fnameCert)
Console.WriteLine("Issued at {0}", s)
s = X509.CertExpiresOn(fnameCert)
Console.WriteLine("Expires at {0}", s)
isok = X509.CertIsValidNow(fnameCert)
If isok Then
Console.WriteLine("OK, {0} is valid now.", fnameCert)
Else
Console.WriteLine("ERROR: {0} is NOT valid now.", fnameCert)
End If
' Extract details from a certificate
fnameCert = "CarlRSASelf.cer"
s = X509.CertIssuerName(fnameCert)
Console.WriteLine("Issuer Name: {0}", s)
s = X509.CertSerialNumber(fnameCert)
Console.WriteLine("Serial Number: {0}", s)
s = X509.HashIssuerAndSN(fnameCert, HashAlgorithm.Sha1)
Console.WriteLine("Hash(IssuerName+SerialNumber) = {0}", s)
' Query the certificate for various details
fnameCert = "CarlRSASelf.cer"
Console.WriteLine("For X.509 certificate '{0}'", fnameCert)
query = "version"
s = X509.QueryCert(fnameCert, query)
Console.WriteLine("X509.QueryCert('{0}') = {1}", query, s)
query = "signatureAlgorithm"
s = X509.QueryCert(fnameCert, query)
Console.WriteLine("X509.QueryCert('{0}') = {1}", query, s)
query = "sigAlgID"
s = X509.QueryCert(fnameCert, query)
Console.WriteLine("X509.QueryCert('{0}') = {1}", query, s)
query = "notBefore"
s = X509.QueryCert(fnameCert, query)
Console.WriteLine("X509.QueryCert('{0}') = {1}", query, s)
query = "notAfter"
s = X509.QueryCert(fnameCert, query)
Console.WriteLine("X509.QueryCert('{0}') = {1}", query, s)
query = "issuerName"
s = X509.QueryCert(fnameCert, query)
Console.WriteLine("X509.QueryCert('{0}') = {1}", query, s)
query = "subjectName"
s = X509.QueryCert(fnameCert, query)
Console.WriteLine("X509.QueryCert('{0}') = {1}", query, s)
query = "subjectPublicKeyAlgorithm"
s = X509.QueryCert(fnameCert, query)
Console.WriteLine("X509.QueryCert('{0}') = {1}", query, s)
query = "isCA"
s = X509.QueryCert(fnameCert, query)
Console.WriteLine("X509.QueryCert('{0}') = {1}", query, s)
query = "serialNumber"
s = X509.QueryCert(fnameCert, query)
Console.WriteLine("X509.QueryCert('{0}') = {1}", query, s)
s = X509.QueryCert(fnameCert, query, X509.OutputOpts.[Decimal])
Console.WriteLine("X509.QueryCert('{0}', Decimal) = {1}", query, s)
' Read in certificate data from a file into a base64-encoded string
fnameCert = "CarlRSASelf.cer"
certBase64 = X509.ReadStringFromFile(fnameCert)
Console.WriteLine("X.509 certificate '{0}' as a string=" & vbLf & "{1}", fnameCert, certBase64)
Debug.Assert(certBase64.Length > 0, "X509.ReadStringFromFile failed")
' Write back string as a new PEM-format certificate file
fnameCheck = fnameCert & ".copy.pem.cer"
n = X509.SaveFileFromString(fnameCheck, certBase64, True)
Console.WriteLine("X509.SaveFileFromString('{0}') returns {1} (expecting 0)", fnameCheck, n)
' Read in string from new file as a check
strCheck = X509.ReadStringFromFile(fnameCheck)
If strCheck = certBase64 Then
Console.WriteLine("OK, strings from new and old X.509 files are identical.")
Else
Console.WriteLine("ERROR: Strings from new and old X.509 files do not match")
End If
Debug.Assert(strCheck = certBase64, "X509.SaveFileFromString failed")
' And check the "thumbprints" of the two certificates
s = X509.CertThumb(fnameCert, HashAlgorithm.Sha1)
strCheck = X509.CertThumb(fnameCheck, HashAlgorithm.Sha1)
Console.WriteLine("Thumbprint('{0}')={1}", fnameCert, s)
Console.WriteLine("Thumbprint('{0}')={1}", fnameCheck, strCheck)
Debug.Assert(strCheck = s, "X509.CertThumb results failed")
' Use base64 string instead of certificate filename in X.509 fn
s = X509.CertThumb(certBase64, HashAlgorithm.Sha1)
Console.WriteLine("Thumbprint('{0}...{1}')={2}", certBase64.Substring(0, 5), certBase64.Substring(certBase64.Length - 5, 5), s)
' Make a certificate signing request using our new private key
prikeyFile = "mykey_epk.bin"
n = X509.CertRequest("myreq.txt", prikeyFile, "CN=myuser;O=Test Org;C=AU;L=Sydney;S=NSW", "", "password", SigAlgorithm.[Default], _
0)
Console.WriteLine("X509.CertRequest returned {0} (expected 0).", n)
Debug.Assert(0 = n, "X509.CertRequest failed")
' Make a certificate signing request using our new private key plus extensions
prikeyFile = "mykey_epk.bin"
n = X509.CertRequest("myreq-ext.csr", prikeyFile, "CN=myuser;O=Test Org;C=AU;L=Sydney;S=NSW", "rfc822name=fred@example.com;dnsname=fred.example.com;uri=ftp://ftp.example.com/;ipaddress=192.168.15.1", "password", SigAlgorithm.[Default], _
X509.CsrOptions.FormatBinary)
Console.WriteLine("X509.CertRequest returned {0} (expected 0).", n)
If n <> 0 Then
disp_error(n)
End If
Debug.Assert(0 = n, "X509.CertRequest failed")
' Extract the certificates from a PKCS-7 cert chain file
fnameInput = "bob.p7b"
' find the number of certs in the chain
'n = X509.GetCertFromP7Chain("", fnameInput, 0);
' New method in [v12.2]
n = X509.GetCertCountInP7Chain(fnameInput)
Console.WriteLine("X509.GetCertCountInP7Chain returns {0} (expected 2).", n)
Debug.Assert(n > 0, "X509.GetCertCountInP7Chain failed")
' Extract the certs in turn
For i = 1 To n
fnameCert = "certfile" & i & ".cer"
r = X509.GetCertFromP7Chain(fnameCert, fnameInput, i)
Debug.Assert(r > 0)
Console.WriteLine("Extracted certificate '{0}' ({1} bytes)", fnameCert, r)
' check its subject name
s = X509.CertSubjectName(fnameCert, "")
Console.WriteLine("{0} has subject {1}.", fnameCert, s)
Next
' Bob creates a self-signed cert using his Chinese nickname, Ben
fnameCert = "benChina.cer"
prikeyFile = "BobPrivRSAEncrypt.p8e"
' Set name using UTF-8-encoded chinese characters:
' CN=ben (U+672C)
' C= zhong guo (U+4E2D, U+570B)
' OU=zong ju (U+7E3D, U+5C40)
distname = "CN=#xe69cac;C=#xe4b8ade59c8b;OU=#xe7b8bde5b180"
n = X509.MakeCertSelf(fnameCert, prikeyFile, &H888, 8, distname, "ben@ho.com.cn", _
X509.KeyUsageOptions.DigitalSignature Or X509.KeyUsageOptions.KeyCertSign, "password", SigAlgorithm.[Default], X509.CertOptions.UTF8String)
Console.WriteLine("X509.MakeCertSelf(chinese) returned {0}", n)
Debug.Assert(n = 0, "Failed to create new certificate")
' Read in the distinguished name from our new certificate
Console.WriteLine("NB Chinese characters will not display in the console unless the code page is set to Chinese")
s = X509.CertSubjectName(fnameCert, "")
Console.WriteLine("Subject's name is '{0}'", s)
' 2 -- displaying in LDAP default format
s = X509.QueryCert(fnameCert, "subjectName", X509.OutputOpts.Ldap)
Console.WriteLine("Subject's name (LDAP) is '{0}'", s)
Debug.Assert(s.Length > 0, "Failed to read subjectName")
' 3 -- displaying in Unicode (UTF-16) converted from UTF-8
s = X509.QueryCert(fnameCert, "subjectName", X509.OutputOpts.Unicode)
' NB Chinese characters will not display in the console unless the code page is set to Chinese
' The string `s` contains the valid Chinese characters, they just don't display in the console.
Console.WriteLine("Check da='大'")
' (? in console)
Console.WriteLine("Subject's name (UTF16) is '{0}'", s)
Debug.Assert(s.Length > 0, "Failed to read subjectName")
' Ben then creates a certificate for a Mexican user
'(using the public key we created above and his chinese certificate. Hey, Silk Road!)
pubkeyFile = "mykey_pub.bin"
issuerCert = "benChina.cer"
fnameCert = "mariaMexico.cer"
' passing the UTF-8 characters for the name in hex format
' C=México;CN=María;OU=#xbabe (yes, we want the OU to be "#xbabe": note the single quotes in the distname string)
distname = "C=#x4de97869636f;CN=#x4d6172ed61;OU='#xbabe'"
n = X509.MakeCert(fnameCert, issuerCert, pubkeyFile, prikeyFile, 7, 2, _
distname, "", 0, "password", SigAlgorithm.[Default], X509.CertOptions.UTF8String)
Console.WriteLine("X509.MakeCertSelf(mexican) returned {0}", n)
Debug.Assert(n = 0, "Failed to create new certificate")
Console.WriteLine("FILE: {0}", fnameCert)
' Now read in the Subject's name using QueryCert
' 0 -- bytes as found (in this case UTF-8)
s = X509.QueryCert("mariaMexico.cer", "subjectName")
Console.WriteLine("Subject's name (default) is '{0}'", s)
Debug.Assert(s.Length > 0, "Failed to read subjectName")
' 1 -- forcing the name to be converted back to Latin-1 encoding
s = X509.QueryCert("mariaMexico.cer", "subjectName", X509.OutputOpts.Latin1)
Console.WriteLine("Subject's name (Latin-1) is '{0}'", s)
Debug.Assert(s.Length > 0, "Failed to read subjectName")
' 2 -- displaying in LDAP default format
s = X509.QueryCert("mariaMexico.cer", "subjectName", X509.OutputOpts.Ldap)
Console.WriteLine("Subject's name (LDAP) is '{0}'", s)
Debug.Assert(s.Length > 0, "Failed to read subjectName")
' 3 -- LDAP format forcing UTF-8 (prints "funny") -- [2021-11-12] REMOVED
' 4 -- LDAP format plus Latin-1
s = X509.QueryCert("mariaMexico.cer", "subjectName", X509.OutputOpts.Ldap Or X509.OutputOpts.Latin1)
Console.WriteLine("Subject's name (LDAP+Latin1) is '{0}'", s)
Debug.Assert(s.Length > 0, "Failed to read subjectName")
' 5 -- UTF-8 output converted automatically to Unicode
s = X509.QueryCert("mariaMexico.cer", "subjectName", X509.OutputOpts.Unicode)
Console.WriteLine("Subject's name (Unicode/UTF16) is '{0}'", s)
Debug.Assert(s.Length > 0, "Failed to read subjectName")
' Dump cert info
Console.WriteLine("TextDumpToString({0}, Latin1):", fnameCert)
s = X509.TextDumpToString(fnameCert, X509.OutputOpts.Latin1)
Console.WriteLine(s)
Debug.Assert(s.Length > 0, "X509.TextDumpToString failed")
' Dump cert info
Console.WriteLine("TextDumpToString({0}, UTF16):", fnameCert)
s = X509.TextDumpToString(fnameCert, X509.OutputOpts.Unicode)
Console.WriteLine(s)
Debug.Assert(s.Length > 0, "X509.TextDumpToString failed")
r = X509.TextDump("mariaMexico.out.UTF8.txt", fnameCert, X509.OutputOpts.Unicode)
Debug.Assert(r = 0, "X509.TextDump failed")
' Make an end-user cert identical to RFC4134 AliceRSASignByCarl.cer
' First we need to extract the public key from the cert (as though we were starting with it)
pubkeyFile = "AlicePubRSA.pub"
sbPublicKey = Rsa.ReadPublicKey("AliceRSASignByCarl.cer")
Debug.Assert(sbPublicKey.Length > 0, "Failed to get public key from cert")
r = Rsa.SavePublicKey(pubkeyFile, sbPublicKey.ToString(), Rsa.Format.[Default])
' Uses Alice's public key; signed by Carl
issuerCert = "CarlRSASelf.cer"
prikeyFile = "CarlPrivRSASign.p8e"
password = "password"
dn = "CN=AliceRSA"
extns = "rfc822name=AliceRSA@example.com;" & "serialNumber=46346BC7800056BC11D36E2EC410B3B0;" & "subjectKeyIdentifier=77D2B4D1B74C8A8AA3CE459DCEEC3CA03AE3FF50;" & "notBefore=1999-09-19T01:08:47;" & "notAfter=2039-12-31;"
Dim kuo As X509.KeyUsageOptions = X509.KeyUsageOptions.DigitalSignature Or X509.KeyUsageOptions.NonRepudiation
fnameCert = "AliceRSA-dup.cer"
r = X509.MakeCert(fnameCert, issuerCert, pubkeyFile, prikeyFile, 0, 0, _
dn, extns, kuo, password, SigAlgorithm.[Default], X509.CertOptions.AuthKeyId)
Console.WriteLine("X509.MakeCert returns {0} (expecting 0)", r)
If r <> 0 Then
Console.WriteLine(" error=" & General.LastError())
End If
Debug.Assert(r = 0, "X509.MakeCert failed")
Console.WriteLine("Created cert file {0}", fnameCert)
' Now check we got the same as our original
hexDigest = X509.CertThumb(fnameCert, HashAlgorithm.Sha1)
Console.WriteLine("{1}=SHA-1({0})", fnameCert, hexDigest)
fnameCheck = "AliceRSASignByCarl.cer"
strCheck = X509.CertThumb(fnameCheck, HashAlgorithm.Sha1)
Console.WriteLine("{1}=SHA-1({0})", fnameCheck, strCheck)
Debug.Assert(hexDigest = strCheck, "Digests are not equal")
' Create a new certificate using a PKCS-10 certificate signing request (CSR)
' instead of using a subjectPublicKey file and distinguished name.
Console.WriteLine("Create a new certificate using a PKCS-10 CSR file...")
csrFile = "myreq.txt"
s = X509.TextDumpToString(csrFile, 0)
Console.WriteLine(s)
fnameCert = "mycert-fromCSR.cer"
issuerCert = "CarlRSASelf.cer"
prikeyFile = "CarlPrivRSASign.p8e"
password = "password"
extns = "notBefore=2010-01-01T12:00"
' Make an end-user cert valid for 24 years from 2010-01-01 using PKCS#10 CSR file.
' Note that we pass the name of the CSR file instead of the subjectPublicKey file
' and pass the empty string for distName to flag that we have a CSR file.
r = X509.MakeCert(fnameCert, issuerCert, csrFile, prikeyFile, &H109, 24, _
"", extns, 0, password, SigAlgorithm.[Default], 0)
Console.WriteLine("X509.MakeCert returns {0} (expecting 0)", r)
If r <> 0 Then
disp_error(r)
End If
Debug.Assert(r = 0, "X509.MakeCert failed")
Console.WriteLine("Created cert file {0}", fnameCert)
' Print out a text dump of the certificate
Console.WriteLine(X509.TextDumpToString(fnameCert, 0))
' Validate certificate paths either in a P7 cert chain file or in a list of certs
' with and without a trusted certificate
fname = "bob.p7b"
Console.WriteLine("Validate certificate path in file {0}...", fname)
r = X509.ValidatePath(fname)
Console.WriteLine("X509.ValidatePath returns {0} (expecting 0)", r)
Debug.Assert(r = 0, "X509.ValidatePath failed")
certList = "BobRSASignByCarl.cer;CarlRSASelf.cer"
certFile = "CarlRSASelf.cer"
Console.WriteLine("Validate certificate path in list '{0}' using trusted cert {1}...", certList, certFile)
r = X509.ValidatePath(certList, certFile, False)
Console.WriteLine("X509.ValidatePath returns {0} (expecting 0)", r)
Debug.Assert(r = 0, "X509.ValidatePath failed")
End Sub
Private Shared Sub test_CRL()
'******************************************
' CRL (CERTIFICATE REVOCATION LIST) TESTS *
'******************************************
Dim r As Integer
Dim prikeyFile As String
Dim issuerCert As String
Dim certList As String, certFile As String, crlFile As String
Dim extns As String, password As String, dateStr As String
' [updated in v12.0]
Console.WriteLine("CRL (CERTIFICATE REVOCATION LIST) TESTS:")
' Carl creates a Certificate Revocation List (CRL)
' -- A CRL dated with the current system time
crlFile = "CarlsNew.crl"
issuerCert = "CarlRSASelf.cer"
prikeyFile = "CarlPrivRSASign.p8e"
password = "password"
certList = "1,2007-12-31; 2, 2009-12-31T12:59:59Z; 66000,2066-01-01; #x0102deadbeef,2010-02-28T01:01:59"
r = X509.MakeCRL(crlFile, issuerCert, prikeyFile, password, certList, "", _
SigAlgorithm.[Default], 0)
Console.WriteLine("X509.MakeCRL returns {0} (expecting 0)", r)
Debug.Assert(r = 0, "X509.MakeCRL failed")
Console.WriteLine("Created CRL file {0}", crlFile)
' -- A CRL using specified times (NB these are GMT times, not local)
' -- with an empty revocation list and using sha256WithRSAEncryption to sign
crlFile = "Carl_20100401.crl"
extns = "thisUpdate=2010-04-01T12:00;nextUpdate=2010-05-01"
r = X509.MakeCRL(crlFile, issuerCert, prikeyFile, password, "", extns, _
SigAlgorithm.Rsa_Sha256, 0)
Console.WriteLine("X509.MakeCRL returns {0} (expecting 0)", r)
Debug.Assert(r = 0, "X509.MakeCRL failed")
Console.WriteLine("Created CRL file {0}", crlFile)
' Show we can now use VerifyCert to check the signature in a CRL
r = X509.VerifyCert(crlFile, issuerCert)
Console.WriteLine("X509.VerifyCert returns {0} (expecting 0)", r)
Debug.Assert(r = 0, "X509.VerifyCert failed")
Console.WriteLine("OK, CRL file {0} was signed by owner of {1}", crlFile, issuerCert)
' Check if a given cert is in a CRL
' Use test CRL and certs from RFC3280
crlFile = "rfc3280bis_CRL.crl"
' This cert has not been revoked -- expected result = zero
certFile = "rfc3280bis_cert1.cer"
Console.WriteLine("CRL ={0}", crlFile)
Console.WriteLine("Cert={0}", certFile)
r = X509.CheckCertInCRL(certFile, crlFile, "", "")
Console.WriteLine("X509.CheckCertInCRL returns {0} (expecting 0)", r)
Debug.Assert(r = 0, "X509.CheckCertInCRL failed")
If X509.Revoked = r Then
Console.WriteLine("CERT HAS BEEN REVOKED")
ElseIf 0 = r Then
Console.WriteLine("Cert has not been revoked")
Else
Console.WriteLine("ERROR: {0}: {1}", General.ErrorLookup(r), General.LastError())
End If
' This cert HAS been revoked -- expected result = X509.Revoked (changed in [v12.0] formerly +1)
certFile = "rfc3280bis_cert2.cer"
Console.WriteLine("CRL ={0}", crlFile)
Console.WriteLine("Cert={0}", certFile)
r = X509.CheckCertInCRL(certFile, crlFile, "", "")
Console.WriteLine("X509.CheckCertInCRL returns {0} (expecting {0})", r, X509.Revoked)
Debug.Assert(r = X509.Revoked, "X509.CheckCertInCRL failed")
If X509.Revoked = r Then
Console.WriteLine("CERT HAS BEEN REVOKED")
ElseIf 0 = r Then
Console.WriteLine("Cert has not been revoked")
Else
Console.WriteLine("ERROR: {0}: {1}", General.ErrorLookup(r), General.LastError())
End If
' But the same cert was not revoked as at 15:00 GMT on 19 November 2004 -- expected result = 0
certFile = "rfc3280bis_cert2.cer"
dateStr = "2004-11-19T15:00Z"
Console.WriteLine("CRL ={0}", crlFile)
Console.WriteLine("Cert={0}", certFile)
Console.WriteLine("Date={0}", dateStr)
r = X509.CheckCertInCRL(certFile, crlFile, "", dateStr)
Console.WriteLine("X509.CheckCertInCRL returns {0} (expecting 0)", r)
Debug.Assert(r = 0, "X509.CheckCertInCRL failed")
If X509.Revoked = r Then
Console.WriteLine("CERT HAS BEEN REVOKED")
ElseIf 0 = r Then
Console.WriteLine("Cert has not been revoked")
Else
Console.WriteLine("ERROR: {0}: {1}", General.ErrorLookup(r), General.LastError())
End If
End Sub
Private Shared Sub test_OCSP()
'**************************************************
' OCSP (ONLINE CERTIFICATE STATUS PROTOCOL) TESTS *
'**************************************************
Dim s As String
Dim fname As String
Dim issuerCert As String
Dim certFile As String, snStr As String
Console.WriteLine(vbLf & "OCSP (ONLINE CERTIFICATE STATUS PROTOCOL) TESTS:")
' Creates an OCSP request to check our own current code signing certificate file dims.cer.
' This was issued by the holder of certificate in the file UTNUSERFirst-Object.cer.
issuerCert = "UTNUSERFirst-Object.cer"
certFile = "dims.cer"
Console.WriteLine("IssuerFile={0}", issuerCert)
Console.WriteLine("CertFile={0}", certFile)
s = Ocsp.MakeRequest(issuerCert, certFile, 0)
Debug.Assert(s.Length > 0, "Ocsp.MakeRequest failed")
Console.WriteLine("OCSPRequest={0}", s)
' Pass a hex serial number instead of filename
snStr = "#x 00 FB C7 23 22 8C 8C 80 22 D8 85 92 23 DE E7 06 60"
Console.WriteLine("Cert SerialNumber={0}", snStr)
s = Ocsp.MakeRequest(issuerCert, snStr, 0)
Debug.Assert(s.Length > 0, "Ocsp.MakeRequest failed")
Console.WriteLine("OCSPRequest={0}", s)
' We use a response received from ocsp.usertrust.com for our own code signing certificate
' (this HAS been signed by our cert's issuer)
fname = "ocsp_response_ok_dims.dat"
issuerCert = "UTNUSERFirst-Object.cer"
Console.WriteLine("ResponseFile={0}", fname)
Console.WriteLine("IssuerFile={0}", issuerCert)
s = Ocsp.ReadResponse(fname, issuerCert)
Debug.Assert(s.Length > 0, "Ocsp.ReadResponse failed")
Console.WriteLine("OCSPResponse={0}", s)
End Sub
Private Shared Sub test_CMS(doBigFile As Boolean)
'*****************************
' CMS (S/MIME OBJECTS) TESTS *
'*****************************
Dim s As String
Dim n As Integer
Dim b As Byte()
Dim bcheck As Byte()
Dim sbPrivateKey As StringBuilder
Dim fnameInput As String, fnameOutput As String, fnameCert As String, fname As String
Dim hexDigest As String
Dim strCheck As String
Dim query As String
Dim certList As String
Dim flen As Long
Console.WriteLine(vbLf & "CMS (S/MIME OBJECTS) TESTS:")
' Create a test text file
fnameInput = "excontent.txt"
File.WriteAllText(fnameInput, "This is some sample content.")
' Create an enveloped CMS object from Alice to Bob using Bob's X.509 certificate
fnameOutput = "cmsalice2bob.p7m"
fnameCert = "BobRSASignByCarl.cer"
' This should return 1 (indicating one successful recipient)
n = Cms.MakeEnvData(fnameOutput, fnameInput, fnameCert, CipherAlgorithm.Tdea)
Console.WriteLine("Cms.MakeEnvData returns {0} (expecting 1)", n)
Debug.Assert(1 = n, "Cms.MakeEnvData failed")
' Now try and read it using Bob's private key
fnameOutput = "cmsalice2bob.p7m.txt"
fnameInput = "cmsalice2bob.p7m"
sbPrivateKey = Rsa.ReadPrivateKey("BobPrivRSAEncrypt.p8e", "password")
Debug.Assert(sbPrivateKey.ToString().Length > 0, "Unable to read Bob's private key")
n = Cms.ReadEnvDataToFile(fnameOutput, fnameInput, "", sbPrivateKey.ToString())
Console.WriteLine("Cms.ReadEnvData returns {0} (expecting 0)", n)
Debug.Assert(0 = n, "Cms.ReadEnvData failed")
s = File.ReadAllText(fnameOutput)
Console.WriteLine("MSG={0}", s)
' and again but read directly into a string
s = Cms.ReadEnvDataToString(fnameInput, "", sbPrivateKey.ToString())
Console.WriteLine("MSG={0}", s)
Debug.Assert(s.Length > 0, "Cms.ReadEnvDataToString failed")
' Try the BigFile option [new in v3.7]
If doBigFile Then
fname = "bigfile.txt"
flen = MakeALargeTextFile(fname)
Console.WriteLine("Created *big* file '{0}' of length {1} bytes", fname, flen)
' Create an enveloped CMS object from Alice to Bob using Bob's X.509 certificate
fnameInput = fname
fnameOutput = "cmsalice2bob-big.p7m"
fnameCert = "BobRSASignByCarl.cer"
' Call MakeEnvData using BigFile option (may be a noticable delay here)
Console.WriteLine("About to envelope using BigFile option...")
n = Cms.MakeEnvData(fnameOutput, fnameInput, fnameCert, CipherAlgorithm.Tdea, Cms.EnvDataOptions.BigFile)
Console.WriteLine("Cms.MakeEnvData returns {0} (expecting 1)", n)
Debug.Assert(1 = n, "Cms.MakeEnvData failed")
' Now try and decrypt using Bob's private key (which we already have from above)
fnameInput = fnameOutput
fnameOutput = fnameInput & ".chk.txt"
' Use BigFile option
Console.WriteLine("About to decrypt using BigFile option...")
n = Cms.ReadEnvDataToFile(fnameOutput, fnameInput, "", sbPrivateKey.ToString(), Cms.ReadOptions.BigFile)
Console.WriteLine("Cms.ReadEnvData returns {0} (expecting 0)", n)
Console.WriteLine("Decrypted file '{0}' is {1} bytes long.", fnameOutput, FileLength(fnameOutput))
Debug.Assert(0 = n, "Cms.ReadEnvData failed")
End If
' Generate a BER-encoded CMS signedData object as a file
' using Alice's private key
sbPrivateKey = Rsa.ReadPrivateKey("AlicePrivRSASign.p8e", "password")
fnameOutput = "BasicSignByAlice.bin"
fnameInput = "excontent.txt"
fnameCert = "AliceRSASignByCarl.cer"
n = Cms.MakeSigData(fnameOutput, fnameInput, fnameCert, sbPrivateKey.ToString(), Cms.SigAlg.[Default], 0)
Console.WriteLine("Cms.MakeSigData returns {0} (expecting 0)", n)
Debug.Assert(0 = n, "Cms.MakeSigData failed")
' again using a string as input instead of a file
s = File.ReadAllText(fnameInput)
fname = "BasicSignByAlice1.bin"
n = Cms.MakeSigDataFromString(fname, s, fnameCert, sbPrivateKey.ToString(), Cms.SigAlg.[Default], 0)
Console.WriteLine("Cms.MakeSigDataFromString returns {0} (expecting 0)", n)
Debug.Assert(0 = n, "Cms.MakeSigDataFromString failed")
' Check we got the same result by comparing the files
b = File.ReadAllBytes(fnameOutput)
bcheck = File.ReadAllBytes(fname)
Debug.Assert(ByteArraysEqual(b, bcheck) = True, "SigData files are not identical")
' Make a detached signature using the message digest hash
fnameOutput = "DetSignByAlice.bin"
hexDigest = "406aec085279ba6e16022d9e0629c0229687dd48"
n = Cms.MakeDetachedSig(fnameOutput, hexDigest, fnameCert, sbPrivateKey.ToString(), HashAlgorithm.Sha1, 0)
Console.WriteLine("Cms.MakeDetachedSig returns {0} (expecting 0)", n)
Debug.Assert(0 = n, "Cms.MakeDetachedSig failed")
' Extract the contents from the signed object into another file
fnameOutput = "excontent_chk.txt"
fnameInput = "BasicSignByAlice.bin"
n = Cms.ReadSigDataToFile(fnameOutput, fnameInput)
' returns value is size of file or -ve error code
Console.WriteLine("Cms.ReadSigDataToFile returns {0} (expecting 28)", n)
Debug.Assert(n >= 0, "Cms.ReadSigDataToFile failed")
strCheck = File.ReadAllText(fnameOutput)
Console.WriteLine("MSG(file)={0}", strCheck)
' Extract the contents directly into a string instead
s = Cms.ReadSigDataToString(fnameInput)
Console.WriteLine("MSG(string)={0}", s)
Debug.Assert([String].Compare(s, strCheck) = 0, "Contents are different")
' Make a signed object in base64 format
fnameOutput = "BasicSignByAlice_64.txt"
fnameInput = "excontent.txt"
fnameCert = "AliceRSASignByCarl.cer"
n = Cms.MakeSigData(fnameOutput, fnameInput, fnameCert, sbPrivateKey.ToString(), Cms.SigAlg.[Default], Cms.SigDataOptions.FormatBase64)
Console.WriteLine("Cms.MakeSigData returns {0} (expecting 0)", n)
Debug.Assert(0 = n, "Cms.MakeSigData failed")
' and read back into a string
fnameInput = fnameOutput
s = Cms.ReadSigDataToString(fnameInput)
Console.WriteLine("MSG(string)={0}", s)
Debug.Assert([String].Compare(s, strCheck) = 0, "Contents are different")
' Make a signed object with signingTime attribute
fnameOutput = "BasicSignByAlice_attr.bin"
fnameInput = "excontent.txt"
fnameCert = "AliceRSASignByCarl.cer"
n = Cms.MakeSigData(fnameOutput, fnameInput, fnameCert, sbPrivateKey.ToString(), Cms.SigAlg.[Default], Cms.SigDataOptions.IncludeAttributes Or Cms.SigDataOptions.AddSignTime)
Console.WriteLine("Cms.MakeSigData returns {0} (expecting 0)", n)
Debug.Assert(0 = n, "Cms.MakeSigData failed")
' Extract and verify the signed hash digest from the signed-data object
fnameInput = "BasicSignByAlice.bin"
fnameCert = "AliceRSASignByCarl.cer"
s = Cms.GetSigDataDigest(fnameInput, fnameCert)
Console.WriteLine("DIG={0}", s)
Debug.Assert([String].Compare(s, hexDigest) = 0, "Hash digests are different")
' ditto from a file in base64 format but with no signature verification
fnameInput = "BasicSignByAlice_64.txt"
s = Cms.GetSigDataDigest(fnameInput, "")
Console.WriteLine("DIG={0}", s)
Debug.Assert([String].Compare(s, hexDigest) = 0, "Hash digests are different")
' Verify the signature directly
fnameInput = "BasicSignByAlice.bin"
n = Cms.VerifySigData(fnameInput)
Console.WriteLine("Cms.VerifySigData returns {0} (expecting 0)", n)
Debug.Assert(0 = n, "Cms.VerifySigData failed")
' Get the hash algorithm ID of the signature
fnameInput = "BasicSignByAlice.bin"
n = Cms.GetSigHashAlgorithm(fnameInput, fnameCert)
Console.WriteLine("Cms.GetSigHashAlgorithm returns {0} (expecting 0 => SHA-1)", n)
Debug.Assert(0 = n, "Cms.GetSigHashAlgorithm failed")
' Try using the wrong certificate
fnameInput = "BasicSignByAlice.bin"
fnameCert = "BobRSASignByCarl.cer"
n = Cms.GetSigHashAlgorithm(fnameInput, fnameCert)
Console.WriteLine("Cms.GetSigHashAlgorithm returns {0} (expecting -ve error code)", n)
Console.WriteLine("{0};{1}", General.ErrorLookup(n), General.LastError())
Debug.Assert(n < 0, "Cms.GetSigHashAlgorithm succeeded when should have failed!")
' Try using a file that's not a valid signed-data object, e.g. a cert
fnameInput = "CarlRSASelf.cer"
fnameCert = "AliceRSASignByCarl.cer"
n = Cms.GetSigHashAlgorithm(fnameInput, fnameCert)
Console.WriteLine("Cms.GetSigHashAlgorithm returns {0} (expecting -ve error code)", n)
Console.WriteLine("{0};{1}", General.ErrorLookup(n), General.LastError())
Debug.Assert(n < 0, "Cms.GetSigHashAlgorithm succeeded when should have failed!")
' Make a signed-data object file using MD5 and in base64 format
fnameOutput = "BasicSignByAlice_MD5.txt"
fnameInput = "excontent.txt"
fnameCert = "AliceRSASignByCarl.cer"
' Ver 12.2 prefer explicit signature algorithm
n = Cms.MakeSigData(fnameOutput, fnameInput, fnameCert, sbPrivateKey.ToString(), Cms.SigAlg.Rsa_Md5, Cms.SigDataOptions.FormatBase64)
Console.WriteLine("Cms.MakeSigData returns {0} (expecting 0)", n)
Debug.Assert(0 = n, "Cms.MakeSigData failed")
' Get the hash algorithm ID of the signature
fnameInput = fnameOutput
n = Cms.GetSigHashAlgorithm(fnameInput, fnameCert)
Console.WriteLine("Cms.GetSigHashAlgorithm returns {0} (expecting 1 => MD5)", n)
Debug.Assert(1 = n, "Cms.GetSigHashAlgorithm failed")
' Prefer explicit SigAlg + Hash option [v12.2]
' Make a signed-data object file using SHA-256
fnameOutput = "BasicSignByAlice_SHA256.bin"
fnameInput = "excontent.txt"
fnameCert = "AliceRSASignByCarl.cer"
n = Cms.MakeSigData(fnameOutput, fnameInput, fnameCert, sbPrivateKey.ToString(), Cms.SigAlg.Rsa_Sha256, 0)
Console.WriteLine("Cms.MakeSigData returns {0} (expecting 0)", n)
Debug.Assert(0 = n, "Cms.MakeSigData failed")
' Get the hash algorithm used in the signature
fnameInput = fnameOutput
s = Cms.QuerySigData(fnameInput, "digestAlgorithm")
Console.WriteLine("digestAlgorithm={0}", s)
' Verify the signature
n = Cms.VerifySigData(fnameInput, fnameCert)
Console.WriteLine("Cms.VerifySigData returns {0} (expecting 0)", n)
Debug.Assert(0 = n, "Cms.VerifySigData failed")
' Again using a string as input instead of a file
' Use SHA-224 and include signed attributes with sign-time
s = File.ReadAllText("excontent.txt")
fname = "BasicSignByAlice_224.bin"
n = Cms.MakeSigDataFromString(fname, s, fnameCert, sbPrivateKey.ToString(), Cms.SigAlg.Rsa_Sha224, Cms.SigDataOptions.IncludeAttributes Or Cms.SigDataOptions.AddSignTime)
Console.WriteLine("Cms.MakeSigDataFromString returns {0} (expecting 0)", n)
Debug.Assert(0 = n, "Cms.MakeSigDataFromString failed")
' Query the signature file we've just made
fnameInput = fname
Console.WriteLine("For file '{0}':", fnameInput)
query = "digestAlgorithm"
s = Cms.QuerySigData(fnameInput, query)
Console.WriteLine("{0}={1}", query, s)
query = "HASsignedAttributes"
s = Cms.QuerySigData(fnameInput, query)
Console.WriteLine("{0}={1}", query, s)
query = "signingTime"
s = Cms.QuerySigData(fnameInput, query)
Console.WriteLine("{0}={1}", query, s)
' Verify the signature
n = Cms.VerifySigData(fnameInput)
Console.WriteLine("Cms.VerifySigData returns {0} (expecting 0)", n)
Debug.Assert(0 = n, "Cms.VerifySigData failed")
' Added v3.4.1 [2010-02-23]
' Create a "certs-only" SignedData file == certificate chain file
fnameOutput = "Alice_new.p7c"
certList = "AliceRSASignByCarl.cer" & ";" & "CarlRSASelf.cer"
'n = Cms.MakeSigData(fnameOutput, "", certList, "", (Cms.Options)0x0400);
n = Cms.MakeSigData(fnameOutput, "", certList, "", Cms.SigAlg.[Default], Cms.SigDataOptions.CertsOnly)
Console.WriteLine("Cms.MakeSigData(certs-only) returns {0} (expecting 0)", n)
Debug.Assert(0 = n, "Cms.MakeSigData failed")
' Query our SignedData files
fnameInput = "BasicSignByAlice_attr.bin"
query = "version"
s = Cms.QuerySigData(fnameInput, query)
Console.WriteLine("Cms.QuerySigData('{0}') returns '{1}'", query, s)
Debug.Assert(s.Length > 0, "QuerySigData failed")
query = "digestAlgorithm"
s = Cms.QuerySigData(fnameInput, query)
Console.WriteLine("Cms.QuerySigData('{0}') returns '{1}'", query, s)
Debug.Assert(s.Length > 0, "QuerySigData failed")
query = "signingTime"
s = Cms.QuerySigData(fnameInput, query)
Console.WriteLine("Cms.QuerySigData('{0}') returns '{1}'", query, s)
Debug.Assert(s.Length > 0, "QuerySigData failed")
' ...that's enough CMS tests.
End Sub
Private Shared Sub test_CMS_SigData_PSS()
Console.WriteLine(vbLf & "CMS SIG-DATA WITH RSA-PSS:")
' Use German Health examples folder for now
Const TESTPATH As String = "C:\Test\GermanHealth\"
Dim prikeyFile As String = TESTPATH & "999009991b_pri.p8e"
Dim userCert As String = TESTPATH & "999009991b.cer"
Dim recipKeyFile As String = TESTPATH & "999009051b_pri.p8e"
Dim recipCert As String = TESTPATH & "999009051b.cer"
Dim certList As String = recipCert & ";" & TESTPATH & "CA_4096_Cert.cer" & ";" & TESTPATH & "Int_4096_Cert.cer"
Dim interFile As String = TESTPATH & "To_999009051b.int"
Dim outFile As String = TESTPATH & "To_999009051b.p7m"
Dim interFile1 As String = TESTPATH & "To_999009051b_1.int"
Dim msg As String = "Hallo Walt"
Dim sbPrivateKey As StringBuilder
Dim r As Integer
Dim s As String
Dim query As String
' Read in the sender's private key
sbPrivateKey = Rsa.ReadPrivateKey(prikeyFile, "password")
Console.WriteLine("Key length={0} bits", Rsa.KeyBits(sbPrivateKey.ToString()))
Debug.Assert(sbPrivateKey.Length > 0)
' Create intermediate signed-data file
r = Cms.MakeSigDataFromString(interFile, msg, userCert, sbPrivateKey.ToString(), Cms.SigAlg.Rsa_Pss_Sha256, Cms.SigDataOptions.IncludeAttributes Or Cms.SigDataOptions.AddSignTime)
Wipe.[String](sbPrivateKey)
Debug.Assert(r = 0)
Console.WriteLine("Created intermediate signed-data file '{0}'", interFile)
asn1DumpFile(interFile)
' While we're here, let's query the signed-data file
query = "signatureAlgorithm"
s = Cms.QuerySigData(interFile, query)
Console.WriteLine("Cms.QuerySigData('{0}')='{1}'", query, s)
query = "pssParams"
s = Cms.QuerySigData(interFile, query)
Console.WriteLine("Cms.QuerySigData('{0}')='{1}'", query, s)
' Encrypt signed-data directly in enveloped-data file: NB returns number of recipients, not zero on success
r = Cms.MakeEnvData(outFile, interFile, certList, CipherAlgorithm.Aes256, Cms.KeyEncrAlgorithm.Rsa_Oaep, HashAlgorithm.Sha256, _
Cms.EnvDataOptions.None)
Debug.Assert(r > 0)
Console.WriteLine("Created enveloped-data file '{0}'", outFile)
' And let's query the enveloped-data file
query = "keyEncryptionAlgorithm"
s = Cms.QueryEnvData(outFile, query)
Console.WriteLine("Cms.QueryEnvData('{0}')='{1}'", query, s)
query = "oaepParams"
s = Cms.QueryEnvData(outFile, query)
Console.WriteLine("Cms.QueryEnvData('{0}')='{1}'", query, s)
' Clean up
Wipe.[String](sbPrivateKey)
Console.WriteLine(vbLf & "Part 2: Reading in the enveloped data...")
' Read in the recipient's private key (which we shouldn't have, but we do here for testing)
sbPrivateKey = Rsa.ReadPrivateKey(recipKeyFile, "password")
Console.WriteLine("Key length={0} bits", Rsa.KeyBits(sbPrivateKey.ToString()))
Debug.Assert(sbPrivateKey.Length > 0)
' Read the enveloped-data file to output the signed-data file
r = Cms.ReadEnvDataToFile(interFile1, outFile, recipCert, sbPrivateKey.ToString())
Debug.Assert(r = 0)
Console.WriteLine("Read in signed-data file '{0}'", interFile1)
' Verify the signed data before reading it
r = Cms.VerifySigData(interFile1)
Console.WriteLine("Cms.VerifySigData() returns {0} (expecting 0)", r)
Debug.Assert(r = 0)
' Read in the data that was signed
s = Cms.ReadSigDataToString(interFile1)
Console.WriteLine("msg='{0}'", s)
Debug.Assert(s.Length > 0)
' Clean up
Wipe.[String](sbPrivateKey)
' Some more tests...
Console.WriteLine("Dump certificate data...")
Console.WriteLine([String].Empty.PadLeft(20, "="C))
s = X509.TextDumpToString(recipCert, X509.OutputOpts.[Decimal] Or X509.OutputOpts.Ldap)
Debug.Assert(s.Length > 0)
Console.WriteLine(s)
Console.WriteLine([String].Empty.PadLeft(20, "="C))
s = Asn1.TextDumpToString(recipCert, 0)
Debug.Assert(s.Length > 0)
Console.WriteLine(s)
r = X509.ValidatePath(certList)
Console.WriteLine("X509.ValidatePath() returns {0} (expecting 0)", r)
Debug.Assert(r = 0)
End Sub
Private Shared Sub test_CMS_EnvData()
Dim s As String
Dim n As Integer
Dim fname As String
Dim sbPrivateKey As StringBuilder
Dim query As String
Dim fnameCert As String
Console.WriteLine(vbLf & "ADVANCED ENVELOPED-DATA OBJECTS:")
' Create an enveloped CMS object Alice to Bob using Bob's X.509 certificate
fname = "cms2bob_aes128.p7m"
fnameCert = "BobRSASignByCarl.cer"
' This should return 1 (indicating one successful recipient)
s = "This is some sample content."
n = Cms.MakeEnvDataFromString(fname, s, fnameCert, CipherAlgorithm.Aes128, Cms.KeyEncrAlgorithm.Rsa_Pkcs1v1_5, 0, _
0)
Console.WriteLine("Cms.MakeEnvDataFromString returns {0} (expecting 1)", n)
Debug.Assert(1 = n, "Cms.MakeEnvDataFromString failed")
' Query the enveloped-data file
query = "keyEncryptionAlgorithm"
s = Cms.QueryEnvData(fname, query)
Console.WriteLine("{0}='{1}'", query, s)
query = "contentEncryptionAlgorithm"
s = Cms.QueryEnvData(fname, query)
Console.WriteLine("{0}='{1}'", query, s)
' Now try and read it using Bob's private key
sbPrivateKey = Rsa.ReadPrivateKey("BobPrivRSAEncrypt.p8e", "password")
Debug.Assert(sbPrivateKey.ToString().Length > 0, "Unable to read Bob's private key")
s = Cms.ReadEnvDataToString(fname, "", sbPrivateKey.ToString())
Console.WriteLine("MSG={0}", s)
Debug.Assert(s.Length > 0, "Cms.ReadEnvDataToString failed")
End Sub
Private Shared Sub test_CMS_EnvData_ecdh()
Dim s As String
Dim n As Integer
Dim fname As String
Dim sbPrivateKeyAlice As StringBuilder, sbPrivateKeyDana As StringBuilder
Dim query As String
Dim certName As String, certList As String
Dim nRecips As Integer
Console.WriteLine(vbLf & "ENVELOPED-DATA OBJECTS USING ECDH KEY AGREEMENT (KARI):")
' Create an enveloped CMS object to Dana (using ECDH) and Alice (using RSA)
fname = "dana_alice_all_defaults.p7m"
certList = "lamps-dana.encrypt.crt;lamps-alice.encrypt.crt"
s = "This is some sample content."
' This should return 2 (indicating two successful recipients)
nRecips = 2
' Use defaults for ECDH
n = Cms.MakeEnvDataFromString(fname, s, certList, CipherAlgorithm.Aes128)
Console.WriteLine("Cms.MakeEnvDataFromString returns {0} (expecting {1})", n, nRecips)
If nRecips <> n Then
Console.WriteLine(General.FormatErrorMessage(n))
End If
Debug.Assert(nRecips = n, "Cms.MakeEnvDataFromString failed")
Console.WriteLine("FILE: {0}", fname)
'Console.WriteLine(Asn1.TextDumpToString(fname));
'
' openssl cms -decrypt -in dana_alice_all_defaults -inform DER -inkey lamps-alice.decrypt.p8.pem -recip lamps-alice.encrypt.crt
' This is some sample content.
'
' Query the enveloped-data file
query = "contentEncryptionAlgorithm"
s = Cms.QueryEnvData(fname, query)
Console.WriteLine("{0}='{1}'", query, s)
query = "recipientInfoType"
s = Cms.QueryEnvData(fname, query)
Console.WriteLine("{0}='{1}'", query, s)
query = "keyEncryptionAlgorithm"
s = Cms.QueryEnvData(fname, query)
Console.WriteLine("{0}='{1}'", query, s)
query = "keyEncryptionAlgorithm/2"
s = Cms.QueryEnvData(fname, query)
Console.WriteLine("{0}='{1}'", query, s)
fname = "dana_alice_oaep_ecc_defaults.p7m"
certList = "lamps-dana.encrypt.crt;lamps-alice.encrypt.crt"
s = "This is some sample content."
' This should return 2 (indicating two successful recipients)
nRecips = 2
' Use RSA-OAEP but defaults for ECDH
n = Cms.MakeEnvDataFromString(fname, s, certList, CipherAlgorithm.Aes128, Cms.KeyEncrAlgorithm.Rsa_Oaep, HashAlgorithm.Sha256, _
Cms.EnvDataOptions.Mgf1Sha1)
Console.WriteLine("Cms.MakeEnvDataFromString returns {0} (expecting {1})", n, nRecips)
If nRecips <> n Then
Console.WriteLine(General.FormatErrorMessage(n))
End If
Debug.Assert(nRecips = n, "Cms.MakeEnvDataFromString failed")
Console.WriteLine("FILE: {0}", fname)
' Query the enveloped-data file
query = "contentEncryptionAlgorithm"
s = Cms.QueryEnvData(fname, query)
Console.WriteLine("{0}='{1}'", query, s)
query = "recipientInfoType"
s = Cms.QueryEnvData(fname, query)
Console.WriteLine("{0}='{1}'", query, s)
query = "keyEncryptionAlgorithm"
s = Cms.QueryEnvData(fname, query)
Console.WriteLine("{0}='{1}'", query, s)
query = "keyEncryptionAlgorithm/2"
s = Cms.QueryEnvData(fname, query)
Console.WriteLine("{0}='{1}'", query, s)
' Read in Alice's RSA and Dana's ECC private key (unencrypted)
Console.WriteLine("Read in Alice's and Dana's private keys")
sbPrivateKeyAlice = Rsa.ReadPrivateKey("lamps-alice.decrypt.p8.pem", "")
Debug.Assert(sbPrivateKeyAlice.ToString().Length > 0, "Unable to read Alices's private key")
sbPrivateKeyDana = Ecc.ReadPrivateKey("lamps-dana.decrypt.p8.pem", "")
Debug.Assert(sbPrivateKeyDana.ToString().Length > 0, "Unable to read Dana's private key")
' Read CMS enveloped-data
Console.WriteLine("Read CMS using Alice's private key")
certName = "lamps-alice.encrypt.crt"
s = Cms.ReadEnvDataToString(fname, certName, sbPrivateKeyAlice.ToString())
Console.WriteLine("MSG={0}", s)
Debug.Assert(s.Length > 0, "Cms.ReadEnvDataToString failed")
' And again using Dana's X25519 key
Console.WriteLine("Read using Dana's ECC X22519 private key")
certName = "lamps-dana.encrypt.crt"
s = Cms.ReadEnvDataToString(fname, certName, sbPrivateKeyDana.ToString())
Console.WriteLine("MSG={0}", s)
Debug.Assert(s.Length > 0, "Cms.ReadEnvDataToString failed")
' Now use specific ECDH parameters added [v20.5]
fname = "dana_alice_hkdf.p7m"
certList = "lamps-dana.encrypt.crt"
nRecips = 1
n = Cms.MakeEnvData(fname, "excontent.txt", certList, CipherAlgorithm.Aes256, 0, HashAlgorithm.Sha256, _
0, Kdf.KdfAlg.Hkdf, Kdf.KeyWrapAlg.Aes256_wrap)
Console.WriteLine("Cms.MakeEnvData returns {0} (expecting {1})", n, nRecips)
If nRecips <> n Then
Console.WriteLine(General.FormatErrorMessage(n))
End If
Debug.Assert(nRecips = n, "Cms.MakeEnvDataFromString failed")
Console.WriteLine("FILE: {0}", fname)
'Console.WriteLine(Asn1.TextDumpToString(fname));
' Query the enveloped-data file
query = "contentEncryptionAlgorithm"
s = Cms.QueryEnvData(fname, query)
Console.WriteLine("{0}='{1}'", query, s)
query = "keyEncryptionAlgorithm"
s = Cms.QueryEnvData(fname, query)
Console.WriteLine("{0}='{1}'", query, s)
query = "keyWrapAlgorithm"
s = Cms.QueryEnvData(fname, query)
Console.WriteLine("{0}='{1}'", query, s)
certName = "lamps-dana.encrypt.crt"
s = Cms.ReadEnvDataToString(fname, certName, sbPrivateKeyDana.ToString())
Console.WriteLine("MSG={0}", s)
Debug.Assert(s.Length > 0, "Cms.ReadEnvDataToString failed")
Console.WriteLine("EXPECTING ERRORS...")
fname = "dana-bad.p7m"
certList = "lamps-dana.encrypt.crt"
nRecips = 1
' Pass bad parameters: MD5 is not valid here for ecdhX963KDF
n = Cms.MakeEnvData(fname, "excontent.txt", certList, CipherAlgorithm.Aes256, 0, HashAlgorithm.Md5)
Console.WriteLine("Cms.MakeEnvData returns {0} (expecting {1})", n, nRecips)
If nRecips <> n Then
Console.WriteLine(General.FormatErrorMessage(n))
End If
Debug.Assert(nRecips <> n, "Cms.MakeEnvDataFromString succeeded when should fail")
' Cannot use cms3DESwrap when content encryption is not Triple DES
n = Cms.MakeEnvData(fname, "excontent.txt", certList, CipherAlgorithm.Aes256, keyWrapAlg := Kdf.KeyWrapAlg.Cms3DESwrap)
Console.WriteLine("Cms.MakeEnvData returns {0} (expecting {1})", n, nRecips)
If nRecips <> n Then
Console.WriteLine(General.FormatErrorMessage(n))
End If
Debug.Assert(nRecips <> n, "Cms.MakeEnvDataFromString succeeded when should fail")
Console.WriteLine("...END OF EXPECTED ERRORS")
End Sub
Private Shared Sub test_CMS_EnvData_auth()
Dim s As String
Dim n As Integer
Dim fname As String
Dim sbPrivateKey As StringBuilder
Dim query As String
Dim fnameCert As String
Console.WriteLine(vbLf & "AUTHENTICATED-ENVELOPED-DATA OBJECTS:")
' Create an authenticated-enveloped CMS object Alice to Bob using Bob's X.509 certificate
fname = "cms2bob_auth.p7m"
fnameCert = "BobRSASignByCarl.cer"
' This should return 1 (indicating one successful recipient)
s = "This is some sample content."
n = Cms.MakeEnvDataFromString(fname, s, fnameCert, CipherAlgorithm.Aes128, Cms.KeyEncrAlgorithm.Rsa_Pkcs1v1_5, 0, _
Cms.EnvDataOptions.Authenticated, count := 13)
Console.WriteLine("Cms.MakeEnvDataFromString returns {0} (expecting 1)", n)
If n < 0 Then
Console.WriteLine(General.FormatErrorMessage(n))
End If
Debug.Assert(1 = n, "Cms.MakeEnvDataFromString failed")
' Query the enveloped-data file
query = "keyEncryptionAlgorithm"
s = Cms.QueryEnvData(fname, query)
Console.WriteLine("{0}='{1}'", query, s)
query = "contentEncryptionAlgorithm"
s = Cms.QueryEnvData(fname, query)
Console.WriteLine("{0}='{1}'", query, s)
' Display ASN.1 data
Console.WriteLine(Asn1.TextDumpToString(fname))
' Now try and read it using Bob's private key
sbPrivateKey = Rsa.ReadPrivateKey("BobPrivRSAEncrypt.p8e", "password")
Debug.Assert(sbPrivateKey.ToString().Length > 0, "Unable to read Bob's private key")
s = Cms.ReadEnvDataToString(fname, "", sbPrivateKey.ToString())
Console.WriteLine("MSG='{0}'", s)
Debug.Assert(s.Length > 0, "Cms.ReadEnvDataToString failed")
End Sub
Private Shared Sub test_CMS_EnvData_pwri()
Dim s As String
Dim n As Integer
Dim fname As String
Dim query As String
Dim sbPassword As New StringBuilder("password1234")
Console.WriteLine(vbLf & "ENVELOPED-DATA USING PWRI:")
fname = "cms_envdata_pwri.p7m"
' This should return 1 (indicating one successful recipient)
s = "This is some sample content."
n = Cms.MakeEnvDataFromString(fname, s, "type=@pwri", CipherAlgorithm.Aes128, keyString := sbPassword.ToString())
Console.WriteLine("Cms.MakeEnvDataFromString(pwri) returns {0} (expecting 1)", n)
If n < 0 Then
Console.WriteLine(General.FormatErrorMessage(n))
End If
Debug.Assert(1 = n, "Cms.MakeEnvDataFromString(pwri) failed")
' Query the enveloped-data file
query = "keyEncryptionAlgorithm"
s = Cms.QueryEnvData(fname, query)
Console.WriteLine("{0}='{1}'", query, s)
query = "contentEncryptionAlgorithm"
s = Cms.QueryEnvData(fname, query)
Console.WriteLine("{0}='{1}'", query, s)
' Display ASN.1 data
Console.WriteLine(Asn1.TextDumpToString(fname))
' Now try and read it using the same password
s = Cms.ReadEnvDataToString(fname, "", sbPassword.ToString())
Console.WriteLine("MSG='{0}'", s)
Debug.Assert(s.Length > 0, "Cms.ReadEnvDataToString failed")
' Clear password
Wipe.[String](sbPassword)
End Sub
Private Shared Sub test_CMS_EnvData_kekri()
Dim s As String
Dim n As Integer
Dim fname As String
Dim query As String
Dim kekstr As String = "#x0123456789ABCDEFF0E1D2C3B4A59687"
' Represents KEK of 16 bytes/128 bits suitable for aes128-wrap
Console.WriteLine(vbLf & "ENVELOPED-DATA USING KEKRI:")
fname = "cms_envdata_kekri.p7m"
' This should return 1 (indicating one successful recipient)
s = "This is some sample content."
n = Cms.MakeEnvDataFromString(fname, s, "type=@kekri,keyid=ourcommonkey", CipherAlgorithm.Aes192, hashAlg := HashAlgorithm.Sha256, keyWrapAlg := Kdf.KeyWrapAlg.Aes128_wrap, _
keyString := kekstr)
Console.WriteLine("Cms.MakeEnvDataFromString(kekri) returns {0} (expecting 1)", n)
If n < 0 Then
Console.WriteLine(General.FormatErrorMessage(n))
End If
Debug.Assert(1 = n, "Cms.MakeEnvDataFromString(kekri) failed")
' Query the enveloped-data file
query = "keyEncryptionAlgorithm"
s = Cms.QueryEnvData(fname, query)
Console.WriteLine("{0}='{1}'", query, s)
query = "contentEncryptionAlgorithm"
s = Cms.QueryEnvData(fname, query)
Console.WriteLine("{0}='{1}'", query, s)
' Display ASN.1 data
Console.WriteLine(Asn1.TextDumpToString(fname))
' Now try and read it using the same KEK
s = Cms.ReadEnvDataToString(fname, "", kekstr)
Console.WriteLine("MSG='{0}'", s)
Debug.Assert(s.Length > 0, "Cms.ReadEnvDataToString failed")
End Sub
Private Shared Sub test_CMS_EnvData_examples()
Dim n As Integer
Console.WriteLine(vbLf & "ENVELOPED-DATA EXAMPLES USED IN DOCS:")
' Create an enveloped CMS object (ktri type) to Bob using Bob's RSA key
n = Cms.MakeEnvData("cms2bob_aes128.p7m", "excontent.txt", "BobRSASignByCarl.cer", CipherAlgorithm.Aes128, Cms.KeyEncrAlgorithm.Rsa_Oaep)
Console.WriteLine("Cms.MakeEnvData returns {0} (expecting 1)", n)
Debug.Assert(1 = n, "Cms.MakeEnvData failed")
' Same but using authenticated encryption and creating an authEnvelopedData object
n = Cms.MakeEnvData("cms2bob_aes128auth.p7m", "excontent.txt", "BobRSASignByCarl.cer", CipherAlgorithm.Aes128, Cms.KeyEncrAlgorithm.Rsa_Oaep, advOptions := Cms.EnvDataOptions.Authenticated)
Console.WriteLine("Cms.MakeEnvData returns {0} (expecting 1)", n)
Debug.Assert(1 = n, "Cms.MakeEnvData failed")
' Create an enveloped CMS object (kari type) to Dana using Dana's ECC key
n = Cms.MakeEnvData("cms2dana_hkdf.p7m", "excontent.txt", "lamps-dana.encrypt.crt", CipherAlgorithm.Aes256, 0, HashAlgorithm.Sha256, _
0, Kdf.KdfAlg.Hkdf, Kdf.KeyWrapAlg.Aes256_wrap)
Console.WriteLine("Cms.MakeEnvData returns {0} (expecting 1)", n)
Debug.Assert(1 = n, "Cms.MakeEnvData failed")
' Create an enveloped CMS object (kekri type) using a previously distributed symmetric key-encryption key (KEK)
n = Cms.MakeEnvData("cms_envdata_kekri.p7m", "excontent.txt", "type=@kekri,keyid=ourcommonkey", CipherAlgorithm.Aes256, hashAlg := HashAlgorithm.Sha256, keyWrapAlg := Kdf.KeyWrapAlg.Aes128_wrap, _
keyString := "#x0123456789ABCDEFF0E1D2C3B4A59687")
Console.WriteLine("Cms.MakeEnvData returns {0} (expecting 1)", n)
Debug.Assert(1 = n, "Cms.MakeEnvData failed")
' Create an enveloped CMS object (pwri type) using password-based key management
n = Cms.MakeEnvData("cms_envdata_pwri.p7m", "excontent.txt", "type=@pwri", CipherAlgorithm.Aes192, keyString := "password12345")
Console.WriteLine("Cms.MakeEnvData returns {0} (expecting 1)", n)
Debug.Assert(1 = n, "Cms.MakeEnvData failed")
' Now read in the enveloped-data objects we made above
Dim s As String
Dim fname As String
Dim sbPrivateKey As StringBuilder
sbPrivateKey = Rsa.ReadPrivateKey("BobPrivRSAEncrypt.p8e", "password")
Debug.Assert(sbPrivateKey.ToString().Length > 0, "Unable to read Bob's private key")
fname = "cms2bob_aes128.p7m"
Console.WriteLine("{0}=>{1}", fname, Cms.QueryEnvData(fname, "recipientInfoType"))
s = Cms.ReadEnvDataToString(fname, "", sbPrivateKey.ToString())
Console.WriteLine("MSG='{0}'", s)
Debug.Assert(s.Length > 0, "Cms.ReadEnvDataToString failed")
fname = "cms2bob_aes128auth.p7m"
Console.WriteLine("{0}=>{1}", fname, Cms.QueryEnvData(fname, "recipientInfoType"))
s = Cms.ReadEnvDataToString(fname, "", sbPrivateKey.ToString())
Console.WriteLine("MSG='{0}'", s)
Debug.Assert(s.Length > 0, "Cms.ReadEnvDataToString failed")
sbPrivateKey = Ecc.ReadPrivateKey("lamps-dana.decrypt.p8.pem", "")
Debug.Assert(sbPrivateKey.ToString().Length > 0, "Unable to read Dana's private key")
fname = "cms2dana_hkdf.p7m"
Console.WriteLine("{0}=>{1}", fname, Cms.QueryEnvData(fname, "recipientInfoType"))
s = Cms.ReadEnvDataToString(fname, "", sbPrivateKey.ToString())
Console.WriteLine("MSG='{0}'", s)
Debug.Assert(s.Length > 0, "Cms.ReadEnvDataToString failed")
fname = "cms_envdata_kekri.p7m"
Console.WriteLine("{0}=>{1}", fname, Cms.QueryEnvData(fname, "recipientInfoType"))
s = Cms.ReadEnvDataToString(fname, "", "#x0123456789ABCDEFF0E1D2C3B4A59687")
Console.WriteLine("MSG='{0}'", s)
Debug.Assert(s.Length > 0, "Cms.ReadEnvDataToString failed")
fname = "cms_envdata_pwri.p7m"
Console.WriteLine("{0}=>{1}", fname, Cms.QueryEnvData(fname, "recipientInfoType"))
s = Cms.ReadEnvDataToString(fname, "", "password12345")
Console.WriteLine("MSG='{0}'", s)
Debug.Assert(s.Length > 0, "Cms.ReadEnvDataToString failed")
End Sub
Private Shared Sub test_CMS_SMIME_Chain()
Dim r As Integer
Dim s As String
Dim inpFile As String
Dim outFile As String
Dim origFile As String = "sonnets.txt"
Dim alicekeyfile As String = "AlicePrivRSASign.p8e"
Dim alicecerfile As String = "AliceRSASignByCarl.cer"
Dim password As String = "password"
Dim bobkeyfile As String = "BobPrivRSAEncrypt.p8e"
Dim bobcerfile As String = "BobRSASignByCarl.cer"
Dim sbPrikey As StringBuilder
Dim query As String
Dim digest1 As String, digest2 As String
Console.WriteLine(vbLf & "CREATE A CHAIN OF CMS OBJECTS WRAPPED IN S/MIME:")
' Start with original input file
inpFile = origFile
Console.WriteLine("File '{0}' is {1} bytes", inpFile, FileLength(inpFile))
' Create a CMS compressed-data object
outFile = "sonnet-compr.p7z"
r = Cms.MakeComprData(outFile, inpFile)
Console.WriteLine("Cms.MakeComprData returns {0} (expected 0)", r)
Debug.Assert(0 = r)
inpFile = outFile
Console.WriteLine("File '{0}' is {1} bytes", inpFile, FileLength(inpFile))
' Wrap in S/MIME
outFile = "sonnet-compr-smime.txt"
r = Smime.Wrap(outFile, inpFile, 0)
Console.WriteLine("Smime.Wrap returns {0} (expected +ve)", r)
Debug.Assert(r > 0)
inpFile = outFile
Console.WriteLine("File '{0}' is {1} bytes", inpFile, FileLength(inpFile))
' Create a CMS signed-data object signed by Alice
outFile = "sonnet-sig-compr.p7m"
sbPrikey = Rsa.ReadPrivateKey(alicekeyfile, password)
Debug.Assert(sbPrikey.Length > 0)
r = Cms.MakeSigData(outFile, inpFile, alicecerfile, sbPrikey.ToString(), Cms.SigAlg.[Default], 0)
Console.WriteLine("Cms.MakeSigData returns {0} (expected 0)", r)
Debug.Assert(0 = r)
inpFile = outFile
Console.WriteLine("File '{0}' is {1} bytes", inpFile, FileLength(inpFile))
' Wrap in S/MIME
outFile = "sonnet-sig-compr-smime.txt"
r = Smime.Wrap(outFile, inpFile, 0)
Console.WriteLine("Smime.Wrap returns {0} (expected +ve)", r)
Debug.Assert(r > 0)
inpFile = outFile
Console.WriteLine("File '{0}' is {1} bytes", inpFile, FileLength(inpFile))
' Create a CMS enveloped-data object encrypted for Bob
outFile = "sonnet-env-sig-compr.p7m"
r = Cms.MakeEnvData(outFile, inpFile, bobcerfile, CipherAlgorithm.Tdea)
Console.WriteLine("Cms.MakeEnvData returns {0} (expected 1)", r)
Debug.Assert(1 = r)
inpFile = outFile
Console.WriteLine("File '{0}' is {1} bytes", inpFile, FileLength(inpFile))
' Wrap in S/MIME
outFile = "sonnet-env-sig-compr-smime.txt"
r = Smime.Wrap(outFile, inpFile, 0)
Console.WriteLine("Smime.Wrap returns {0} (expected +ve)", r)
Debug.Assert(r > 0)
inpFile = outFile
Console.WriteLine("File '{0}' is {1} bytes", inpFile, FileLength(inpFile))
' NOW REVERSE THE PROCEDURE...
Console.WriteLine(vbLf & "Reverse the procedure (and check file types as we go)...")
' What S/MIME type are we starting with?
query = "smime-type"
s = Smime.Query(inpFile, query)
Console.WriteLine("{0} is '{1}'", query, s)
' Extract from S/MIME
outFile = "sonnet-out-env-sig-compr.p7m"
r = Smime.Extract(outFile, inpFile, 0)
Console.WriteLine("Smime.Extract returns {0} (expected +ve)", r)
Debug.Assert(r > 0)
inpFile = outFile
Console.WriteLine("File '{0}' is {1} bytes", inpFile, FileLength(inpFile))
' What ASN.1 type did we get?
s = Asn1.Type(inpFile)
Console.WriteLine("Found a '{0}' file", s)
' Bob decrypts enveloped-file using his private key
outFile = "sonnet-out-sig-compr-smime.txt"
sbPrikey = Rsa.ReadPrivateKey(bobkeyfile, password)
Debug.Assert(sbPrikey.Length > 0)
r = Cms.ReadEnvDataToFile(outFile, inpFile, "", sbPrikey.ToString())
Console.WriteLine("Cms.ReadEnvDataToFile returns {0} (expected 0)", r)
Debug.Assert(r = 0)
inpFile = outFile
Console.WriteLine("File '{0}' is {1} bytes", inpFile, FileLength(inpFile))
' What S/MIME type was it?
query = "smime-type"
s = Smime.Query(inpFile, query)
Console.WriteLine("{0} is '{1}'", query, s)
' Extract from S/MIME
outFile = "sonnet-out-sig-compr.p7m"
r = Smime.Extract(outFile, inpFile, 0)
Console.WriteLine("Smime.Extract returns {0} (expected +ve)", r)
Debug.Assert(r > 0)
inpFile = outFile
Console.WriteLine("File '{0}' is {1} bytes", inpFile, FileLength(inpFile))
' What ASN.1 type did we get?
s = Asn1.Type(inpFile)
Console.WriteLine("Found a '{0}' file", s)
Debug.Assert(s.Length > 0)
' Verify the signature in the signed-data object using its embedded certificate
r = Cms.VerifySigData(inpFile)
Console.WriteLine("Cms.VerifySigData returns {0} (0=>signature OK)", r)
Debug.Assert(r = 0)
' Extract contents of signed-data
outFile = "sonnet-out-compr-smime.txt"
r = Cms.ReadSigDataToFile(outFile, inpFile)
Console.WriteLine("Cms.ReadSigDataToFile returns {0} (expected +ve)", r)
Debug.Assert(r > 0)
inpFile = outFile
Console.WriteLine("File '{0}' is {1} bytes", inpFile, FileLength(inpFile))
' What S/MIME type was it?
query = "smime-type"
s = Smime.Query(inpFile, query)
Console.WriteLine("{0} is '{1}'", query, s)
' Extract from S/MIME
outFile = "sonnet-out-compr.p7z"
r = Smime.Extract(outFile, inpFile, 0)
Console.WriteLine("Smime.Extract returns {0} (expected +ve)", r)
Debug.Assert(r > 0)
inpFile = outFile
Console.WriteLine("File '{0}' is {1} bytes", inpFile, FileLength(inpFile))
' What ASN.1 type did we get?
s = Asn1.Type(inpFile)
Console.WriteLine("Found a '{0}' file", s)
Debug.Assert(s.Length > 0)
' Finally, read contents of CMS compressed-data object
outFile = "sonnet-out.txt"
r = Cms.ReadComprData(outFile, inpFile, 0)
Console.WriteLine("Cms.ReadComprData returns {0} (expected +ve)", r)
Debug.Assert(r > 0)
inpFile = outFile
Console.WriteLine("File '{0}' is {1} bytes", inpFile, FileLength(inpFile))
' Check we have no more S/MIME wrapping
query = "smime-type"
s = Smime.Query(inpFile, query)
Console.WriteLine("{0} is '{1}'", query, s)
' Did we get the same as we started?
Console.WriteLine("Compute SHA-1 digests and compare...")
digest1 = Hash.HexFromFile(outFile, HashAlgorithm.Sha1)
Console.WriteLine("SHA1('{0}')=" & vbTab & "{1}", outFile, digest1)
digest2 = Hash.HexFromFile(origFile, HashAlgorithm.Sha1)
Console.WriteLine("SHA1('{0}')=" & vbTab & "{1}", origFile, digest2)
Debug.Assert(digest1 = digest2, "Digests do not match")
End Sub
Private Shared Sub test_Hash()
'*************
' HASH TESTS *
'*************
Dim s As String
Dim fname As String
Dim strCheck As String
Dim b As Byte()
Console.WriteLine(vbLf & "HASH DIGEST TESTS:")
s = Hash.HexFromString("abc", HashAlgorithm.Sha1)
Console.WriteLine("SHA-1('abc') ={0}", s)
s = Hash.HexFromString("abc", HashAlgorithm.Md5)
Console.WriteLine("MD5('abc') ={0}", s)
s = Hash.HexFromString("abc", HashAlgorithm.Md2)
Console.WriteLine("MD2('abc') ={0}", s)
s = Hash.HexFromString("abc", HashAlgorithm.Sha256)
Console.WriteLine("SHA-256('abc')=" & vbLf & "{0}", s)
s = Hash.HexFromString("abc", HashAlgorithm.Sha384)
Console.WriteLine("SHA-384('abc')=" & vbLf & "{0}", s)
s = Hash.HexFromString("abc", HashAlgorithm.Sha512)
Console.WriteLine("SHA-512('abc')=" & vbLf & "{0}", s)
' Create a test file
fname = "hello.txt"
File.WriteAllText(fname, "hello world" & vbCr & vbLf)
' get digest from binary file
s = Hash.HexFromFile(fname, HashAlgorithm.Sha1)
Console.WriteLine("SHA1('hello world+CR+LF')={0}", s)
' and again treating CR-LF as a single LF
' (we use this when moving between Unix and Windows systems)
s = Hash.HexFromTextFile(fname, HashAlgorithm.Sha1)
Console.WriteLine("SHA1('hello world+LF')= {0}", s)
' Hash of "abc" with input in hex format using SHA-224
s = Hash.HexFromHex("616263", HashAlgorithm.Sha224)
Console.WriteLine("SHA-224('abc') ={0}", s)
strCheck = "23097D223405D8228642A477BDA255B32AADBCE4BDA0B3F7E36C9DA7"
Console.WriteLine("Correct ={0}", strCheck)
Debug.Assert([String].Compare(s, strCheck, True) = 0, "SHA-224('abc') failed")
' New in [v11.0]
s = Hash.HexFromString("abc", HashAlgorithm.Ripemd160)
Console.WriteLine("RIPEMD160('abc') =" & s)
Debug.Assert([String].Compare(s, "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc", True) = 0, "RIPEMD160('abc') failed")
s = Hash.HexFromString("abc", HashAlgorithm.Bitcoin160)
Console.WriteLine("BITCOIN160('abc')=" & s)
Debug.Assert([String].Compare(s, "bb1be98c142444d7a56aa3981c3942a978e4dc33", True) = 0, "BITCOIN160('abc') failed")
b = Hash.[Double](Cnv.FromHex("616263"), HashAlgorithm.Sha256)
Console.WriteLine("SHA256(SHA256('abc'))=" & vbLf & Cnv.ToHex(b))
Debug.Assert([String].Compare(Cnv.ToHex(b), "4f8b42c22dd3729b519ba6f68d2da7cc5b2d606d05daed5ad5128cc03e6c6358", True) = 0, "SHA256(SHA256('abc')) failed")
End Sub
Private Shared Sub test_Hash_SHA3()
'*************
' SHA-3 HASH TESTS *
'*************
Dim s As String
Dim fname As String
Dim b As Byte()
Console.WriteLine(vbLf & "SHA-3 HASH DIGEST TESTS:")
s = Hash.HexFromString("abc", HashAlgorithm.Sha3_224)
Console.WriteLine("SHA-3-224('abc'):" & vbLf & "{0}", s)
Debug.Assert([String].Compare(s, "e642824c3f8cf24ad09234ee7d3c766fc9a3a5168d0c94ad73b46fdf", True) = 0, "SHA-224('abc') failed")
s = Hash.HexFromString("abc", HashAlgorithm.Sha3_256)
Console.WriteLine("SHA-3-256('abc'):" & vbLf & "{0}", s)
Debug.Assert([String].Compare(s, "3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532", True) = 0, "SHA-256('abc') failed")
s = Hash.HexFromString("abc", HashAlgorithm.Sha3_384)
Console.WriteLine("SHA-3-384('abc'):" & vbLf & "{0}", s)
Debug.Assert([String].Compare(s, "ec01498288516fc926459f58e2c6ad8df9b473cb0fc08c2596da7cf0e49be4b298d88cea927ac7f539f1edf228376d25", True) = 0, "SHA-384('abc') failed")
s = Hash.HexFromString("abc", HashAlgorithm.Sha3_512)
Console.WriteLine("SHA-3-512('abc'):" & vbLf & "{0}", s)
Debug.Assert([String].Compare(s, "b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0", True) = 0, "SHA-512('abc') failed")
' Using bytes
b = Hash.BytesFromBytes(Cnv.FromHex("616263"), HashAlgorithm.Sha3_256)
Console.WriteLine("SHA3-256(b'abc')=" & vbLf & Cnv.ToHex(b))
' Create a test file
fname = "abc.txt"
File.WriteAllText(fname, "abc")
' Compute digest from binary file
s = Hash.HexFromFile(fname, HashAlgorithm.Sha3_256)
Console.WriteLine("SHA-3-256(FILE('abc'))={0}", s)
Debug.Assert([String].Compare(s, "3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532", True) = 0, "SHA-256('abc') failed")
b = Hash.BytesFromFile(fname, HashAlgorithm.Sha3_512)
Console.WriteLine("SHA-3-512(FILE('abc'))={0}", Cnv.ToHex(b))
'Debug.Assert(String.Compare(Cnv.ToHex(b), "3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532", true) == 0, "SHA-256('abc') failed");
b = Hash.[Double](Cnv.FromHex("616263"), HashAlgorithm.Sha3_256)
Console.WriteLine("SHA3-256(SHA3-256('abc'))=" & vbLf & Cnv.ToHex(b))
'Debug.Assert(String.Compare(Cnv.ToHex(b), "4f8b42c22dd3729b519ba6f68d2da7cc5b2d606d05daed5ad5128cc03e6c6358", true) == 0, "BITCOIN160('abc') failed");
b = Hash.[Double](Cnv.FromHex("616263"), HashAlgorithm.Sha3_224)
Console.WriteLine("SHA3-224(SHA3-224('abc'))=" & vbLf & Cnv.ToHex(b))
End Sub
Private Shared Sub test_Hmac()
'*************
' HMAC TESTS *
'*************
Dim s As String
Dim i As Integer
Dim b As Byte()
Dim key As Byte()
Dim msg As Byte()
Dim strCheck As String
Console.WriteLine(vbLf & "HMAC TESTS:")
' Test case 2 from RFC 2202 and RFC 4231
' key = "Jefe"
' key_len 4
' data = "what do ya want for nothing?"
' data_len = 28
Console.WriteLine("Test case 2 from RFC 2202 and RFC 4231...")
' Convert strings to byte arrays
key = System.Text.Encoding.[Default].GetBytes("Jefe")
msg = System.Text.Encoding.[Default].GetBytes("what do ya want for nothing?")
' Compute HMAC-SHA-1 then check against known test vector
s = Hmac.HexFromBytes(msg, key, HashAlgorithm.Sha1)
Console.WriteLine("HMAC-SHA-1('WDYWFN?','Jefe')={0}", s)
strCheck = "effcdf6ae5eb2fa2d27416d5f184df9c259a7c79"
Console.WriteLine("CORRECT= {0}", strCheck)
Debug.Assert([String].Compare(strCheck, s, True) = 0, "HMAC does not match test vector")
' Compute HMAC-SHA-256 then check against known test vector
s = Hmac.HexFromBytes(msg, key, HashAlgorithm.Sha256)
Console.WriteLine("HMAC-SHA-256('WDYWFN?','Jefe')=" & vbLf & "{0}", s)
strCheck = "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843"
Console.WriteLine("CORRECT=" & vbLf & "{0}", strCheck)
Debug.Assert([String].Compare(strCheck, s, True) = 0, "HMAC does not match test vector")
' Test case 4 from RFC 2202 and RFC 4231
' key = 0x0102030405060708090a0b0c0d0e0f10111213141516171819
' key_len 25
' data = 0xcd repeated 50 times
' data_len = 50
Console.WriteLine("Test case 4 from RFC 2202 and RFC 4231...")
key = New Byte(24) {}
For i = 0 To 24
key(i) = CByte(i + 1)
Next
Console.WriteLine("Key={0}", Cnv.ToHex(key))
msg = New Byte(49) {}
For i = 0 To 49
msg(i) = &Hcd
Next
Console.WriteLine("Msg={0}", Cnv.ToHex(msg))
' Output in byte format
' Compute HMAC-SHA-1 then check against known test vector
b = Hmac.BytesFromBytes(msg, key, HashAlgorithm.Sha1)
Console.WriteLine("HMAC-SHA-1(50(0xcd), 0x0102..19)={0}", Cnv.ToHex(b))
strCheck = "4c9007f4026250c6bc8414f9bf50c86c2d7235da"
Console.WriteLine("CORRECT= {0}", strCheck)
Debug.Assert([String].Compare(strCheck, Cnv.ToHex(b), True) = 0, "HMAC does not match test vector")
' Compute HMAC-SHA-256 then check against known test vector
b = Hmac.BytesFromBytes(msg, key, HashAlgorithm.Sha256)
Console.WriteLine("HMAC-SHA-256(50(0xcd), 0x0102..19)=" & vbLf & "{0}", Cnv.ToHex(b))
strCheck = "82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b"
Console.WriteLine("CORRECT=" & vbLf & "{0}", strCheck)
Debug.Assert([String].Compare(strCheck, Cnv.ToHex(b), True) = 0, "HMAC does not match test vector")
' MORE HMAC TESTS
' Hmac of <Test Case 1> with input in hex format
s = Hmac.HexFromHex("4869205468657265", "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", HashAlgorithm.Sha1)
Console.WriteLine("HMAC-SHA-1('Hi There', (0x0b)*20)={0}", s)
strCheck = "B617318655057264E28BC0B6FB378C8EF146BE00"
Console.WriteLine("Correct ={0}", strCheck)
Debug.Assert([String].Compare(s, strCheck, True) = 0, "HMAC-SHA-1('Hi There', (0x0b)*20) failed")
s = Hmac.HexFromHex("4869205468657265", "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", HashAlgorithm.Sha224)
Console.WriteLine("HMAC-SHA-224('Hi There', (0x0b)*20)=" & vbLf & "{0}", s)
strCheck = "896FB1128ABBDF196832107CD49DF33F47B4B1169912BA4F53684B22"
Console.WriteLine("Correct =" & vbLf & "{0}", strCheck)
Debug.Assert([String].Compare(s, strCheck, True) = 0, "HMAC-SHA-224('Hi There', (0x0b)*20) failed")
s = Hmac.HexFromHex("4869205468657265", "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", HashAlgorithm.Sha256)
Console.WriteLine("HMAC-SHA-256('Hi There', (0x0b)*20)=" & vbLf & "{0}", s)
strCheck = "B0344C61D8DB38535CA8AFCEAF0BF12B881DC200C9833DA726E9376C2E32CFF7"
Console.WriteLine("Correct =" & vbLf & "{0}", strCheck)
Debug.Assert([String].Compare(s, strCheck, True) = 0, "HMAC-SHA-256('Hi There', (0x0b)*20) failed")
End Sub
Private Shared Sub test_Hmac_SHA3()
'*************
' HMAC-SHA3 TESTS *
'*************
Dim s As String
Dim b As Byte()
Dim key As Byte()
Dim msg As Byte()
Dim strCheck As String
Console.WriteLine(vbLf & "HMAC-SHA-3 TESTS:")
Console.WriteLine("NIST HMAC_SHA3-256.pdf Sample #1")
key = Cnv.FromHex("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F")
msg = System.Text.Encoding.[Default].GetBytes("Sample message for keylen<blocklen")
strCheck = "4fe8e202c4f058e8dddc23d8c34e467343e23555e24fc2f025d598f558f67205"
b = Hmac.BytesFromBytes(msg, key, HashAlgorithm.Sha3_256)
Console.WriteLine("HMAC-SHA-3-256: {0}", Cnv.ToHex(b))
Console.WriteLine("Correct: {0}", strCheck)
Debug.Assert([String].Compare(Cnv.ToHex(b), strCheck, True) = 0, "HMAC-SHA3-256('Sample #1) failed")
Console.WriteLine("NIST HMAC_SHA3-512.pdf Sample #3")
key = Cnv.FromHex("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F" & vbCr & vbLf & " 202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F" & vbCr & vbLf & " 404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F" & vbCr & vbLf & " 606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F" & vbCr & vbLf & " 8081828384858687")
msg = System.Text.Encoding.[Default].GetBytes("Sample message for keylen>blocklen")
strCheck = "5f464f5e5b7848e3885e49b2c385f0694985d0e38966242dc4a5fe3fea4b37d46b65ceced5dcf59438dd840bab22269f0ba7febdb9fcf74602a35666b2a32915"
s = Hmac.HexFromBytes(msg, key, HashAlgorithm.Sha3_512)
Console.WriteLine("HMAC-SHA-3-512: " & vbLf & "{0}", s)
Console.WriteLine("Correct: " & vbLf & "{0}", strCheck)
Debug.Assert([String].Compare(s, strCheck, True) = 0, "HMAC-SHA3-512('Sample #3) failed")
End Sub
Private Shared Sub test_Wipe()
'******************
' WIPE DATA TESTS *
'******************
Dim s As String
Dim b As Byte()
Dim isok As Boolean
Dim fname As String
Dim sbPrivateKey As StringBuilder
Console.WriteLine(vbLf & "WIPE DATA TESTS:")
fname = "ImportantSecret.txt"
File.WriteAllText(fname, "Very important secrets here.")
s = File.ReadAllText(fname)
isok = Wipe.File(fname)
Console.WriteLine("Wipe.File {0}", (If(isok, "OK", "FAILED!")))
b = System.Text.Encoding.[Default].GetBytes("Secret data")
Console.WriteLine("Before Wipe.Data, b = [{0}]", System.Text.Encoding.[Default].GetString(b))
Wipe.Data(b)
Console.WriteLine("After Wipe.Data, b = [{0}]", System.Text.Encoding.[Default].GetString(b))
sbPrivateKey = Rsa.ReadPrivateKey("BobPrivRSAEncrypt.p8e", "password")
Console.WriteLine("Before Wipe.String, sbPrivateKey contains {0} characters.", sbPrivateKey.Length)
Wipe.[String](sbPrivateKey)
Console.WriteLine("After Wipe.String, sbPrivateKey = [{0}]", sbPrivateKey.ToString())
End Sub
Private Shared Sub test_Prompt(doPrompt As Boolean)
'************************
' PASSWORD PROMPT TESTS *
'************************
Dim s As String
If doPrompt Then
s = Pwd.Prompt(32, "My caption for the dialog here")
Console.WriteLine("Password=[{0}]", s)
s = Pwd.Prompt(32, "My caption for the dialog here", "My new prompt:")
Console.WriteLine("Password=[{0}]", s)
End If
End Sub
Private Shared Sub test_Rng(doPrompt As Boolean)
Dim s As String
Dim i As Integer, n As Integer
Dim b As Byte()
Dim fname As String
Dim isok As Boolean
'************
' RNG TESTS *
'************
Console.WriteLine(vbLf & "GENERATE SOME RANDOM DATA...")
For i = 0 To 2
b = Rng.Bytes(24)
Console.WriteLine("RNG={0}", Cnv.ToHex(b))
Next
' And some random numbers in a given range
Console.Write("{random x : -10<=x<=+10} = ")
For i = 0 To 11
n = Rng.Number(-10, +10)
Console.Write("{0} ", n)
Next
Console.Write(vbLf)
' Initialize with a seed file
fname = "seed.dat"
If Not FileExists(fname) Then
' No seed file yet, so we'll make one
If doPrompt Then
' prompting the user for keyboard entropy
Console.WriteLine("Creating a new seed file...")
isok = Rng.MakeSeedFile(fname)
Console.WriteLine("Rng.MakeSeedFile('{0}') returns {1} (expecting 0)", fname, isok)
Debug.Assert(True = isok, "Rng.MakeSeedFile failed")
Else
' Create a dummy seed file to avoid the annoying prompt.
' (this will get overwritten with real random data when initialized)
b = New Byte(Rng.SeedFileSize - 1) {}
File.WriteAllBytes(fname, b)
End If
End If
isok = Rng.Initialize(fname)
Console.WriteLine("Rng.Initialize('{0}') returns {1} (expecting True)", fname, isok)
Debug.Assert(True = isok, "Rng.Initialize failed")
Console.WriteLine("Generate some more random data...")
For i = 0 To 2
b = Rng.Bytes(24)
Console.WriteLine("RNG={0}", Cnv.ToHex(b))
Next
' Update the seedfile
isok = Rng.UpdateSeedFile(fname)
Console.WriteLine("Rng.UpdateSeedFile('{0}') returns {1} (expecting True)", fname, isok)
Debug.Assert(True = isok, "Rng.UpdateSeedFile failed")
If doPrompt Then
Console.WriteLine("Ask user to type some random keystrokes to add entropy...")
b = Rng.BytesWithPrompt(16)
Console.WriteLine("RNG={0}", Cnv.ToHex(b))
Console.WriteLine("And again...")
b = Rng.BytesWithPrompt(16, "Type until we reach 128 bits...", CryptoSysPKI.Rng.Strength.Bits_128)
Console.WriteLine("RNG={0}", Cnv.ToHex(b))
End If
' Test the ability to add "user-entropy"...
s = "this is some user entropy in a string, well it should be!"
b = Rng.Bytes(16, s)
Console.WriteLine("RNG={0}", Cnv.ToHex(b))
' and with some bytes as a "seed"...
b = New Byte(3) {&Hde, &Had, &Hbe, &Hef}
Console.WriteLine("'seed'={0}", Cnv.ToHex(b))
b = Rng.Bytes(16, b)
Console.WriteLine("RNG={0}", Cnv.ToHex(b))
' Do some tests on the RNG function
fname = "Fips140.txt"
isok = Rng.Test(fname)
Console.WriteLine("Rng.Test('{0}') returns {1} (expecting True)", fname, isok)
Debug.Assert(True = isok, "Rng.Test failed")
isok = Rng.Test("")
Console.WriteLine("Rng.Test('{0}') returns {1} (expecting True)", "", isok)
Debug.Assert(True = isok, "Rng.Test failed")
End Sub
'****************************************
' GENERIC BLOCK CIPHER ENCRYPTION TESTS *
'****************************************
Private Shared Sub test_Cipher()
Dim b As Byte()
Dim n As Integer
Dim key As Byte(), plain As Byte(), cipher__1 As Byte(), iv As Byte()
Console.WriteLine(vbLf & "TESTING CIPHER(tdea, bytes):")
' Encrypt in CBC mode using byte arrays
key = Cnv.FromHex("737C791F25EAD0E04629254352F7DC6291E5CB26917ADA32")
iv = Cnv.FromHex("B36B6BFB6231084E")
plain = Cnv.FromHex("5468697320736F6D652073616D706520636F6E74656E742E0808080808080808")
cipher__1 = Cnv.FromHex("d76fd1178fbd02f84231f5c1d2a2f74a4159482964f675248254223daf9af8e4")
b = Cipher.Encrypt(plain, key, iv, CipherAlgorithm.Tdea, Mode.CBC)
Console.WriteLine("KY={0}", Cnv.ToHex(key))
Console.WriteLine("IV={0}", Cnv.ToHex(iv))
Console.WriteLine("PT={0}", Cnv.ToHex(plain))
Console.WriteLine("CT={0}", Cnv.ToHex(b))
Console.WriteLine("OK={0}", Cnv.ToHex(cipher__1))
Debug.Assert(ByteArraysEqual(b, cipher__1), "Cipher.Encrypt{bytes,tdea-CBC} failed")
' Decrypt
b = Cipher.Decrypt(cipher__1, key, iv, CipherAlgorithm.Tdea, Mode.CBC)
Console.WriteLine("P'={0}", Cnv.ToHex(b))
Console.WriteLine("OK={0}", Cnv.ToHex(plain))
Debug.Assert(ByteArraysEqual(b, plain), "Cipher.Decrypt{bytes,tdea-CBC} failed")
Console.WriteLine("TESTING CIPHER(aes128, bytes):")
' AES using byte arrays
key = Cnv.FromHex("0123456789ABCDEFF0E1D2C3B4A59687")
iv = Cnv.FromHex("FEDCBA9876543210FEDCBA9876543210")
' "Now is the time for all good men"
plain = Cnv.FromHex("4E6F77206973207468652074696D6520666F7220616C6C20676F6F64206D656E")
cipher__1 = Cnv.FromHex("c3153108a8dd340c0bcb1dfe8d25d2320ee0e66bd2bb4a313fb75c5638e9e177")
b = Cipher.Encrypt(plain, key, iv, CipherAlgorithm.Aes128, Mode.CBC)
Console.WriteLine("KY={0}", Cnv.ToHex(key))
Console.WriteLine("IV={0}", Cnv.ToHex(iv))
Console.WriteLine("PT={0}", Cnv.ToHex(plain))
Console.WriteLine("CT={0}", Cnv.ToHex(b))
Console.WriteLine("OK={0}", Cnv.ToHex(cipher__1))
Debug.Assert(ByteArraysEqual(b, cipher__1), "Cipher.Encrypt{bytes,Aes128-CBC} failed")
' Decrypt
b = Cipher.Decrypt(cipher__1, key, iv, CipherAlgorithm.Aes128, Mode.CBC)
Console.WriteLine("P'={0}", Cnv.ToHex(b))
Console.WriteLine("OK={0}", Cnv.ToHex(plain))
Debug.Assert(ByteArraysEqual(b, plain), "Cipher.Decrypt{bytes,Aes128-CBC} failed")
' Test some errors
Console.WriteLine("TESTING CIPHER ERRORS:")
Console.WriteLine("Test an invalid key length...")
Dim badkey As Byte() = New Byte(22) {}
b = Cipher.Encrypt(plain, key, Nothing, CipherAlgorithm.Tdea, Mode.ECB)
Console.Write("Cipher.Encrypt returns '{0}' ", Cnv.ToHex(b))
n = General.ErrorCode()
Console.WriteLine("ErrorCode={0} {1}", n, General.ErrorLookup(n))
Debug.Assert(b.Length = 0, "Should be an error")
Console.WriteLine("Test an invalid IV length...")
Dim badiv As Byte() = New Byte(6) {}
b = Cipher.Encrypt(plain, key, badiv, CipherAlgorithm.Aes128, Mode.CTR)
Console.Write("Cipher.Encrypt returns '{0}' ", Cnv.ToHex(b))
n = General.ErrorCode()
Console.WriteLine("ErrorCode={0} {1}", n, General.ErrorLookup(n))
Debug.Assert(b.Length = 0, "Should be an error")
Console.WriteLine("Test invalid length for plaintext...")
Dim badblk As Byte() = New Byte(30) {}
b = Cipher.Encrypt(badblk, key, iv, CipherAlgorithm.Aes128, Mode.CBC)
Console.Write("Cipher.Encrypt returns '{0}' ", Cnv.ToHex(b))
n = General.ErrorCode()
Console.WriteLine("ErrorCode={0} {1}", n, General.ErrorLookup(n))
Debug.Assert(b.Length = 0, "Should be an error")
Console.WriteLine("Test invalid length for ciphertext...")
b = Cipher.Decrypt(badblk, key, iv, CipherAlgorithm.Aes128, Mode.CBC)
Console.Write("Cipher.Decrypt returns '{0}' ", Cnv.ToHex(b))
n = General.ErrorCode()
Console.WriteLine("ErrorCode={0} {1}", n, General.ErrorLookup(n))
Debug.Assert(b.Length = 0, "Should be an error")
Console.WriteLine("...END TESTING CIPHER ERRORS.")
End Sub
Private Shared Sub test_Cipher_Hex()
Dim s As String
Dim n As Integer
Dim keyhex As String, plainStr As String, cipherStr As String, ivhex As String
Console.WriteLine(vbLf & "TESTING CIPHER(tdea, hex):")
' Encrypt in CBC mode using hex strings
keyhex = "737C791F25EAD0E04629254352F7DC6291E5CB26917ADA32"
ivhex = "B36B6BFB6231084E"
plainStr = "5468697320736F6D652073616D706520636F6E74656E742E0808080808080808"
cipherStr = "d76fd1178fbd02f84231f5c1d2a2f74a4159482964f675248254223daf9af8e4"
s = Cipher.Encrypt(plainStr, keyhex, ivhex, CipherAlgorithm.Tdea, Mode.CBC)
Console.WriteLine("KY={0}", keyhex)
Console.WriteLine("IV={0}", ivhex)
Console.WriteLine("PT={0}", plainStr)
Console.WriteLine("CT={0}", s)
Console.WriteLine("OK={0}", cipherStr)
Debug.Assert([String].Compare(s, cipherStr, True) = 0, "Cipher.Encrypt{Hex,tdea-CBC} failed")
' Decrypt
s = Cipher.Decrypt(cipherStr, keyhex, ivhex, CipherAlgorithm.Tdea, Mode.CBC)
Console.WriteLine("P'={0}", s)
Console.WriteLine("OK={0}", plainStr)
Debug.Assert([String].Compare(s, plainStr, True) = 0, "Cipher.Decrypt{Hex,tdea-CBC} failed")
Console.WriteLine("TESTING CIPHER(aes128, hex):")
' AES using hex strings
keyhex = "0123456789ABCDEFF0E1D2C3B4A59687"
ivhex = "FEDCBA9876543210FEDCBA9876543210"
' "Now is the time for all good men"
plainStr = "4E6F77206973207468652074696D6520666F7220616C6C20676F6F64206D656E"
cipherStr = "c3153108a8dd340c0bcb1dfe8d25d2320ee0e66bd2bb4a313fb75c5638e9e177"
s = Cipher.Encrypt(plainStr, keyhex, ivhex, CipherAlgorithm.Aes128, Mode.CBC)
Console.WriteLine("KY={0}", keyhex)
Console.WriteLine("IV={0}", ivhex)
Console.WriteLine("PT={0}", plainStr)
Console.WriteLine("CT={0}", s)
Console.WriteLine("OK={0}", cipherStr)
Debug.Assert([String].Compare(s, cipherStr, True) = 0, "Cipher.Encrypt{Hex,aes128-CBC} failed")
' Decrypt
s = Cipher.Decrypt(cipherStr, keyhex, ivhex, CipherAlgorithm.Aes128, Mode.CBC)
Console.WriteLine("P'={0}", s)
Console.WriteLine("OK={0}", plainStr)
Debug.Assert([String].Compare(s, plainStr, True) = 0, "Cipher.Decrypt{Hex,tdea-CBC} failed")
' Test some errors
Console.WriteLine("TESTING CIPHER ERRORS:")
Console.WriteLine("Test an invalid key...")
s = Cipher.Encrypt(plainStr, "GARBAGEKEY", "", CipherAlgorithm.Tdea, Mode.ECB)
Console.Write("Cipher.Encrypt returns '{0}' ", s)
n = General.ErrorCode()
Console.WriteLine("ErrorCode={0} {1}", n, General.ErrorLookup(n))
Console.WriteLine("Test an invalid IV...")
s = Cipher.Encrypt(plainStr, keyhex, "DEADIV", CipherAlgorithm.Aes128, Mode.CTR)
Console.Write("Cipher.Encrypt returns '{0}' ", s)
n = General.ErrorCode()
Console.WriteLine("ErrorCode={0} {1}", n, General.ErrorLookup(n))
Console.WriteLine("Test invalid length for plaintext...")
s = Cipher.Encrypt("DEADBEEF", keyhex, ivhex, CipherAlgorithm.Aes128, Mode.CBC)
Console.Write("Cipher.Encrypt returns '{0}' ", s)
n = General.ErrorCode()
Console.WriteLine("ErrorCode={0} {1}", n, General.ErrorLookup(n))
Console.WriteLine("...END TESTING CIPHER ERRORS.")
End Sub
Private Shared Sub test_Cipher_Size()
Dim alg As CipherAlgorithm
Console.WriteLine(vbLf & "BLOCK CIPHER SIZES:")
alg = CipherAlgorithm.Aes128
Console.WriteLine("ALG=" & alg.ToString() & ": Cipher.KeyBytes=" & Cipher.KeyBytes(alg) & ", Cipher.BlockBytes=" & Cipher.BlockBytes(alg))
alg = CipherAlgorithm.Aes192
Console.WriteLine("ALG=" & alg.ToString() & ": Cipher.KeyBytes=" & Cipher.KeyBytes(alg) & ", Cipher.BlockBytes=" & Cipher.BlockBytes(alg))
alg = CipherAlgorithm.Aes256
Console.WriteLine("ALG=" & alg.ToString() & ": Cipher.KeyBytes=" & Cipher.KeyBytes(alg) & ", Cipher.BlockBytes=" & Cipher.BlockBytes(alg))
alg = CipherAlgorithm.Tdea
Console.WriteLine("ALG=" & alg.ToString() & ": Cipher.KeyBytes=" & Cipher.KeyBytes(alg) & ", Cipher.BlockBytes=" & Cipher.BlockBytes(alg))
End Sub
Private Shared Sub test_Cipher_File()
Console.WriteLine(vbLf & "TESTING CIPHER FILE:")
' Encrypt random data of random length using alg/mode selected at random
Dim algs As CipherAlgorithm() = New CipherAlgorithm() {CipherAlgorithm.Aes128, CipherAlgorithm.Aes192, CipherAlgorithm.Aes256, CipherAlgorithm.Tdea}
Dim modes As Mode() = New Mode() {Mode.CBC, Mode.CFB, Mode.CTR, Mode.ECB, Mode.OFB}
Dim paddings As Padding() = New Padding() {Padding.[Default], Padding.Pkcs5, Padding.OneAndZeroes, Padding.AnsiX923, Padding.W3CPadding}
Dim opts As Cipher.Opts() = New Cipher.Opts() {Cipher.Opts.[Default], Cipher.Opts.PrefixIV}
Dim file_pt As String = "file-pt.txt"
Dim file_ct As String = "file-ct.dat"
Dim file_ck As String = "file-ck.txt"
Dim alg As CipherAlgorithm
Dim mode__1 As Mode
Dim pad As Padding
Dim opt As Cipher.Opts
Dim key As Byte()
Dim iv As Byte()
Dim b As Byte()
Dim buf As Char()
Dim s As String, s1 As String
Dim len As Integer, r As Integer, counter As Integer
Dim ntests As Integer = 5
Console.WriteLine("NTESTS=" & ntests)
For counter = 0 To ntests - 1
' Create a text file of random data of random length
len = Rng.Number(0, 73)
Console.WriteLine("Test {0}: random len={1}", counter + 1, len)
buf = New Char(len - 1) {}
For i As Integer = 0 To len - 1
' random printable character in [' ', '~']
Dim ch As Char = ChrW(Rng.Number(&H20, &H7e))
buf(i) = ch
Next
s = New String(buf)
Console.WriteLine("PT=[" & s & "]")
File.WriteAllText(file_pt, s)
' Read in the ciphertext bytes as a check
b = File.ReadAllBytes(file_pt)
Console.WriteLine("PT:" & Cnv.ToHex(b))
' Choose an algorithm from list
alg = algs(Rng.Number(0, algs.Length - 1))
Console.WriteLine("ALG=" & alg.ToString())
' Choose a mode
mode__1 = modes(Rng.Number(0, modes.Length - 1))
Console.WriteLine("MODE=" & mode__1.ToString())
' Choose type of padding, if relevant
If mode__1 = Mode.ECB OrElse mode__1 = Mode.CBC Then
pad = paddings(Rng.Number(0, paddings.Length - 1))
Else
' Note: padding is ignored for other modes
pad = Padding.NoPad
End If
Console.WriteLine("PAD=" & pad.ToString())
' Choose an advanced option
opt = opts(Rng.Number(0, opts.Length - 1))
Console.WriteLine("OPT=" & opt.ToString())
' Generate random key of required length
key = Rng.Bytes(Cipher.KeyBytes(alg))
Console.WriteLine("KY:" & Cnv.ToHex(key))
' Generate IV of required length (ignored for ECB)
If mode__1 <> Mode.ECB Then
iv = Rng.Bytes(Cipher.BlockBytes(alg))
Console.WriteLine("IV:" & Cnv.ToHex(iv))
Else
iv = Nothing
End If
' Encrypt
r = Cipher.FileEncrypt(file_ct, file_pt, key, iv, alg, mode__1, _
pad, opt)
Console.WriteLine("Cipher.FileEncrypt() returns {0} (expecting 0)", r)
Debug.Assert(0 = r, "Cipher.FileEncrypt failed.")
' Read in the ciphertext bytes as a check
b = File.ReadAllBytes(file_ct)
Console.WriteLine("CT:" & Cnv.ToHex(b))
' Decrypt
If (opt And Cipher.Opts.PrefixIV) = Cipher.Opts.PrefixIV Then
' IV is not required if already exists prefixed to file
iv = Nothing
End If
r = Cipher.FileDecrypt(file_ck, file_ct, key, iv, alg, mode__1, _
pad, opt)
Console.WriteLine("Cipher.FileDecrypt() returns {0} (expecting 0)", r)
Debug.Assert(0 = r, "Cipher.FileDecrypt failed.")
' Read in the decrypted plaintext as a check
s1 = File.ReadAllText(file_ck)
Console.WriteLine("P1:[" & s & "]")
Debug.Assert(s1 = s)
Next
End Sub
Private Shared Sub test_KeyWrap()
' **************
' KEY WRAPPING
' **************
Dim arrPlain As Byte(), arrKey As Byte()
Dim arrCipher As Byte(), bcheck As Byte()
Console.WriteLine(vbLf & "KEY WRAPPING WITH BLOCK CIPHER:")
' Some test AES-128 key material data
arrPlain = Cnv.FromHex("00112233 44556677 8899aabb ccddeeff")
Console.WriteLine("Key material={0}", Cnv.ToHex(arrPlain))
' Key Encryption Key
arrKey = Cnv.FromHex("c17a44e8 e28d7d64 81d1ddd5 0a3b8914")
Console.WriteLine("KEK ={0}", Cnv.ToHex(arrKey))
' Wrap with AES128-Wrap algorithm
Console.WriteLine("Using AES128-Wrap")
arrCipher = Cipher.KeyWrap(arrPlain, arrKey, CipherAlgorithm.Aes128)
Debug.Assert(arrCipher.Length > 0, "Cipher.KeyWrap failed.")
Console.WriteLine("Wrapped Key ={0}", Cnv.ToHex(arrCipher))
' Check we can unwrap it
bcheck = Cipher.KeyUnwrap(arrCipher, arrKey, CipherAlgorithm.Aes128)
Debug.Assert(arrCipher.Length > 0, "Cipher.KeyUnwrap failed.")
Console.WriteLine("Check ={0}", Cnv.ToHex(bcheck))
Debug.Assert(ByteArraysEqual(bcheck, arrPlain), "Unwrapped key is different.")
End Sub
Private Shared Sub test_Autack()
Dim s As String
Dim b As Byte()
Dim msg As Byte()
Dim hexDigest As String
Dim strCheck As String
Dim xmlKey As String, msgStr As String, keyStr As String
Dim keyBits As Integer
' *********************
' AUTACK SIGNATURES
' *********************
' (This is specialist stuff)
Console.WriteLine(vbLf & "AUTACK SIGNATURES:")
' Ref: EDIFACT, Section 12.9 Worked Examples
' Short RSA private key in XML format -- this is NOT SECURE!
xmlKey = "<RSAKeyPair>" & "<Modulus EncodingType='hexBinary'>" & "A59FBFE322244760E5B430B197967FDCF240D6B134D0F3783EDE652B565AC9C6" & "105768F11EE59AED359ED6DB6CE6AFC84233F35B60895B90AF85A66E598C15CE" & "FB860EA37CCEDB4A45B4C0594974EB76BC955C43B56B17940DFDCAB3E0C03F49" & "A308835772405E74085BF59FBA726969CBE348DAB6F9456DA57B40B64E6E3C65</Modulus>" & "<Exponent EncodingType='hexBinary'>010001</Exponent>" & "<D EncodingType='hexBinary'>" & "244FFDD97DED0FD4441089638A7D85FBAA86823BB87D7E7FF4E2BC322FFCF843" & "AB660ABD60DD8CE5E8AD72648A001AF6B06324FE3A106B89B19DFF232F116A5F" & "4C7151C38D4A132E0EEBC55EC0DC44EBE0CCBA8FCACB6C93F32997DAD8B9ACEA" & "B4BEC5D4A1F38A2218337C8C92D301C433A7E02EB4A456F5DE83AE1AD76E3D31</D>" & "</RSAKeyPair>"
msgStr = "abc"
' The correct answer
strCheck = "4897C41FFCB27C4B77F0711890C5C48E9C42AE5A1548E1A4653CDF444C60350F" & "635A16393D5862DCBD83EF3727435B750CE889EB3C48C02EA0B14F6F6B4BA0D1" & "E16A010D42830110AB36AB183F2976B784656D4272A6215A44EAA504610C59AC" & "C615E661BE4EC5ACE09B8D9DCE165F0CE71AE8743266ED2F20F35862B3C9252D"
keyStr = Rsa.FromXMLString(xmlKey, False)
keyBits = Rsa.KeyBits(keyStr)
Console.WriteLine("Private key is {0} bits long", keyBits)
' Compute message digest of data
hexDigest = Hash.HexFromString(msgStr, HashAlgorithm.Sha1)
Console.WriteLine("Message-to-encode=Digest={0}", hexDigest)
' Convert digest to byte array
msg = Cnv.FromHex(hexDigest)
' Encode digest using ISO-9796-1
b = Rsa.EncodeMsgIso9796(msg, keyBits)
Debug.Assert(b.Length > 0, "Failed to Encode for ISO9796-1")
Console.WriteLine("Encoded block=" & vbLf & "{0}", Cnv.ToHex(b))
' Sign block with RSA private key
' -- use special RSA2 method with magic nibble value 6
b = Rsa.RawPrivate(b, keyStr, &H6)
' Convert to hex encoding
s = Cnv.ToHex(b)
Console.WriteLine("Autack Signature=" & vbLf & "{0}", s)
Debug.Assert(String.Compare(s, strCheck, True) = 0, "Autack signature is wrong")
' Now we verify the Autack signature using the public key
xmlKey = "<RSAKeyValue>" & "<Modulus EncodingType='hexBinary'>" & "A59FBFE322244760E5B430B197967FDCF240D6B134D0F3783EDE652B565AC9C6" & "105768F11EE59AED359ED6DB6CE6AFC84233F35B60895B90AF85A66E598C15CE" & "FB860EA37CCEDB4A45B4C0594974EB76BC955C43B56B17940DFDCAB3E0C03F49" & "A308835772405E74085BF59FBA726969CBE348DAB6F9456DA57B40B64E6E3C65</Modulus>" & "<Exponent EncodingType='hexBinary'>010001</Exponent>" & "</RSAKeyValue>"
' Read in the public key from the XML string
keyStr = Rsa.FromXMLString(xmlKey, True)
keyBits = Rsa.KeyBits(keyStr)
Console.WriteLine("Public key is {0} bits long", keyBits)
' Convert the hex singature string to a byte array
b = Cnv.FromHex(s)
' Decrypt the signature block using the public key
' -- use special RSA2 method with magic nibble value 0x6
b = Rsa.RawPublic(b, keyStr, &H6)
Console.WriteLine("Decrypted block=" & vbLf & "{0}", Cnv.ToHex(b))
' Recover the message from the block using the ISO9796-1 method
msg = Rsa.DecodeMsgIso9796(b, keyBits)
Debug.Assert(msg.Length > 0, "Failed to Decode for ISO9796-1")
s = Cnv.ToHex(msg)
Console.WriteLine("Recovered message='{0}'", s)
' This should be equal to the message digest we prepared earlier
Debug.Assert(String.Compare(s, hexDigest, True) = 0, "Recovered message is wrong")
End Sub
Private Shared Sub test_PEM()
Dim s As String
Dim r As Integer
Dim fnameInput As String, fnameOutput As String, fnameOutputUnix As String
Dim hexDigest As String
Dim strCheck As String
' *********************
' PEM FILE CONVERSIONS
' *********************
Console.WriteLine(vbLf & "PEM FILE CONVERSIONS:")
fnameInput = "AliceRSASignByCarl.cer"
fnameOutput = "AliceRSASignByCarl.pem.cer"
fnameOutputUnix = "AliceRSASignByCarl.unix.cer"
' Make a PEM file from a binary one
r = Pem.FileFromBinFile(fnameOutput, fnameInput, "CERTIFICATE", 72)
Debug.Assert(r = 0, "Pem.FileFromBinFile failed.")
Console.WriteLine("Created new PEM file {0}", fnameOutput)
' Read and display
s = File.ReadAllText(fnameOutput)
Console.WriteLine("{0}", s)
' Check these two certs have the same thumbprint
hexDigest = X509.CertThumb(fnameOutput, HashAlgorithm.Sha1)
Console.WriteLine("{1}=SHA-1({0})", fnameOutput, hexDigest)
strCheck = hexDigest
hexDigest = X509.CertThumb(fnameInput, HashAlgorithm.Sha1)
Console.WriteLine("{1}=SHA-1({0})", fnameInput, hexDigest)
Debug.Assert(strCheck = hexDigest, "Digests are not equal")
' Output in Unix/SSL LF line-endings, instead of Windows CR-LF endings.
r = Pem.FileFromBinFile(fnameOutputUnix, fnameInput, "CERTIFICATE", 72, True)
Debug.Assert(r = 0, "Pem.FileFromBinFile failed.")
Console.WriteLine("Created new PEM file {0}", fnameOutputUnix)
' Read and display
s = File.ReadAllText(fnameOutput)
Console.WriteLine("{0}", s)
' Check these two certs have the same thumbprint
hexDigest = X509.CertThumb(fnameOutputUnix, HashAlgorithm.Sha1)
Console.WriteLine("{1}=SHA-1({0})", fnameOutputUnix, hexDigest)
Debug.Assert(strCheck = hexDigest, "Digests are not equal")
' Now make a new binary file back from the PEM file
fnameInput = fnameOutput
fnameOutput = "AliceRSASignByCarl-dup.cer"
r = Pem.FileToBinFile(fnameOutput, fnameInput)
Debug.Assert(r = 0, "Pem.FileToBinFile failed.")
Console.WriteLine("Created binary file {0}", fnameOutput)
' Check we have the same thumbprint
hexDigest = X509.CertThumb(fnameOutput, HashAlgorithm.Sha1)
Console.WriteLine("{1}=SHA-1({0})", fnameOutput, hexDigest)
Debug.Assert(strCheck = hexDigest, "Digests are not equal")
End Sub
Private Shared Sub test_Padding()
Dim s As String
Dim i As Integer
Dim b As Byte()
' *************************
' PADDING FOR BLOCK CIPHERS
' *************************
Console.WriteLine(vbLf & "PADDING FOR BLOCK CIPHERS:")
' 1. Pad a byte array of 5 bytes for Triple DES ECB/CBC mode
b = New Byte(4) {&Hff, &Hff, &Hff, &Hff, &Hff}
Console.WriteLine("Input =0x{0}", Cnv.ToHex(b))
b = Cipher.Pad(b, CipherAlgorithm.Tdea)
Console.WriteLine("Padded =0x{0}", Cnv.ToHex(b))
' Now strip the padding
b = Cipher.Unpad(b, CipherAlgorithm.Tdea)
Console.WriteLine("Unpadded=0x{0}", Cnv.ToHex(b))
' 2. Pad a byte array of 18 bytes for AES ECB/CBC mode
b = New Byte(17) {}
For i = 0 To b.Length - 1
b(i) = &Hff
Next
Console.WriteLine("Input =0x{0}", Cnv.ToHex(b))
b = Cipher.Pad(b, CipherAlgorithm.Aes128)
Console.WriteLine("Padded =0x{0}", Cnv.ToHex(b))
' Now strip the padding
b = Cipher.Unpad(b, CipherAlgorithm.Aes128)
Console.WriteLine("Unpadded=0x{0}", Cnv.ToHex(b))
' 3. Pad an empty byte array for TDEA
b = New Byte(-1) {}
Console.WriteLine("Input =0x{0}", Cnv.ToHex(b))
b = Cipher.Pad(b, CipherAlgorithm.Tdea)
Console.WriteLine("Padded =0x{0}", Cnv.ToHex(b))
' Now strip the padding
b = Cipher.Unpad(b, CipherAlgorithm.Tdea)
Console.WriteLine("Unpadded=0x{0}", Cnv.ToHex(b))
' 4. Pad a hex string for AES
s = "ff"
Console.WriteLine("Input ='{0}'", s)
s = Cipher.Pad(s, CipherAlgorithm.Aes128)
Console.WriteLine("Padded ='{0}'", s)
' Now strip the padding
s = Cipher.Unpad(s, CipherAlgorithm.Aes128)
Console.WriteLine("Unpadded='{0}'", s)
' 5. Pad an empty hex string for AES
s = ""
Console.WriteLine("Input ='{0}'", s)
s = Cipher.Pad(s, CipherAlgorithm.Aes128)
Console.WriteLine("Padded ='{0}'", s)
' Now strip the padding
s = Cipher.Unpad(s, CipherAlgorithm.Aes128)
Console.WriteLine("Unpadded='{0}'", s)
' 6. Pad single byte using OneAndZeroes
Console.WriteLine("OneAndZeroes")
s = "ff"
Console.WriteLine("Input ='{0}'", s)
s = Cipher.Pad(s, CipherAlgorithm.Aes128, Padding.OneAndZeroes)
Console.WriteLine("Padded ='{0}'", s)
' Now strip the padding
s = Cipher.Unpad(s, CipherAlgorithm.Aes128, Padding.OneAndZeroes)
Console.WriteLine("Unpadded='{0}'", s)
End Sub
Private Shared Sub test_Cnv_hex()
Dim s As String
Dim b As Byte()
'**************************
' HEX CONVERSION TESTS *
'**************************
Console.WriteLine(vbLf & "HEX CONVERSION TESTS:")
s = "DEADbeefCAFEBABE01"
b = Cnv.FromHex(s)
Console.WriteLine("'{0}'->0x{1}", s, Cnv.ToHex(b))
' [v11.1] NB This behaviour has changed: punctuation chars like ':' and whitespace are OK,
' but letters [G-Zg-z] and other non-hex chars are now an error
Console.WriteLine("The Cnv.FromHex() method will ignore punctuation characters and whitespace...")
' Convert a hex string containing ":" and space characters -> 16 bytes
s = "30:21:30:09:06:05:2B:0E: 03:02:1A:05:00:04:14:00"
b = Cnv.FromHex(s)
Console.WriteLine("Cnv.FromHex('{0}')->", s)
Console.WriteLine("...to give a valid byte array:")
Console.WriteLine("{0} ({1} bytes)", Cnv.ToHex(b), b.Length)
Debug.Assert(16 = b.Length, "Cnv.FromHex failed: wrong # of bytes")
Console.WriteLine("...but will give an error for invalid chars like [G-Zg-z]...")
s = "FEGCBA9876543210"
Console.WriteLine("Bad hex = '{0}'", s)
b = Cnv.FromHex(s)
Console.WriteLine("Cnv.FromHex() returns '{0}' (expected empty => error)", Cnv.ToHex(b))
Debug.Assert(b.Length = 0)
Console.WriteLine(General.FormatErrorMessage())
End Sub
Private Shared Sub test_Cnv_base64()
Dim s As String
Dim b As Byte()
Dim b64str As String
'**************************
' BASE64 CONVERSION TESTS *
'**************************
Console.WriteLine(vbLf & "BASE64 CONVERSION TESTS:")
' 0xFEDCBA9876543210 in base64
b64str = "/ty6mHZUMhA="
b = Cnv.FromBase64(b64str)
Console.WriteLine("'{0}'->0x{1}", b64str, Cnv.ToHex(b))
' Back to base64
s = Cnv.ToBase64(b)
Console.WriteLine("In base64='{0}'", s)
' Directly to hex
Console.WriteLine("In hex='{0}'", Cnv.HexFromBase64(b64str))
' hex -> base64
s = "FEDCBA9876543210"
b64str = Cnv.Base64FromHex(s)
Console.WriteLine("0x{0}->'{1}'", s, b64str)
' string -> base64
s = "México"
b64str = Cnv.ToBase64(s)
' base64 -> hex
Console.WriteLine("'{0}'->'{1}'", s, b64str)
Console.WriteLine("In hex='{0}'", Cnv.HexFromBase64(b64str))
' base64 -> string
s = Cnv.StringFromBase64(b64str)
Console.WriteLine("'{0}'->'{1}'", b64str, s)
' Use a string with invalid base64 characters
s = "%/ty6m.!*HZUMhA=&é"
' Try with unfiltered string = an error [New in v11.1]
Console.WriteLine("Bad base64 = '{0}'", s)
b = Cnv.FromBase64(s)
Console.WriteLine("Cnv.FromBase64() returns '{0}' (expected empty => error)", Cnv.ToHex(b))
Debug.Assert(b.Length = 0)
Console.WriteLine(General.FormatErrorMessage())
' Filter out non-base64 chars (%.!*&) and e-acute
b64str = Cnv.Base64Filter(s)
Console.WriteLine("Filter: '{0}'->'{1}'->0x{2}", s, b64str, Cnv.HexFromBase64(b64str))
Debug.Assert(Cnv.HexFromBase64(b64str) = "FEDCBA9876543210", "Cnv.FilterBase64 failed")
End Sub
Private Shared Sub test_Cnv_other()
Dim s As String
Dim n As Integer
Dim b As Byte()
Dim fname As String
Dim s1 As String
Dim b1 As Byte()
'*******************
' CONVERSION TESTS *
'*******************
Console.WriteLine(vbLf & "OTHER CONVERSION TESTS:")
' Create a string that includes some Latin-1 accented characters:
s = "abcóéíáñ"
' This should contain the following 8 characters:
' U+0061 LATIN SMALL LETTER A
' U+0062 LATIN SMALL LETTER B
' U+0063 LATIN SMALL LETTER C
' U+00F3 LATIN SMALL LETTER O WITH ACUTE
' U+00E9 LATIN SMALL LETTER E WITH ACUTE
' U+00ED LATIN SMALL LETTER I WITH ACUTE
' U+00E1 LATIN SMALL LETTER A WITH ACUTE
' U+00F1 LATIN SMALL LETTER N WITH TILDE
Console.WriteLine("Use GetBytes to convert a string to bytes...")
Console.WriteLine("Test string='{0}' ({1} chars)", s, s.Length)
Debug.Assert(8 = s.Length, "String must be 8 chars for these tests")
Console.WriteLine("Use GetBytes in 'Default' mode:")
b = System.Text.Encoding.[Default].GetBytes(s)
Console.WriteLine("Default.GetBytes=>{0} ({1} bytes)", Cnv.ToHex(b), b.Length)
Console.WriteLine("Use GetBytes in 'Latin-1' mode. Three alternatives:")
b = System.Text.Encoding.GetEncoding("iso-8859-1").GetBytes(s)
Console.WriteLine("GetEncoding(""iso-8859-1"").GetBytes=>{0} ({1} bytes)", Cnv.ToHex(b), b.Length)
' Code page 28591 == iso-8859-1
b = System.Text.Encoding.GetEncoding(28591).GetBytes(s)
Console.WriteLine("GetEncoding(28591).GetBytes=>{0} ({1} bytes)", Cnv.ToHex(b), b.Length)
' Note: Windows-1252 is *almost* the same as ISO-8859-1
b = System.Text.Encoding.GetEncoding(1252).GetBytes(s)
Console.WriteLine("GetEncoding(1252).GetBytes =>{0} ({1} bytes)", Cnv.ToHex(b), b.Length)
Console.WriteLine("But in UTF-8 the bytes are different:")
b = System.Text.Encoding.UTF8.GetBytes(s)
Console.WriteLine("UTF8.GetBytes=>{0} ({1} bytes)", Cnv.ToHex(b), b.Length)
' Check that byte array contains valid UTF-8 characters
b = System.Text.Encoding.UTF8.GetBytes(s)
n = Cnv.CheckUTF8(b)
Console.WriteLine("Cnv.CheckUTF8(b)={0} (expected 2)", n)
Debug.Assert(2 = n, "Expected return value 2")
' Test a file instead of a byte array [New in v3.7]
fname = "test-utf8.txt"
File.WriteAllBytes(fname, b)
n = Cnv.CheckUTF8File(fname)
Console.WriteLine("Cnv.CheckUTF8File({1})={0} (expected 2)", n, fname)
Debug.Assert(2 = n, "Expected return value 2")
' AN ASIDE TO DO SOME TESTS ON THE BOUNDARIES...
' Test subtle differences between ISO-8859-1 and WINDOWS-1252
' Create a byte array representing some characters in ISO-8859-1 "hole"
b1 = New Byte() {&H61, &H93, &H86, &H87, &H8c, &H94, _
&H62}
Console.WriteLine("Show difference between ISO-8859-1 and Windows-1252 for chars 0x80 to 0x9E...")
Console.WriteLine("Test bytes for GetString={0}", Cnv.ToHex(b1))
s1 = System.Text.Encoding.GetEncoding("iso-8859-1").GetString(b1)
Console.WriteLine("s1(iso-8859-1)='{0}'", s1)
s1 = System.Text.Encoding.GetEncoding(1252).GetString(b1)
Console.WriteLine("s1(Windows-1252)='{0}'", s1)
' Check code page values
Dim encod As Encoding = Encoding.[Default]
Console.WriteLine("Default code page={0} (usually 1252, but might not be)", encod.CodePage)
encod = Encoding.GetEncoding("iso-8859-1")
Console.WriteLine("iso-8859-1 code page={0} (expecting 28591)", encod.CodePage)
' Try converting invalid UTF-8 bytes
Console.WriteLine("Try passing invalid UTF-8 bytes to UTF8.GetString...")
b1 = New Byte() {&Hef, &Hbf, &Hbf}
Console.WriteLine("Pass illegal UTF-8 bytes to UTF8.GetString <- 0x{0}", Cnv.ToHex(b1))
s1 = System.Text.Encoding.UTF8.GetString(b1)
Console.WriteLine("s1(UTF8)='{0}' Cnv.CheckUTF={1} (0=>invalid UTF-8)", s1, Cnv.CheckUTF8(b1))
b1 = New Byte() {&Hc3, &Hb3, &Hc3, &Ha9, &Hc3, &Had, _
&Hc3, &Ha1, &Hc3}
Console.WriteLine("Pass chopped UTF-8 bytes to UTF8.GetString <- 0x{0}", Cnv.ToHex(b1))
s1 = System.Text.Encoding.UTF8.GetString(b1)
Console.WriteLine("s1(UTF8)='{0}' Cnv.CheckUTF={1}", s1, Cnv.CheckUTF8(b1))
' Use byte-to-byte encoding conversions
Console.WriteLine("Use Cnv.ByteEncoding to convert bytes between different encodings...")
' b contains UTF-8-encoded data, so convert to Latin-1
b1 = Cnv.ByteEncoding(b, Cnv.EncodingConversion.Latin1_From_Utf8)
Console.Write("Cnv.ByteEncoding(Latin1_From_Utf8): ")
Console.WriteLine("{0} ({1} bytes)", Cnv.ToHex(b), b.Length)
Console.WriteLine(" --> {0} ({1} bytes)", Cnv.ToHex(b1), b1.Length)
Debug.Assert(8 = b1.Length, "Invalid conversion: expected 8 bytes")
n = Cnv.CheckUTF8(b1)
Console.WriteLine("Cnv.CheckUTF8(b1) returns {0} (expected 0 => not valid UTF-8)", n)
Debug.Assert(0 = n, "Cnv.CheckUTF8(b1) failed")
' and back to UTF-8
b = Cnv.ByteEncoding(b1, Cnv.EncodingConversion.Utf8_From_Latin1)
Console.Write("Cnv.ByteEncoding(Utf8_From_Latin1): ")
Console.WriteLine("{0} ({1} bytes)", Cnv.ToHex(b1), b1.Length)
Console.WriteLine(" --> {0} ({1} bytes)", Cnv.ToHex(b), b.Length)
Debug.Assert(13 = b.Length, "Invalid conversion: expected 13 bytes")
n = Cnv.CheckUTF8(b)
Console.WriteLine("Cnv.CheckUTF8(b) returns {0} (expected 2 => Valid UTF-8 w/8-bit ANSI)", n)
Debug.Assert(2 = n, "Cnv.CheckUTF8(b) failed")
' Do test in the documentation that fails
b = Cnv.FromHex("61E962")
' A valid byte array representing the Latin-1 string "aéb" but invalid UTF-8
b1 = Cnv.ByteEncoding(b, Cnv.EncodingConversion.Latin1_From_Utf8)
n = General.ErrorCode()
' NB remember ErrorCode before we call Cnv that clears it!
Console.WriteLine("Cnv.ByteEncoding(0x{0},Latin1_From_Utf8) = '{1}' (expected empty result)", Cnv.ToHex(b), Cnv.ToHex(b1))
Console.WriteLine("General.ErrorCode={0} {1} (expected error here)", n, General.ErrorLookup(n))
End Sub
Private Shared Sub test_Cnv_base58()
Dim s As String
Dim b As Byte()
Dim b58str As String
'**************************
' BASE58 CONVERSION TESTS *
'**************************
' Fixed typos [2021-10-17]
Console.WriteLine(vbLf & "BASE58 CONVERSION TESTS:")
b58str = "16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM"
b = Cnv.FromBase58(b58str)
Console.WriteLine("'" & b58str & "'->" & vbLf & "0x" & Cnv.ToHex(b))
' Back to base58
s = Cnv.ToBase58(b)
Console.WriteLine("In base58='" & s & "'")
Debug.Assert(s = b58str, "Base58 conversion failed")
' Convert directly from base58 to hex
s = Cnv.ToHex(Cnv.FromBase58(b58str))
Console.WriteLine("In hex='" & s & "'")
Debug.Assert(s = "00010966776006953D5567439E5E39F86A0D273BEED61967F6", "Cnv.FromBase58 failed")
End Sub
Private Shared Sub test_CipherPad()
Dim s As String
Dim key As Byte(), iv As Byte(), pt As Byte(), ct As Byte(), p1 As Byte(), correct As Byte()
Console.WriteLine(vbLf & "TEST THE CIPHER CLASS WITH PADDING...")
Console.WriteLine("Tdea/CBC/Pkcs5")
key = Cnv.FromHex("737C791F25EAD0E04629254352F7DC6291E5CB26917ADA32")
iv = Cnv.FromHex("B36B6BFB6231084E")
Console.WriteLine("KY=" & Cnv.ToHex(key))
Console.WriteLine("IV=" & Cnv.ToHex(iv))
pt = Cnv.FromHex("5468697320736F6D652073616D706520636F6E74656E742E")
Console.WriteLine("PT=" & Cnv.ToHex(pt))
Console.WriteLine("PT='" & System.Text.Encoding.[Default].GetString(pt) & "'")
correct = Cnv.FromHex("d76fd1178fbd02f84231f5c1d2a2f74a4159482964f675248254223daf9af8e4")
ct = Cipher.Encrypt(pt, key, iv, CipherAlgorithm.Tdea, Mode.CBC, Padding.Pkcs5)
Console.WriteLine("CT=" & Cnv.ToHex(ct))
Console.WriteLine("OK=" & Cnv.ToHex(correct))
Debug.Assert(ByteArraysEqual(ct, correct), "Cipher.Encrypt with padding failed")
' Now decrypt
p1 = Cipher.Decrypt(ct, key, iv, CipherAlgorithm.Tdea, Mode.CBC, Padding.Pkcs5)
Console.WriteLine("P'=" & Cnv.ToHex(p1))
Console.WriteLine("P'='" & System.Text.Encoding.[Default].GetString(p1) & "'")
Debug.Assert(ByteArraysEqual(p1, pt), "Cipher.Decrypt with padding failed")
Console.WriteLine("Aes128/CBC/pkcs5")
key = Cnv.FromHex("0123456789ABCDEFF0E1D2C3B4A59687")
iv = Cnv.FromHex("FEDCBA9876543210FEDCBA9876543210")
Console.WriteLine("KY=" & Cnv.ToHex(key))
Console.WriteLine("IV=" & Cnv.ToHex(iv))
s = "Now is the time for all good men to"
pt = System.Text.Encoding.[Default].GetBytes(s)
Console.WriteLine("PT=" & Cnv.ToHex(pt))
Console.WriteLine("PT='" & System.Text.Encoding.[Default].GetString(pt) & "'")
correct = Cnv.FromHex("C3153108A8DD340C0BCB1DFE8D25D2320EE0E66BD2BB4A313FB75C5638E9E17753C7E8DF5975A36677355F5C6584228B")
ct = Cipher.Encrypt(pt, key, iv, CipherAlgorithm.Aes128, Mode.CBC, Padding.Pkcs5)
Console.WriteLine("CT=" & Cnv.ToHex(ct))
Console.WriteLine("OK=" & Cnv.ToHex(correct))
Debug.Assert(ByteArraysEqual(ct, correct), "Cipher.Encrypt with padding failed")
' Now decrypt
p1 = Cipher.Decrypt(ct, key, iv, CipherAlgorithm.Aes128, Mode.CBC, Padding.Pkcs5)
Console.WriteLine("P'=" & Cnv.ToHex(p1))
Console.WriteLine("P'='" & System.Text.Encoding.[Default].GetString(p1) & "'")
Debug.Assert(ByteArraysEqual(p1, pt), "Cipher.Decrypt with padding failed")
p1 = Cipher.Decrypt(ct, key, iv, CipherAlgorithm.Aes128, Mode.CBC, Padding.NoPad)
Console.WriteLine("Pn=" & Cnv.ToHex(p1))
Console.WriteLine("Aes128/ECB/OneAndZeroes...")
ct = Cipher.Encrypt(pt, key, iv, CipherAlgorithm.Aes128, Mode.ECB, Padding.OneAndZeroes)
Console.WriteLine("CT=" & Cnv.ToHex(ct))
p1 = Cipher.Decrypt(ct, key, iv, CipherAlgorithm.Aes128, Mode.ECB, Padding.NoPad)
Console.WriteLine("Pn=" & Cnv.ToHex(p1))
p1 = Cipher.Decrypt(ct, key, iv, CipherAlgorithm.Aes128, Mode.ECB, Padding.OneAndZeroes)
Console.WriteLine("P'=" & Cnv.ToHex(p1))
Console.WriteLine("P'='" & System.Text.Encoding.[Default].GetString(p1) & "'")
Debug.Assert(ByteArraysEqual(p1, pt))
End Sub
Private Shared Sub test_Pbkdf2()
'***************
' PBKDF2 TESTS *
'***************
Dim n As Integer
Dim arrKey As Byte()
Dim strCheck As String
Dim keyStr As String
Dim arrPwd As Byte(), salt As Byte()
Dim saltHex As String
Console.WriteLine(vbLf & "TESTING PBKDF2...")
' convert password string to bytes
arrPwd = System.Text.Encoding.[Default].GetBytes("password")
' make a salt
salt = New Byte() {&H78, &H57, &H8e, &H5a, &H5d, &H63, _
&Hcb, &H6}
' create a 24-byte (192-bit) key
n = 24
arrKey = Pbe.Kdf2(n, arrPwd, salt, 2048)
Debug.Assert(arrKey.Length > 0, "ERROR with Pbe.Kdf2")
Console.WriteLine("Key({0})={1}", n * 8, Cnv.ToHex(arrKey))
' and again for a 64-byte (512-bit) key
n = 64
arrKey = Pbe.Kdf2(n, arrPwd, salt, 2048)
Debug.Assert(arrKey.Length > 0, "ERROR with Pbe.Kdf2")
Console.WriteLine("Key({0})={1}", n * 8, Cnv.ToHex(arrKey))
' Same example using hex format
saltHex = "78578e5a5d63cb06"
n = 24
strCheck = "BFDE6BE94DF7E11DD409BCE20A0255EC327CB936FFE93643"
keyStr = Pbe.Kdf2(n, "password", saltHex, 2048)
Debug.Assert(keyStr.Length > 0, "ERROR with PbeKdf2/Hex")
Console.WriteLine("Key({0})={1}", n * 8, keyStr)
' Compare with known test vector
Debug.Assert([String].Compare(strCheck, keyStr, True) = 0, "PBKDF Derived key {HMAC-SHA-1} does not match test vector")
' Use different hash function (SHA-256) in KDF
Console.WriteLine("Using SHA-256 in KDF...")
n = 24
arrKey = Pbe.Kdf2(n, arrPwd, salt, 2048, HashAlgorithm.Sha256)
Debug.Assert(arrKey.Length > 0, "ERROR with Pbe.Kdf2")
Console.WriteLine("Key({0})={1}", n * 8, Cnv.ToHex(arrKey))
' using hex format
saltHex = "78578e5a5d63cb06"
n = 24
strCheck = "97B5A91D35AF542324881315C4F849E327C4707D1BC9D322"
keyStr = Pbe.Kdf2(n, "password", saltHex, 2048, HashAlgorithm.Sha256)
Debug.Assert(keyStr.Length > 0, "ERROR with PbeKdf2/Hex")
Console.WriteLine("Key({0})={1}", n * 8, keyStr)
' Compare with known test vector
Debug.Assert([String].Compare(strCheck, keyStr, True) = 0, "PBKDF Derived key {HMAC-SHA-256} does not match test vector")
' And again using SHA-224 in KDF
Console.WriteLine("Using SHA-224 in KDF...")
n = 24
arrKey = Pbe.Kdf2(n, arrPwd, salt, 2048, HashAlgorithm.Sha224)
Debug.Assert(arrKey.Length > 0, "ERROR with Pbe.Kdf2")
Console.WriteLine("Key({0})={1}", n * 8, Cnv.ToHex(arrKey))
' using hex format
saltHex = "78578e5a5d63cb06"
n = 24
strCheck = "10CFFEDFB13503519969151E466F587028E0720B387F9AEF"
keyStr = Pbe.Kdf2(n, "password", saltHex, 2048, HashAlgorithm.Sha224)
Debug.Assert(keyStr.Length > 0, "ERROR with PbeKdf2/Hex")
Console.WriteLine("Key({0})={1}", n * 8, keyStr)
' Compare with known test vector
Debug.Assert([String].Compare(strCheck, keyStr, True) = 0, "PBKDF Derived key {HMAC-SHA-224} does not match test vector")
End Sub
Private Shared Sub test_Asn1()
'***************
' ASN.1 TESTS *
'***************
Dim s As String
Dim fname As String
Dim b64str As String
' Alice's RSA public key as a base64 string
b64str = "MIGJAoGBAOCJczmN2PX16Id2OX9OsAW7U4PeD7er3H3HdSkNBS5tEt+mhibU" & "0m+qWCn8l+z6glEPMIC+sVCeRkTxLLvYMs/GaG8H2bBgrL7uNAlqE/X3BQWT" & "3166NVbZYf8Zf8mB5vhs6odAcO+sbSx0ny36VTq5mXcCpkhSjE7zVzhXdFdf" & "AgMBAAE="
Console.WriteLine(vbLf & "TESTING ASN.1...")
fname = "smallca.cer"
Console.WriteLine("FILE: {0}", fname)
s = Asn1.TextDumpToString(fname, 0)
Debug.Assert(s.Length > 0, "Asn1.TextDumpToString failed")
Console.WriteLine(s)
' Pass data as a base64 string
s = "MAQwAgUA"
' Very simple ASN.1 data
Console.WriteLine("STRING: '{0}'", s)
s = Asn1.TextDumpToString("MAQwAgUA", 0)
Debug.Assert(s.Length > 0, "Asn1.TextDumpToString failed")
Console.WriteLine(s)
' Again, but without comments
Console.WriteLine("Again, without comments...")
s = Asn1.TextDumpToString("MAQwAgUA", Asn1.Options.NoComments)
Debug.Assert(s.Length > 0, "Asn1.TextDumpToString failed")
Console.WriteLine(s)
Console.WriteLine("Pass data as base64 string...")
Console.WriteLine("DATA='" & b64str & "'")
s = Asn1.TextDumpToString(b64str, 0)
Debug.Assert(s.Length > 0, "Asn1.TextDumpToString failed")
Console.WriteLine(s)
Console.WriteLine("Print type names of various ASN.1 data files...")
fname = "smallca.cer"
s = Asn1.Type(fname)
Console.WriteLine("Asn1.Type('" & fname & "')=" & s)
fname = "AlicePrivRSASign.p8e"
s = Asn1.Type(fname)
Console.WriteLine("Asn1.Type('" & fname & "')=" & s)
fname = "rfc3280bis_CRL.crl"
s = Asn1.Type(fname)
Console.WriteLine("Asn1.Type('" & fname & "')=" & s)
fname = "bob.p7b"
s = Asn1.Type(fname)
Console.WriteLine("Asn1.Type('" & fname & "')=" & s)
fname = "ocsp_response_ok_dims.dat"
s = Asn1.Type(fname)
Console.WriteLine("Asn1.Type('" & fname & "')=" & s)
fname = b64str
s = Asn1.Type(fname)
Console.WriteLine("Asn1.Type('" & fname & "')=" & s)
End Sub
Private Shared Sub test_Sig()
Dim n As Integer
Dim b As Byte()
Dim s As String, correct_sha1 As String, correct_sha256 As String
Dim keyFile As String, password As String, certFile As String, dataFile As String
'***************
' SIG TESTS *
'***************
Console.WriteLine(vbLf & "TESTING SIG...")
keyFile = "AlicePrivRSASign.p8e"
' Used to sign data
certFile = "AliceRSASignByCarl.cer"
' Used to verify signature
password = "password"
' Create RSA signatures over the string "abc"
' -- these are all known values we can check for a given private key
b = System.Text.Encoding.[Default].GetBytes("abc")
' Set byte array with ASCII string "abc"
Console.WriteLine("data=(0x)" & Cnv.ToHex(b) & " (" & b.Length & " bytes)")
Console.WriteLine("Alice signs 'abc' using default SHA-1 with RSA")
' Alice/'abc'/SHA-1
correct_sha1 = "YK1aePtKQDDsVCyJdM0V9VOE6DZVTO3ZoyLV9BNcYmep0glwxU5mUQcLAUTUOETImTIN2Pp4Gffr" & "xqdxUoczLshnXBNhg7P4ofge+WlBgmcTCnVv27LHHZpmdEbjTg6tnPMb+2b4FvMZ0LfkMKXyiRVTmG4A" & "NyAmHH6QIsDZ8R8="
s = Sig.SignData(b, keyFile, password, SigAlgorithm.[Default])
Console.WriteLine("Sig.signData returns " & vbLf & "'" & s & "'")
Debug.Assert(s.Equals(correct_sha1), "Sig.signData failed")
' Now verify the signature we just made using Alice's certificate
n = Sig.VerifyData(s, b, certFile, SigAlgorithm.[Default])
Console.WriteLine("Sig.verifyData returns " & n & " (expecting 0)")
Debug.Assert(0 = n, "Sig.verifyData failed")
Console.WriteLine("Alice signs 'abc' using SHA-256 with RSA")
' Alice/'abc'/SHA-256
correct_sha256 = "tLy6hJadL4w9JI/A/qLCG0Vz1fWPIrPMWD8NGmA5wP7HHlUID54elztUYrpdm9RFeh0RCMJ618dw" & "BpgIutuZg2qQ2i9uMUYB0DvZvkyeD6MqmtVa4ihgc9SLqhigKeP+KB7voEi7PH3hpEr9Wa3kn4mbPpeD" & "1VHSzgu/qirjOaA="
s = Sig.SignData(b, keyFile, password, SigAlgorithm.Rsa_Sha256)
Console.WriteLine("Sig.signData returns " & vbLf & "'" & s & "'")
Debug.Assert(s.Equals(correct_sha256), "Sig.signData failed")
' Now verify the signature we just made
n = Sig.VerifyData(s, b, certFile, SigAlgorithm.Rsa_Sha256)
Console.WriteLine("Sig.verifyData returns " & n & " (expecting 0)")
Debug.Assert(0 = n, "Sig.verifyData failed")
Console.WriteLine("Alice signs 'abc' using digest value")
' Known SHA-1 digest value of 'abc'
b = Cnv.FromHex("a9993e364706816aba3e25717850c26c9cd0d89d")
s = Sig.SignDigest(b, keyFile, password, SigAlgorithm.Rsa_Sha1)
Console.WriteLine("Sig.signDigest returns " & vbLf & "'" & s & "'")
Debug.Assert(s.Equals(correct_sha1), "Sig.signDigest failed")
' Now verify the signature we just made
n = Sig.VerifyDigest(s, b, certFile, SigAlgorithm.Rsa_Sha1)
Console.WriteLine("Sig.verifyData returns " & n & " (expecting 0)")
Debug.Assert(0 = n, "Sig.verifyData failed")
Console.WriteLine("Alice signs 'abc' using SHA-256 digest value")
' Known SHA-256 digest value of 'abc'
b = Cnv.FromHex("ba7816bf 8f01cfea 414140de 5dae2223 b00361a3 96177a9c b410ff61 f20015ad")
s = Sig.SignDigest(b, keyFile, password, SigAlgorithm.Rsa_Sha256)
Console.WriteLine("Sig.signDigest returns " & vbLf & "'" & s & "'")
Debug.Assert(s.Equals(correct_sha256), "Sig.signDigest failed")
' Now verify the signature we just made
n = Sig.VerifyDigest(s, b, certFile, SigAlgorithm.Rsa_Sha256)
Console.WriteLine("Sig.verifyData returns " & n & " (expecting 0)")
Debug.Assert(0 = n, "Sig.verifyData failed")
' Create a file containing exactly the 3-char string "abc"
dataFile = "abc.txt"
File.WriteAllText(dataFile, "abc")
Console.WriteLine("Alice signs file containing 'abc' using SHA-1 with RSA")
s = Sig.SignFile(dataFile, keyFile, password, SigAlgorithm.Rsa_Sha1)
Console.WriteLine("Sig.signDigest returns " & vbLf & "'" & s & "'")
Debug.Assert(s.Equals(correct_sha1), "Sig.signDigest failed")
' Now verify the signature we just made
n = Sig.VerifyFile(s, dataFile, certFile, SigAlgorithm.Rsa_Sha1)
Console.WriteLine("Sig.VerifyData returns " & n & " (expecting 0)")
Debug.Assert(0 = n, "Sig.VerifyData failed")
End Sub
Private Shared Function checkSig(sig64 As [String], sigAlg As SigAlgorithm, publicKeyStr As [String]) As [Boolean]
' An obscure check that we can reproduce the signature using Rsa.EncodeDigestForSignature
' (for our own testing purposes - you don't need to do this in practice)
' 1. Convert base64-encoded signature to a byte array
Dim sig__1 As Byte() = Cnv.FromBase64(sig64)
' 2. Decrypt using internal public key string
Dim b As Byte() = Rsa.RawPublic(sig__1, publicKeyStr)
Console.WriteLine("Decrypted block:")
Console.WriteLine(Cnv.ToHex(b))
Debug.Assert(b.Length > 0)
' 3. Extract the message digest from decrypted block
' -- this should be the digest of "abc"
Dim digest As Byte() = Rsa.DecodeDigestForSignature(b)
Console.WriteLine("digest=" & Cnv.ToHex(digest))
' 4. Now encode for signature using specified digest algorithm
' -- this should match exactly
Dim hashAlg As HashAlgorithm = Sig.GetHashAlgFromSigAlg(sigAlg)
Dim b1 As Byte() = Rsa.EncodeDigestForSignature(b.Length, digest, hashAlg)
Console.WriteLine("Re-encoded block with " & Convert.ToString(hashAlg) & ":")
Console.WriteLine(Cnv.ToHex(b1))
Debug.Assert(ByteArraysEqual(b, b1), "Blocks are not equal")
Return True
End Function
Private Shared Sub test_Sig_Vars()
Dim r As Integer
Dim b As Byte()
Dim s As [String]
Dim keyFile As [String], password As [String], certFile As [String]
Dim publicKeyStr As [String]
Dim sigAlg As SigAlgorithm
Console.WriteLine(vbLf & "TESTING SIG VARS...")
keyFile = "AlicePrivRSASign.p8e"
' Used to sign data
certFile = "AliceRSASignByCarl.cer"
' Used to verify signature
password = "password"
' CAUTION: DO NOT HARD-CODE REAL PASSWORDS
b = System.Text.Encoding.[Default].GetBytes("abc")
' Set byte array with ASCII string "abc"
Console.WriteLine("data=(0x)" & Cnv.ToHex(b) & " (" & b.Length & " bytes)")
publicKeyStr = Rsa.ReadPublicKey(certFile).ToString()
sigAlg = SigAlgorithm.Rsa_Sha1
s = Sig.SignData(b, keyFile, password, sigAlg)
Console.WriteLine("Sig.signData(" & Convert.ToString(sigAlg) & ") returns " & vbLf & s)
checkSig(s, sigAlg, publicKeyStr)
r = Sig.VerifyData(s, b, publicKeyStr, sigAlg)
Console.WriteLine("Sig.VerifyData returns " & r & " (expected 0)")
Debug.Assert(0 = r)
sigAlg = SigAlgorithm.Rsa_Sha224
s = Sig.SignData(b, keyFile, password, sigAlg)
Console.WriteLine("Sig.signData(" & Convert.ToString(sigAlg) & ") returns " & vbLf & s)
checkSig(s, sigAlg, publicKeyStr)
r = Sig.VerifyData(s, b, publicKeyStr, sigAlg)
Console.WriteLine("Sig.VerifyData returns " & r & " (expected 0)")
Debug.Assert(0 = r)
sigAlg = SigAlgorithm.Rsa_Sha256
s = Sig.SignData(b, keyFile, password, sigAlg)
Console.WriteLine("Sig.signData(" & Convert.ToString(sigAlg) & ") returns " & vbLf & s)
checkSig(s, sigAlg, publicKeyStr)
r = Sig.VerifyData(s, b, publicKeyStr, sigAlg)
Console.WriteLine("Sig.VerifyData returns " & r & " (expected 0)")
Debug.Assert(0 = r)
sigAlg = SigAlgorithm.Rsa_Sha384
s = Sig.SignData(b, keyFile, password, sigAlg)
Console.WriteLine("Sig.signData(" & Convert.ToString(sigAlg) & ") returns " & vbLf & s)
checkSig(s, sigAlg, publicKeyStr)
r = Sig.VerifyData(s, b, publicKeyStr, sigAlg)
Console.WriteLine("Sig.VerifyData returns " & r & " (expected 0)")
Debug.Assert(0 = r)
sigAlg = SigAlgorithm.Rsa_Sha512
s = Sig.SignData(b, keyFile, password, sigAlg)
Console.WriteLine("Sig.signData(" & Convert.ToString(sigAlg) & ") returns " & vbLf & s)
checkSig(s, sigAlg, publicKeyStr)
r = Sig.VerifyData(s, b, publicKeyStr, sigAlg)
Console.WriteLine("Sig.VerifyData returns " & r & " (expected 0)")
Debug.Assert(0 = r)
sigAlg = SigAlgorithm.Rsa_Md5
s = Sig.SignData(b, keyFile, password, sigAlg)
Console.WriteLine("Sig.signData(" & Convert.ToString(sigAlg) & ") returns " & vbLf & s)
checkSig(s, sigAlg, publicKeyStr)
r = Sig.VerifyData(s, b, publicKeyStr, sigAlg)
Console.WriteLine("Sig.VerifyData returns " & r & " (expected 0)")
Debug.Assert(0 = r)
End Sub
Private Shared Sub test_Sig_Ecc()
Dim n As Integer
Dim s As String
Dim b As Byte()
Dim digest As Byte()
Dim sig__1 As String
Dim fname As String
Dim prikeyfile As String = "prime256v1.p8"
Dim pubkeyfile As String = "prime256v1.pub"
Dim sigAlg As SigAlgorithm = SigAlgorithm.Ecdsa_Sha256
Dim sbPassword As New StringBuilder("password")
Dim sb As StringBuilder
Dim hashAlg As HashAlgorithm
Console.WriteLine(vbLf & "TESTING SIG ECC...")
' 1. Make a new 256-bit keypair using P-256 curve (`Prime256v1` is a synonym)
n = Ecc.MakeKeys(pubkeyfile, prikeyfile, Ecc.CurveName.Prime256v1, sbPassword.ToString())
Console.WriteLine("Ecc.MakeKeys returns " & n & " (expected 0)")
' 1a. Query the keys we just made, just to check
sb = Ecc.ReadPrivateKey(prikeyfile, sbPassword.ToString())
s = Ecc.QueryKey(sb.ToString(), "curveName")
Console.WriteLine("CurveName: " & s)
s = Ecc.QueryKey(sb.ToString(), "keyBits")
Console.WriteLine("KeyBits:" & s)
Wipe.[String](sb)
' A. Sign the DATA
Console.WriteLine("SigAlgorithm: " & sigAlg.ToString())
' 2. Prepare input data as an array of bytes
b = System.Text.Encoding.[Default].GetBytes("abc")
Console.WriteLine("DATA: " & System.Text.Encoding.[Default].GetString(b))
' 3. Sign DATA using the private key we made above
sig__1 = Sig.SignData(b, prikeyfile, sbPassword.ToString(), sigAlg)
' NB signature value will be different each time
Console.WriteLine("SIG: " & sig__1)
' 4. Verify that the signature over the DATA
n = Sig.VerifyData(sig__1, b, pubkeyfile, sigAlg)
Console.WriteLine("Sig.VerifyData returns " & n & " (expected 0)")
Debug.Assert(0 = n)
' B. Sign the DIGEST of the data
' Get the hash algorithm to use
hashAlg = Sig.GetHashAlgFromSigAlg(sigAlg)
Console.WriteLine("HashAlgorithm: " & hashAlg.ToString())
' Compute the digest value
digest = Hash.BytesFromBytes(b, hashAlg)
Console.WriteLine("DIGEST: " & Cnv.ToHex(digest))
' Sign the DIGEST
sig__1 = Sig.SignDigest(digest, prikeyfile, sbPassword.ToString(), sigAlg)
Console.WriteLine("SIG: " & sig__1)
' And verify the signature using the digest value
n = Sig.VerifyDigest(sig__1, digest, pubkeyfile, sigAlg)
Console.WriteLine("Sig.VerifyDigest returns " & n & " (expected 0)")
Debug.Assert(0 = n)
' C. Sign a FILE containing the data
fname = "abc.txt"
Console.WriteLine("FILE: " & fname)
File.WriteAllBytes(fname, b)
' Sign the FILE
sig__1 = Sig.SignFile(fname, prikeyfile, sbPassword.ToString(), sigAlg)
Console.WriteLine("SIG: " & sig__1)
' And verify the signature over the file
n = Sig.VerifyFile(sig__1, fname, pubkeyfile, sigAlg)
Console.WriteLine("Sig.VerifyFile returns " & n & " (expected 0)")
Debug.Assert(0 = n)
' Finally, wipe the password
Wipe.[String](sbPassword)
End Sub
Private Shared Sub test_Sig_Ecc_det()
Dim sig__1 As String, intKey As String, intPubKey As String
Dim b As Byte()
Dim n As Integer
Dim hexKey As String
Dim curveName As Ecc.CurveName
Dim sigdetok As String = "0f2141a0ebbc44d2e1af90a50ebcfce5e197b3b7d4de036deb18bc9e1f3d7387500cb99cf5f7c157070a8961e38700b7"
Console.WriteLine(vbLf & "TESTING SIG ECC DETERMINISTIC...")
' Ref: [RFC6979] "Deterministic Usage of the DSA and ECDSA"
' A.2.3. ECDSA, 192 Bits (Prime Field)
' 1. READ IN PRIVATE KEY IN (HEX,CURVENAME) FORMAT
hexKey = "6FAB034934E4C0FC9AE67F5B5659A9D7D1FEFD187EE09FD4"
curveName = Ecc.CurveName.P_192
Console.WriteLine("KEYHEX: " & hexKey)
Console.WriteLine("CURVE: " & curveName.ToString())
intKey = Ecc.ReadKeyByCurve(hexKey, curveName)
'Console.WriteLine("INTERNAL KEY (different each time!):\n[" + intKey + "]");
' 2. PREPARE INPUT DATA AS AN ARRAY OF BYTES
b = System.Text.Encoding.[Default].GetBytes("test")
' 3. SIGN IT USING DETERMINISTIC ALGORITHM FROM [RFC6979]
' with output in hex encoding
' -- deterministic method always gives the same signature value for same input
sig__1 = Sig.SignData(b, intKey, "", SigAlgorithm.Ecdsa_Sha1, Sig.SigOptions.UseDeterministic, Sig.Encoding.Base16)
Console.WriteLine("SIG(hex): " & sig__1)
Console.WriteLine("SIG(OK) : " & sigdetok)
Debug.Assert([String].Compare(sig__1, sigdetok, True) = 0, "Sig.SignData failed")
' 4. VERIFY IT WITH THE PUBLIC KEY
intPubKey = Ecc.PublicKeyFromPrivate(intKey)
n = Sig.VerifyData(Cnv.ToBase64(Cnv.FromHex(sig__1)), b, intPubKey, SigAlgorithm.Ecdsa_Sha1)
Console.WriteLine("Sig.VerifyData returns " & n & " (expected 0)")
Debug.Assert(0 = n)
' SIGN IT AGAIN WITH SIG IN ASN1DER FORM
sig__1 = Sig.SignData(b, intKey, "", SigAlgorithm.Ecdsa_Sha1, Sig.SigOptions.UseDeterministic Or Sig.SigOptions.Asn1DERStructure, Sig.Encoding.Base16)
Console.WriteLine("SIG(asn1der): " & sig__1)
' VERIFY IT AGAIN
n = Sig.VerifyData(sig__1, b, intPubKey, SigAlgorithm.Ecdsa_Sha1)
Console.WriteLine("Sig.VerifyData returns " & n & " (expected 0)")
Debug.Assert(0 = n)
' SIGN IT AGAIN WITH SIG IN ASN1DER FORM AND ENCODE IN DEFAULT BASE64
sig__1 = Sig.SignData(b, intKey, "", SigAlgorithm.Ecdsa_Sha1, Sig.SigOptions.UseDeterministic Or Sig.SigOptions.Asn1DERStructure, 0)
Console.WriteLine("SIG(asn1der): " & sig__1)
' VERIFY IT AGAIN
n = Sig.VerifyData(sig__1, b, intPubKey, SigAlgorithm.Ecdsa_Sha1)
Console.WriteLine("Sig.VerifyData returns " & n & " (expected 0)")
Debug.Assert(0 = n)
' SIGN IT AGAIN WITH SIG ENCODED IN "URL_SAFE" BASE64URL
sig__1 = Sig.SignData(b, intKey, "", SigAlgorithm.Ecdsa_Sha1, Sig.SigOptions.UseDeterministic Or Sig.SigOptions.Asn1DERStructure, Sig.Encoding.Base64url)
Console.WriteLine("SIG(base64url): " & sig__1)
' VERIFY IT AGAIN (note the encoding is detected automatically by Sig.Verifydata)
n = Sig.VerifyData(sig__1, b, intPubKey, SigAlgorithm.Ecdsa_Sha1)
Console.WriteLine("Sig.VerifyData returns " & n & " (expected 0)")
Debug.Assert(0 = n)
' SIGN IT USING DEFAULT NON-DETERMINISTIC METHOD (different each time)
sig__1 = Sig.SignData(b, intKey, "", SigAlgorithm.Ecdsa_Sha1)
Console.WriteLine("SIG(random-k): " & sig__1)
' VERIFY IT AGAIN
n = Sig.VerifyData(sig__1, b, intPubKey, SigAlgorithm.Ecdsa_Sha1)
Console.WriteLine("Sig.VerifyData returns " & n & " (expected 0)")
Debug.Assert(0 = n)
End Sub
Private Shared Sub test_Sig_Ecc_btc()
Dim r As Integer
Dim s As String
Dim sig__1 As String, internalKey As String, internalPubKey As String
Dim hexKey As String
Dim curveName As Ecc.CurveName
Dim datahex As String
Dim data As Byte(), digest As Byte()
Dim sigweb As String = "3045022100da43201760bda697222002f56266bf65023fef2094519e13077f777baed553b102205ce35d05eabda58cd50a67977a65706347cc25ef43153e309ff210a134722e9e"
Dim pubkeyok As String = "042daa93315eebbe2cb9b5c3505df4c6fb6caca8b756786098567550d4820c09db988fe9997d049d687292f815ccd6e7fb5c1b1a91137999818d17c73d0f80aef9"
Dim sigdetok As String = "30450220587ce0cf0252e2db3a7c3c91b355aa8f3385e128227cd8727c5f7777877ad772022100edc508b7c14891ed15ab38c687019d7ebaf5c12908cf21a83e8ae57e8c47e95c"
Console.WriteLine(vbLf & "TESTING SIG ECC FOR BITCOIN RAW EXAMPLE...")
' Ref: http://bitcoin.stackexchange.com/questions/32628/redeeming-a-raw-transaction-step-by-step-example-required
' https://blockchain.info/tx/211b8fb30990632751a83d1dc4f0323ff7d2fd3cad88084de13c9be2ae1c6426
' ?format=hex
' READ IN PRIVATE KEY IN (HEX,CURVENAME) FORMAT
hexKey = "0ecd20654c2e2be708495853e8da35c664247040c00bd10b9b13e5e86e6a808d"
curveName = Ecc.CurveName.Secp256k1
Console.WriteLine("KEYHEX: " & hexKey)
Console.WriteLine("CURVE: " & curveName.ToString())
internalKey = Ecc.ReadKeyByCurve(hexKey, curveName)
' Derive public key in hex form from given private key and check against known value
s = Ecc.QueryKey(internalKey, "publicKey")
Console.WriteLine("Ecc.QueryKey('publicKey')=" & vbLf & s)
Console.WriteLine("OK PUBKEY:" & vbLf & pubkeyok)
Debug.Assert(s = pubkeyok)
' THE RAW_TX DATA TO BE SIGNED (derived from blockchain info from link above)
'
' 01000000
' 01
' be66e10da854e7aea9338c1f91cd489768d1d6d7189f586d7a3613f2a24d5396
' 00000000
' 19 76 a9 14 dd6cce9f255a8cc17bda8ba0373df8e861cb866e 88 ac
' ffffffff
' 01
' 23ce010000000000
' 19 76 a9 14 2bc89c2702e0e618db7d59eb5ce2f0f147b40754 88 ac
' 00000000
' 01000000
'
datahex = "0100000001be66e10da854e7aea9338c1f91cd489768d1d6d7189f586d7a3613f2a24d5396000000001976a914dd6cce9f255a8cc17bda8ba0373df8e861cb866e88acffffffff0123ce0100000000001976a9142bc89c2702e0e618db7d59eb5ce2f0f147b4075488ac0000000001000000"
data = Cnv.FromHex(datahex)
Console.WriteLine("RAW_TX:" & vbLf & Cnv.ToHex(data))
' COMPUTE THE DOUBLE SHA-256 DIGEST OF THE RAW DATA
digest = Hash.[Double](data, HashAlgorithm.Sha256)
Console.WriteLine("SHA256(SHA256(RAW_TX)):" & vbLf & Cnv.ToHex(digest))
Console.WriteLine("Same hash value but reversed:" & vbLf & Cnv.ToHex(Cnv.ReverseBytes(digest)))
' Sign using ECDSA deterministic method of RFC6979
' -- NOTE this will not be the same as the published signature (which used a random k we cannot reproduce)
' but the deterministic method should always produce the same signature value:
' 30450220587ce0cf0252e2db3a7c3c91b355aa8f3385e128227cd8727c5f7777877ad772022100edc508b7c14891ed15ab38c687019d7ebaf5c12908cf21a83e8ae57e8c47e95c
sig__1 = Sig.SignDigest(digest, internalKey, "", SigAlgorithm.Ecdsa_Sha256, Sig.SigOptions.UseDeterministic Or Sig.SigOptions.Asn1DERStructure, Sig.Encoding.Base16)
Console.WriteLine("SIG (DET): " & sig__1)
Debug.Assert(sig__1 = sigdetok)
' Generate the public key from the private in internal key string form.
' -- we use this to verify the signature.
internalPubKey = Ecc.PublicKeyFromPrivate(internalKey)
' Now we verify over the same data using (a) our signature and (b) the one from the web page
' -- they both should work.
' (a) Use the deterministic signature `sig` we created above
r = Sig.VerifyDigest(sig__1, digest, internalPubKey, SigAlgorithm.Ecdsa_Sha256)
Console.WriteLine("Sig.VerifyDigest returns " & r & " (expected 0)")
Debug.Assert(0 = r)
' (b) Use the signature `sigweb` from the published Bitcoin transaction web page
Console.WriteLine("SIG (TX): " & sigweb)
r = Sig.VerifyDigest(sigweb, digest, internalPubKey, SigAlgorithm.Ecdsa_Sha256)
Console.WriteLine("Sig.VerifyDigest returns " & r & " (expected 0)")
Debug.Assert(0 = r)
End Sub
Private Shared Sub test_Ecc_MakeKeys()
Dim n As Integer
Dim s As String
Dim pubkeyfile As String
Dim prikeyfile As String
Dim sbIntKey As StringBuilder
Dim h1 As Integer, h2 As Integer
Console.WriteLine(vbLf & "TESTING ECC MAKEKEYS...")
Console.WriteLine("Create a new pair of ECC keys using 'Bitcoin' curve, saving private key with default parameters")
pubkeyfile = "myeckeyk256.pub"
prikeyfile = "myeckeyk256.p8"
n = Ecc.MakeKeys(pubkeyfile, prikeyfile, Ecc.CurveName.Secp256k1, "password")
Console.WriteLine("Ecc.MakeKeys returns " & n & " (expected 0)")
Debug.Assert(0 = n)
s = Asn1.Type(pubkeyfile)
Console.WriteLine("'" & pubkeyfile & "'-->" & s)
s = Asn1.Type(prikeyfile)
Console.WriteLine("'" & prikeyfile & "'-->" & s)
Console.WriteLine("Create a new pair of ECC keys using P-192 curve, saving private key with stronger encryption")
pubkeyfile = "myeckeyp192.pub"
prikeyfile = "myeckeyp192.p8"
n = Ecc.MakeKeys(pubkeyfile, prikeyfile, Ecc.CurveName.Prime192v1, "password", Ecc.PbeScheme.Pbe_Pbkdf2_aes128_CBC, "count=3999;prf=hmacWithSha256", _
Ecc.Format.PEM)
Console.WriteLine("Ecc.MakeKeys returns " & n & " (expected 0)")
Debug.Assert(0 = n)
Console.WriteLine("Display some info about the key we just made...")
s = Asn1.Type(pubkeyfile)
Console.WriteLine("'" & pubkeyfile & "'-->" & s)
s = Asn1.Type(prikeyfile)
Console.WriteLine("'" & prikeyfile & "'-->" & s)
asn1DumpFile(prikeyfile)
' Read in the private key to an internal key string, then query it
sbIntKey = Ecc.ReadPrivateKey(prikeyfile, "password")
s = Ecc.QueryKey(sbIntKey.ToString(), "keybits")
Console.WriteLine("QueryKey('keyBits')=" & s)
s = Ecc.QueryKey(sbIntKey.ToString(), "publicKey")
Console.WriteLine("QueryKey('publicKey')=" & vbLf & "[" & s & "]")
h1 = Ecc.KeyHashCode(sbIntKey.ToString())
Console.WriteLine("Ecc.KeyhashCode(private)=0x{0:X8}", h1)
' Read in the public key to an internal key string, then check its HashCode
sbIntKey = Ecc.ReadPublicKey(pubkeyfile)
h2 = Ecc.KeyHashCode(sbIntKey.ToString())
Console.WriteLine("Ecc.KeyhashCode(public) =0x{0:X8}", h2)
Debug.Assert(h1 = h2)
Wipe.[String](sbIntKey)
End Sub
Private Shared Sub test_ECC_Brainpool()
Dim n As Integer
Dim s As String
Dim pubkeyfile As String
Dim prikeyfile As String
Dim sbIntKey As StringBuilder
Dim h1 As Integer, h2 As Integer
Dim sigval As String
Dim r As Integer
Console.WriteLine(vbLf & "TESTING ECC BRAINPOOL...")
Console.WriteLine("Create a new pair of ECC keys using Brainpool curve, saving private key with stronger encryption")
pubkeyfile = "myeckeyBrainpool256.pub"
prikeyfile = "myeckeyBrainpool256.p8e"
n = Ecc.MakeKeys(pubkeyfile, prikeyfile, Ecc.CurveName.BrainpoolP256r1, "password", Ecc.PbeScheme.Pbe_Pbkdf2_aes128_CBC, "count=3999;prf=hmacWithSha256", _
Ecc.Format.PEM)
Console.WriteLine("Ecc.MakeKeys returns " & n & " (expected 0)")
Debug.Assert(0 = n)
Console.WriteLine("Display some info about the key we just made...")
s = Asn1.Type(pubkeyfile)
Console.WriteLine("'" & pubkeyfile & "'-->" & s)
s = Asn1.Type(prikeyfile)
Console.WriteLine("'" & prikeyfile & "'-->" & s)
asn1DumpFile(pubkeyfile)
' Read in the private key to an internal key string, then query it
sbIntKey = Ecc.ReadPrivateKey(prikeyfile, "password")
s = Ecc.QueryKey(sbIntKey.ToString(), "keybits")
Console.WriteLine("QueryKey('keyBits')=" & s)
s = Ecc.QueryKey(sbIntKey.ToString(), "curveName")
Console.WriteLine("QueryKey('curveName')=" & s)
s = Ecc.QueryKey(sbIntKey.ToString(), "publicKey")
Console.WriteLine("QueryKey('publicKey')=" & vbLf & "[" & s & "]")
h1 = Ecc.KeyHashCode(sbIntKey.ToString())
Console.WriteLine("Ecc.KeyhashCode(private)=0x{0:X8}", h1)
' Read in the public key to an internal key string, then check its HashCode
sbIntKey = Ecc.ReadPublicKey(pubkeyfile)
h2 = Ecc.KeyHashCode(sbIntKey.ToString())
Console.WriteLine("Ecc.KeyhashCode(public) =0x{0:X8}", h2)
Debug.Assert(h1 = h2)
Wipe.[String](sbIntKey)
Console.WriteLine(vbLf & "Again using stronger 512-bit algorithms...")
pubkeyfile = "myeckeyBrainpool512.pub"
prikeyfile = "myeckeyBrainpool512.p8e"
n = Ecc.MakeKeys(pubkeyfile, prikeyfile, Ecc.CurveName.BrainpoolP512r1, "password", Ecc.PbeScheme.Pbe_Pbkdf2_aes256_CBC, "count=5999;prf=hmacWithSha512")
Console.WriteLine("Ecc.MakeKeys returns " & n & " (expected 0)")
Debug.Assert(0 = n)
Console.WriteLine("Display some info about the key we just made...")
s = Asn1.Type(pubkeyfile)
Console.WriteLine("'" & pubkeyfile & "'-->" & s)
s = Asn1.Type(prikeyfile)
Console.WriteLine("'" & prikeyfile & "'-->" & s)
asn1DumpFile(pubkeyfile)
' Read in the private key to an internal key string, then query it
sbIntKey = Ecc.ReadPrivateKey(prikeyfile, "password")
s = Ecc.QueryKey(sbIntKey.ToString(), "keybits")
Console.WriteLine("QueryKey('keyBits')=" & s)
s = Ecc.QueryKey(sbIntKey.ToString(), "curveName")
Console.WriteLine("QueryKey('curveName')=" & s)
s = Ecc.QueryKey(sbIntKey.ToString(), "publicKey")
Console.WriteLine("QueryKey('publicKey')=" & vbLf & "[" & s & "]")
h1 = Ecc.KeyHashCode(sbIntKey.ToString())
Console.WriteLine("Ecc.KeyhashCode(private)=0x{0:X8}", h1)
' Read in the public key to an internal key string, then check its HashCode
sbIntKey = Ecc.ReadPublicKey(pubkeyfile)
h2 = Ecc.KeyHashCode(sbIntKey.ToString())
Console.WriteLine("Ecc.KeyhashCode(public) =0x{0:X8}", h2)
Debug.Assert(h1 = h2)
Wipe.[String](sbIntKey)
Console.WriteLine("Sign 'abc' using ECDSA...")
Dim msg As Byte() = System.Text.Encoding.[Default].GetBytes("abc")
Console.WriteLine("MSG: {0}", Cnv.ToHex(msg))
sigval = Sig.SignData(msg, prikeyfile, "password", SigAlgorithm.Ecdsa_Sha512, Sig.SigOptions.UseDeterministic)
If sigval.Length = 0 Then
Console.WriteLine(General.FormatErrorMessage())
End If
Console.WriteLine("Sig={0}", sigval)
' Verify the signature
r = Sig.VerifyData(sigval, msg, pubkeyfile, SigAlgorithm.Ecdsa_Sha512)
Console.WriteLine("Sig.VerifyData returns {0} (expected 0)", r)
End Sub
Private Shared Sub test_Ecc_MakeReadSaveKeys()
Dim n As Integer
Dim s As String
Dim pubkeyfile As String
Dim prikeyfile As String, fname As String
Dim sbIntKey As StringBuilder
Dim query As String
Console.WriteLine(vbLf & "TESTING ECC MAKEREADSAVEKEYS...")
Console.WriteLine("Create a new pair of ECC keys using P-521 curve")
pubkeyfile = "myeckey521.pub"
prikeyfile = "myeckey521.p8"
n = Ecc.MakeKeys(pubkeyfile, prikeyfile, Ecc.CurveName.P_521, "password")
Console.WriteLine("Ecc.MakeKeys returns " & n & " (expected 0)")
Debug.Assert(0 = n)
s = Asn1.Type(pubkeyfile)
Console.WriteLine("'" & pubkeyfile & "'-->" & s)
s = Asn1.Type(prikeyfile)
Console.WriteLine("'" & prikeyfile & "'-->" & s)
' Read in the private key to an internal key string, then save it without any encryption (!)
sbIntKey = Ecc.ReadPrivateKey(prikeyfile, "password")
Console.WriteLine("Ecc.ReadPrivateKey returns a string of length " & sbIntKey.Length & " (expected >0)")
Debug.Assert(sbIntKey.Length > 0)
query = "curveName"
s = Ecc.QueryKey(sbIntKey.ToString(), query)
Console.WriteLine("QueryKey('" & query & "')=" & s)
Console.WriteLine("Save private key without any encryption")
fname = "myeckey521plain.key"
n = Ecc.SaveKey(fname, sbIntKey.ToString(), 0, Ecc.Format.PEM)
Console.WriteLine("Ecc.SaveKey(default) returns " & n & " (expected 0)")
Debug.Assert(0 = n)
s = Asn1.Type(fname)
Console.WriteLine("'" & fname & "'-->" & s)
' Read in the private key we just saved, just to show we can
sbIntKey = Ecc.ReadPrivateKey(fname, "")
Console.WriteLine("Ecc.ReadPrivateKey returns a string of length " & sbIntKey.Length & " (expected >0)")
Debug.Assert(sbIntKey.Length > 0)
query = "curveName"
s = Ecc.QueryKey(sbIntKey.ToString(), query)
Console.WriteLine("QueryKey('" & query & "')=" & s)
Console.WriteLine("Save private key in PKCS8 format")
fname = "myeckey521pkcs8.key"
n = Ecc.SaveKey(fname, sbIntKey.ToString(), Ecc.KeyType.Pkcs8PrivateKeyInfo, 0)
Console.WriteLine("Ecc.SaveKey(pkcs8) returns " & n & " (expected 0)")
Debug.Assert(0 = n)
' Read in the private key we just saved, just to show we can
sbIntKey = Ecc.ReadPrivateKey(fname, "")
Console.WriteLine("Ecc.ReadPrivateKey returns a string of length " & sbIntKey.Length & " (expected >0)")
Debug.Assert(sbIntKey.Length > 0)
query = "isPrivate"
s = Ecc.QueryKey(sbIntKey.ToString(), query)
Console.WriteLine("QueryKey('" & query & "')=" & s)
query = "privateKey"
s = Ecc.QueryKey(sbIntKey.ToString(), query)
Console.WriteLine("QueryKey('" & query & "')=" & s)
' Read in the public key file to an internal key string
Console.WriteLine("Read in the public key file to an internal key string")
sbIntKey = Ecc.ReadPublicKey(pubkeyfile)
Console.WriteLine("Ecc.ReadPublicKey returns a string of length " & sbIntKey.Length & " (expected >0)")
Debug.Assert(sbIntKey.Length > 0)
query = "isPrivate"
s = Ecc.QueryKey(sbIntKey.ToString(), query)
Console.WriteLine("QueryKey('" & query & "')=" & s)
query = "privateKey"
s = Ecc.QueryKey(sbIntKey.ToString(), query)
Console.WriteLine("QueryKey('" & query & "')=" & s)
End Sub
Private Shared Sub test_Ecc_KeyByCurve()
Dim s As String
Dim hexKey As String
Dim curveName As Ecc.CurveName
Dim internalKey As String
Dim query As String
Dim b58Key As String
Console.WriteLine(vbLf & "TESTING ECC READKEYBYCURVE...")
Console.WriteLine("1. A NIST P-192 public key in X9.63 uncompressed format")
hexKey = "0496C248BE456192FA1380CCF615D171452F41FF31B92BA733524FD77168DEA4425A3EA8FD79B98DC7AFE83C86DCC39A96"
curveName = Ecc.CurveName.Prime192v1
' A synonym for P-192
Console.WriteLine("KEYHEX: " & hexKey)
Console.WriteLine("CURVE: " & Convert.ToString(curveName))
' Read into internal key string
internalKey = Ecc.ReadKeyByCurve(hexKey, curveName)
' Find the key size in bits
query = "keyBits"
s = Ecc.QueryKey(internalKey, query)
Console.WriteLine("QueryKey('" & query & "')=" & s)
Debug.Assert(Convert.ToInt32(s) = 192)
' Is it a private or public key?
query = "isPrivate"
s = Ecc.QueryKey(internalKey, query)
Console.WriteLine("QueryKey('" & query & "')=" & s)
Debug.Assert(Convert.ToInt32(s) = 0)
Console.WriteLine("2. A Bitcoin private key in base58 form")
b58Key = "6ACCbmy9qwiFcuVgvxNNwMPfoghobzznWrLs3v7t3RmN"
curveName = Ecc.CurveName.Secp256k1
Console.WriteLine("KEYB58: " & b58Key)
' Convert base58 to a hex string
hexKey = Cnv.ToHex(Cnv.FromBase58(b58Key))
Console.WriteLine("KEYHEX: " & hexKey)
Console.WriteLine("CURVE: " & Convert.ToString(curveName))
' Read into internal key string
internalKey = Ecc.ReadKeyByCurve(hexKey, curveName)
' Find the key size in bits
query = "keyBits"
s = Ecc.QueryKey(internalKey, query)
Console.WriteLine("QueryKey('" & query & "')=" & s)
Debug.Assert(Convert.ToInt32(s) = 256)
' Is it a private or public key?
query = "isPrivate"
s = Ecc.QueryKey(internalKey, query)
Console.WriteLine("QueryKey('" & query & "')=" & s)
Debug.Assert(Convert.ToInt32(s) = 1)
' Extract the public key in hex form from the private key
query = "publicKey"
s = Ecc.QueryKey(internalKey, query)
Console.WriteLine("QueryKey('" & query & "')=" & s)
Debug.Assert(s.Length > 0)
End Sub
Private Shared Sub test_Ecc_SaveKey()
Dim n As Integer
Dim s As String
Dim hexKey As String
Dim curveName As Ecc.CurveName
Dim intPriKey As String, intPubKey As String
Dim query As String
Dim fname As String
Console.WriteLine(vbLf & "TESTING ECC SAVEKEYS...")
Console.WriteLine("1. Read in a 'Bitcoin' private key in hex form")
hexKey = "0ecd20654c2e2be708495853e8da35c664247040c00bd10b9b13e5e86e6a808d"
curveName = Ecc.CurveName.Secp256k1
Console.WriteLine("KEYHEX: " & hexKey)
Console.WriteLine("CURVE: " & Convert.ToString(curveName))
' Read into an internal key string
intPriKey = Ecc.ReadKeyByCurve(hexKey, curveName)
' Check we got what we expect
query = "keyBits"
s = Ecc.QueryKey(intPriKey, query)
Console.WriteLine("QueryKey('" & query & "')=" & s)
Debug.Assert(Convert.ToInt32(s) = 256)
query = "curveName"
s = Ecc.QueryKey(intPriKey, query)
Console.WriteLine("QueryKey('" & query & "')=" & s)
query = "isPrivate"
s = Ecc.QueryKey(intPriKey, query)
Console.WriteLine("QueryKey('" & query & "')=" & s)
Console.WriteLine("2. Get the public key from the private key")
intPubKey = Ecc.PublicKeyFromPrivate(intPriKey)
query = "isPrivate"
s = Ecc.QueryKey(intPubKey, query)
Console.WriteLine("QueryKey('" & query & "')=" & s)
Console.WriteLine("3. Save the public and private keys in various forms...")
Console.WriteLine(" 3a. There is only one format to save public keys: SubjectPublicKeyInfo [RFC5480]")
fname = "mybitcoinkey.pub"
n = Ecc.SaveKey(fname, intPubKey, 0, 0)
Console.WriteLine("Ecc.SaveKey returns " & n & " (expected 0)")
' Get ASN.1 type
s = Asn1.Type(fname)
Console.WriteLine("'" & fname & "'-->" & s)
Console.WriteLine(" 3b. There is only one *encrypted* format to save private keys: PKCS#8 EncryptedPrivateKeyInfo [RFC5208]")
fname = "mybitcoinkey_enc.p8"
n = Ecc.SaveEncKey(fname, intPriKey, "password", 0, "", 0)
Console.WriteLine("Ecc.SaveEncKey returns " & n & " (expected 0)")
' Get ASN.1 type
s = Asn1.Type(fname)
Console.WriteLine("'" & fname & "'-->" & s)
Console.WriteLine(" 3c. There are two *unencrypted* formats to save private keys:")
Console.WriteLine(" 3c(i). ECPrivateKey [RFC5915]")
fname = "mybitcoinkey_ec.key"
n = Ecc.SaveKey(fname, intPriKey, 0, 0)
Console.WriteLine("Ecc.SaveKey(default) returns " & n & " (expected 0)")
' Get ASN.1 type
s = Asn1.Type(fname)
Console.WriteLine("'" & fname & "'-->" & s)
Console.WriteLine(" 3c(ii). PKCS#8 PrivateKeyInfo [RFC5208]")
fname = "mybitcoinkey.p8"
n = Ecc.SaveKey(fname, intPriKey, Ecc.KeyType.Pkcs8PrivateKeyInfo, 0)
Console.WriteLine("Ecc.SaveKey(default) returns " & n & " (expected 0)")
' Get ASN.1 type
s = Asn1.Type(fname)
Console.WriteLine("'" & fname & "'-->" & s)
End Sub
' BYTE UTILITIES
Private Shared Sub test_Byte_Utils()
Dim b As Byte()
' NOTE: this is only place we explicitly use an unsigned integer
Dim n As UInteger
Console.WriteLine(vbLf & "TESTING BYTE UTILS...")
Console.WriteLine("Testing Cnv.ReverseBytes()...")
b = New Byte(4) {&H1, &H2, &H3, &H4, &H5}
Console.WriteLine("(before)=" & Cnv.ToHex(b))
b = Cnv.ReverseBytes(b)
Console.WriteLine("(after)= " & Cnv.ToHex(b))
Debug.Assert(b(0) = &H5 AndAlso b(4) = &H1, "Cnv.ReverseBytes failed")
b = New Byte(3) {&H1, &H2, &H3, &H4}
Console.WriteLine("(before)=" & Cnv.ToHex(b))
b = Cnv.ReverseBytes(b)
Console.WriteLine("(after)= " & Cnv.ToHex(b))
Debug.Assert(b(0) = &H4 AndAlso b(3) = &H1, "Cnv.ReverseBytes failed")
b = New Byte(0) {&H1}
Console.WriteLine("(before)=" & Cnv.ToHex(b))
b = Cnv.ReverseBytes(b)
Console.WriteLine("(after)= " & Cnv.ToHex(b))
Debug.Assert(b(0) = &H1, "Cnv.ReverseBytes failed")
Console.WriteLine("Testing Cnv.NumToBytes()...")
b = Cnv.NumToBytes(&HdeadbeefUI, Cnv.EndianNess.BigEndian)
Console.WriteLine("(0xdeadbeef,BE)->" & Cnv.ToHex(b))
b = Cnv.NumToBytes(&HdeadbeefUI, Cnv.EndianNess.LittleEndian)
Console.WriteLine("(0xdeadbeef,LE)->" & Cnv.ToHex(b))
Console.WriteLine("Testing Cnv.NumFromBytes()...")
b = New Byte(3) {&Hde, &Had, &Hbe, &Hef}
n = Cnv.NumFromBytes(b, Cnv.EndianNess.BigEndian)
Console.WriteLine("(" & Cnv.ToHex(b) & ",BE)->0x" & n.ToString("x8"))
Debug.Assert(&HdeadbeefUI = n)
n = Cnv.NumFromBytes(b, Cnv.EndianNess.LittleEndian)
Console.WriteLine("(" & Cnv.ToHex(b) & ",LE)->0x" & n.ToString("x8"))
Debug.Assert(&HefbeaddeUI = n)
b = Cnv.FromHex("DEAD")
' Short array
n = Cnv.NumFromBytes(b, Cnv.EndianNess.BigEndian)
Console.WriteLine("(" & Cnv.ToHex(b) & ",BE)->0x" & n.ToString("x8"))
n = Cnv.NumFromBytes(b, Cnv.EndianNess.LittleEndian)
Console.WriteLine("(" & Cnv.ToHex(b) & ",LE)->0x" & n.ToString("x8"))
b = Cnv.FromHex("EF")
' Shorter array
n = Cnv.NumFromBytes(b, Cnv.EndianNess.BigEndian)
Console.WriteLine("(" & Cnv.ToHex(b) & ",BE)->0x" & n.ToString("x8"))
n = Cnv.NumFromBytes(b, Cnv.EndianNess.LittleEndian)
Console.WriteLine("(" & Cnv.ToHex(b) & ",LE)->0x" & n.ToString("x8"))
b = Cnv.FromHex("DEADBEEFCAFEBABE")
' Longer array
n = Cnv.NumFromBytes(b, Cnv.EndianNess.BigEndian)
Console.WriteLine("(" & Cnv.ToHex(b) & ",BE)->0x" & n.ToString("x8"))
n = Cnv.NumFromBytes(b, Cnv.EndianNess.LittleEndian)
Console.WriteLine("(" & Cnv.ToHex(b) & ",LE)->0x" & n.ToString("x8"))
End Sub
Private Shared Sub test_Compress()
Console.WriteLine(vbLf & "COMPRESS DATA USING ZLIB COMPRESSION:")
Dim data As Byte(), cdata As Byte(), udata As Byte()
' Put data into a byte array
data = System.Text.Encoding.UTF8.GetBytes("hello, hello, hello. This is a 'hello world' message for the world, repeat, for the world.")
' Compress it
cdata = Compr.Compress(data)
Console.WriteLine("Compressed {0} bytes to {1}", data.Length, cdata.Length)
' Now decompress it
udata = Compr.Uncompress(cdata)
Console.WriteLine("Uncompressed length is {0}", udata.Length)
' Show data as an ascii string
Console.WriteLine("[{0}]", System.Text.Encoding.UTF8.GetString(udata))
End Sub
'************************************
' CODE FORMERLY IN TestPKISharpV12.cs
'************************************
Private Shared Sub test_MakeRSA_ECCKeys()
' Demonstrates:
' * Rsa.MakeKeys() (Updated [v20.3])
' * Ecc.MakeKeys()
'
Dim r As Integer
Console.WriteLine("Generating two 2048-bit RSA keys...")
r = Rsa.MakeKeys("CA_RSA_2048.pub", "CA_RSA_2048.p8e", "password", 2048, pbes := Rsa.PbeOptions.Pbe_Pbkdf2_aes256_CBC)
r = Rsa.MakeKeys("User_RSA_2048.pub", "User_RSA_2048.p8e", "password", 2048, pbes := Rsa.PbeOptions.Pbe_Pbkdf2_aes256_CBC)
Console.WriteLine("Generating two ECC keys using P-256...")
r = Ecc.MakeKeys("CA_ECC_P256.pub", "CA_ECC_P256.p8e", Ecc.CurveName.P_256, "password", Ecc.PbeScheme.Pbe_Pbkdf2_aes256_CBC, "", _
0)
r = Ecc.MakeKeys("User_ECC_P256.pub", "User_ECC_P256.p8e", Ecc.CurveName.P_256, "password", Ecc.PbeScheme.Pbe_Pbkdf2_aes256_CBC, "", _
0)
End Sub
Private Shared Sub test_ReadRSA_ECCKeys()
Console.WriteLine(vbLf & "Show we can read the key files we made...")
' Demonstrates:
' * Rsa.ReadPrivateKey()
' * Rsa.ReadPublicKey()
' * Rsa.KeyBits()
' * Rsa.KeyHashCode()
' * Rsa.KeyMatch()
' * Ecc.ReadPrivateKey()
' * Ecc.ReadPublicKey()
' * Ecc.QueryKey()
' * Ecc.KeyHashCode()
'
Dim sbPriKey As StringBuilder
Dim pubkey As String
Dim r As Integer
' RSA keys:
sbPriKey = Rsa.ReadPrivateKey("CA_RSA_2048.p8e", "password")
Debug.Assert(sbPriKey.Length > 0, "Failed to read CA_RSA_2048 private key")
Console.WriteLine("CA_RSA pri key length={0}", Rsa.KeyBits(sbPriKey.ToString()))
Console.WriteLine("CA_RSA pri key hash code={0,8:X}", Rsa.KeyHashCode(sbPriKey.ToString()))
pubkey = Rsa.ReadPublicKey("CA_RSA_2048.pub").ToString()
Debug.Assert(pubkey.Length > 0, "Failed to read CA_RSA_2048 public key")
Console.WriteLine("CA_RSA pub key length={0}", Rsa.KeyBits(pubkey))
Console.WriteLine("CA_RSA pub key hash code={0,8:X}", Rsa.KeyHashCode(pubkey))
' Check they match
r = Rsa.KeyMatch(sbPriKey.ToString(), pubkey)
Console.WriteLine("Rsa.KeyMatch() returns {0} (expected 0)", r)
Debug.Assert(0 = r)
' ECC keys:
sbPriKey = Ecc.ReadPrivateKey("CA_ECC_P256.p8e", "password")
Debug.Assert(sbPriKey.Length > 0, "Failed to read CA_ECC_P256 private key")
Console.WriteLine("CA_ECC pri key length={0}", Ecc.QueryKey(sbPriKey.ToString(), "keyBits"))
Console.WriteLine("CA_ECC pri key hash code={0,8:X}", Ecc.KeyHashCode(sbPriKey.ToString()))
pubkey = Ecc.ReadPublicKey("CA_ECC_P256.pub").ToString()
Debug.Assert(pubkey.Length > 0, "Failed to read CA_ECC_P256 public key")
Console.WriteLine("CA_ECC pub key length={0}", Ecc.QueryKey(pubkey, "keyBits"))
Console.WriteLine("CA_ECC pub key hash code={0,8:X}", Ecc.KeyHashCode(pubkey))
End Sub
Private Shared Sub test_MakeCerts_ECDSA()
Console.WriteLine(vbLf & "Create a new CA certificate and end-user certificates using ECDSA...")
' Demonstrates:
' * X509.MakeCertSelf() using SigAlgorithm.Ecdsa_Sha256
' * X509.MakeCert() using SigAlgorithm.Ecdsa_Sha256 and X509.CertOptions.Ecdsa_Deterministic
' * X509.CertRequest() using SigAlgorithm.Ecdsa_Sha256
' * X509.VerifyCert() for an X.509 certificate
' * X509.VerifyCert() for a PKCS#10 CSR
' * X509.VerifyCert() for an X.509 CRL
' * X509.MakeCRL() using SigAlgorithm.Ecdsa_Sha256
' * X509.CheckCertInCRL()
' * X509.TextDumpToString() using X509.OutputOpts.Ldap
' * Asn1.TextDumpToString()
' * Ecc.ReadPublicKey()
'
Dim r As Integer
Dim kuFlags As X509.KeyUsageOptions
Dim dn As String, extns As String
Dim s As String, query As String, pubkey As String
' Create a self-signed CA certificate
Dim ca_cert As String = "CA_ECC_P256.cer"
kuFlags = X509.KeyUsageOptions.KeyCertSign Or X509.KeyUsageOptions.CrlSign Or X509.KeyUsageOptions.NonRepudiation
dn = "C=AU;OU=Elliptical;O=Cert Services;CN=El Jefe"
extns = "serialNumber=#xECC0CA;notBefore=2018-01-01;notAfter=2023-12-31"
r = X509.MakeCertSelf(ca_cert, "CA_ECC_P256.p8e", 0, 0, dn, extns, _
kuFlags, "password", SigAlgorithm.Ecdsa_Sha256, X509.CertOptions.UTF8String)
Console.WriteLine("X509.MakeCertSelf returns {0} (expecting 0)", r)
Debug.Assert(0 = r)
' Display cert details (with distinguished name in LDAP form (NB reverse order to dn above) and serial number in Decimal
Console.WriteLine("FILE: {0}", ca_cert)
s = X509.TextDumpToString(ca_cert, X509.OutputOpts.[Decimal] Or X509.OutputOpts.Ldap)
Console.WriteLine(s)
' Use the CA certificate to create an end-user certificate
Dim user_cert As String = "User_ECC_P256.cer"
kuFlags = X509.KeyUsageOptions.DataEncipherment Or X509.KeyUsageOptions.DigitalSignature Or X509.KeyUsageOptions.KeyEncipherment
dn = "C=AU;OU=Elliptical;O=User Org;CN=The User"
extns = "serialNumber=#xECD5A0;notBefore=2018-01-02;notAfter=2023-12-30"
r = X509.MakeCert(user_cert, ca_cert, "User_ECC_P256.pub", "CA_ECC_P256.p8e", 0, 0, _
dn, extns, kuFlags, "password", SigAlgorithm.Ecdsa_Sha256, X509.CertOptions.UTF8String Or X509.CertOptions.Ecdsa_Deterministic)
Console.WriteLine("X509.MakeCert returns {0} (expecting 0)", r)
Debug.Assert(0 = r)
' Query cert for information
Console.WriteLine("FILE: {0}", user_cert)
query = "signatureAlgorithm"
Console.WriteLine("X509.QueryCert('{0}')={1}", query, X509.QueryCert(user_cert, query))
query = "serialNumber"
Console.WriteLine("X509.QueryCert('{0}')={1}", query, X509.QueryCert(user_cert, query))
' Extract public key from certificate
pubkey = Ecc.ReadPublicKey(user_cert).ToString()
Debug.Assert(pubkey.Length > 0, "Failed to read public key from certificate")
Console.WriteLine("ECC public key length={0}", Ecc.QueryKey(pubkey, "keyBits"))
' Validate the end user cert was issued by CA
r = X509.VerifyCert(user_cert, ca_cert)
Console.WriteLine("X509.VerifyCert returns {0} (expecting 0)", r)
If r <> 0 Then
disp_error(r)
End If
Debug.Assert(0 = r)
Console.WriteLine(vbLf & "Create a PKCS10 certificate signing request (CSR) using ECC P-256 key then use to issue new X.509 certificate...")
Dim user_csr As String = "User2_ECC_P256.p10"
dn = "C=AU;OU=Elliptic;O=User Org;CN=User 2"
extns = "keyUsage=digitalSignature,dataEncipherment,dataEncipherment;"
' Make a CSR - must match ECC key with ECC signature algorithm
r = X509.CertRequest(user_csr, "User2_ECC_P256.p8e", dn, extns, "password", SigAlgorithm.Ecdsa_Sha256, _
0)
Console.WriteLine("X509.CertRequest returns {0} (expecting 0)", r)
If r <> 0 Then
disp_error(r)
End If
Debug.Assert(0 = r)
' We can verify that the signature is good
r = X509.VerifyCert(user_csr, "")
Console.WriteLine("X509.VerifyCert('{1}') returns {0} (expecting 0)", r, user_csr)
Debug.Assert(0 = r)
' CA receives the CSR and issues a new end-user certificate
Dim user2_cert As String = "User2_ECC_P256.cer"
extns = "notBefore=2018-01-02;"
r = X509.MakeCert(user2_cert, ca_cert, user_csr, "CA_ECC_P256.p8e", &Hecd5a2, 4, _
"", extns, 0, "password", SigAlgorithm.Ecdsa_Sha256, 0)
Console.WriteLine("X509.MakeCert returns {0} (expecting 0)", r)
If r <> 0 Then
disp_error(r)
End If
Debug.Assert(0 = r)
' Dump the ASN.1 structure of the user certificate
Console.WriteLine("FILE: {0}", user2_cert)
s = Asn1.TextDumpToString(user2_cert, 0)
Console.WriteLine(s)
Console.WriteLine(vbLf & "The CA creates a Certificate Revocation List (CRL) revoking User2's certificate as of 1 April 2018")
Dim crlFile As String = "ECC_P256.crl"
r = X509.MakeCRL(crlFile, ca_cert, "CA_ECC_P256.p8e", "password", "#xECD5A2,2018-04-01", "", _
SigAlgorithm.Ecdsa_Sha256, 0)
Console.WriteLine("X509.MakeCRL returns {0} (expecting 0)", r)
If r <> 0 Then
disp_error(r)
End If
Debug.Assert(0 = r)
' Verify that the signature in the CRL file is good
r = X509.VerifyCert(crlFile, ca_cert)
Console.WriteLine("X509.VerifyCert('{1}') returns {0} (expecting 0)", r, crlFile)
Debug.Assert(0 = r)
' See if certificate has been revoked as of today
r = X509.CheckCertInCRL(user2_cert, crlFile, Nothing, "")
Console.WriteLine("X509.CheckCertInCRL('{1}',now) returns {0} (expecting {2}=X509.Revoked)", r, crlFile, X509.Revoked)
Debug.Assert(X509.Revoked = r)
' See if certificate has been revoked as of 2018-02-01
Dim datestr As String = "2018-02-01"
r = X509.CheckCertInCRL(user2_cert, crlFile, Nothing, datestr)
Console.WriteLine("X509.CheckCertInCRL('{1}',{2}) returns {0} (expecting 0=NOT REVOKED)", r, crlFile, datestr)
Debug.Assert(0 = r)
End Sub
Private Shared Sub test_MakeCerts_PSS()
Console.WriteLine(vbLf & "Create a new CA certificate and end-user certificate using RSA-PSS...")
' Demonstrates:
' * X509.MakeCertSelf() using SigAlgorithm.Rsa_Pss_Sha256
' * X509.MakeCert() using SigAlgorithm.Rsa_Pss_Sha256
' * X509.QueryCert()
' * X509.ValidatePath()
' * X509.TextDumpToString() using X509.OutputOpts.Ldap
' * Rsa.ReadPublicKey()
' * Rsa.KeyBits()
'
Dim r As Integer
Dim kuFlags As X509.KeyUsageOptions
Dim dn As String, extns As String
Dim s As String, query As String, pubkey As String
' Create a self-signed CA certificate
Dim ca_cert As String = "CA_RSA_2048.cer"
kuFlags = X509.KeyUsageOptions.KeyCertSign Or X509.KeyUsageOptions.CrlSign Or X509.KeyUsageOptions.NonRepudiation
dn = "C=AU;OU=PSS;O=Cert Services;CN=El Jefe"
extns = "serialNumber=#d1234567;notBefore=2018-01-01;notAfter=2023-12-31"
r = X509.MakeCertSelf(ca_cert, "CA_RSA_2048.p8e", 0, 0, dn, extns, _
kuFlags, "password", SigAlgorithm.Rsa_Pss_Sha256, X509.CertOptions.UTF8String)
Console.WriteLine("X509.MakeCertSelf returns {0} (expecting 0)", r)
Debug.Assert(0 = r)
' Display cert details (with distinguished name in LDAP form (NB reverse order to dn above) and serial number in Decimal
Console.WriteLine("FILE: {0}", ca_cert)
s = X509.TextDumpToString(ca_cert, X509.OutputOpts.[Decimal] Or X509.OutputOpts.Ldap)
Console.WriteLine(s)
' Use the CA certificate to create an end-user certificate
Dim user_cert As String = "User_RSA_2048.cer"
kuFlags = X509.KeyUsageOptions.DataEncipherment Or X509.KeyUsageOptions.DigitalSignature Or X509.KeyUsageOptions.KeyEncipherment
dn = "C=AU;OU=PSS;O=User Org;CN=The User"
extns = "serialNumber=#d2345678;notBefore=2018-01-02;notAfter=2023-12-30"
r = X509.MakeCert(user_cert, ca_cert, "User_RSA_2048.pub", "CA_RSA_2048.p8e", 0, 0, _
dn, extns, kuFlags, "password", SigAlgorithm.Rsa_Pss_Sha256, X509.CertOptions.UTF8String)
Console.WriteLine("X509.MakeCert returns {0} (expecting 0)", r)
Debug.Assert(0 = r)
' Query cert for information
Console.WriteLine("FILE: {0}", user_cert)
query = "signatureAlgorithm"
Console.WriteLine("X509.QueryCert('{0}')={1}", query, X509.QueryCert(user_cert, query))
query = "serialNumber"
Console.WriteLine("X509.QueryCert('{0}')={1}", query, X509.QueryCert(user_cert, query, X509.OutputOpts.[Decimal]))
' Extract public key from certificate
pubkey = Rsa.ReadPublicKey(user_cert).ToString()
Debug.Assert(pubkey.Length > 0, "Failed to read public key from certificate")
Console.WriteLine("Rsa public key length={0}", Rsa.KeyBits(pubkey))
' Validate the certificate path
Dim certpath As String = ca_cert & ";" & user_cert
r = X509.ValidatePath(certpath)
Console.WriteLine("X509.ValidatePath('{0}') returns {1} (expecting 0)", certpath, r)
If r <> 0 Then
disp_error(r)
End If
Debug.Assert(0 = r)
End Sub
Private Shared Sub test_SIG_VerifyData_PSS()
Console.WriteLine(vbLf & "VERIFY A SIGNATURE VALUE:")
' Demonstrates:
' * Sig.VerifyData() using SigAlgorithm.Rsa_Pss_Sha1 and SigAlgorithm.Rsa_Pss_Sha512
' * Sig.VerifyDigest()
'
Dim r As Integer
Dim rsakeyvalue As String, msghex As String, S As String
Dim rsaprikey As String
Dim msg As Byte(), digest As Byte()
Console.WriteLine("1. NIST test CAVS 11.1 FIPS186-3 - SigVer RSA PKCS#1 RSASSA-PSS...")
' Example No 1 from NIST test
' # CAVS 11.1
' # "FIPS186-3 - SigVer RSA PKCS#1 RSASSA-PSS" information for "rsa2_check"
' CryptoSys-PKI-specific way to read in an RSA key using hex-encoded components
rsakeyvalue = "<RSAKeyValue>" & "<Modulus EncodingType=""hexBinary"">ec996bc93e81094436fd5fc2eef511782eb40fe60cc6f27f24bc8728d686537f1caa82cfcfa5c323604b6918d7cd0318d98395c855c7c7ada6fc447f192283cdc81e7291e232336019d4dac12356b93a349883cd2c0a7d2eae9715f1cc6dd657cea5cb2c46ce6468794b326b33f1bff61a00fa72931345ca6768365e1eb906dd</Modulus>" & "<Exponent EncodingType=""hexBinary"">90c6d3</Exponent></RSAKeyValue>"
msghex = "a4daf4621676917e28493a585d9baffca3755e77e1f18e3ccfb3dec60ab8ee7e684f5cde8864f2d7ae041d70ce1ea1b1e7878cbf93416848dbfdb5214fde972e5780cb83c439dfc8aa9fa3e2724adbd02bdb36d2213c84d1b12a23fb5bf1baae19772a97ef7cc21bc420b3f570a6c321167745f9b46a489ff8420f9a5679c1c4"
S = "319c62984acd52423e59a17d27d4eca7722703b054a71a1ee5f7a218b6f4a274632eaf8ef2a577a7e8a7f654b8deb1ec9b1e529cf93459cc8af4c6df6fffabc3edded0c421604ea2aae35836b05fd9de7abd78540d45fd6d0ea714733a3427b00d9d6404db8ede4a27932b47d88243eefcbffe1e55841823def30c57de7562cf"
msg = Cnv.FromHex(msghex)
r = Sig.VerifyData(S, msg, rsakeyvalue, SigAlgorithm.Rsa_Pss_Sha1)
Console.WriteLine("Sig.VerifyData() returns {0} (expecting 0)", r)
If r <> 0 Then
disp_error(r)
End If
Debug.Assert(0 = r)
' Example from NIST with SHA512 and sLen = 0
Console.WriteLine("2. NIST test with SHA512 and sLen = 0...")
rsakeyvalue = "<RSAKeyValue>" & "<Modulus EncodingType=""hexBinary"">a3f2235ad2053b4c83fa38f8284ed805421621fe98845fb01b689f5b82b32511b6d16173e7b40a66a3a999c189beb9e06822150ac8be677186370c823b5277d909de07564e281cca2f13873d9d07b7bd85a2b9ac66f4ce4f5e38b8e9eebec04c8caf311e375d69e80851d559b8e90e85ba6b96476790f727c25aa8163062ec8543fcc7759be62c7768ecc37f340bb06102762bf0441ca1aa2c7a81bf37dc8b27439d3abba93812c9bb44fe4d6a94baae709379f5ce5d0c8f81d00086b9caa3026819588f491b525807899cdab33d8e992150d2b105d3aab615217c6a3d740831c7dc76faabd9c9b9817ead0b494566de1433fff5ba4604c6b8446f6fc35e746aff84ff8bd7500410d10e82bf4c9036489de47dee9a327a5c4510d8561321b91d55559a4cba85e0c361767084b25217e8a63c4e151a1e88689feecffd16fa0a65ae41d2babca99cf1b959c3c076c0f75974146f2cc494126fbecad4217b9aaa00f169fa512527ff5a0b50da46d6be870ecef2af7a1e6c4556f6f7a0a00b9f47cb</Modulus>" & "<Exponent EncodingType=""hexBinary"">000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b3f57f</Exponent></RSAKeyValue>"
msghex = "be2f3e1dc8a3711570401bd535185426944d094e8481a12a438de07d54760c88c99d4fdbbe355d6a26fa56e3ca20ee3f8e8acb98f63d2f3aea14d6fcb6b522d155c3759aef56de3ea0a8f9fd7b111001cf358636a87c765c99c2975bb95063d6ec0b780264ec3eb967b0caca52d10294deb402d3a224bfb9d9ffea41662f18c0"
S = "787cdd6e1d4fdf9a0d9f965eb85725232a9efcc12abfa1ef25a81e0983111d9000d494fc7d3201eb3bba327302727f7086147a755b4827030c7276536f425593ab2e9127a149e754de7ad77f8c2043267db49f8a35031d83f13d140d5df4d424b47454041a23b92ff6818e749d65d01fc50bebf69152f3f5fcb4873b1036219e22b1e74f8368c8c501ce65f2c929d90a8ec899630e802547a7ca6ef18ab3cb3eb4a691ee68aebeaf1b9c055ad12218039cf480cd8d294332c5e16ebbe6af11f8f4bf49f9b4ed2f511126ae780a3b784be8f4426abd17f8600074483f2af3b71a8964c6e0fa00049a1d940d34cc08839e0c59253d99e90d17871d489674695663626166d36ff91d8c2299a2f051eae2d60e8ed0bc3fac1e490b470c12f3d697f6fbfd880de2e90e9fcbd485fa3393198372fb01e4cec5c15917ecdd42e57c43ecf55a8c0ecbdcef1bce4e36d96d46b112570b53f82f3d2064b08ac78613670a28ea69d79c717eb1c294090dbd561fa6e504d09d265724e37a2dc6f445f6f528c9"
msg = Cnv.FromHex(msghex)
r = Sig.VerifyData(S, msg, rsakeyvalue, SigAlgorithm.Rsa_Pss_Sha512)
Console.WriteLine("Sig.VerifyData() returns {0} (expecting 0)", r)
If r <> 0 Then
disp_error(r)
End If
Debug.Assert(0 = r)
Console.WriteLine("3. Test using independently-generated signature...")
rsaprikey = "-----BEGIN RSA PRIVATE KEY-----" & " MIICXgIBAAKBgQDH/zRrIL8qvdyGlYFRnddU7NjXY3u6P2YCrS/Gy4vkYhmUtfF0" & " slIvY6RTF+kDEYCbZagsSjQYAFuqLZwAF5gNBPzDMfhZFmjY42Da9MGIg/0ePpye" & " zJWXO7FN0DxQ1Jw8iHzvon4bVT++VswAQe2158w/Q5cwOF2h89E/KMuwqQIDAQAB" & " AoGBAIVP2vwRzvvJpQbc/1+NDC0i14PzX1UNz4y3LqKfqXcp4Q1cnj+AYgIOtElj" & " JcIS15w+DfS/3aumCXQNhPAWyhWtEiLNifOGvIK31G7Xb1QPnrfRueEnE5PEG5XZ" & " zAC9cnxNoyun/6NcC4oo0qETj4obTNNStI30uo+bEtJ6g9ZVAkEA9Fa/acw+DpN1" & " IxRo4ZIfrikqjCwZ+RO1aXKmndXv3s8dzWQvRgr72m31kZol1UmnpoMdPnps8Qgi" & " dnNU6B2gMwJBANGKs5B/IDB5LwIJZteCrFsltcC3cdzxmcRTKfCq6m4wx2oDWTXF" & " ZaygFtA+CXrrGxz0B0Jte3eGUpvsyasXn7MCQQDyyL+qAKgpE5xxHvaYLPoNtBny" & " 7l9gf5TjEmk8rDeMzYBvdf0DPCbFBD3eT60IIgfUDLQiQMO/PLYBvNfBTK7BAkAN" & " ZmBLSkXls6o06CMCfyHEhmnUFCcc6PpbWrIg6N0rBMWL2wD2dlQlMOukj4MNsEFA" & " nb5lGhk+MIHR5NeUsGMPAkEAuYLHs1uMpunnWbWf7XzsRPfs4mZE1VfZefqle2v6" & " L9mZsntuuiwZ/9tegrNgIMrWovHy33K9xcu9g9KIeojrag==" & " -----END RSA PRIVATE KEY-----"
S = "445488de220010752634cf01df16172c22260abcb9dc26eccbe046a38e01e2fcb098266e39e337d99bb6ce33c7c4c8334e5f19d81ef341a1e3baf14e7d0a0e1eb67ac08bd5b0b2860b214a22e5254562f743bcf66d19c9dd05e4030f5aeb07e04d016973bf639c339f600ff7be39c27b3841728726e6c22b18fe69265a701d6b"
msg = New Byte() {&H61, &H62, &H63}
' "abc"
' Extract RSA public key from private
Dim pubkeystr As String = Rsa.PublicKeyFromPrivate(Rsa.ReadPrivateKey(rsaprikey, "")).ToString()
' Verify signature using public key
r = Sig.VerifyData(S, msg, pubkeystr, SigAlgorithm.Rsa_Pss_Sha1)
Console.WriteLine("Sig.VerifyData() returns {0} (expecting 0)", r)
If r <> 0 Then
disp_error(r)
End If
Debug.Assert(0 = r)
' Same again but verify against message digest
Console.WriteLine("4. Same again but verify against message digest...")
digest = Hash.BytesFromBytes(msg, HashAlgorithm.Sha1)
Console.WriteLine("SHA1('{0}')={1}", System.Text.Encoding.[Default].GetString(msg), Cnv.ToHex(digest))
r = Sig.VerifyDigest(S, digest, pubkeystr, SigAlgorithm.Rsa_Pss_Sha1)
Console.WriteLine("Sig.VerifyDigest() returns {0} (expecting 0)", r)
If r <> 0 Then
disp_error(r)
End If
Debug.Assert(0 = r)
End Sub
Private Shared Sub test_SIG_SignData_PSS()
Console.WriteLine(vbLf & "SIGN DATA USING RSA-PSS:")
' Demonstrates:
' * Sig.SignData() using SigAlgorithm.Rsa_Pss_Sha256
' * Sig.SignData() using Sig.SigOptions.PssSaltLenZero and Sig.SigOptions.Mgf1Sha1
' * Sig.VerifyData()
' * Sig.SignFile() using SigAlgorithm.Rsa_Pss_Sha512 and Sig.SigOptions.Mgf1Sha1
' * Sig.VerifyFile()
'
Dim msg As Byte()
Dim sigval As String, oksig As String
Dim r As Integer
Dim certFile As String = "AliceRSAPssSignByCarl.cer"
Dim priKeyFile As String = "AliceRSAPSS.p8e"
' pkcs8-encrypted
Dim mypassword As String = "password"
' Input data = three-char ASCII string "abc"
msg = System.Text.Encoding.[Default].GetBytes("abc")
Console.WriteLine("MSG: {0}", Cnv.ToHex(msg))
Console.WriteLine("Sign using RSA-PSS-SHA256 (different each time)")
' This will be different each time
sigval = Sig.SignData(msg, priKeyFile, mypassword, SigAlgorithm.Rsa_Pss_Sha256)
Console.WriteLine("SIG: {0}", sigval)
If sigval.Length = 0 Then
disp_error()
End If
Debug.Assert(sigval.Length > 0)
Console.WriteLine("Verify using X.509 certificate")
' We must specify the signature algorithm used to sign it
r = Sig.VerifyData(sigval, msg, certFile, SigAlgorithm.Rsa_Pss_Sha256)
Console.WriteLine("Sig.VerifyData() returns {0} (expecting 0)", r)
If r <> 0 Then
disp_error(r)
End If
Debug.Assert(0 = r)
Console.WriteLine("Sign using RSA-PSS-SHA256 with zero-length salt (so signature is deterministic) and MGF1-with-SHA1 (just to be awkward)")
' (This should be the same each time)
sigval = Sig.SignData(msg, priKeyFile, mypassword, SigAlgorithm.Rsa_Pss_Sha256, Sig.SigOptions.PssSaltLenZero Or Sig.SigOptions.Mgf1Sha1, 0)
Console.WriteLine("SIG: {0}", sigval)
Debug.Assert(sigval.Length > 0)
' Known result
oksig = "e0eb1ocnqg9raQBcjPYhjI5+l23P8aNWUHSPgaW5mUlfh2py1IjD1c/TDGQoIpQisbaBq0yDB4DSSpW0p9RqeQK33bELI3KM6A83q/5+J76WY/ZCPDSGJRTtovV4jiRSvoqPqcL/bJcQv1j9pqH2tTQmdSgArCYAntnLpBLYR2bbm3Q/1hnrs1T8CttYje+qSPvFAmShxSS8ryIm5POj6p2aXXtdDqo47B46nYeHAVArPUT1CKEXMelZWItlTWEjzqnofLO+nquYIpb7gNBExSfkwxTbBHa88UPu35eEe0AfLaxqEudi7YCAZ6/8cBC4MUXlx8Th6PQ5kPKN+i+ibw=="
Debug.Assert(sigval = oksig)
Console.WriteLine("Verify using X.509 certificate")
' We must specify the signature algorithm used to sign it and must specify MGF1-with-SHA1, since we used that option
' (however, salt length can be detected automatically from signature value)
r = Sig.VerifyData(sigval, msg, certFile, SigAlgorithm.Rsa_Pss_Sha256, Sig.VerifyOpts.Mgf1Sha1)
Console.WriteLine("Sig.VerifyData() returns {0} (expecting 0)", r)
If r <> 0 Then
disp_error(r)
End If
Debug.Assert(0 = r)
Console.WriteLine(vbLf & "Sign a file using RSA-PSS-SHA512 with salt length set to the maximum possible; output encoded in hex")
Dim dataFile As String = "excontent.txt"
Console.WriteLine("FILE: {0}", dataFile)
' (This will be different each time)
' Set the salt length to be the maximum possible and output signature in hex encoding
sigval = Sig.SignFile(dataFile, priKeyFile, mypassword, SigAlgorithm.Rsa_Pss_Sha512, Sig.SigOptions.PssSaltLenMax, Sig.Encoding.Base16)
Console.WriteLine("SIG: {0}", sigval)
If sigval.Length = 0 Then
disp_error()
End If
Debug.Assert(sigval.Length > 0)
Console.WriteLine("Verify using X.509 certificate")
' We must specify the signature algorithm used to sign it (but salt length is found automatically)
r = Sig.VerifyFile(sigval, dataFile, certFile, SigAlgorithm.Rsa_Pss_Sha512)
Console.WriteLine("Sig.VerifyFile() returns {0} (expecting 0)", r)
If r <> 0 Then
disp_error(r)
End If
Debug.Assert(0 = r)
End Sub
Private Shared Sub test_SIG_SignData_ECDSA()
Console.WriteLine(vbLf & "SIGN DATA USING ECDSA:")
' Demonstrates:
' * Sig.SignData() using SigAlgorithm.Ecdsa_Sha256
' * Sig.SignData() using Sig.SigOptions.UseDeterministic and Sig.SigOptions.Asn1DERStructure
' * Sig.VerifyData()
'
Dim msg As Byte()
Dim sigval As String, oksig As String
Dim r As Integer
Dim certFile As String = "User_ECC_P256.cer"
Dim priKeyFile As String = "User_ECC_P256.p8e"
' pkcs8-encrypted
Dim mypassword As String = "password"
' Input data = three-char ASCII string "abc"
msg = System.Text.Encoding.[Default].GetBytes("abc")
Console.WriteLine("MSG: {0}", Cnv.ToHex(msg))
Console.WriteLine("Sign using PKI_SIG_ECDSA_SHA256 (different each time)")
' This will be different each time
sigval = Sig.SignData(msg, priKeyFile, mypassword, SigAlgorithm.Ecdsa_Sha256)
Console.WriteLine("SIG: {0}", sigval)
Debug.Assert(sigval.Length > 0)
Console.WriteLine("Verify using X.509 certificate")
' We must specify the signature algorithm used to sign it
r = Sig.VerifyData(sigval, msg, certFile, SigAlgorithm.Ecdsa_Sha256)
Console.WriteLine("Sig.VerifyData() returns {0} (expecting 0)", r)
If r <> 0 Then
disp_error(r)
End If
Debug.Assert(0 = r)
Console.WriteLine("Sign using PKI_SIG_ECDSA_SHA256 with deterministic digital signature generation procedure of [RFC6979] ")
Console.WriteLine("--output as BitCoin DER-encoded ASN.1 structure encoded in hex")
' This should be the same each time
sigval = Sig.SignData(msg, priKeyFile, mypassword, SigAlgorithm.Ecdsa_Sha256, Sig.SigOptions.UseDeterministic Or Sig.SigOptions.Asn1DERStructure, Sig.Encoding.Base16)
Console.WriteLine("SIG: {0}", sigval)
Debug.Assert(sigval.Length > 0)
' Known result
oksig = "304402202f088efe451adba26ccafe507c3db0083f14e6c7fc822970dbf73a8e30de5bc702203e8c02b4e4310aff7d1e990dc50fa633c396bebd8e1b3f7daa599e9cd8d89a74"
Console.WriteLine("OK : {0}", oksig)
Console.WriteLine("Verify using X.509 certificate")
' We must specify the signature algorithm used to sign it (everything else is detected automatically)
r = Sig.VerifyData(sigval, msg, certFile, SigAlgorithm.Ecdsa_Sha256)
Console.WriteLine("Sig.VerifyData() returns {0} (expecting 0)", r)
If r <> 0 Then
disp_error(r)
End If
Debug.Assert(0 = r)
End Sub
Private Shared Sub test_RSA_EncryptDecrypt()
Console.WriteLine(vbLf & "ENCRYPT/DECRYPT SHORT MESSAGE USING RSA:")
' Demonstrates:
' * Rsa.Encrypt() using Rsa.EME.OAEP with default SHA-1
' * Rsa.Encrypt() using Rsa.EME.OAEP and Rsa.HashAlg.Sha256
' * Rsa.Encrypt() using default PKCS#1v1_5
' * Rsa.Decrypt()
'
Dim encHex As String, msgHex As String, correctHex As String
Dim encmsg As Byte(), msg As Byte(), outmsg As Byte()
' RSA key file 1024-bit from pkcs-1v2-1-vec
Dim priKeyFile As String = "rsa-oaep-1.p8"
' PKCS#8 unencrypted PrivateKeyInfo
Dim pubKeyFile As String = "rsa-oaep-1.pub"
' PKCS#1 RSAPublicKey
' RSAES-OAEP Encryption Example 1.1 from `oaep-vect.txt` in `pkcs-1v2-1-vec.zip`
Console.WriteLine("1. Decrypt RSAES-OAEP Encryption Example 1.1 from `oaep-vect.txt` in `pkcs-1v2-1-vec.zip`")
' Cipher value from RSA-OAEP test vector
encHex = "354fe67b4a126d5d35fe36c777791a3f7ba13def484e2d3908aff722fad468fb21696de95d0be911c2d3174f8afcc201035f7b6d8e69402de5451618c21a535fa9d7bfc5b8dd9fc243f8cf927db31322d6e881eaa91a996170e657a05a266426d98c88003f8477c1227094a0d9fa1e8c4024309ce1ecccb5210035d47ac72e8a"
msg = Rsa.Decrypt(Cnv.FromHex(encHex), priKeyFile, "", Rsa.EME.OAEP, 0, 0)
msgHex = Cnv.ToHex(msg)
Console.WriteLine("msg={0}", msgHex)
' Known result from test vector
correctHex = "6628194e12073db03ba94cda9ef9532397d50dba79b987004afefe34"
Console.WriteLine("OK ={0}", correctHex)
Debug.Assert([String].Equals(correctHex, msgHex, StringComparison.OrdinalIgnoreCase))
Console.WriteLine("2a. Encrypt using RSA-OAEP with SHA-256 (different each time)")
Console.WriteLine("INPUT : {0}", Cnv.ToHex(msg))
encmsg = Rsa.Encrypt(msg, pubKeyFile, Rsa.EME.OAEP, Rsa.HashAlg.Sha256, 0)
Console.WriteLine("OUTPUT: {0}", Cnv.ToHex(encmsg))
Console.WriteLine("2b. Decrypt")
' Note we must we must specify the hash function used in RSA-OAEP
outmsg = Rsa.Decrypt(encmsg, priKeyFile, "", Rsa.EME.OAEP, Rsa.HashAlg.Sha256, 0)
Console.WriteLine("OUTPUT: {0}", Cnv.ToHex(outmsg))
Debug.Assert([String].Equals(correctHex, Cnv.ToHex(outmsg), StringComparison.OrdinalIgnoreCase))
Console.WriteLine("3a. Encrypt using default PKCS#1v1_5")
msg = Cnv.FromHex("616263")
' "abc"
Console.WriteLine("INPUT : {0}", Cnv.ToHex(msg))
encmsg = Rsa.Encrypt(msg, pubKeyFile)
Console.WriteLine("OUTPUT: {0}", Cnv.ToHex(encmsg))
Console.WriteLine("3b. Decrypt")
outmsg = Rsa.Decrypt(encmsg, priKeyFile, "")
Console.WriteLine("OUTPUT: {0}", Cnv.ToHex(outmsg))
Debug.Assert([String].Equals(Cnv.ToHex(msg), Cnv.ToHex(outmsg), StringComparison.OrdinalIgnoreCase))
End Sub
Private Shared Sub test_RSA_ToXMLStringEx()
Console.WriteLine(vbLf & "Create an XML string representation of an RSA internal key string with 'ds:' namespace prefix...")
' Demonstrates:
' * Rsa.ReadPublicKey()
' * Rsa.ToXMLString() using prefix "ds:"
'
Dim keyFile As String = "AliceRSAPssSignByCarl.cer"
' Public key inside an X.509 certificate
Console.WriteLine("FILE: {0}", keyFile)
Dim priKey As String = Rsa.ReadPublicKey(keyFile).ToString()
' Create XML string with "ds:" namespace prefix.
Dim xmlKey As String = Rsa.ToXMLString(priKey, "ds", 0)
' You'd insert this inside an <ds:KeyInfo><ds:KeyValue> element
Console.WriteLine("XML:" & vbLf & "{0}", xmlKey)
Debug.Assert(xmlKey.Length > 0)
End Sub
Private Shared Sub test_CMS_MakeSigData_PSS()
Console.WriteLine(vbLf & "Create a signed-data object using RSA-PSS...")
' Demonstrates:
' * Rsa.ReadPrivateKey()
' * Cms.MakeSigData() using Cms.SigAlg.Rsa_Pss_Sha224
' * Cms.QuerySigData()
' * Cms.VerifySigData()
' * Cms.ReadSigDataToString()
'
Dim outFile As String = "SignedData_PSS.p7s"
Dim inFile As String = "excontent.txt"
Dim certFile As String = "User_RSA_2048.cer"
Dim priKeyFile As String = "User_RSA_2048.p8e"
Dim r As Integer
Dim s As String, query As String
Dim sbPriKey As StringBuilder = Rsa.ReadPrivateKey(priKeyFile, "password")
Debug.Assert(sbPriKey.Length > 0, "Failed to read private key file")
r = Cms.MakeSigData(outFile, inFile, certFile, sbPriKey.ToString(), Cms.SigAlg.Rsa_Pss_Sha224, 0)
Debug.Assert(0 = r, "Cms.MakeSigData failed")
Console.WriteLine("Created '{0}'", outFile)
Console.WriteLine("SIGNED-DATA:" & vbLf & "{0}", Asn1.TextDumpToString(outFile, 0))
' Query the signed-data object
query = "digestAlgorithm"
s = Cms.QuerySigData(outFile, query)
Console.WriteLine("Cms.QuerySigData('{0}')={1}", query, s)
query = "signatureAlgorithm"
s = Cms.QuerySigData(outFile, query)
Console.WriteLine("Cms.QuerySigData('{0}')={1}", query, s)
query = "pssParams"
s = Cms.QuerySigData(outFile, query)
Console.WriteLine("Cms.QuerySigData('{0}')={1}", query, s)
' Verify the signed-data
r = Cms.VerifySigData(outFile)
Console.WriteLine("Cms.VerifySigData() returns {0} (expecting 0)", r)
Debug.Assert(r = 0, "Cms.VerifySigData failed")
' Read the signed data
s = Cms.ReadSigDataToString(outFile)
Console.WriteLine("signed-data='{0}'", s)
End Sub
Private Shared Sub test_MakeSignedEnveloped_PSS_OAEP()
Console.WriteLine(vbLf & "Create an enveloped-data object using RSA-OAEP" & vbLf & " containing a signed-data object signed using RSA-PSS-SHA256...")
' Wrap a signed-data object directly inside an enveloped-data object (no S/MIME wrapping).
' -- the same technique used by the latest German Health specifications (current in 2018).
' Demonstrates:
' * Rsa.ReadPrivateKey()
' * Cms.MakeSigDataFromString() using Cms.SigAlg.Rsa_Pss_Sha256
' * Cms.MakeEnvData() using Cms.KeyEncrAlgorithm.Rsa_Oaep and HashAlgorithm.Sha256
' * Cms.ReadEnvDataToFile()
' * Cms.ReadSigDataToString()
' * Cms.VerifySigData()
' * Cms.QueryEnvData()
' * Cms.QuerySigData()
' * Wipe.File()
' * Wipe.String()
'
Dim r As Integer
Dim s As String, query As String
Dim msg As String = "Hi Bob, this is a secret message from Alice."
Dim tempFile As String = "intermediate.tmp"
Dim envDataFile As String = "ToBobSignedByAlice.p7m"
Dim sbPriKey As StringBuilder
' 1.1 Alice signs the message, saved as a temp intermediate file
' -- Uses RSA-PSS with SHA-256
sbPriKey = Rsa.ReadPrivateKey("AliceRSAPSS.p8e", "password")
r = Cms.MakeSigDataFromString(tempFile, msg, "AliceRSAPssSignByCarl.cer;CarlRSAPssSelf.cer", sbPriKey.ToString(), Cms.SigAlg.Rsa_Pss_Sha256, Cms.SigDataOptions.IncludeAttributes Or Cms.SigDataOptions.AddSignTime)
Console.WriteLine("Cms.MakeSigDataFromString() returns {0} (expecting 0)", r)
Debug.Assert(0 = r)
' 1.2 The message is encrypted in an enveloped-data file using Bob's public key from his X.509 certificate
' -- uses RSA-OAEP + SHA-256 + AES-256 content encryption
r = Cms.MakeEnvData(envDataFile, tempFile, "BobRSAPssSignByCarl.cer", CipherAlgorithm.Aes256, Cms.KeyEncrAlgorithm.Rsa_Oaep, HashAlgorithm.Sha256, _
Cms.EnvDataOptions.None)
Console.WriteLine("Cms.MakeEnvData() returns {0} (expecting 1)", r)
Debug.Assert(r > 0)
' Historical anomaly - returns number or recipients, not zero
' 1.3 Delete the intermediate file and private key string
Wipe.File(tempFile)
Wipe.[String](sbPriKey)
' Show the ASN (optional - if you understand ASN.1 encoding)
'Console.WriteLine(Asn1.TextDumpToString(envDataFile, 0));
' Query some details in the enveloped-data file
Console.WriteLine("Query some details in the enveloped-data file...")
query = "contentEncryptionAlgorithm"
s = Cms.QueryEnvData(envDataFile, query)
Console.WriteLine("{0}={1}", query, s)
query = "keyEncryptionAlgorithm"
s = Cms.QueryEnvData(envDataFile, query)
Console.WriteLine("{0}={1}", query, s)
query = "oaepParams"
s = Cms.QueryEnvData(envDataFile, query)
Console.WriteLine("{0}={1}", query, s)
' Now send the encrypted file to Bob
Console.WriteLine(vbLf & "Bob decrypts the file and verifies the signed-data...")
Dim sigDataFile As String = "FromAlice.p7s"
' 2.1 Bob decrypts the outer enveloped-data object using his own private key
sbPriKey = Rsa.ReadPrivateKey("BobRSAPSS.p8e", "password")
r = Cms.ReadEnvDataToFile(sigDataFile, envDataFile, "BobRSAPssSignByCarl.cer", sbPriKey.ToString())
Console.WriteLine("Cms.ReadEnvDataToFile() returns {0} (expecting 0)", r)
Debug.Assert(0 = r, "Cannot decrypt enveloped-data object")
' 2.2a (optional) Check we have a proper signed-data object
Console.WriteLine("Query some details in the signed-data file...")
query = "signatureAlgorithm"
s = Cms.QuerySigData(sigDataFile, query)
Console.WriteLine("{0}={1}", query, s)
query = "digestAlgorithm"
s = Cms.QuerySigData(sigDataFile, query)
Console.WriteLine("{0}={1}", query, s)
query = "pssParams"
s = Cms.QuerySigData(sigDataFile, query)
Console.WriteLine("{0}={1}", query, s)
' 2.2b Verify the signature
r = Cms.VerifySigData(sigDataFile)
Console.WriteLine("Cms.VerifySigData() returns {0} (expecting 0)", r)
Debug.Assert(0 = r, "Cms.VerifysigData failed")
' 2.3 Extract the signed message
s = Cms.ReadSigDataToString(sigDataFile)
Console.WriteLine("Cms.ReadSigDataToString() returns string of length {0} (expecting +ve)", s.Length)
Debug.Assert(s.Length > 0)
Console.WriteLine("message='{0}'", s)
' 2.4 Clean up
Wipe.[String](sbPriKey)
End Sub
Private Shared Sub test_PFX_MakeFile_PSS()
Console.WriteLine(vbLf & "Create a PFX file using RSA-PSS...")
Dim pfxFile As String = "AliceRSAPSS.pfx"
Dim keyFile As String = "AliceRSAPSS.p8e"
Dim certFile As String = "AliceRSAPssSignByCarl.cer"
Dim r As Integer
Dim keyStr As String
r = Pfx.MakeFile(pfxFile, certFile, keyFile, "password", Nothing, 0)
Console.WriteLine("Pfx.MakeFile() returns {0} (expecting 0)", r)
If r <> 0 Then
disp_error(r)
End If
Debug.Assert(0 = r, "Pfx.MakeFile() failed")
' Test what sort of ASN.1 file we made (expecting "PKCS12 PFX")
Console.WriteLine("Asn1.Type({0})={1}", pfxFile, Asn1.Type(pfxFile))
' Read in the RSA private key stored in the PFX file
keyStr = Rsa.ReadPrivateKey(pfxFile, "password").ToString()
' Show we got something...
Console.WriteLine("Key bits={0}", Rsa.KeyBits(keyStr))
End Sub
Private Shared Sub test_PFX_MakeFile_AES256()
Console.WriteLine(vbLf & "Create a PFX file using AES256-SHA256...")
Dim pfxFile As String = "bob-aes256.pfx"
Dim plainKeyFile As String = "lamps-bob.p8.pem"
Dim keyFile As String = "lamps-bob.p8e"
Dim certFile As String = "lamps-bob.crt"
Dim password As String = "password"
' BAD!!
Dim r As Integer
Dim keyStr As String, certStr As String
Dim isok As Boolean
' Read in unencrypted key file then save as encrypted
keyStr = Rsa.ReadPrivateKey(plainKeyFile, "").ToString()
Debug.Assert(keyStr.Length > 0, "Rsa.ReadPrivateKey failed")
r = Rsa.SaveEncKey(keyFile, keyStr, password, Rsa.PbeOptions.Pbe_Pbkdf2_aes128_CBC)
Debug.Assert(r = 0, "Rsa.SaveEncKey failed")
' Make a PFX file using AES256-SHA256
r = Pfx.MakeFile(pfxFile, certFile, keyFile, password, "Bob's friendly AES256 ID", Pfx.Options.Aes256_Sha256)
Console.WriteLine("Pfx.MakeFile() returns {0} (expecting 0)", r)
If r <> 0 Then
disp_error(r)
End If
Debug.Assert(0 = r, "Pfx.MakeFile() failed")
' Test what sort of ASN.1 file we made (expecting "PKCS12 PFX")
Console.WriteLine("Asn1.Type({0})={1}", pfxFile, Asn1.Type(pfxFile))
' Verify the MAC in the PFX file
isok = Pfx.SignatureIsValid(pfxFile, password)
Console.WriteLine("Pfx.SignatureIsValid returns {0}", isok)
Debug.Assert(isok, "Pfx.SignatureIsValid failed")
' Dump the ASN.1 structure
Console.WriteLine(Asn1.TextDumpToString(pfxFile))
' Read in the RSA private key stored in the PFX file
keyStr = Rsa.ReadPrivateKey(pfxFile, password).ToString()
Debug.Assert(keyStr.Length > 0, "Rsa.ReadPrivateKey failed")
' Show we got something...
Console.WriteLine("Key bits={0}", Rsa.KeyBits(keyStr))
' Read in the certificate stored in the PFX file
certStr = X509.ReadCertStringFromPFX(pfxFile, password)
Debug.Assert(certStr.Length > 0, "X509.ReadCertStringFromPFX failed")
' Show we got something...
Console.WriteLine("SHA1(new-cert)={0}", X509.CertThumb(certStr, HashAlgorithm.Sha1))
Console.WriteLine("SHA1(origcert)={0}", X509.CertThumb(certFile, HashAlgorithm.Sha1))
Console.WriteLine("subjectName: {0}", X509.QueryCert(certStr, "subjectName"))
End Sub
Private Shared Sub test_CIPHER_EncryptAEAD()
Console.WriteLine(vbLf & "ENCRYPT USING AEAD...")
Dim key As Byte(), iv As Byte(), pt As Byte(), aad As Byte()
Dim ct As Byte(), dt As Byte()
Dim okhex As String
' GCM Test Case #03 (AES-128)
Console.WriteLine("GCM Test Case #03 (AES-128)")
key = Cnv.FromHex("feffe9928665731c6d6a8f9467308308")
iv = Cnv.FromHex("cafebabefacedbaddecaf888")
pt = Cnv.FromHex("d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255")
okhex = "42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091473f59854d5c2af327cd64a62cf35abd2ba6fab4"
Console.WriteLine("KY={0}", Cnv.ToHex(key))
Console.WriteLine("IV={0}", Cnv.ToHex(iv))
Console.WriteLine("PT={0}", Cnv.ToHex(pt))
ct = Cipher.EncryptAEAD(pt, key, iv, AeadAlgorithm.Aes_128_Gcm)
Console.WriteLine("CT={0}", Cnv.ToHex(ct))
Console.WriteLine("OK={0}", okhex)
If ct.Length = 0 Then
disp_error()
End If
Debug.Assert(ByteArraysEqual(ct, Cnv.FromHex(okhex)))
Console.WriteLine("Decrypt...")
dt = Cipher.DecryptAEAD(ct, key, iv, AeadAlgorithm.Aes_128_Gcm)
Console.WriteLine("DT={0}", Cnv.ToHex(dt))
Debug.Assert(ByteArraysEqual(dt, pt))
Console.WriteLine("Same again but prepend IV to start of output")
ct = Cipher.EncryptAEAD(pt, key, iv, Nothing, AeadAlgorithm.Aes_128_Gcm, Cipher.Opts.PrefixIV)
Console.WriteLine("CT={0}", Cnv.ToHex(ct))
Console.WriteLine("Decrypt...")
dt = Cipher.DecryptAEAD(ct, key, iv, Nothing, AeadAlgorithm.Aes_128_Gcm, Cipher.Opts.PrefixIV)
Console.WriteLine("DT={0}", Cnv.ToHex(dt))
Debug.Assert(ByteArraysEqual(dt, pt))
Console.WriteLine("GCM Test Case #16 (AES-256)")
key = Cnv.FromHex("feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308")
iv = Cnv.FromHex("cafebabefacedbaddecaf888")
pt = Cnv.FromHex("d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39")
aad = Cnv.FromHex("feedfacedeadbeeffeedfacedeadbeefabaddad2")
okhex = "522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f66276fc6ece0f4e1768cddf8853bb2d551b"
Console.WriteLine("KY={0}", Cnv.ToHex(key))
Console.WriteLine("IV={0}", Cnv.ToHex(iv))
Console.WriteLine("PT={0}", Cnv.ToHex(pt))
Console.WriteLine("AD={0}", Cnv.ToHex(aad))
ct = Cipher.EncryptAEAD(pt, key, iv, aad, AeadAlgorithm.Aes_256_Gcm, 0)
Console.WriteLine("CT={0}", Cnv.ToHex(ct))
Console.WriteLine("OK={0}", okhex)
If ct.Length = 0 Then
disp_error()
End If
Debug.Assert(ByteArraysEqual(ct, Cnv.FromHex(okhex)))
Console.WriteLine("Decrypt...")
dt = Cipher.DecryptAEAD(ct, key, iv, aad, AeadAlgorithm.Aes_256_Gcm, 0)
Console.WriteLine("DT={0}", Cnv.ToHex(dt))
Debug.Assert(ByteArraysEqual(dt, pt))
Console.WriteLine("GCM Test Case #07 (AES-192)")
key = Cnv.FromHex("000000000000000000000000000000000000000000000000")
iv = Cnv.FromHex("000000000000000000000000")
' Plaintext is the empty string - a zero-length byte array
pt = Cnv.FromHex("")
' IV is prepended to output
okhex = "000000000000000000000000cd33b28ac773f74ba00ed1f312572435"
Console.WriteLine("KY={0}", Cnv.ToHex(key))
Console.WriteLine("IV={0}", Cnv.ToHex(iv))
Console.WriteLine("PT={0}", Cnv.ToHex(pt))
ct = Cipher.EncryptAEAD(pt, key, iv, Nothing, AeadAlgorithm.Aes_192_Gcm, Cipher.Opts.PrefixIV)
Console.WriteLine("CT={0}", Cnv.ToHex(ct))
Console.WriteLine("OK={0}", okhex)
If ct.Length = 0 Then
disp_error()
End If
Debug.Assert(ByteArraysEqual(ct, Cnv.FromHex(okhex)))
Console.WriteLine("Decrypt...")
dt = Cipher.DecryptAEAD(ct, key, iv, Nothing, AeadAlgorithm.Aes_256_Gcm, Cipher.Opts.PrefixIV)
Console.WriteLine("DT={0}", Cnv.ToHex(dt))
Debug.Assert(ByteArraysEqual(dt, pt))
End Sub
Private Shared Sub test_X509_ReadCertFromP7Chain()
Console.WriteLine(vbLf & "READ CERTS AS BASE64 STRING FROM P7 CHAIN DATA...")
Dim ncerts As Integer, i As Integer
Dim certstr As String
Dim s As String
' Input is a P7 chain file as a string in PEM format
' bob.p7b (contains 2 X.509 certs: BobRSA and CarlRSA)
Dim p7str As String = "-----BEGIN PKCS7-----" & "MIIERQYJKoZIhvcNAQcCoIIENjCCBDICAQExADALBgkqhkiG9w0BBwGgggQaMIICJzCCAZCgAwIB" & "AgIQRjRrx4AAVrwR024uzV1x0DANBgkqhkiG9w0BAQUFADASMRAwDgYDVQQDEwdDYXJsUlNBMB4X" & "DTk5MDkxOTAxMDkwMloXDTM5MTIzMTIzNTk1OVowETEPMA0GA1UEAxMGQm9iUlNBMIGfMA0GCSqG" & "SIb3DQEBAQUAA4GNADCBiQKBgQCp4WeYPznVX/Kgk0FepnmJhcg1XZqRW/sdAdoZcCYXD72lItA1" & "hW16mGYUQVzPt7cIOwnJkbgZaTdt+WUee9mpMySjfzu7r0YBhjY0MssHA1lS/IWLMQS4zBgIFEjm" & "Txz7XWDE4FwfU9N/U9hpAfEF+Hpw0b6Dxl84zxwsqmqn6wIDAQABo38wfTAMBgNVHRMBAf8EAjAA" & "MA4GA1UdDwEB/wQEAwIFIDAfBgNVHSMEGDAWgBTp4JAnrHggeprTTPJCN04irp44uzAdBgNVHQ4E" & "FgQU6PS4Z9izlqQq8xGqKdOVWoYWtCQwHQYDVR0RBBYwFIESQm9iUlNBQGV4YW1wbGUuY29tMA0G" & "CSqGSIb3DQEBBQUAA4GBAHuOZsXxED8QIEyIcat7QGshM/pKld6dDltrlCEFwPLhfirNnJOIh/uL" & "t359QWHh5NZt+eIEVWFFvGQnRMChvVl52R1kPCHWRbBdaDOS6qzxV+WBfZjmNZGjOd539OgcOync" & "f1EHl/M28FAK3Zvetl44ESv7V+qJba3JiNiPzyvTMIIB6zCCAVSgAwIBAgIQRjRrx4AAVrwR024u" & "n/JQIDANBgkqhkiG9w0BAQUFADASMRAwDgYDVQQDEwdDYXJsUlNBMB4XDTk5MDgxODA3MDAwMFoX" & "DTM5MTIzMTIzNTk1OVowEjEQMA4GA1UEAxMHQ2FybFJTQTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw" & "gYkCgYEA5Ev/GLgkV/R3/25ze5NxXLwzGpKSciPYQUbQzRE6BLOOr4KdvVEeF3rydiwrhjmnvdeN" & "GlPs5ADV6OyiNrHt4lDiMgmKP5+ZJY+4Tqu5fdWWZdoWoMW+Dq5EW+9e9Kcpy4LdrETpqpOUKQ74" & "GNbIV17ydsTyEWA4uRs8HZfJavECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E" & "BAMCAYYwHQYDVR0OBBYEFOngkCeseCB6mtNM8kI3TiKunji7MA0GCSqGSIb3DQEBBQUAA4GBALee" & "1ATT7Snk/4mJFS5M2wzwSA8yYe7EBOwSXS3/D2RZfgrD7Rj941ZAN6cHtfA4EmFQ7e/dP+MLuGGl" & "pJs85p6cVJq2ldbabDu1LUU1nUkBdvq5uTH5+WsSU6D1FGCbfco+8lNrsDdvreZ019v6WuoUQWNd" & "zb7IDsHaao1TNBgCMQA=" & "-----END PKCS7-----"
' Check type of ASN.1 data
s = Asn1.Type(p7str)
Console.WriteLine("Data type is [{0}]", s)
' Get count of certs in P7
s = X509.ReadCertStringFromP7Chain(p7str, 0)
Debug.Assert(s.Length > 0)
' Count is returned as a string, e.g. "2", so convert to a number
ncerts = Int32.Parse(s)
Console.WriteLine("ncerts={0}", ncerts)
' Read each cert in turn
For i = 1 To ncerts
certstr = X509.ReadCertStringFromP7Chain(p7str, i)
Console.WriteLine("{0}", certstr)
' Query the cert for subjectName
s = X509.QueryCert(certstr, "subjectName")
Console.WriteLine("subjectName='{0}'", s)
Next
End Sub
Private Shared Sub test_X509_ReadCertFromPFX()
Console.WriteLine(vbLf & "READ CERT AS BASE64 STRING FROM PFX...")
Dim certstr As String
Dim s As String
' Input is a PFX file as a string in PEM format
' bob.pfx (password="password")
Dim pfxStr As String = "-----BEGIN PKCS12-----" & "MIIGhAIBAzCCBkoGCSqGSIb3DQEHAaCCBjsEggY3MIIGMzCCAv8GCSqGSIb3DQEHBqCCAvAwggLsAgEAMIIC5QYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQYwDgQIawU" & "AVTFvAiECAggAgIICuNwEuFcRnZamZyMyIn+vH+wC5BVUtZAWNrlIqToezF7cYqt/18+HXB/46nllz+qUD3Dv9rS78MnPeAM47afFRTricHsiOpE+2eXf32lxduoF5+" & "CLS3S7TAhRUMp2Fh18LlukzK9lY67BGfU9Y3yCukTmwVXqe49dkj8y9JjVJhXnoc2c7eOk3o5RjXHFsAMHwirqdsESHstrDZYLMVGw5HnAamY7zQd8WUpIweAFaEDLJ" & "fyzqY1/LTL/txvZ9VQ/B/36HKyEpoIvuH6iOCBkebpJwWSkkffuVFbUfMLguMztL/sf+jE2NiuljSBJ9pTNsZziZWERb6CxZH0a2xkkBTciXM5Dl5efWL0GmBg+aJSI" & "yh+Gw5W8Q7gmnH6H9myszvW9uYv/epwCbIpHd0dRHPbL3fR4KGhFexq24tAG86tDqPKb6H6n0lSA+Oq46SwZ00xIFpVcFaO/8yVqf6+JRDGoZ55aAZF6OCi7R1GvI+6" & "pzz37pvP7SWfqVSuXCTNQq9uKw97SH5YftQ9hkELQ4vHCjFh4UJSBUCZgDtqR1uB/+44H5UpP8KvbETaOFJszMxsqXBMqc1uEODSNg+EHEx+yg7Bx1CcNrm+6rtThC4" & "9+ow18HDMxbn3lAw1ooblANvSzR4YTt68N/4dtwROOdXjwKzyg03qWK2sJaiH5LzbB5MMmrdAChb9dLoRKBN2LREob7KRKEs6v51IW1yq4UCwSmpP+RbchZwIoKVXx/" & "MYKjVqzGfZAgBRpXEq/KH/8R+ttFPKdab2GAEjd7hIOmetp5einQmK4C7JYE6Uyabf1IImtVhBw2dGU3GiM2zSIGqCx3bmYETZheMTAV9MMVUYe8gQeEpbXM4GAnwX0" & "wpS0aYapzGeA/62X2nFh21eRHVzUcf0miXVvyOy6a1vj6O6N5F1jVaCV3jCCAywGCSqGSIb3DQEHAaCCAx0EggMZMIIDFTCCAxEGCyqGSIb3DQEMCgECoIICpjCCAqI" & "wHAYKKoZIhvcNAQwBAzAOBAjw/dx4SlLcWwICCAAEggKALm91I8gYuPpRTCSn5pN4OQBLbI6jSW+9FGeNYvOy/+Pt3Oq0i15ZXZZez7dP8rdb0tmTCSZwVPIwtJRKxY" & "UNaTppUTWZhXhnmeTMtSZpFuKmo6UhW8lGUcg45sO5UKUtdH0/UgewaSUfV4L06vp4j7Fugwbp666seJJ/9vQwMAxoqj0blxNNmASAcW7yj/lA2/p4KuGlnGkv4MSW5" & "ViH7T24VeFXTzyFFR7UR1Nw9Blr5jdr7b2rZSdTj0GeHZ/L3FksFWJocl8PEEL4ZdVscbvO+l7vtbeBz0y9TDr/HUwt2tfqXgjckVVoJhmsczJXrG5Ai+brKnGQ7R5u" & "IpIsqd9O6EpG68VMMGA5iSKsLYtibieqom8mRO00sFiQharxONEdveY+3O98nG6xzHlaBdNbxVo38Y+4LK6Gc81dUWYwss3ajdiJWe0+TYQjMPF72eWctcQAoTxITpd" & "/j6rD7EmvLVyPIR46L4w6Gb/uz5G1T1UiLoh9luM1nRKKICyo2XllZDNO0msaub7DH1xzJzEy2OT9cwChqYfKKeWEE2BWL699fmq5RMCbIQVtE2bJDP8obu9j6HLskC" & "iZcJm6nC7IKS1pQ2BA/JJVKxC8ADuLOAOdicWquDd8MWL5a9HpXd5TtUlfiRecTw8IRozTLaoDVlhaYNGPzwkjL9zZ+Up5Uy6HHXMDb0aD0fgvMqdAspB1+Xlt2RgP6" & "CnEH2hwQqGFoA8TtijeS+DtdMy8BxJ7g1fiEH0+4UISl1vymjPI1MJCI1VlFLvpjZvKHluwjgp1SHk3tFRJLJ8a/eApvmscKXSlxcYz+5Bv8dxPGdhO/KOLQS7XZ4a8" & "VSg977WS1jFYMCMGCSqGSIb3DQEJFTEWBBRj8EbS3XBC5R/cJqUR73yB6mItizAxBgkqhkiG9w0BCRQxJB4iAEIAbwBiACcAcwAgAGYAcgBpAGUAbgBkAGwAeQAgAEk" & "ARDAxMCEwCQYFKw4DAhoFAAQUaHSMUJ415FfKGv3cZpwloKDmqgYECAreM3EkHVjCAgIIAA==" & "-----END PKCS12-----"
' Check type of ASN.1 data
s = Asn1.Type(pfxStr)
Console.WriteLine("Data type is [{0}]", s)
' Read in cert as base64 string
certstr = X509.ReadCertStringFromPFX(pfxStr, "password")
' SECURITY!!
Console.WriteLine("{0}", certstr)
' Query the cert for subjectName
s = X509.QueryCert(certstr, "subjectName")
Console.WriteLine("subjectName='{0}'", s)
End Sub
' NEW IN [v12.2]
Private Shared Sub test_Cms_Data_Bytes()
Console.WriteLine(vbLf & "CMS SIGNED DATA USING RAW BYTES:")
' We will create a signed-data object with "raw" content as a UTF-8-encoded XML document.
Dim sigdataFile As String = "sigDataByAlice.p7m"
Dim prikeyFile As String = "AlicePrivRSASign.p8e"
Dim certFile As String = "AliceRSASignByCarl.cer"
Dim sbPrivateKey As StringBuilder
Dim r As Integer
Dim query As String, s As String
Dim contentArr As Byte()
' Create an XML document as a string with lots of obscure characters
' and a Byte-Order Mark (BOM).
Dim xmlStr As String = "<?xml version=""1.0""?><doc>" & vbLf & "<name c='es'>Íñigo</name>" & vbLf & "<name c='fr'>Françoise</name>" & vbLf & "<name c='pl'>Błażej</name>" & vbLf & "<name c='cn'>大卫</name>" & vbLf & "</doc>"
Console.OutputEncoding = System.Text.Encoding.UTF8
Console.WriteLine("Raw XML (may not all display correctly in console):")
Console.WriteLine("{0}", xmlStr)
Console.WriteLine("XML as string is {0} chars", xmlStr.Length)
' Convert this .NET Unicode string to UTF8 encoding
Dim xmlArr As Byte() = System.Text.Encoding.UTF8.GetBytes(xmlStr)
Console.WriteLine("XML as UTF-8 bytes is {0} bytes", xmlArr.Length)
' Display in hex
Console.WriteLine("UTF-8 in hex:")
Console.WriteLine(Cnv.ToHex(xmlArr))
' Now sign this using Alice's private key
sbPrivateKey = Rsa.ReadPrivateKey(prikeyFile, "password")
r = Cms.MakeSigDataFromBytes(sigdataFile, xmlArr, certFile, sbPrivateKey.ToString(), Cms.SigAlg.Rsa_Sha1, 0)
Console.WriteLine("Cms.MakeSigDataFromBytes() returns {0} (expecting 0)", r)
' Clean up private key
Wipe.[String](sbPrivateKey)
Debug.Assert(0 = r)
Console.WriteLine("Created signed-data file '{0}'", sigdataFile)
' Query the new signed-data object
query = "HASeContent"
s = Cms.QuerySigData(sigdataFile, query)
Console.WriteLine("Cms.QuerySigData('{0}')={1}", query, s)
' Extract the signed content to a new byte array
contentArr = Cms.ReadSigDataToBytes(sigdataFile)
Console.WriteLine("Content length is {0} bytes", contentArr.Length)
' We know it's UTF-8-encoded so we can convert back to a .NET Unicode string
Dim contentStr As String = System.Text.Encoding.UTF8.GetString(contentArr)
Console.WriteLine("{0}", contentStr)
Console.WriteLine("Content as string is {0} chars", contentStr.Length)
' Extract and save UTF-8-encoded XML to file
Dim xmlFile As String = "exampleUTF8.xml"
r = Cms.ReadSigDataToFile(xmlFile, sigdataFile)
Console.WriteLine("Cms.ReadSigDataToFile() returns {0} (expecting +ve)", r)
Debug.Assert(r > 0)
' NB returns # bytes in file, not zero
Console.WriteLine("Extracted content to file '{0}'", xmlFile)
Console.WriteLine(vbLf & "CMS ENVELOPED DATA USING RAW BYTES:")
' Use the same XML data to make an enveloped data file for Bob, Alice and Carl
' But first we'll make a PKCS#7 certificate chain file and use that to create the env-data
Dim p7file As String = "bob_alice_carl.p7b"
' No need for input file or private key (P7 cert chain is a "degenerate" signed-data file)
r = Cms.MakeSigData(p7file, "", "BobRSASignByCarl.cer;AliceRSASignByCarl.cer;CarlRSASelf.cer", "", Cms.SigAlg.[Default], Cms.SigDataOptions.CertsOnly)
Console.WriteLine("Cms.MakeSigData returns {0}", r)
Debug.Assert(0 = r)
Console.WriteLine("Created P7 chain file '{0}'", p7file)
Console.WriteLine("ASN.1 type={0}", Asn1.Type(p7file))
Dim envdataFile As String = "envDataForBobAliceCarl.p7m"
' Use AES-128 for content encryption and RSA-OAEP with SHA-256 for key transport
' [New in v12.2] we can pass a P7 file instead of a list of certificates
r = Cms.MakeEnvDataFromBytes(envdataFile, xmlArr, p7file, CipherAlgorithm.Aes128, Cms.KeyEncrAlgorithm.Rsa_Oaep, HashAlgorithm.Sha256, _
0)
Console.WriteLine("Cms.MakeEnvDataFromBytes returns {0} (= # recipients)", r)
Debug.Assert(r > 1)
Console.WriteLine("Created enveloped-data file '{0}'", envdataFile)
' Any of Bob, Alice or Carl can decrypt the message - we'll use Bob's private key
sbPrivateKey = Rsa.ReadPrivateKey("BobPrivRSAEncrypt.p8e", "password")
Dim arrMsg As Byte() = Cms.ReadEnvDataToBytes(envdataFile, "", sbPrivateKey.ToString())
' Display in hex
Console.WriteLine("Received message in hex:")
Console.WriteLine(Cnv.ToHex(arrMsg))
End Sub
Private Shared Sub test_ReadJWK()
Console.WriteLine(vbLf & "READ IN RSA KEY REPRESENTED AS JSON JWK:")
' RSA public key as a JSON string
' Ref: RFC 7517 JSON Web Key (JWK) Appendix A.1
Dim json As String = "{""kty"":""RSA""," & """n"": ""0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx" & "4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMs" & "tn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2" & "QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbI" & "SD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqb" & "w0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw""," & """e"":""AQAB""," & """alg"":""RS256""," & """kid"":""2011-04-29""}"
Console.WriteLine("JSON key={0}", json)
Dim sbPublicKey As StringBuilder = Rsa.ReadPublicKey(json)
Debug.Assert(sbPublicKey.Length > 0)
' Display some key properties
Console.WriteLine("RSA key size = {0} bits", Rsa.KeyBits(sbPublicKey.ToString()))
Console.WriteLine("Key hash code = 0x{0,8:X}", Rsa.KeyHashCode(sbPublicKey.ToString()))
End Sub
' NEW IN [v12.3]
Private Shared Sub test_Cipher_Encrypt_Prefix()
Console.WriteLine(vbLf & "ENCRYPT WITH PREFIXED IV xmlenc#aes128-cbc:")
Dim plain As String = "<encryptme>hello world</encryptme>"
Dim ciphervalue As String
Dim key As Byte() = Cnv.FromHex("6162636465666768696A6B6C6D6E6F70")
Dim iv As Byte() = Rng.Bytes(Cipher.BlockBytes(CipherAlgorithm.Aes128))
Dim pt As Byte() = Encoding.UTF8.GetBytes(plain)
Console.WriteLine("PT='{0}'", plain)
Console.WriteLine("PT={0}", Cnv.ToHex(pt))
Console.WriteLine("KEY={0}", Cnv.ToHex(key))
Console.WriteLine("IV={0}", Cnv.ToHex(iv))
Dim ct As Byte() = Cipher.Encrypt(pt, key, iv, CipherAlgorithm.Aes128, Mode.CBC, Padding.Pkcs5, _
Cipher.Opts.PrefixIV)
Console.WriteLine("IV|CT={0}", Cnv.ToHex(ct))
' Encode using base64
ciphervalue = Cnv.ToBase64(ct)
' NB different each time
Console.WriteLine("<CipherValue>{0}</CipherValue>", ciphervalue)
'------------------
' PART 2 - decrypt
Console.WriteLine("DECRYPTING...")
ct = Cnv.FromBase64(ciphervalue)
Console.WriteLine("IV|CT={0}", Cnv.ToHex(ct))
Dim dt As Byte() = Cipher.Decrypt(ct, key, Nothing, CipherAlgorithm.Aes128, Mode.CBC, Padding.Pkcs5, _
Cipher.Opts.PrefixIV)
Console.WriteLine("DT={0}", Cnv.ToHex(dt))
' Convert from bytes to string
Console.WriteLine("DT='{0}'", Encoding.UTF8.GetString(dt))
End Sub
Private Shared Sub test_X509_MakeCert_EmptyDN()
Console.WriteLine(vbLf & "MAKE CERT WITH EMPTY DN:")
Dim certname As String = "AliceRSA-emptyDN.cer"
Dim issuerCert As String = "CarlRSASelf.cer"
Dim prikeyfile As String = "CarlPrivRSASign.p8e"
Dim password As String = "password"
Dim subjectPubKeyFile As String = "AlicePubRSA.pub"
Dim dn As String = "$"
' special flag for empty DN
Dim extns As String = "iPAddress=192.168.15.1"
' at least one field for subject alt name is required
Dim keyUsage As X509.KeyUsageOptions = X509.KeyUsageOptions.DigitalSignature Or X509.KeyUsageOptions.NonRepudiation
' Create a new certificate for Alice signed by Carl valid for 2 years signed using RSA-SHA-256
' Subject's distinguished name is empty, Subject alternative name is automatically marked CRITICAL (denoted "[!]" in dump)
Dim r As Integer = X509.MakeCert(certname, issuerCert, subjectPubKeyFile, prikeyfile, &H1001, 2, _
dn, extns, keyUsage, password, SigAlgorithm.Rsa_Sha256, X509.CertOptions.AuthKeyId)
If r <> 0 Then
disp_error(r)
End If
Debug.Assert(0 = r, "X509.MakeCert failed")
Console.WriteLine("Created new X509 file '{0}'", certname)
x509DumpFile(certname)
End Sub
Private Shared Sub test_X509_CertRequest_EmptyDN_extKeyUsage()
Console.WriteLine(vbLf & "MAKE CERTIFICATE SIGNING REQUEST WITH EMPTY DN AND EXTENDED KEY USAGE:")
Dim csrfile As String = "req_emptydn_extkeyusage.p10"
Dim epkfile As String = "AlicePrivRSASign.p8e"
Dim password As String = "password"
Dim dn As String = "$"
' special flag for empty DN
' Use extensions parameter to add alt subject name and extended key usage flags
Dim extns As String = "iPAddress=192.168.15.1;extKeyUsage=serverAuth,clientAuth,emailProtection,critical;"
Dim r As Integer
Dim certfile As String = "certfromcsr_emptydn_extkeyusage.cer"
Dim issuerCert As String = "CarlRSASelf.cer"
Dim issuerEpkfile As String = "CarlPrivRSASign.p8e"
Dim issuerPassword As String = "password"
Dim query As String
Dim s As String
' Create a CSR for Alice
' Subject's distinguished name is empty, Subject alternative name is marked CRITICAL (denoted "[!]" in dump)
r = X509.CertRequest(csrfile, epkfile, dn, extns, password, SigAlgorithm.Rsa_Sha256, _
X509.CsrOptions.[Default])
If r <> 0 Then
disp_error(r)
End If
Debug.Assert(0 = r, "X509.CertRequest failed")
Console.WriteLine("Created certificate request '{0}'", csrfile)
x509DumpFile(csrfile)
' Now use this PKCS#10 CSR to create an end-user X.509 certificate for Alice signed by Carl valid for 4 years
r = X509.MakeCert(certfile, issuerCert, csrfile, issuerEpkfile, &H10b, 4, _
"", "", 0, issuerPassword, SigAlgorithm.Rsa_Sha256, X509.CertOptions.[Default])
If r <> 0 Then
disp_error(r)
End If
Debug.Assert(0 = r, "X509.MakeCert failed")
Console.WriteLine("Created end-user X.509 certificate '{0}'", certfile)
x509DumpFile(certfile)
' Query the new certificate
query = "subjectName"
s = X509.QueryCert(certfile, query)
Console.WriteLine("Query {0}='{1}'", query, s)
query = "subjectAltName"
s = X509.QueryCert(certfile, query)
Console.WriteLine("Query {0}='{1}'", query, s)
query = "extKeyUsageString"
s = X509.QueryCert(certfile, query)
Console.WriteLine("Query {0}='{1}'", query, s)
End Sub
Private Shared Sub test_X509_ReadCertStringFromPFX_3des()
Console.WriteLine(vbLf & "READ IN CERT AS A STRING FROM PFX FILE USING 3DES ENCRYPTION:")
' PFX file from draft-dkg-lamps-samples-02 with cert encrypted using "stronger" 3DES
' Ref: IETF LAMPS WG https://gitlab.com/dkg/lamps-samples
Dim pfxfile As String = "bob-lamps.p12"
Dim password As String = "bob"
Dim okcerthash As String = "6688f64f99744f7faf1059e2b49d1f5042bb2406"
Console.WriteLine("FILE: {0}", pfxfile)
' Extract cert as a base64 string
Dim certstr As String = X509.ReadCertStringFromPFX(pfxfile, password)
Debug.Assert(certstr.Length > 0, "X509.ReadCertstringFromPFX failed")
Console.WriteLine("BASE64(CER)={0}...{1}", certstr.Substring(0, 30), certstr.Substring(certstr.Length - 20))
' Check digest
Dim digest As String = X509.CertThumb(certstr, HashAlgorithm.Sha1)
Console.WriteLine("SHA-1(CER)={0}", digest)
Console.WriteLine("OK ={0}", okcerthash)
Debug.Assert(digest = okcerthash, "Cert thumbprints do not match")
' Get name of ASN.1 object
Dim asn1type As String = Asn1.Type(certstr)
Console.WriteLine("Asn1.Type(CER)={0}", asn1type)
End Sub
Private Shared Sub test_PFX_MakeFile_3DES()
Console.WriteLine(vbLf & "CREATE A NEW PFX FILE USING 3DES TO ENCRYPT THE CERT:")
Dim epkfile As String = "BobPrivRSAEncrypt.p8e"
Dim certfile As String = "BobRSASignByCarl.cer"
Dim pfxfile As String = "bob-3des.pfx"
Dim password As String = "password"
' Use StrongCert option to encrypt cert using "stronger" 3DES instead of weak default 40-bit RC2.
Dim r As Integer = Pfx.MakeFile(pfxfile, certfile, epkfile, password, "Old Bob", Pfx.Options.StrongCert)
Console.WriteLine("Pfx.MakeFile returns {0} (expecting 0)", r)
Debug.Assert(0 = r, "Pfx.MakeFile failed")
' Check type of file we just made
Dim asn1type As String = Asn1.Type(pfxfile)
Console.WriteLine("Asn1.Type={0}", asn1type)
' Now dump the ASN.1
' Note that "pkcs-12-pkcs-8ShroudedKeyBag" is encrypted with "pbeWithSHAAnd3-KeyTripleDES-CBC"
' (see lines 89 and 95 (approx) of output)
asn1DumpFile(pfxfile)
End Sub
Private Shared Sub test_Rng_Guid()
Console.WriteLine(vbLf & "GENERATE RANDOM GUID (UUID) STRINGS:")
Dim s As String
For i As Integer = 0 To 4
s = Rng.Guid()
Console.WriteLine(s)
Next
End Sub
' [v12.3.1]
Private Shared Sub test_CMS_MakeSigData_signingcert()
Console.WriteLine(vbLf & "MAKE CMS SIGNED DATA WITH SIGNING CERTIFICATE ATTRIBUTE:")
Dim xmldata As String = "<a>Some sample content.</a>"
Dim certfile As String = "alice-lamps.crt"
Dim keyfile As String = "alice-lamps.p12"
Dim password As String = "alice"
Dim outfile As String = "signedbyalice-signingcert.p7m"
' Read in private key to an ephemeral string
Dim sbPrivateKey As StringBuilder = Rsa.ReadPrivateKey(keyfile, password)
' Set options
Dim sdopts As Cms.SigDataOptions = Cms.SigDataOptions.AltAlgId Or Cms.SigDataOptions.IncludeAttributes Or Cms.SigDataOptions.AddSignTime Or Cms.SigDataOptions.AddSigningCertificate
' Create signed-data object using RSA-SHA256
Dim r As Integer = Cms.MakeSigDataFromString(outfile, xmldata, certfile, sbPrivateKey.ToString(), Cms.SigAlg.Rsa_Sha256, sdopts)
Console.WriteLine("Cms.MakeSigDataFromString returns {0} (expected 0)", r)
asn1DumpFile(outfile)
End Sub
' [v20.0.0]
Private Shared Sub test_CIPHER_EncryptHex()
Console.WriteLine(vbLf & "ENCRYPT DATA USING HEX-ENCODED PARAMETERS:")
' Aes128/CBC/OneAndZeroes
Dim keyHex As String = "0123456789ABCDEFF0E1D2C3B4A59687"
Dim ivHex As String = "FEDCBA9876543210FEDCBA9876543210"
' "Now is the time for all good men to"
Dim plainHex As String = "4E6F77206973207468652074696D6520666F7220616C6C20676F6F64206D656E20746F"
Dim okHex As String = "C3153108A8DD340C0BCB1DFE8D25D2320EE0E66BD2BB4A313FB75C5638E9E1771D4CDA34FBFB7E74B321F9A2CF4EA61B"
Dim cipherHex As String, chkHex As String
Dim alg As CipherAlgorithm = CipherAlgorithm.Aes128
Dim mode__1 As Mode = Mode.CBC
Dim pad As Padding = Padding.OneAndZeroes
Console.WriteLine("ALG: {0}/{1}/{2}", alg, mode__1, pad)
Console.WriteLine("KY={0}", keyHex)
Console.WriteLine("IV={0}", ivHex)
Console.WriteLine("PT={0}", plainHex)
' Aes128/CBC/OneAndZeroes
cipherHex = Cipher.Encrypt(plainHex, keyHex, ivHex, alg, mode__1, pad)
Console.WriteLine("CT={0}", cipherHex)
Debug.Assert(cipherHex = okHex, "Cipher.Encrypt failed")
chkHex = Cipher.Decrypt(cipherHex, keyHex, ivHex, alg, mode__1, pad)
Console.WriteLine("P'={0}", chkHex)
Debug.Assert(chkHex = plainHex, "Cipher.Decrypt failed")
Console.WriteLine("P'='{0}'", Cnv.StringFromHex(chkHex))
' Again using PrefixIV
cipherHex = Cipher.Encrypt(plainHex, keyHex, ivHex, alg, mode__1, pad, _
Cipher.Opts.PrefixIV)
Console.WriteLine("CT(PrefixIV)={0}", cipherHex)
Debug.Assert(cipherHex = ivHex & okHex, "Cipher.Encrypt(PrefixIV) failed")
chkHex = Cipher.Decrypt(cipherHex, keyHex, ivHex, alg, mode__1, pad, _
Cipher.Opts.PrefixIV)
Console.WriteLine("P'={0}", chkHex)
Debug.Assert(chkHex = plainHex, "Cipher.Decrypt failed")
Console.WriteLine("P'='{0}'", Cnv.StringFromHex(chkHex))
End Sub
Private Shared Sub test_RSA_XML_withprefixes()
Console.WriteLine(vbLf & "CONVERT BETWEEN RSA KEY VALUE AND XML KEY FORM:")
' Read in private key from key file
Dim keyfile As String = "AlicePrivRSASign.p8e"
Console.WriteLine("FILE: {0}", keyfile)
Dim prikeystr As String = Rsa.ReadPrivateKey(keyfile, "password").ToString()
Console.WriteLine("Private key has {0} bits", Rsa.KeyBits(prikeystr))
Console.WriteLine("Private key hashcode = 0x{0,8:X}", Rsa.KeyHashCode(prikeystr))
' Convert to XML RSAKeyPair form with prefix
Dim xmlstr As String = Rsa.ToXMLString(prikeystr, "ds:", 0)
Console.WriteLine(xmlstr)
' Now read in public key from this XML string (fixed to cope with prefixes in [v20.0])
Dim pubkeystr As String = Rsa.ReadPublicKey(xmlstr).ToString()
Console.WriteLine("Public key has {0} bits", Rsa.KeyBits(pubkeystr))
Console.WriteLine("Public key hashcode = 0x{0,8:X}", Rsa.KeyHashCode(pubkeystr))
Debug.Assert(Rsa.KeyHashCode(prikeystr) = Rsa.KeyHashCode(pubkeystr), "KeyHashCodes do not match")
End Sub
Private Shared Sub test_ECC_DHSharedSecret()
Console.WriteLine(vbLf & "ECDH SHARED SECRET USING P-256:")
' Ref: CAVS 14.1 ECC CDH Primitive (SP800 - 56A Section 5.7.1.2)
' Test Information for "testecccdh" ecccdhtestvectors.zip
' [P-256]
Dim curve As Ecc.CurveName = Ecc.CurveName.P_256
' Our private key is dUIT:
Dim ourPrivateKeyHex As String = "7d7dc5f71eb29ddaf80d6214632eeae03d9058af1fb6d22ed80badb62bc1a534"
' Their public key as hex is "04" || QCAVSx || QCAVSy
Dim theirPublicKeyHex As String = "04" & "700c48f77f56584c5cc632ca65640db91b6bacce3a4df6b42ce7cc838833d287" & "db71e509e3fd9b060ddb20ba5c51dcc5948d46fbf640dfe0441782cab85fa4ac"
' Correct expected result
Dim zzOK As String = "46FC62106420FF012E54A434FBDD2D25CCC5852060561E68040DD7778997BD7B"
Dim ourPrivateKey As String = Ecc.ReadKeyByCurve(ourPrivateKeyHex, curve)
Console.WriteLine("Curve = {0}", Ecc.QueryKey(ourPrivateKey, "curveName"))
Console.WriteLine("Our private key has {0} bits", Ecc.QueryKey(ourPrivateKey, "keyBits"))
Dim theirPublicKey As String = Ecc.ReadKeyByCurve(theirPublicKeyHex, curve)
Console.WriteLine("Their public key has {0} bits", Ecc.QueryKey(theirPublicKey, "keyBits"))
' Compute shared secret
Dim zz As Byte() = Ecc.DHSharedSecret(ourPrivateKey, theirPublicKey)
Console.WriteLine("ZZ={0}", Cnv.ToHex(zz))
Debug.Assert(Cnv.ToHex(zz) = zzOK, "Ecc.DHSharedSecret failed")
End Sub
Private Shared Sub test_ECC_DHSharedSecret_25519()
Console.WriteLine(vbLf & "ECDH SHARED SECRET USING X25519:")
' Ref: RFC7748 Section 6.1
' https://tools.ietf.org/html/rfc7748#section-6.1
'
' Test vector:
' Alice's private key, a:
' 77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a
' Alice's public key, X25519(a, 9):
' 8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a
' Bob's private key, b:
' 5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb
' Bob's public key, X25519(b, 9):
' de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f
' Their shared secret, K:
' 4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742
'
Dim curve As Ecc.CurveName = Ecc.CurveName.X25519
Dim alicePrivateKeyHex As String = "77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a"
Dim alicePublicKeyHex As String = "8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a"
Dim bobPrivateKeyHex As String = "5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb"
Dim bobPublicKeyHex As String = "de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f"
' Correct expected result
Dim zzOK As String = "4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742"
' 1. Alice's private + Bob's public
' NB we *must* specify whether X25519 keys are public or private
Dim ourPrivateKey As String = Ecc.ReadKeyByCurve(alicePrivateKeyHex, curve, Ecc.KeyType.PrivateKey)
Console.WriteLine("Curve = {0}", Ecc.QueryKey(ourPrivateKey, "curveName"))
Console.WriteLine("Our private key has {0} bits", Ecc.QueryKey(ourPrivateKey, "keyBits"))
Dim theirPublicKey As String = Ecc.ReadKeyByCurve(bobPublicKeyHex, curve, Ecc.KeyType.PublicKey)
Console.WriteLine("Their public key has {0} bits", Ecc.QueryKey(theirPublicKey, "keyBits"))
' Compute shared secret
Dim zz1 As Byte() = Ecc.DHSharedSecret(ourPrivateKey, theirPublicKey)
Console.WriteLine("ZZ={0}", Cnv.ToHex(zz1))
Debug.Assert(Cnv.ToHex(zz1).ToLower() = zzOK, "Ecc.DHSharedSecret failed")
' 2. Bob's private + Alice's public
ourPrivateKey = Ecc.ReadKeyByCurve(bobPrivateKeyHex, curve, Ecc.KeyType.PrivateKey)
theirPublicKey = Ecc.ReadKeyByCurve(alicePublicKeyHex, curve, Ecc.KeyType.PublicKey)
' Compute shared secret
Dim zz2 As Byte() = Ecc.DHSharedSecret(ourPrivateKey, theirPublicKey)
Console.WriteLine("ZZ={0}", Cnv.ToHex(zz2))
Debug.Assert(Cnv.ToHex(zz2).ToLower() = zzOK, "Ecc.DHSharedSecret failed")
End Sub
Private Shared Sub test_SIG_SignData_Ed25519()
Console.WriteLine(vbLf & "SIGN DATA USING Ed25519:")
' Ref: [RFC8032] https://tools.ietf.org/html/rfc8032#section-7.1
' -----TEST SHA(abc)
' Read in private key from hex (NB need explicitly to identify as private key)
Dim privateKey As String = Ecc.ReadKeyByCurve("833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42", Ecc.CurveName.Ed25519, Ecc.KeyType.PrivateKey)
Debug.Assert(privateKey.Length > 0, "Failed to read Ed25519 private key")
Console.WriteLine("Private key has {0} bits", Ecc.QueryKey(privateKey, "keyBits"))
Console.WriteLine("ALGORITHM: {0}", Ecc.QueryKey(privateKey, "curveName"))
' Message is the 64-byte SHA-512 hash of "abc"
Dim message As Byte() = Cnv.FromHex("ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f")
Dim sig__1 As String = Sig.SignData(message, privateKey, "", SigAlgorithm.Ed25519, 0, Sig.Encoding.Base16)
Console.WriteLine("SIGNATURE:" & vbLf & "{0}", sig__1)
' Check against known correct result
Debug.Assert(sig__1 = "dc2a4459e7369633a52b1bf277839a00201009a3efbf3ecb69bea2186c26b58909351fc9ac90b3ecfdfbc7c66431e0303dca179c138ac17ad9bef1177331a704")
' Now verify using the public key
Dim publicKey As String = Ecc.ReadKeyByCurve("ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf", Ecc.CurveName.Ed25519, Ecc.KeyType.PublicKey)
Debug.Assert(publicKey.Length > 0, "Failed to read Ed25519 public key")
Console.WriteLine("Public key has {0} bits", Ecc.QueryKey(publicKey, "keyBits"))
Dim r As Integer = Sig.VerifyData(sig__1, message, publicKey, SigAlgorithm.Ed25519)
Console.WriteLine("Sig.VerifyData returns {0} (expected 0)", r)
Debug.Assert(0 = r)
End Sub
Private Shared Sub test_X509_MakeCertSelf_Ed25519()
Console.WriteLine(vbLf & "CREATE A SELF-SIGNED X.509 CERTIFICATE USING Ed25519:")
' Ref: [RFC8410] https://tools.ietf.org/html/rfc8410
Dim dn As String, extns As String, certname As String, prikeyfile As String, query As String
Dim pubkeystr As String, issuercert As String
Dim keyUsage As X509.KeyUsageOptions
Dim r As Integer
Dim s As String
' 1. Create a new self-*signed* certificate using the Ed25519 key in RFC8410
certname = "ietf-Ed25519-self.cer"
prikeyfile = "edwards-ietf.p8"
' No password
dn = "CN=IETF Test Demo"
extns = "notBefore=2016-01-01;notAfter=2040-12-31"
'Digital Signature, Certificate Signing, [Off-line CRL Signing], CRL Signing
keyUsage = X509.KeyUsageOptions.DigitalSignature Or X509.KeyUsageOptions.KeyCertSign Or X509.KeyUsageOptions.CrlSign
r = X509.MakeCertSelf(certname, prikeyfile, &Hed25519, 0, dn, extns, _
keyUsage, "", SigAlgorithm.Ed25519, X509.CertOptions.UTF8String)
Console.WriteLine("X509.MakeCertSelf returns {0} (expecting 0)", r)
Debug.Assert(0 = r, "X509.MakeCertSelf failed")
' Dump details
Console.WriteLine("FILE: {0}", certname)
Console.WriteLine(X509.TextDumpToString(certname, 0))
' Do a query on the cert
query = "signatureAlgorithm"
s = X509.QueryCert(certname, query)
Console.WriteLine("{0}={1}", query, s)
Debug.Assert(s.Length > 0, "X509.QueryCert failed")
' 2. Now create a self-*issued* cert using Ed25519 to sign an X25519 public key
' [RFC8410] 10.2. Example X25519 Certificate
' NB This is self-*issued* in that the public key is for an X25519 key intended for ECDH,
' but it is signed using an Ed25519 signature with a key also belonging to ones self.
' Read in X25519 public key from its hex value
' NB we *must* specify that it's a public key
pubkeystr = Ecc.ReadKeyByCurve("8520F0098930A754748B7DDCB43EF75A0DBF3A0D26381AF4EBA4A98EAA9B4E6A", Ecc.CurveName.X25519, Ecc.KeyType.PublicKey)
Debug.Assert(pubkeystr.Length > 0, "Ecc.ReadKeyByCurve failed")
' Set cert parameters to closely duplicate the cert given in RFC8410 (almost!)
dn = "CN=IETF Test Demo"
extns = "notBefore=2016-08-01T12:19:24;notAfter=2040-12-31T23:59:59;keyUsage=noncritical;serialNumber=#x5601474A2A8DC330;" & "subjectKeyIdentifier=9B1F5EEDED043385E4F7BC623C5975B90BC8BB3B"
keyUsage = X509.KeyUsageOptions.KeyAgreement
issuercert = certname
' Use the self-signed cert we made above to issue this new cert
certname = "ietf-X25519-self-issued.cer"
r = X509.MakeCert(certname, issuercert, pubkeystr, prikeyfile, 0, 0, _
dn, extns, keyUsage, "", SigAlgorithm.Ed25519, X509.CertOptions.UTF8String)
Console.WriteLine("X509.MakeCert returns {0} (expecting 0)", r)
Debug.Assert(0 = r, "X509.MakeCert failed")
' Dump details
Console.WriteLine("FILE: {0}", certname)
Console.WriteLine(X509.TextDumpToString(certname, 0))
' Verify that this cert was signed by the above
r = X509.VerifyCert(certname, issuercert)
Console.WriteLine("X509.VerifyCert returns {0} (expecting 0 => verified OK)", r)
Debug.Assert(0 = r, "X509.VerifyCert failed")
End Sub
Private Shared Sub test_CMS_MakeSigData_Ed25519()
Console.WriteLine(vbLf & "CREATE A CMS SIGNED-DATA OBJECT USING Ed25519:")
Dim outFile As String = "SignedData_Ed25519.p7m"
Dim inFile As String = "excontent.txt"
Dim certFile As String = "Ed25519-ietf-selfsigned.cer"
' Self-signed cert created using private Ed25519 key in [RFC8410]
Dim priKeyFile As String = "edwards-ietf-ex.p8"
' No password, from [RFC8410]
Dim r As Integer
Dim s As String, query As String
' Read in private key to internal key string
Dim sbPriKey As StringBuilder = Ecc.ReadPrivateKey(priKeyFile, "")
Debug.Assert(sbPriKey.Length > 0, "Failed to read private key file")
' Create the signed-data object using Ed25519 with signed attributes incl Algorithm Protection
Dim opts As Cms.SigDataOptions = Cms.SigDataOptions.IncludeAttributes Or Cms.SigDataOptions.AddAlgProtection
r = Cms.MakeSigData(outFile, inFile, certFile, sbPriKey.ToString(), Cms.SigAlg.Ed25519, opts)
Debug.Assert(0 = r, "Cms.MakeSigData failed")
Console.WriteLine("Created '{0}'", outFile)
Console.WriteLine("SIGNED-DATA:" & vbLf & "{0}", Asn1.TextDumpToString(outFile, 0))
' Query the signed-data object
query = "digestAlgorithm"
s = Cms.QuerySigData(outFile, query)
Console.WriteLine("Cms.QuerySigData('{0}')={1}", query, s)
query = "signatureAlgorithm"
s = Cms.QuerySigData(outFile, query)
Console.WriteLine("Cms.QuerySigData('{0}')={1}", query, s)
' Verify the signed-data
r = Cms.VerifySigData(outFile)
Console.WriteLine("Cms.VerifySigData() returns {0} (expecting 0)", r)
Debug.Assert(r = 0, "Cms.VerifySigData failed")
' Read the signed data
s = Cms.ReadSigDataToString(outFile)
Console.WriteLine("signed-data='{0}'", s)
Debug.Assert(s.Length > 0, "Cms.ReadSigDataToString failed")
End Sub
Private Shared Sub test_RSA_SaveEncKey()
Console.WriteLine(vbLf & "READ THEN SAVE AN ENCRYPTED RSA KEY:")
Dim r As Integer
Dim keyFile As String = "AlicePrivRSASign.p8e"
Console.WriteLine("FILE: {0}", keyFile)
' Read in private key to internal key string
Dim sbPriKey As StringBuilder = Rsa.ReadPrivateKey(keyFile, "password")
Debug.Assert(sbPriKey.Length > 0, "Rsa.ReadPrivateKey failed")
Console.WriteLine("Private key size = {0} bits", Rsa.KeyBits(sbPriKey.ToString()))
Console.WriteLine("KeyHashCode = {0,8:X}", Rsa.KeyHashCode(sbPriKey.ToString()))
' Save with stronger encryption in PEM textual form
keyFile = "AlicePrivRSASign-stronger.p8e"
r = Rsa.SaveEncKey(keyFile, sbPriKey.ToString(), "password1", Rsa.PbeOptions.Pbe_Pbkdf2_aes192_CBC, "count=6666;prf=hmacWithSHA384", Rsa.Format.PEM)
Debug.Assert(r = 0, "Rsa.SaveEncKey failed")
Console.WriteLine("Saved new key file '{0}'", keyFile)
' Read in ASN.1 dump of file we just created
Dim s As String = Asn1.TextDumpToString(keyFile)
' Console.WriteLine(s);
' Expected to contain certain strings consistent with arguments above
Debug.Assert(s.IndexOf("hmacWithSHA384") > 0)
Debug.Assert(s.IndexOf("--6666") > 0)
Debug.Assert(s.IndexOf("aes192-CBC") > 0)
Dim sbPriKey1 As StringBuilder = Rsa.ReadPrivateKey(keyFile, "password1")
Console.WriteLine("KeyHashCode = {0,8:X}", Rsa.KeyHashCode(sbPriKey1.ToString()))
Debug.Assert(Rsa.KeyHashCode(sbPriKey.ToString()) = Rsa.KeyHashCode(sbPriKey1.ToString()), "KeyHashCodes do not match")
End Sub
Private Shared Sub test_General_FormatErrorMessage()
Console.WriteLine(vbLf & "FORMAT ERROR MESSAGE:")
Console.WriteLine(General.FormatErrorMessage(11))
Console.WriteLine(General.FormatErrorMessage(11), "User message!")
' Try and read missing file
Dim s As String = Asn1.Type("missing.file")
Console.WriteLine(General.FormatErrorMessage())
Dim r As Integer = Cms.MakeEnvData("not-to-be-made.p7m", "missing.file", "", CipherAlgorithm.Aes128)
Console.WriteLine(General.FormatErrorMessage(r))
' Try to create a signed-data object but passing a missing cert file
Dim sbPrivKey As StringBuilder = Rsa.ReadPrivateKey("AlicePrivRSASign.p8e", "password")
r = Cms.MakeSigData("sigdata.p7m", "excontent.txt", "missing.file", sbPrivKey.ToString(), Cms.SigAlg.Rsa_Sha1, 0)
Console.WriteLine(General.FormatErrorMessage(r, "Expected error!"))
End Sub
Private Shared Sub test_KDF_Bytes()
Console.WriteLine(vbLf & "TEST KDF FUNCTION:")
Dim kek As Byte(), zz As Byte(), info As Byte()
Dim nbytes As Integer
Dim okhex As String
' ansx963_2001.rsp CAVS 12.0 'ANS X9.63-2001' information for sample
nbytes = 128 \ 8
zz = Cnv.FromHex("96c05619d56c328ab95fe84b18264b08725b85e33fd34f08")
okhex = "443024c3dae66b95e6f5670601558f71"
kek = Kdf.Bytes(nbytes, zz, Kdf.KdfAlg.X963, Kdf.HashAlg.Sha256)
Console.WriteLine("KEK={0}", Cnv.ToHex(kek))
Console.WriteLine("OK ={0}", okhex)
Debug.Assert([String].Equals(Cnv.ToHex(kek), okhex, StringComparison.OrdinalIgnoreCase), "Kdf.Bytes failed")
' [RFC 5869] A.1. Test Case 1 Basic test case with SHA-256
nbytes = 42
zz = Cnv.FromHex("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b")
info = Cnv.FromHex("f0f1f2f3f4f5f6f7f8f9")
okhex = "3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865"
kek = Kdf.Bytes(nbytes, zz, Kdf.KdfAlg.Hkdf, Kdf.HashAlg.Sha256, info, "salt=000102030405060708090a0b0c")
Console.WriteLine("KEK={0}", Cnv.ToHex(kek))
Console.WriteLine("OK ={0}", okhex)
Debug.Assert([String].Equals(Cnv.ToHex(kek), okhex, StringComparison.OrdinalIgnoreCase), "Kdf.Bytes failed")
' [RFC 5869] A.3. Test with SHA-256 and zero-length salt/info
nbytes = 42
zz = Cnv.FromHex("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b")
okhex = "8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d9d201395faa4b61a96c8"
kek = Kdf.Bytes(nbytes, zz, Kdf.KdfAlg.Hkdf, Kdf.HashAlg.Sha256)
Console.WriteLine("KEK={0}", Cnv.ToHex(kek))
Console.WriteLine("OK ={0}", okhex)
Debug.Assert([String].Equals(Cnv.ToHex(kek), okhex, StringComparison.OrdinalIgnoreCase), "Kdf.Bytes failed")
End Sub
Private Shared Sub test_KDF_ForCms()
Console.WriteLine(vbLf & "TEST KDF FOR CMS:")
Dim kek As Byte(), zz As Byte(), ukm As Byte()
Dim okhex As String
zz = Cnv.FromHex("160E3F5588C6FB4E9CEE8BC3C1C5000AB86396468C3D1CAEC0CB6E21536B5513")
okhex = "04D616C654CDF62BB186A5A088B60FB5"
kek = Kdf.ForCms(zz, Kdf.KeyWrapAlg.Aes128_wrap, Kdf.KdfAlg.X963, Kdf.HashAlg.Sha1)
Console.WriteLine("KEK={0}", Cnv.ToHex(kek))
Console.WriteLine("OK ={0}", okhex)
Debug.Assert([String].Equals(Cnv.ToHex(kek), okhex, StringComparison.OrdinalIgnoreCase), "Kdf.Bytes failed")
' Use same ZZ but use HKDF, SHA-256, and add user key material
ukm = Cnv.FromHex("616263")
' "abc"
okhex = "1D06D6FD5C1EBFB33CAD875E6B99781D3D750875F573C9093CECBFBA6937ACC5"
kek = Kdf.ForCms(zz, Kdf.KeyWrapAlg.Aes256_wrap, Kdf.KdfAlg.Hkdf, Kdf.HashAlg.Sha256, ukm)
Console.WriteLine("KEK={0}", Cnv.ToHex(kek))
Console.WriteLine("OK ={0}", okhex)
Debug.Assert([String].Equals(Cnv.ToHex(kek), okhex, StringComparison.OrdinalIgnoreCase), "Kdf.Bytes failed")
End Sub
Private Shared Sub test_HASH_Length()
Console.WriteLine(vbLf & "TEST HASH LENGTH:")
Dim alg As HashAlgorithm
alg = HashAlgorithm.Sha1
Console.WriteLine("len({0})={1}", alg.ToString(), Hash.Length(alg))
alg = HashAlgorithm.Sha256
Console.WriteLine("len({0})={1}", alg.ToString(), Hash.Length(alg))
alg = HashAlgorithm.Sha512
Console.WriteLine("len({0})={1}", alg.ToString(), Hash.Length(alg))
alg = HashAlgorithm.Ripemd160
Console.WriteLine("len({0})={1}", alg.ToString(), Hash.Length(alg))
End Sub
Private Shared Sub test_Xof()
Console.WriteLine(vbLf & "TEST XOF FUNCTIONS:")
Dim nbytes As Integer
Dim msg As Byte()
Dim b As Byte()
Dim okhex As String
' Ref: "SHA-3 XOF Test Vectors for Byte-Oriented Output"
' File `SHAKE256VariableOut.rsp` COUNT = 1244
Console.WriteLine("SHAKE256")
nbytes = 2000 \ 8
msg = Cnv.FromHex("6ae23f058f0f2264a18cd609acc26dd4dbc00f5c3ee9e13ecaea2bb5a2f0bb6b")
okhex = "b9b92544fb25cfe4ec6fe437d8da2bbe" & "00f7bdaface3de97b8775a44d753c3ad" & "ca3f7c6f183cc8647e229070439aa953" & "9ae1f8f13470c9d3527fffdeef6c94f9" & "f0520ff0c1ba8b16e16014e1af43ac6d" & "94cb7929188cce9d7b02f81a2746f52b" & "a16988e5f6d93298d778dfe05ea0ef25" & "6ae3728643ce3e29c794a0370e9ca6a8" & "bf3e7a41e86770676ac106f7ae79e670" & "27ce7b7b38efe27d253a52b5cb54d6eb" & "4367a87736ed48cb45ef27f42683da14" & "0ed3295dfc575d3ea38cfc2a3697cc92" & "864305407369b4abac054e497378dd9f" & "d0c4b352ea3185ce1178b3dc1599df69" & "db29259d4735320c8e7d33e8226620c9" & "a1d22761f1d35bdff79a"
b = Xof.Bytes(nbytes, msg, Xof.Alg.Shake256)
Console.WriteLine("OUT={0}", Cnv.ToHex(b))
Debug.Assert([String].Equals(Cnv.ToHex(b), okhex, StringComparison.OrdinalIgnoreCase), "Xof.Bytes failed")
' Using MGF1-SHA-256
' From SPHINCS+ test vectors r.3
Console.WriteLine("MGF1-SHA-256")
nbytes = 34
msg = Cnv.FromHex("3b5c056af3ebba70d4c805380420585562b32410a778f558ff951252407647e3")
okhex = "5b7eb772aecf04c74af07d9d9c1c1f8d3a90dcda00d5bab1dc28daecdc86eb87611e"
b = Xof.Bytes(nbytes, msg, Xof.Alg.Mgf1_Sha256)
Console.WriteLine("OUT={0}", Cnv.ToHex(b))
Debug.Assert([String].Equals(Cnv.ToHex(b), okhex, StringComparison.OrdinalIgnoreCase), "Xof.Bytes failed")
' Test other MGF1's
Console.WriteLine("MGF1-SHA-1")
nbytes = 24
msg = Cnv.FromHex("012345ff")
okhex = "242fb2e7a338ae07e580047f82b7acff83a41ec5d8ff9bab"
b = Xof.Bytes(nbytes, msg, Xof.Alg.Mgf1_Sha1)
Console.WriteLine("OUT={0}", Cnv.ToHex(b))
Debug.Assert([String].Equals(Cnv.ToHex(b), okhex, StringComparison.OrdinalIgnoreCase), "Xof.Bytes failed")
End Sub
Private Shared Sub test_Prf()
Console.WriteLine(vbLf & "TEST PRF FUNCTIONS:")
Dim nbytes As Integer
Dim msg As Byte()
Dim key As Byte()
Dim b As Byte()
Dim okhex As String
' `KMAC_samples.pdf` "Secure Hashing - KMAC-Samples" 2017-02-27
' Sample #1
Console.WriteLine("Sample #1: ""standard"" KMAC output length KMAC128 => 256 bits, no custom string")
nbytes = 256 \ 8
msg = Cnv.FromHex("00010203")
key = Cnv.FromHex("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F")
okhex = "E5780B0D3EA6F7D3A429C5706AA43A00FADBD7D49628839E3187243F456EE14E"
b = Prf.Bytes(nbytes, msg, key, Prf.Alg.Kmac128)
Console.WriteLine("OUT={0}", Cnv.ToHex(b))
Debug.Assert([String].Equals(Cnv.ToHex(b), okhex, StringComparison.OrdinalIgnoreCase), "Prf.Bytes failed")
' Sample #6
Console.WriteLine("Sample #6: ""standard"" KMAC output length KMAC256 => 512 bits, no custom string")
nbytes = 512 \ 8
msg = Cnv.FromHex("000102030405060708090A0B0C0D0E0F" & vbCr & vbLf & " 101112131415161718191A1B1C1D1E1F" & vbCr & vbLf & " 202122232425262728292A2B2C2D2E2F" & vbCr & vbLf & " 303132333435363738393A3B3C3D3E3F" & vbCr & vbLf & " 404142434445464748494A4B4C4D4E4F" & vbCr & vbLf & " 505152535455565758595A5B5C5D5E5F" & vbCr & vbLf & " 606162636465666768696A6B6C6D6E6F" & vbCr & vbLf & " 707172737475767778797A7B7C7D7E7F" & vbCr & vbLf & " 808182838485868788898A8B8C8D8E8F" & vbCr & vbLf & " 909192939495969798999A9B9C9D9E9F" & vbCr & vbLf & " A0A1A2A3A4A5A6A7A8A9AAABACADAEAF" & vbCr & vbLf & " B0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF" & vbCr & vbLf & " C0C1C2C3C4C5C6C7")
key = Cnv.FromHex("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F")
okhex = "75358CF39E41494E949707927CEE0AF20A3FF553904C86B08F21CC414BCFD691589D27CF5E15369CBBFF8B9A4C2EB17800855D0235FF635DA82533EC6B759B69"
b = Prf.Bytes(nbytes, msg, key, Prf.Alg.Kmac256)
Console.WriteLine("OUT={0}", Cnv.ToHex(b))
Debug.Assert([String].Equals(Cnv.ToHex(b), okhex, StringComparison.OrdinalIgnoreCase), "Prf.Bytes failed")
' Sample #2
Console.WriteLine("Sample #2: same as Sample #1 except with custom string")
nbytes = 256 \ 8
msg = Cnv.FromHex("00010203")
key = Cnv.FromHex("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F")
okhex = "3B1FBA963CD8B0B59E8C1A6D71888B7143651AF8BA0A7070C0979E2811324AA5"
b = Prf.Bytes(nbytes, msg, key, Prf.Alg.Kmac128, "My Tagged Application")
Console.WriteLine("OUT={0}", Cnv.ToHex(b))
Debug.Assert([String].Equals(Cnv.ToHex(b), okhex, StringComparison.OrdinalIgnoreCase), "Prf.Bytes failed")
End Sub
Private Shared Sub test_X509_MakeCert_Internal_X25519()
Console.WriteLine(vbLf & "CREATE A NEW CERTIFICATE USING INTERNAL KEY STRINGS:")
Dim certname As String = "new-lamps-dana.encrypt.cer"
Dim issuercert As String = "lamps-ca.ed25519.crt"
Dim prikeyfile As String = "lamps-ca.ed25519.p8"
' No password
Dim pubkeyfile As String = "lamps-dana.encrypt.crt"
' We get the public key from the cert we are trying to reproduce...
' Try and reproduce lamps-dana.encrypt.cer from [RFC9216]
' (well, not quite, because the order of the extension fields will be different in our cert, so the signature and thumbprint will not match.
' The content is identical, just in a different order)
Dim dn As String = "O=IETF;OU=LAMPS WG;CN=Dana Hopper"
' ECDH with HKDF using SHA-256; uses AES-128 key wrap
Dim extns As String = "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
Dim sbPrikeystr As StringBuilder = Ecc.ReadPrivateKey(prikeyfile, "")
Debug.Assert(sbPrikeystr.Length > 0, "Ecc.ReadPrivateKey failed")
Dim sbPubkeystr As StringBuilder = Ecc.ReadPublicKey(pubkeyfile)
Debug.Assert(sbPubkeystr.Length > 0, "Ecc.ReadPublicKey failed")
' Create the new certificate
Dim r As Integer = X509.MakeCert(certname, issuercert, sbPubkeystr.ToString(), sbPrikeystr.ToString(), 0, 0, _
dn, extns, 0, "", SigAlgorithm.Ed25519, X509.CertOptions.AuthKeyId)
Console.WriteLine("X509.MakeCert returns {0} (expecting 0)", r)
Debug.Assert(0 = r, "X509.MakeCert failed")
' Dump details of cert we just made...
x509DumpFile(certname)
' For comparison, dump details of original lamps cert
x509DumpFile(pubkeyfile)
' 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
Private Shared Sub test_CIPHER_File_GCM()
Console.WriteLine(vbLf & "ENCRYPT FILE USING GCM:")
Dim filein As String, fileenc As String, filechk As String
Dim r As Integer
' 128-bit key (16 bytes)
Dim key As Byte() = New Byte() {&H2b, &H7e, &H15, &H16, &H28, &Hae, _
&Hd2, &Ha6, &Hab, &Hf7, &H15, &H88, _
&H9, &Hcf, &H4f, &H3c}
' 96-bit IV (12 bytes)
Dim iv As Byte() = New Byte() {&H0, &H1, &H2, &H3, &H4, &H5, _
&H6, &H7, &H8, &H9, &Ha, &Hb}
filein = "excontent.txt"
Console.WriteLine("Input file '{0}' length {1}", filein, FileLength(filein))
fileenc = "excontent-gcm-enc.dat"
' Encrypt the file
r = Cipher.FileEncrypt(fileenc, filein, key, iv, CipherAlgorithm.Aes128, Mode.GCM, _
opts := Cipher.Opts.PrefixIV)
Console.WriteLine("Cipher.FileEncrypt(GCM) returns {0} (expecting 0)", r)
Debug.Assert(r = 0, "Cipher.FileEncrypt(GCM) failed")
Console.WriteLine("Encrypted file '{0}' length {1} expected {2}+{3}+{4}", fileenc, FileLength(fileenc), FileLength(filein), 12, 16)
' Now decrypt it
filechk = "excontent-gcm-chk.dat"
r = Cipher.FileDecrypt(filechk, fileenc, key, Nothing, CipherAlgorithm.Aes128, Mode.GCM, _
opts := Cipher.Opts.PrefixIV)
Debug.Assert(r = 0, "Cipher.FileDecrypt(GCM) failed")
Console.WriteLine("Decrypted file '{0}' length {1}", filechk, FileLength(filechk))
' Check files are equal by comparing their file hashes
Debug.Assert(Hash.HexFromFile(filein, HashAlgorithm.Sha1) = Hash.HexFromFile(filechk, HashAlgorithm.Sha1), "File hashes do not match")
Console.WriteLine(vbLf & "Try to write output to file of same name but different form...")
Dim fileout As String = ".\" & filein
Console.WriteLine("filein='{0}', fileout='{1}'", filein, fileout)
r = Cipher.FileEncrypt(fileout, filein, key, iv, CipherAlgorithm.Aes128, Mode.GCM, _
opts := Cipher.Opts.PrefixIV)
Console.WriteLine("Cipher.FileEncrypt(GCM) returns {0} (expecting error)", r)
If r <> 0 Then
Console.WriteLine(General.FormatErrorMessage(r))
End If
Debug.Assert(r <> 0, "Expected error did not happen!")
End Sub
Private Shared Sub test_RSA_ReadPublicKey_CSR()
Console.WriteLine(vbLf & "READ PUBLIC KEY FROM CSR:")
Dim csrfile As String, keyfile As String, dn As String, extns As String
Dim keystr As String
Dim r As Integer
' 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, "", SigAlgorithm.Rsa_Sha256, _
0)
Console.WriteLine("X509.CertRequest returns {0} (expecting 0)", r)
If r <> 0 Then
Console.WriteLine(General.FormatErrorMessage(r))
End If
Debug.Assert(0 = r, "X509.CertRequest failed")
' Dump details of CSR we just made...
x509DumpFile(csrfile, X509.OutputOpts.Ldap)
' Read in public key from this CSR file
keystr = Rsa.ReadPublicKey(csrfile).ToString()
Debug.Assert(keystr.Length > 0, "Failed to read public key from CSR")
Console.WriteLine("Keysize={0} bits, HashCode=0x{1,8:X}", Rsa.KeyBits(keystr), Rsa.KeyHashCode(keystr))
' EXPECTED: Keysize=2048 bits, HashCode=0xCA0B84DA
End Sub
Private Shared Sub test_X509_MakeCert_Ex()
Console.WriteLine(vbLf & "MAKE X.509 CERT WITH LATEST OPTIONS V20.7:")
Dim r As Integer
Dim dn As String, extns As String
Dim certname As String = "myca-newattributes2022.cer"
Dim keyfile As String = "lamps-ca.rsa.p8"
' No password
Dim serialnum As Integer = &H889
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;"
r = X509.MakeCertSelf(certname, keyfile, serialnum, 10, dn, extns, _
0, "", SigAlgorithm.Rsa_Sha256, 0)
Console.WriteLine("X509.MakeCertSelf returns {0} (expecting 0)", r)
If r <> 0 Then
Console.WriteLine(General.FormatErrorMessage(r))
End If
Debug.Assert(0 = r, "X509.MakeCertSelf failed")
' Dump details of cert we just made...
x509DumpFile(certname, X509.OutputOpts.Ldap)
End Sub
Private Shared Sub test_CNV_ShortNamePath()
Console.WriteLine(vbLf & "GET SHORT NAME PATH:")
Dim longpath As String, shortpath As String
longpath = "File with a long name and spaces hello there all good yes thanks.txt"
Console.WriteLine("longpath='{0}'", longpath)
shortpath = Cnv.ShortPathName(longpath)
Console.WriteLine("shortpath='{0}'", shortpath)
longpath = "你好.txt"
Console.WriteLine("longpath='{0}' (may not print nicely on console)", longpath)
shortpath = Cnv.ShortPathName(longpath)
Console.WriteLine("shortpath='{0}'", shortpath)
End Sub
Private Shared Sub test_CNV_ShortNamePath_EncryptFile()
Console.WriteLine(vbLf & "USE SHORT NAME PATH TO ENCRYPT FILE:")
' 128-bit key (16 bytes)
Dim key As Byte() = New Byte() {&H2b, &H7e, &H15, &H16, &H28, &Hae, _
&Hd2, &Ha6, &Hab, &Hf7, &H15, &H88, _
&H9, &Hcf, &H4f, &H3c}
' 96-bit IV (12 bytes)
Dim iv As Byte() = New Byte() {&H0, &H1, &H2, &H3, &H4, &H5, _
&H6, &H7, &H8, &H9, &Ha, &Hb}
Dim r As Integer
Dim longpath As String, shortpath As String
Dim filein As String, fileenc As String
' Use a file with Chinese characters in its name (which will fail)...
longpath = "你好.txt"
filein = longpath
fileenc = "cn-enc.dat"
Console.WriteLine("Try using Chinese filename to call Cipher.FileEncrypt...")
Console.WriteLine("filein={0}", filein)
r = Cipher.FileEncrypt(fileenc, filein, key, iv, CipherAlgorithm.Aes128, Mode.GCM, _
opts := Cipher.Opts.PrefixIV)
Console.WriteLine("Cipher.FileEncrypt returns {0} (expected error)", r)
If r <> 0 Then
Console.WriteLine(General.FormatErrorMessage(r))
End If
Console.WriteLine("Get short path name and use that instead...")
shortpath = Cnv.ShortPathName(longpath)
filein = shortpath
Console.WriteLine("filein={0}", filein)
r = Cipher.FileEncrypt(fileenc, filein, key, iv, CipherAlgorithm.Aes128, Mode.GCM, _
opts := Cipher.Opts.PrefixIV)
Console.WriteLine("Cipher.FileEncrypt returns {0} (expected 0)", r)
If r <> 0 Then
Console.WriteLine(General.FormatErrorMessage(r))
End If
Debug.Assert(r = 0, "Cipher.FileEncrypt failed")
Console.WriteLine("Created encrypted file '{0}'", fileenc)
' Now say we want to *output* to a file with Chinese characters in its name
longpath = "您好加密.dat"
' 'hello encrypted.txt'
Console.WriteLine("Now output to a file with Chinese characters in its name '{0}' (name may not display properly)", longpath)
' So, as a fudge, create a dummy file of that name then get its short path name and overwrite it
If Not File.Exists(longpath) Then
File.WriteAllText(longpath, "")
End If
shortpath = Cnv.ShortPathName(longpath)
fileenc = shortpath
Console.WriteLine("fileenc={0}", fileenc)
' Overwrite the dummy file
r = Cipher.FileEncrypt(fileenc, filein, key, iv, CipherAlgorithm.Aes128, Mode.GCM, _
opts := Cipher.Opts.PrefixIV)
Console.WriteLine("Cipher.FileEncrypt returns {0} (expected 0)", r)
If r <> 0 Then
Console.WriteLine(General.FormatErrorMessage(r))
End If
Debug.Assert(r = 0, "Cipher.FileEncrypt failed")
Console.WriteLine("Created encrypted file '{0}'", fileenc)
' Display contents of encrypted file
Dim ct As Byte() = File.ReadAllBytes(fileenc)
Console.WriteLine("CONTENTS: " & Cnv.ToHex(ct))
' Decrypt the contents directly in memory
Dim dt As Byte() = Cipher.Decrypt(ct, key, Nothing, CipherAlgorithm.Aes128, Mode.GCM, opts := Cipher.Opts.PrefixIV)
Console.WriteLine("DECRYPTED: [" & System.Text.Encoding.[Default].GetString(dt) & "]")
End Sub
'*****************
' FILE UTILITIES *
'*****************
Private Shared Function MakeALargeTextFile(fileName As String) As Long
' Make a large (~10MB) text file. Return length.
Dim targetsize As Integer = 1024 * 1024 * 10
Dim nblocks As Integer
Dim s As String
Dim sb As New StringBuilder()
' Make a string of all printable ASCII chars
For i As Integer = 32 To 126
sb.Append(ChrW(i))
Next
sb.Append(ControlChars.Cr)
sb.Append(ControlChars.Lf)
s = sb.ToString()
' Write out the text file
nblocks = targetsize \ s.Length
Dim fs As FileStream
Dim sw As StreamWriter
fs = New FileStream(fileName, FileMode.Create, FileAccess.Write)
sw = New StreamWriter(fs)
For i As Integer = 0 To nblocks - 1
sw.Write(s)
Next
sw.Close()
fs.Close()
Return FileLength(fileName)
End Function
Private Shared Function FileExists(filePath As String) As Boolean
Dim fi As New FileInfo(filePath)
Return fi.Exists
End Function
Private Shared Function FileLength(filePath As String) As Long
Dim fi As New FileInfo(filePath)
Return fi.Length
End Function
Private Shared Function FileIsNotPresent(filePath As String, message As String) As Boolean
If Not FileExists(filePath) Then
Console.WriteLine(vbLf & "{0}: {1}", message, filePath)
Return True
End If
Return False
End Function
' Amazingly, .NET doesn't have a Compare Bytes function...
Private Shared Function ByteArraysEqual(data1 As Byte(), data2 As Byte()) As Boolean
' Thanks to Jon Skeet http://www.pobox.com/~skeet
' If both are null, they're equal
If data1 Is Nothing AndAlso data2 Is Nothing Then
Return True
End If
' If either but not both are null, they're not equal
If data1 Is Nothing OrElse data2 Is Nothing Then
Return False
End If
If data1.Length <> data2.Length Then
Return False
End If
For i As Integer = 0 To data1.Length - 1
If data1(i) <> data2(i) Then
Return False
End If
Next
Return True
End Function
' ASN.1 DISPLAY CONTENTS
Private Shared Function asn1DumpFile(infile As String) As Boolean
If FileLength(infile) >= 0 Then
Console.WriteLine("FILE: " & infile)
Else
Console.WriteLine("STRING: " & infile)
End If
Dim s As String = Asn1.TextDumpToString(infile)
If s.Length > 0 Then
Console.WriteLine(s)
Else
Console.WriteLine("ERROR!")
End If
Return (s.Length > 0)
End Function
' X.509 DISPLAY
Private Shared Function x509DumpFile(infile As String, Optional opts As X509.OutputOpts = X509.OutputOpts.[Default]) As Boolean
If FileLength(infile) >= 0 Then
Console.WriteLine("FILE: " & infile)
Else
Console.WriteLine("STRING: " & infile)
End If
Dim s As String = X509.TextDumpToString(infile, opts)
If s.Length > 0 Then
Console.WriteLine(s)
Else
Console.WriteLine("ERROR:" & General.LastError())
End If
Return (s.Length > 0)
End Function
'***********************
' DISPLAY ERROR DETAILS
'***********************
''' <summary>
''' Display details of last error given error code
''' </summary>
''' <param name="nErr">Error code returned by last call</param>
Private Shared Sub disp_error(Optional nErr As Integer = 0)
Dim s As String = General.FormatErrorMessage(nErr)
Console.WriteLine(s)
End Sub
'**********************
' HOUSEKEEPING STUFF...
'**********************
Private Shared Function SetupTestFilesAndDirectory(arrFileNames As String()) As String
Dim subdir As String
'**************************************************
' Check we have required files in local directory *
'**************************************************
Dim assemblyFile As String = Assembly.GetExecutingAssembly().Location
Dim assemblyDir As String = Path.GetDirectoryName(assemblyFile)
Console.WriteLine("Local directory is '{0}'.", assemblyDir)
Console.WriteLine("Checking required test files are in local directory...")
Dim missingFile As String = [String].Format("STOPPED: Required file is missing." & vbLf & " Look in {0}", zippedTestFiles)
For Each fn As String In arrFileNames
If FileIsNotPresent(fn, missingFile) Then
Return Nothing
End If
Next
'*************************************************
' Create a test sub-directory with a random name,
' copy these test files to it, and work in that sub-directory
'*************************************************
subdir = "pkitest." & Cnv.ToHex(Rng.Bytes(4))
Console.WriteLine("Creating test sub-directory '{0}'", subdir)
System.IO.Directory.CreateDirectory(subdir)
' Copy test files
For Each fn As String In arrFileNames
System.IO.File.Copy(fn, subdir & "\" & fn, True)
Next
' Change current working directory to sub-dir
System.IO.Directory.SetCurrentDirectory(subdir)
Console.WriteLine("CWD is " & System.IO.Directory.GetCurrentDirectory())
Return subdir
End Function
'*********************************************************
' Put CWD back to parent and offer to remove the test dir
'*********************************************************
Private Shared Sub RestoreDirectory(subdir As String, askDelete As Boolean)
Dim s As String
System.IO.Directory.SetCurrentDirectory("..")
Console.WriteLine(vbLf & "CWD reset to " & System.IO.Directory.GetCurrentDirectory())
If askDelete Then
Console.Write("The temp test directory '{0}' was created by this program." & vbLf & "Do you want to remove it? ([Y]/N) ", subdir)
s = Console.ReadLine()
If "N" <> s AndAlso "n" <> s Then
' Remove directory
Console.WriteLine("Removing test directory...")
System.IO.Directory.Delete(subdir, True)
Else
Console.WriteLine("Temp directory '{0}' left in place.", subdir)
End If
Else
' Remove directory regardless
Console.WriteLine("Removing test directory '{0}'", subdir)
System.IO.Directory.Delete(subdir, True)
End If
End Sub
End Class
End Namespace