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