Imports System
Imports System.Diagnostics
Imports System.Reflection
Imports System.IO
Imports System.Text
Imports CryptoSysPKI
' This is a straight port of TestPKIcsharp.cs from C# to VB.NET.
' With thanks to Alex Lowe's "C# to VB.NET Translation tool"
' http://authors.aspalliance.com/aldotnet/examples/translate.aspx
' $Id: TestPKIvbnet.vb $
' Last updated:
' $Date: 2006-08-09 08:39:00 $
' $Version: 2.9.0 $
' NOTE: This program requires the following files to exist in the
' same directory as the executable:
' CarlRSASelf.cer
' CarlRSASign.epk
' AliceRSASignByCarl.cer
' AlicePrivRSASign.epk
' BobRSASignByCarl.cer
' BobPrivRSAEncrypt.epk (NOTE: the .EPK extension is one we made up)
' bob.p7b
Module TestPKIvbnet
Sub Main()
Dim s As String
Dim ch As Char
Dim i, n, nblock, r 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 keyhex, plain, cipher, ivhex, okhex As String
Dim arrPlain() As Byte
Dim arrCipher() As Byte
Dim arrKey() As Byte
Dim arrIV() As Byte
Dim excontent, fnameData, fnameEnc, fnameCheck As String
Dim fnameInput, fnameOutput, fnameCert, fname As String
Dim pubkeyFile, prikeyFile As String
Dim issuerCert As String
Dim hexDigest As String
Dim strCheck As String
Dim query As String
'****************
' GENERAL TESTS *
'****************
Console.WriteLine("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.CompileTime()
Console.WriteLine("CompileTime={0}", s)
s = CryptoSysPKI.General.LastError()
Console.WriteLine("LastError='{0}' (expecting empty)", s)
n = CryptoSysPKI.General.PowerUpTests()
Console.WriteLine("PowerUpTests={0}", n)
'**************************************************
' 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"
If FileIsNotPresent("CarlRSASelf.cer", missingFile) Then
Return
End If
If FileIsNotPresent("CarlPrivRSASign.epk", missingFile) Then
Return
End If
If FileIsNotPresent("AliceRSASignByCarl.cer", missingFile) Then
Return
End If
If FileIsNotPresent("AlicePrivRSASign.epk", missingFile) Then
Return
End If
If FileIsNotPresent("BobRSASignByCarl.cer", missingFile) Then
Return
End If
If FileIsNotPresent("BobPrivRSAEncrypt.epk", missingFile) Then
Return
End If
If FileIsNotPresent("bob.p7b", missingFile) Then
Return
End If
'*******************************************
' TDEA (Triple DES, 3DES) ENCRYPTION TESTS *
'*******************************************
Console.WriteLine("TESTING TRIPLE DES:")
keyhex = "010101010101010101010101010101010101010101010101"
plain = "8000000000000000"
cipher = "95F8A5E5DD31D900"
' Encrypt in ECB mode using hex strings
s = Tdea.Encrypt(plain, keyhex, Mode.ECB, Nothing)
Console.WriteLine("KY={0}", keyhex)
Console.WriteLine("PT={0}", plain)
Console.WriteLine("CT={0}", s)
Console.WriteLine("OK={0}", cipher)
Debug.Assert([String].Compare(s, cipher, True) = 0, "Tdea.HexECB failed")
' Decrypt
s = Tdea.Decrypt(cipher, keyhex, Mode.ECB, Nothing)
Console.WriteLine("P'={0}", s)
Console.WriteLine("OK={0}", plain)
Debug.Assert([String].Compare(s, plain, True) = 0, "Tdea.HexECB failed")
' Ditto using byte arrays
arrPlain = Cnv.FromHex(plain)
arrCipher = Cnv.FromHex(cipher)
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"
plain = "5468697320736F6D652073616D706520636F6E74656E742E0808080808080808"
cipher = "d76fd1178fbd02f84231f5c1d2a2f74a4159482964f675248254223daf9af8e4"
s = Tdea.Encrypt(plain, keyhex, Mode.CBC, ivhex)
Console.WriteLine("KY={0}", keyhex)
Console.WriteLine("IV={0}", ivhex)
Console.WriteLine("PT={0}", plain)
Console.WriteLine("CT={0}", s)
Console.WriteLine("OK={0}", cipher)
Debug.Assert([String].Compare(s, cipher, True) = 0, "Tdea.Encrypt{Hex,CBC} failed")
' Decrypt
s = Tdea.Decrypt(cipher, keyhex, Mode.CBC, ivhex)
Console.WriteLine("P'={0}", s)
Console.WriteLine("OK={0}", plain)
Debug.Assert([String].Compare(s, plain, True) = 0, "Tdea.Decrypt{Hex,CBC} failed")
' Ditto using byte arrays
arrPlain = Cnv.FromHex(plain)
arrCipher = Cnv.FromHex(cipher)
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"
MakeATextFile(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 = ReadABinaryFile(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 = ReadATextFile(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.")
'************
' RSA TESTS *
'************
Console.WriteLine("RSA FUNCTION TESTS:")
' Read the public key from the recipient's X.509 certificate
sbPublicKey = Rsa.GetPublicKeyFromCert("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.ReadEncPrivateKey("AlicePrivRSASign.epk", "password")
Console.WriteLine("PrivateKey={0}", sbPrivateKey.ToString())
Console.WriteLine("PrivateKeyBits={0}", Rsa.KeyBits(sbPrivateKey.ToString().ToString()))
Console.WriteLine("PrivateKeyBytes={0}", Rsa.KeyBytes(sbPrivateKey.ToString().ToString()))
' Decrypt with private key
b = Rsa.RawPrivate(b, sbPrivateKey.ToString().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().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().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 CompareByteArrays(bcheck, b) Then
Console.WriteLine("OK, verification OK")
Else
Console.WriteLine("ERROR: verification failed")
End If
Debug.Assert(CompareByteArrays(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(CompareByteArrays(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(CompareByteArrays(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(CompareByteArrays(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())
' Export key to XML format
s = Rsa.ToXMLString(sbPrivateKey.ToString(), Rsa.XmlOptions.ForceRSAKeyValue)
Console.WriteLine("Key in XML format={0}", s)
' Test re-import from XML
s = Rsa.FromXMLString(s, False)
Debug.Assert([String].Compare(s, sbPrivateKey.ToString().ToString()) = 0, "Private key string from XML does not match original")
' Create a PKCS-12 file containing Alice's private key
fname = "alice.pfx"
n = Pfx.MakeFile(fname, "AliceRSASignByCarl.cer", "AlicePrivRSASign.epk", "password", "Alice's Key", False)
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, isok)
Debug.Assert(isok, "PFX signature is invalid")
' Extract the encrypted private key from the PKCS12 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.ReadEncPrivateKey(fnameOutput, "password")
strCheck = sbPrivateKey.ToString()
sbPrivateKey = Rsa.ReadEncPrivateKey("AlicePrivRSASign.epk", "password")
Debug.Assert(strCheck = 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()
sbPrivateKey = Rsa.ReadPrivateKeyInfo(fname)
Debug.Assert(strCheck = sbPrivateKey.ToString(), "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()
sbPublicKey = Rsa.ReadPublicKey(fname)
Debug.Assert(strCheck = sbPublicKey.ToString(), "Public keys don't match")
' Extract the certificate from a PKCS-12 PFX file
fnameInput = "alice.pfx"
fnameCert = "alice_fromPFX.cer"
n = X509.GetCertFromPFX(fnameCert, fnameInput)
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)
' Generate a fresh RSA key which we'll use later
pubkeyFile = "mykey_pub.bin"
prikeyFile = "mykey_epk.bin"
n = Rsa.MakeKeys(pubkeyFile, prikeyFile, 512, Rsa.PublicExponent.Exp_EQ_65537, 1024, "password", Rsa.PbeOptions.Default, 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")
'*************
' X509 TESTS *
'*************
Console.WriteLine("X509 TESTS:")
' 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", X509.Options.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.epk"
n = X509.MakeCert(fnameCert, issuerCert, pubkeyFile, prikeyFile, 101, 2, "CN=Me;C=US;O=MyOrg", "", 0, "password", X509.Options.SigAlg_Md5WithRSAEncryption Or X509.Options.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}" + ControlChars.Lf + ControlChars.Tab + "--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
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)
' 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", 0)
Console.WriteLine("X509.CertRequest returned {0} (expected 0).", n)
' 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)
Console.WriteLine("X509.GetCertFromP7Chain(0) returns {0} (expected 2).", n)
' 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 i
'*****************************
' CMS (S/MIME OBJECTS) TESTS *
'*****************************
Console.WriteLine("CMS (S/MIME OBJECTS) TESTS:")
' Create a test text file
fnameInput = "excontent.txt"
MakeATextFile(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, 0)
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.ReadEncPrivateKey("BobPrivRSAEncrypt.epk", "password")
Debug.Assert(sbPrivateKey.ToString().Length > 0, "Unable to read Bob's private key")
n = Cms.ReadEnvDataToFile(fnameOutput, fnameInput, "", sbPrivateKey.ToString(), 0)
Console.WriteLine("Cms.ReadEnvData returns {0} (expecting 0)", n)
Debug.Assert(0 = n, "Cms.ReadEnvData failed")
s = ReadATextFile(fnameOutput)
Console.WriteLine("MSG={0}", s)
' and again but read directly into a string
s = Cms.ReadEnvDataToString(fnameInput, "", sbPrivateKey.ToString(), 0)
Console.WriteLine("MSG={0}", s)
Debug.Assert(s.Length > 0, "Cms.ReadEnvDataToString failed")
' Generate a BER-encoded CMS signedData object as a file
' using Alice's private key
sbPrivateKey = Rsa.ReadEncPrivateKey("AlicePrivRSASign.epk", "password")
fnameOutput = "BasicSignByAlice.bin"
fnameInput = "excontent.txt"
fnameCert = "AliceRSASignByCarl.cer"
n = Cms.MakeSigData(fnameOutput, fnameInput, fnameCert, sbPrivateKey.ToString(), 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 = ReadATextFile(fnameInput)
fname = "BasicSignByAlice1.bin"
n = Cms.MakeSigDataFromString(fname, s, fnameCert, sbPrivateKey.ToString(), 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 = ReadABinaryFile(fnameOutput)
bcheck = ReadABinaryFile(fname)
Debug.Assert(CompareByteArrays(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(), 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, False)
' 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 = ReadATextFile(fnameOutput)
Console.WriteLine("MSG(file)={0}", strCheck)
' Extract the contents directly into a string instead
s = Cms.ReadSigDataToString(fnameInput, False)
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.Options.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, True)
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.Options.IncludeAttributes Or Cms.Options.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, False)
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, "", True)
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, "", "", False)
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, False)
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, False)
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, False)
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"
n = Cms.MakeSigData(fnameOutput, fnameInput, fnameCert, sbPrivateKey.ToString(), Cms.Options.FormatBase64 Or Cms.Options.UseMD5)
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, True)
Console.WriteLine("Cms.GetSigHashAlgorithm returns {0} (expecting 1 => MD5)", n)
Debug.Assert(1 = n, "Cms.GetSigHashAlgorithm failed")
' Query our SignedData files
fnameInput = "BasicSignByAlice_attr.bin"
query = "version"
s = Cms.QuerySigData(fnameInput, query, False)
Console.WriteLine("Cms.QuerySigData('{0}') returns '{1}'", query, s)
Debug.Assert(s.Length > 0, "QuerySigData failed")
query = "digestAlgorithm"
s = Cms.QuerySigData(fnameInput, query, False)
Console.WriteLine("Cms.QuerySigData('{0}') returns '{1}'", query, s)
Debug.Assert(s.Length > 0, "QuerySigData failed")
query = "signingTime"
s = Cms.QuerySigData(fnameInput, query, False)
Console.WriteLine("Cms.QuerySigData('{0}') returns '{1}'", query, s)
Debug.Assert(s.Length > 0, "QuerySigData failed")
' ...that's enough CMS tests.
'*************
' HASH TESTS *
'*************
Console.WriteLine("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')={0}", s)
' Create a test file
fnameInput = "hello.txt"
MakeATextFile(fnameInput, "hello world" + ControlChars.Cr + ControlChars.Lf)
' get digest from binary file
s = Hash.HexFromFile(fnameInput, 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(fnameInput, HashAlgorithm.Sha1)
Console.WriteLine("SHA1('hello world+LF')= {0}", s)
'******************
' WIPE DATA TESTS *
'******************
Console.WriteLine("WIPE DATA TESTS:")
fname = "ImportantSecret.txt"
MakeATextFile(fname, "Very important secrets here.")
s = ReadATextFile(fname)
isok = Wipe.File(fname)
Console.WriteLine("Wipe.File {0}", isok)
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))
Console.WriteLine("Before Wipe.String, sbPrivateKey contains {0} characters.", sbPrivateKey.Length)
Wipe.String(sbPrivateKey)
Console.WriteLine("After Wipe.String, sbPrivateKey = [{0}]", sbPrivateKey.ToString())
'*******************
' CONVERSION TESTS *
'*******************
' Convert an "impure" hex string of 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}')={1} ({2} bytes)", s, Cnv.ToHex(b), b.Length)
Debug.Assert(16 = b.Length, "Cnv.FromHex failed: wrong # of bytes")
' Given a string that includes some Latin-1 accented characters:
s = "abcóéíáñ"
Console.WriteLine("Original Latin-1 string={0}", s)
Console.WriteLine("# of characters in Latin-1 string = {0}", s.Length)
' Check and see if this tests as valid UTF-8
n = Cnv.CheckUTF8(s)
Console.WriteLine("Cnv.CheckUTF8(s) returns {0} (expected 0 => not valid UTF-8)", n)
'************************
' PASSWORD PROMPT TESTS *
'************************
' -- uncomment to test (these are tedious on repetitive tests!)
'' 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);
'************
' RNG TESTS *
'************
Console.WriteLine("SOME RANDOM NUMBERS:")
For i = 0 To 2
b = Rng.Bytes(24)
Console.WriteLine("RNG={0}", Cnv.ToHex(b))
Next i
Console.Write("{x:990<=x<=1000}=")
For i = 0 To 4
n = Rng.Number(990, 1000)
Console.Write("{0} ", n)
Next i
Console.Write(ControlChars.Lf)
Console.WriteLine(ControlChars.Lf + "ALL TESTS COMPLETED.")
End Sub 'Main End Sub
'*****************
' FILE UTILITIES *
'*****************
Private Function MakeATextFile(ByVal fileName As String, ByVal data As String) As Boolean
Dim fs As FileStream
Dim sw As StreamWriter
' Create a test text file
fs = New FileStream(fileName, FileMode.Create, FileAccess.Write)
sw = New StreamWriter(fs)
sw.Write(data)
sw.Close()
fs.Close()
Return True
End Function 'MakeATextFile
Private Function ReadATextFile(ByVal fileName As String) As String
Dim s As String = [String].Empty
Dim finfo As New FileInfo(fileName)
If finfo.Exists Then
Dim fsi As FileStream = finfo.OpenRead()
Dim sr As New StreamReader(fsi)
s = sr.ReadToEnd()
Console.WriteLine(s)
sr.Close()
fsi.Close()
End If
Debug.Assert(finfo.Exists, "File '" + fileName + "' does not exist.")
Return s
End Function 'ReadATextFile
Private Function ReadABinaryFile(ByVal fileName As String) As Byte()
Dim b(0) As Byte
Dim finfo As New FileInfo(fileName)
If finfo.Exists Then
Dim fsi As FileStream = finfo.OpenRead()
Dim br As New BinaryReader(fsi)
Dim count As Integer = CInt(fsi.Length)
b = br.ReadBytes(count)
br.Close()
fsi.Close()
End If
Debug.Assert(finfo.Exists, "File '" + fileName + "' does not exist.")
Return b
End Function 'ReadABinaryFile
Private Function FileExists(ByVal filePath As String) As Boolean
Dim fi As New FileInfo(filePath)
Return fi.Exists
End Function 'FileExists
Private Function FileIsNotPresent(ByVal filePath As String, ByVal message As String) As Boolean
If Not FileExists(filePath) Then
Console.WriteLine(ControlChars.Lf + "{0}: {1}", message, filePath)
Return True
End If
Return False
End Function 'FileIsNotPresent
Private Function CompareByteArrays(ByVal data1() As Byte, ByVal 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 And data2 Is Nothing Then
Return True
End If
' If either but not both are null, they're not equal
If data1 Is Nothing Or data2 Is Nothing Then
Return False
End If
If data1.Length <> data2.Length Then
Return False
End If
Dim i As Integer
For i = 0 To data1.Length - 1
If data1(i) <> data2(i) Then
Return False
End If
Next i
Return True
End Function 'CompareByteArrays
End Module