Imports System Imports System.Diagnostics Imports System.Reflection Imports System.IO Imports System.Text Imports CryptoSysPKI ' $Id: TestPKIcsharpV12.vb $ ' * Last updated: ' * $Date: 2020-03-6 09:13 $ ' * $Version: 12.3.0 $ ' ' Some tests demonstrating new features in CryptoSys PKI v12.1 ' * in particular RSA-PSS and ECC signatures in X.509 certificates. ' * ' * Test files are in `pkiDotNetTestFiles.zip`. These must be in the CWD. ' '****************************** LICENSE *********************************** ' * Copyright (C) 2018-20 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> '**************************************************************************** ' ' Ported from C# to VB.NET using icsharpcode.net's SharpDevelop. Namespace TestPKIcsharpV12 Class TestPKIcsharpV12 Private Const MIN_PKI_VERSION As Integer = 120100 ' Test files required to exist in the current working directory: ' Unencrypted version ' Encrypted, password="password" Private Shared arrFileNames As String() = New String() {"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"} ' Name of file with zipped test files Private Shared zippedTestFiles As String = "pkiDotNetTestFiles.zip" Public Shared Sub Main(args As String()) Console.WriteLine("TESTING CRYPTOSYS PKI FOR CHANGES IN V12.0 AND V12.1") ' 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 ' Deal with command-line options Dim doSome As Boolean = False Dim askDelete As Boolean = False For iarg As Integer = 0 To args.Length - 1 If args(iarg) = "some" Then doSome = True End If If args(iarg) = "askdelete" Then askDelete = True End If Next ' Check required files exist and setup temp directory Dim origdir As String = 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 ' //test_MakeKeys(); // Only do this once! 'test_ReadKeys(); '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(); ' NEW IN [v12.1] 'test_X509_ReadCertFromP7Chain(); 'test_X509_ReadCertFromPFX(); test_CIPHER_EncryptAEAD() 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}]", General.ModuleName()) '******************************************** 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() ' //test_MakeKeys(); // Only do this once! test_ReadKeys() 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() ' New in [v12.1] test_CIPHER_EncryptAEAD() test_X509_ReadCertFromP7Chain() test_X509_ReadCertFromPFX() End Sub '******************** ' THE TEST MODULES... '******************** Private Shared Sub test_MakeKeys() ' Demonstrates: ' * Rsa.MakeKeys() ' * 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", 2048, Rsa.PublicExponent.Exp_EQ_65537, 80, "password", _ Rsa.PbeOptions.Pbe_Pbkdf2_aes256_CBC, False) r = Rsa.MakeKeys("User_RSA_2048.pub", "User_RSA_2048.p8e", 2048, Rsa.PublicExponent.Exp_EQ_65537, 80, "password", _ Rsa.PbeOptions.Pbe_Pbkdf2_aes256_CBC, False) 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_ReadKeys() 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_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 ' END TESTS '****************************************************** '***************** ' FILE UTILITIES * '***************** 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 '****************** ' SETUP 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 = "STOPPED: Required file is missing." & vbLf & " Look in '" & 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 '*********************** ' DISPLAY ERROR DETAILS '*********************** ''' <summary> ''' Display details of last error given error code ''' </summary> ''' <param name="nErr">Error code returned</param> Private Shared Sub disp_error(nErr As Integer) Dim s As String = General.LastError() Console.WriteLine("ERROR Returned={0}/{1}: {2}; {3}", nErr, General.ErrorCode(), General.ErrorLookup(nErr), s) End Sub ''' <summary> ''' Display details of last error (no error code) ''' </summary> Private Shared Sub disp_error() Dim s As String = General.LastError() Dim nErr As Integer = General.ErrorCode() Console.WriteLine("ERROR {0}: {1}: {2}", nErr, General.ErrorLookup(nErr), s) End Sub 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 End Class End Namespace