Imports System
Imports System.Diagnostics
Imports System.Reflection
Imports System.IO
Imports System.Text
Imports CryptoSysPKI


Module TestChile

    ' $Id: basTestChile $
    ' $Date: 2009-05-07 17:41 $
    ' $Author: dai $

    ' This module uses functions from the CryptoSys (tm) PKI Toolkit available from
    ' <www.cryptosys.net/pki/>.

    ' *************************** COPYRIGHT NOTICE ******************************
    ' This code was originally written by David Ireland and is copyright
    ' (C) 2008-10 DI Management Services Pty Ltd <www.di-mgt.com.au>.
    ' Provided "as is". No warranties. Use at your own risk. You must make your
    ' own assessment of its accuracy and suitability for your own purposes.
    ' It is not to be altered or distributed, except as part of an application.
    ' You are free to use it in any application, provided this copyright notice
    ' is left unchanged.
    ' ************************ END OF COPYRIGHT NOTICE **************************

    ' NOTES: Some of these procedures are specific for the Chile SII examples.
    ' Other procedures are more generic and could be used in more general PKI
    ' programs, perhaps with minor amendments.
    ' These are marked $GENERIC-FUNCTION$.

    ' Ref: F60T33-ejemplo.xml

    Public Sub Read_SmallerKeys()
        ' From manual_certificacion.pdf, 2003-11-26, p25
        Dim strKeyPem As String
        Dim nRet As Integer
        Dim strPrivateKey As String
        Dim strPublicKey As String
        Dim strXmlKey As String
        Dim strSig64 As String
        Dim abData() As Byte
        Dim nDataLen As Integer
        Dim nKeyLen As Integer
        Dim abDigest() As Byte

        ' CAUTION: Your real Private Key should be kept SECRET and should never be hard-coded in code like, er, this...
        ' Put PEM data into a string
        ' (Note two critical vbCrLF's added before and after base64 data)
        strKeyPem = "-----BEGIN RSA PRIVATE KEY-----" & vbCrLf & _
    "MIIBOwIBAAJBANGuDuim8fEI9yuIlkj+MOyp3mWHifoP6a4oWLSBKJSrd3MpEsZd" & _
    "czvL0l7t/e0IU5rF+0gRLnU1Mfvtsw1wYWcCAQMCQQCLyV9FxKFLW09yWw7bVCCd" & _
    "xpRDr7FRX/EexZB4VhsNxm/vtJfDZyYle0Lfy42LlcsXxPm1w6Q6NnjuW+AeBy67" & _
    "AiEA7iMi5q5xjswqq+49RP55o//jqdZL/pC9rdnUKxsNRMMCIQDhaHdIctErN2hC" & _
    "IP9knS3+9zra4R+5jSXOvI+3xVhWjQIhAJ7CF0R0S7SIHHKe04NUURf/7RvkMqm1" & _
    "08k74sdnXi3XAiEAlkWk2vc2HM+a1sCqQxNz/098ketqe7NuidMKeoOQObMCIQCk" & _
    "FAMS9IcPcMjk7zI2r/4EEW63PSXyN7MFAX7TYe25mw==" & vbCrLf & _
    "-----END RSA PRIVATE KEY-----"

        ' Read the PEM private key data into an internal key string we can use later on...
        ' -- this example key is stored in a PKCS#8 PrivateKeyInfo without a password :-(
        strPrivateKey = Rsa.ReadPrivateKeyInfo(strKeyPem).ToString()
        ' CAUTION: the above trick to read into a string is a big security risk
        ' -- the point of using a StringBuilder is that it can be wiped later

        Console.WriteLine("Private key is " & Rsa.KeyBits(strPrivateKey) & " bits")

        ' Now we compare this private key with the published public key in the XML file...

        ' Form XML string of public key in proper XMLSIG format using <RSAPK> element from XML file
        ' <RSAPK><M>0a4O6Kbx8Qj3K4iWSP4w7KneZYeJ+g/prihYtIEolKt3cykSxl1zO8vSXu397QhTmsX7SBEudTUx++2zDXBhZw==</M><E>Aw==</E></RSAPK>
        ' NOTE: We have changed the element names to the required XMLSIG format:
        ' <RSAPK> --> <RSAKeyValue>
        ' <M>     --> <Modulus>
        ' <E>     --> <Exponent>
        strXmlKey = "<RSAKeyValue>" & _
            "<Modulus>0a4O6Kbx8Qj3K4iWSP4w7KneZYeJ+g/prihYtIEolKt3cykSxl1zO8vSXu397QhTmsX7SBEudTUx++2zDXBhZw==</Modulus>" & _
            "<Exponent>Aw==</Exponent></RSAKeyValue>"
        ' Convert XML form to our internal format
        strPublicKey = Rsa.FromXMLString(strXmlKey, False)
        Console.WriteLine("Public key is " & Rsa.KeyBits(strPublicKey) & " bits")

        ' Check that key pairs match...
        nRet = Rsa.KeyMatch(strPrivateKey, strPublicKey)
        Console.WriteLine("RSA_KeyMatch returns " & nRet & " (expecting 0)")

        ' Then use the PUBLIC key to extract the message digest from the signature value...

        ' Extract digest from FRMT
        ' <FRMT algoritmo="SHA1withRSA">GbmDcS9e/jVC2LsLIe1iRV12Bf6lxsILtbQiCkh6mbjckFCJ7fj/kakFTS06Jo8i
        ' S4HXvJj3oYZuey53Krniew==</FRMT>
        strSig64 = "GbmDcS9e/jVC2LsLIe1iRV12Bf6lxsILtbQiCkh6mbjckFCJ7fj/kakFTS06Jo8iS4HXvJj3oYZuey53Krniew=="

        ' Convert signatureValue to byte format
        abData = System.Convert.FromBase64String(strSig64)
        Console.WriteLine("SIGNATURE=" & Cnv.ToHex(abData))
        nDataLen = abData.Length
        Console.WriteLine("Signature is " & nDataLen & " bytes long")
        ' Check the length
        nKeyLen = Rsa.KeyBytes(strPublicKey)
        Console.WriteLine("Key is " & nKeyLen & " bytes long")
        If nKeyLen <> nDataLen Then
            Console.WriteLine("ERROR: Key is the wrong length!")
            Exit Sub
        End If
        ' Decrypt the signature
        abData = Rsa.RawPublic(abData, strPublicKey)
        Console.WriteLine("RSA_RawPublic returns " & nRet & " (expecting 0)")
        If nRet <> 0 Then
            Console.WriteLine("ERROR: " & General.ErrorLookup(nRet))
            Exit Sub
        End If
        Console.WriteLine("EMSA BLOCK=" & Cnv.ToHex(abData))

        ' Extract digest from block
        abDigest = Rsa.DecodeDigestForSignature(abData)

        ' Display digest bytes as hex and base64
        Console.WriteLine("DIGEST=" & Cnv.ToHex(abDigest))
        Console.WriteLine("base64=" & System.Convert.ToBase64String(abDigest))

    End Sub

    Public Sub MakeFRMTdigest()
        ' This should give the same digest value we obtained above.
        Dim strData As String
        Dim strDigest As String
        ' Put <DD> data into a single string with no spaces between elements (and fix double-quotes for VB when hard-coded here!)
        strData = "<DD><RE>97975000-5</RE><TD>33</TD><F>60</F><FE>2003-10-13</FE><RR>77777777-7</RR><RSR>EMPRESA  LTDA</RSR><MNT>119000</MNT><IT1>Parlantes Multimedia 180W.</IT1><CAF version=""1.0""><DA><RE>97975000-5</RE><RS>RUT DE PRUEBA</RS><TD>33</TD><RNG><D>1</D><H>200</H></RNG><FA>2003-09-04</FA><RSAPK><M>0a4O6Kbx8Qj3K4iWSP4w7KneZYeJ+g/prihYtIEolKt3cykSxl1zO8vSXu397QhTmsX7SBEudTUx++2zDXBhZw==</M><E>Aw==</E></RSAPK><IDK>100</IDK></DA><FRMA algoritmo=""SHA1withRSA"">g1AQX0sy8NJugX52k2hTJEZAE9Cuul6pqYBdFxj1N17umW7zG/hAavCALKByHzdYAfZ3LhGTXCai5zNxOo4lDQ==</FRMA></CAF><TSTED>2003-10-13T09:33:20</TSTED></DD>"
        ' Create an SHA-1 digest value in hex format
        strDigest = Hash.HexFromString(strData, HashAlgorithm.Sha1)
        Console.WriteLine("SHA1(DD)=" & strDigest)
        ' Display in base64
        Console.WriteLine("SHA1(DD)=" & System.Convert.ToBase64String(Cnv.FromHex(strDigest)))
    End Sub

    Public Sub SignDDtoMakeFRMTsig()
        ' Use the RSA private key to sign the <DD> data.
        ' INPUT:  RSA private key in PEM format
        '         Data-to-be signed
        ' OUTPUT: SignatureValue in base64 form

        Dim strKeyPem As String
        Dim strData As String
        Dim strPrivateKey As String
        Dim nKeyBytes As Integer
        Dim abBlock() As Byte
        Dim abData() As Byte
        Dim nDataLen As Integer
        Dim strSigVal64 As String

        ' Input data:
        strData = "<DD><RE>97975000-5</RE><TD>33</TD><F>60</F><FE>2003-10-13</FE><RR>77777777-7</RR><RSR>EMPRESA  LTDA</RSR><MNT>119000</MNT><IT1>Parlantes Multimedia 180W.</IT1><CAF version=""1.0""><DA><RE>97975000-5</RE><RS>RUT DE PRUEBA</RS><TD>33</TD><RNG><D>1</D><H>200</H></RNG><FA>2003-09-04</FA><RSAPK><M>0a4O6Kbx8Qj3K4iWSP4w7KneZYeJ+g/prihYtIEolKt3cykSxl1zO8vSXu397QhTmsX7SBEudTUx++2zDXBhZw==</M><E>Aw==</E></RSAPK><IDK>100</IDK></DA><FRMA algoritmo=""SHA1withRSA"">g1AQX0sy8NJugX52k2hTJEZAE9Cuul6pqYBdFxj1N17umW7zG/hAavCALKByHzdYAfZ3LhGTXCai5zNxOo4lDQ==</FRMA></CAF><TSTED>2003-10-13T09:33:20</TSTED></DD>"
        strKeyPem = "-----BEGIN RSA PRIVATE KEY-----" & vbCrLf & _
    "MIIBOwIBAAJBANGuDuim8fEI9yuIlkj+MOyp3mWHifoP6a4oWLSBKJSrd3MpEsZd" & _
    "czvL0l7t/e0IU5rF+0gRLnU1Mfvtsw1wYWcCAQMCQQCLyV9FxKFLW09yWw7bVCCd" & _
    "xpRDr7FRX/EexZB4VhsNxm/vtJfDZyYle0Lfy42LlcsXxPm1w6Q6NnjuW+AeBy67" & _
    "AiEA7iMi5q5xjswqq+49RP55o//jqdZL/pC9rdnUKxsNRMMCIQDhaHdIctErN2hC" & _
    "IP9knS3+9zra4R+5jSXOvI+3xVhWjQIhAJ7CF0R0S7SIHHKe04NUURf/7RvkMqm1" & _
    "08k74sdnXi3XAiEAlkWk2vc2HM+a1sCqQxNz/098ketqe7NuidMKeoOQObMCIQCk" & _
    "FAMS9IcPcMjk7zI2r/4EEW63PSXyN7MFAX7TYe25mw==" & vbCrLf & _
    "-----END RSA PRIVATE KEY-----"

        ' Read the PEM private key data into an internal key string
        strPrivateKey = Rsa.ReadPrivateKeyInfo(strKeyPem).ToString()
        ' CAUTION: the above trick to read into a string is a big security risk
        ' -- the point of using a StringBuilder is that it can be wiped later

        Console.WriteLine("Private key is " & Rsa.KeyBits(strPrivateKey) & " bits long")

        ' Convert the input data string into a byte array
        abData = System.Text.Encoding.Default.GetBytes(strData)
        Console.WriteLine("Data=(0x)" & Cnv.ToHex(abData))
        nDataLen = UBound(abData) + 1
        Console.WriteLine("Input data is " & nDataLen & " bytes long")

        ' Encode into a block the exact same length as the RSA key...

        ' Get the length of the key in bytes -- we need an output block exactly this length
        nKeyBytes = Rsa.KeyBytes(strPrivateKey)
        Console.WriteLine("Private key is  " & nKeyBytes & " bytes long")

        ' Encode the data -- this computes the message digest and then encodes into an EMSA block in one step
        abBlock = Rsa.EncodeMsgForSignature(nKeyBytes, abData, HashAlgorithm.Sha1)
        If abBlock.Length = 0 Then
            Console.WriteLine("ERROR: RSA_EncodeMsg failed. Error: " & General.LastError())
            Exit Sub
        End If
        Console.WriteLine("EMSA BLOCK=" & Cnv.ToHex(abBlock))

        ' Sign, i.e. encrypt, the encoded block with the RSA private key
        abBlock = Rsa.RawPrivate(abBlock, strPrivateKey)
        If abBlock.Length = 0 Then
            Console.WriteLine("ERROR: RSA_RawPrivate failed. Error: " & General.LastError())
            Exit Sub
        End If
        Console.WriteLine("SIGNATURE= " & Cnv.ToHex(abBlock))

        ' Convert byte array to base64
        strSigVal64 = System.Convert.ToBase64String(abBlock)
        Console.WriteLine("SignatureValue=" & strSigVal64)

    End Sub

    Public Function XmlHexFromInternalKey(ByVal strKey As String) As String
        ' $GENERIC-FUNCTION$
        ' INPUT:  Public or private RSA key in internal format
        ' OUTPUT: String containing RSAKeyValue in XML format
        Dim strXmlKey As String
        Dim nOptions As Rsa.XmlOptions

        nOptions = Rsa.XmlOptions.HexBinaryFormat or Rsa.XmlOptions.ExcludePrivateParams or Rsa.XmlOptions.ForceRSAKeyValue
        strXmlKey = Rsa.ToXMLString(strKey, nOptions)
        If strXmlKey.Length > 0 Then
            XmlHexFromInternalKey = strXmlKey
        Else
            XmlHexFromInternalKey = "**Failed to create public key in XML"
        End If

    End Function

    Public Function IsCertAndKeyValueMatched(ByVal strCert64 As String, ByVal strXmlKey As String) As Boolean
        ' $GENERIC-FUNCTION$
        ' Compare the public key values in <RSAKeyValue> and <X509Certificate> values
        ' INPUT:  RSAKeyValue in base64 string INCLUDING <RSAKeyValue> tags;
        '         X509Certificate in base64 string EXCLUDING <X509Certificate> tags
        ' OUTPUT: True if public key matches; otherwise False.
        ' REMARKS: The X509Certificate contains the public key value plus other info.

        Dim strPublicKey As String
        Dim strQuery As String
        Dim strOutput As String
        Dim nHashCode1 As Integer
        Dim nHashCode2 As Integer

        ' Query the certificate for details...
        strQuery = "issuerName"
        strOutput = X509.QueryCert(strCert64, strQuery)
        If strOutput.Length = 0 Then
            Console.WriteLine("ERROR: Error reading certificate: " & General.LastError)
            Exit Function ' ERROR
        End If
        Console.WriteLine(strQuery & "=" & strOutput)

        strQuery = "serialNumber"
        strOutput = X509.QueryCert(strCert64, strQuery)
        If strOutput.Length = 0 Then
            Console.WriteLine("ERROR: Error reading certificate: " & General.LastError)
            Exit Function ' ERROR
        End If
        Console.WriteLine(strQuery & "=" & strOutput)

        strQuery = "subjectName"
        strOutput = X509.QueryCert(strCert64, strQuery)
        If strOutput.Length = 0 Then
            Console.WriteLine("ERROR: Error reading certificate: " & General.LastError)
            Exit Function ' ERROR
        End If
        Console.WriteLine(strQuery & "=" & strOutput)

        strQuery = "notBefore"
        strOutput = X509.QueryCert(strCert64, strQuery)
        If strOutput.Length = 0 Then
            Console.WriteLine("ERROR: Error reading certificate: " & General.LastError)
            Exit Function ' ERROR
        End If
        Console.WriteLine(strQuery & "=" & strOutput)

        strQuery = "signatureAlgorithm"
        strOutput = X509.QueryCert(strCert64, strQuery)
        If strOutput.Length = 0 Then
            Console.WriteLine("ERROR: Error reading certificate: " & General.LastError)
            Exit Function ' ERROR
        End If
        Console.WriteLine(strQuery & "=" & strOutput)

        ' Extract public key from X.509 certificate
        strPublicKey = Rsa.GetPublicKeyFromCert(strCert64).ToString()
        If strPublicKey.Length = 0 Then
            Console.WriteLine("ERROR: Error reading certificate key: " & General.LastError)
            Exit Function ' ERROR
        End If
        Console.WriteLine("Public key extracted from <X509Certificate>:")
        Console.WriteLine("Public key is " & Rsa.KeyBits(strPublicKey) & " bits")
        nHashCode1 = Rsa.KeyHashCode(strPublicKey)
        Console.WriteLine("Public key hashcode = {0,8:X}", nHashCode1)

        ' While we're here, display the public key in XML format
        Console.WriteLine(XmlHexFromInternalKey(strPublicKey))

        ' Convert XML form to our internal format (this requires the <RSAKeyvalue> tags)
        strPublicKey = Rsa.FromXMLString(strXmlKey, false)
        If strPublicKey.Length = 0 Then
            Console.WriteLine("ERROR: Unable to read XML key string")
            Exit Function
        End If
        Console.WriteLine("Public key given in <RSAKeyValue>:")
        Console.WriteLine("Public key is " & Rsa.KeyBits(strPublicKey) & " bits")
        nHashCode2 = Rsa.KeyHashCode(strPublicKey)
        Console.WriteLine("Public key hashcode = {0,8:X}", nHashCode2)
        Console.WriteLine(XmlHexFromInternalKey(strPublicKey))

        If nHashCode1 = nHashCode2 Then
            IsCertAndKeyValueMatched = True
            Console.WriteLine("OK, public keys match.")
        Else
            IsCertAndKeyValueMatched = False
            Console.WriteLine("ERROR: public keys do not match.")
        End If

    End Function

    Public Sub CheckExampleCertAndRSAKey()
        ' Ref: F60T33-ejemplo.xml, 2003-10-13

        ' THIS TEST FAILS BECAUSE THE RSAKeyValue IS WRONG

        ' <RSAKeyValue>
        ' <Modulus>
        ' tNEknkb1kHiD1OOAWlLKkcH/UP5UGa6V6MYso++JB+vYMg2OXFROAF7G8BNFFPQx
        ' iuS/7y1azZljN2xq+bW3bAou1bW2ij7fxSXWTJYFZMAyndbLyGHM1e3nVmwpgEpx
        ' BHhZzPvwLb55st1wceuKjs2Ontb13J33sUb7bbJMWh0=
        ' </Modulus>
        ' <Exponent>
        ' AQAB
        ' </Exponent>
        ' </RSAKeyValue>

        ' <X509Certificate>MIIEgjCCA+ugAwIBAgIEAQAApzANBgkqhkiG9w0BAQUFADCBtTELMAkGA1UEBhMC
        ' Q0wxHTAbBgNVBAgUFFJlZ2lvbiBNZXRyb3BvbGl0YW5hMREwDwYDVQQHFAhTYW50
        ' aWFnbzEUMBIGA1UEChQLRS1DRVJUQ0hJTEUxIDAeBgNVBAsUF0F1dG9yaWRhZCBD
        ' ZXJ0aWZpY2Fkb3JhMRcwFQYDVQQDFA5FLUNFUlRDSElMRSBDQTEjMCEGCSqGSIb3
        ' DQEJARYUZW1haWxAZS1jZXJ0Y2hpbGUuY2wwHhcNMDMxMDAxMTg1ODE1WhcNMDQw
        ' OTMwMDAwMDAwWjCBuDELMAkGA1UEBhMCQ0wxFjAUBgNVBAgUDU1ldHJvcG9saXRh
        ' bmExETAPBgNVBAcUCFNhbnRpYWdvMScwJQYDVQQKFB5TZXJ2aWNpbyBkZSBJbXB1
        ' ZXN0b3MgSW50ZXJub3MxDzANBgNVBAsUBlBpc28gNDEjMCEGA1UEAxQaV2lsaWJh
        ' bGRvIEdvbnphbGV6IENhYnJlcmExHzAdBgkqhkiG9w0BCQEWEHdnb256YWxlekBz
        ' aWkuY2wwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALxZlVh1xr9sKQIBDF/6
        ' Va+lsHQSG5AAmCWvtNTIOXN3E9EQCy7pOPHrDg6EusvoHyesZSKJbc0TnIFXZp78
        ' q7mbdHijzKqvMmyvwbdP7KK8LQfwf84W4v9O8MJeUHlbJGlo5nFACrPAeTtONbHa
        ' ReyzeMDv2EganNEDJc9c+UNfAgMBAAGjggGYMIIBlDAjBgNVHREEHDAaoBgGCCsG
        ' AQQBwQEBoAwWCjA3ODgwNDQyLTQwCQYDVR0TBAIwADA8BgNVHR8ENTAzMDGgL6At
        ' hitodHRwOi8vY3JsLmUtY2VydGNoaWxlLmNsL2UtY2VydGNoaWxlY2EuY3JsMCMG
        ' A1UdEgQcMBqgGAYIKwYBBAHBAQKgDBYKOTY5MjgxODAtNTAfBgNVHSMEGDAWgBTg
        ' KP3S4GBPs0brGsz1CJEHcjodCDCB0AYDVR0gBIHIMIHFMIHCBggrBgEEAcNSBTCB
        ' tTAvBggrBgEFBQcCARYjaHR0cDovL3d3dy5lLWNlcnRjaGlsZS5jbC8yMDAwL0NQ
        ' Uy8wgYEGCCsGAQUFBwICMHUac0VsIHRpdHVsYXIgaGEgc2lkbyB2YWxpZG8gZW4g
        ' Zm9ybWEgcHJlc2VuY2lhbCwgcXVlZGFuZG8gZWwgQ2VydGlmaWNhZG8gcGFyYSB1
        ' c28gdHJpYnV0YXJpbywgcGFnb3MsIGNvbWVyY2lvIHkgb3Ryb3MwCwYDVR0PBAQD
        ' AgTwMA0GCSqGSIb3DQEBBQUAA4GBABMfCyJF0mNXcov8iEWvjGFyyPTsXwvsYbbk
        ' OJ41wjaGOFMCInb4WY0ngM8BsDV22bGMs8oLyX7rVy16bGA8Z7WDUtYhoOM7mqXw
        ' /Hrpqjh3JgAf8zqdzBdH/q6mAbdvq/yb04JHKWPC7fMFuBoeyVWAnhmuMZfReWQi
        ' MUEHGGIW</X509Certificate>

        Dim strCert64 As String
        Dim strXmlKey As String

        strCert64 = "MIIEgjCCA+ugAwIBAgIEAQAApzANBgkqhkiG9w0BAQUFADCBtTELMAkGA1UEBhMCQ0wxHTAbBgNVBAgUFFJlZ2lvbiBNZXRyb3BvbGl0YW5hMREwDwYDVQQHFAhTYW50aWFnbzEUMBIGA1UEChQLRS1DRVJUQ0hJTEUxIDAeBgNVBAsUF0F1dG9yaWRhZCBDZXJ0aWZpY2Fkb3JhMRcwFQYDVQQDFA5FLUNFUlRDSElMRSBD" & _
    "QTEjMCEGCSqGSIb3DQEJARYUZW1haWxAZS1jZXJ0Y2hpbGUuY2wwHhcNMDMxMDAxMTg1ODE1WhcNMDQwOTMwMDAwMDAwWjCBuDELMAkGA1UEBhMCQ0wxFjAUBgNVBAgUDU1ldHJvcG9saXRhbmExETAPBgNVBAcUCFNhbnRpYWdvMScwJQYDVQQKFB5TZXJ2aWNpbyBkZSBJbXB1ZXN0b3MgSW50ZXJub3MxDzANBgNVBAsU" & _
    "BlBpc28gNDEjMCEGA1UEAxQaV2lsaWJhbGRvIEdvbnphbGV6IENhYnJlcmExHzAdBgkqhkiG9w0BCQEWEHdnb256YWxlekBzaWkuY2wwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALxZlVh1xr9sKQIBDF/6Va+lsHQSG5AAmCWvtNTIOXN3E9EQCy7pOPHrDg6EusvoHyesZSKJbc0TnIFXZp78q7mbdHijzKqvMmyv" & _
    "wbdP7KK8LQfwf84W4v9O8MJeUHlbJGlo5nFACrPAeTtONbHaReyzeMDv2EganNEDJc9c+UNfAgMBAAGjggGYMIIBlDAjBgNVHREEHDAaoBgGCCsGAQQBwQEBoAwWCjA3ODgwNDQyLTQwCQYDVR0TBAIwADA8BgNVHR8ENTAzMDGgL6AthitodHRwOi8vY3JsLmUtY2VydGNoaWxlLmNsL2UtY2VydGNoaWxlY2EuY3JsMCMG" & _
    "A1UdEgQcMBqgGAYIKwYBBAHBAQKgDBYKOTY5MjgxODAtNTAfBgNVHSMEGDAWgBTgKP3S4GBPs0brGsz1CJEHcjodCDCB0AYDVR0gBIHIMIHFMIHCBggrBgEEAcNSBTCBtTAvBggrBgEFBQcCARYjaHR0cDovL3d3dy5lLWNlcnRjaGlsZS5jbC8yMDAwL0NQUy8wgYEGCCsGAQUFBwICMHUac0VsIHRpdHVsYXIgaGEgc2lk" & _
    "byB2YWxpZG8gZW4gZm9ybWEgcHJlc2VuY2lhbCwgcXVlZGFuZG8gZWwgQ2VydGlmaWNhZG8gcGFyYSB1c28gdHJpYnV0YXJpbywgcGFnb3MsIGNvbWVyY2lvIHkgb3Ryb3MwCwYDVR0PBAQDAgTwMA0GCSqGSIb3DQEBBQUAA4GBABMfCyJF0mNXcov8iEWvjGFyyPTsXwvsYbbkOJ41wjaGOFMCInb4WY0ngM8BsDV22bGM" & _
    "s8oLyX7rVy16bGA8Z7WDUtYhoOM7mqXw/Hrpqjh3JgAf8zqdzBdH/q6mAbdvq/yb04JHKWPC7fMFuBoeyVWAnhmuMZfReWQiMUEHGGIW"

        strXmlKey = "<RSAKeyValue><Modulus>" & _
            "tNEknkb1kHiD1OOAWlLKkcH/UP5UGa6V6MYso++JB+vYMg2OXFROAF7G8BNFFPQx" & _
            "iuS/7y1azZljN2xq+bW3bAou1bW2ij7fxSXWTJYFZMAyndbLyGHM1e3nVmwpgEpx" & _
            "BHhZzPvwLb55st1wceuKjs2Ontb13J33sUb7bbJMWh0=</Modulus>" & _
            "<Exponent>AQAB</Exponent></RSAKeyValue>"

        Console.WriteLine(IsCertAndKeyValueMatched(strCert64, strXmlKey))

    End Sub

    Public Sub CheckManualCertAndRSAKey()
        ' Ref: manual_certificacion.pdf, 2003-11-26

        ' THIS TEST FAILS BECAUSE THE RSAKeyValue IS WRONG

        ' <RSAKeyValue>
        ' <Modulus>
        ' tNEknkb1kHiD1OOAWlLKkcH/UP5UGa6V6MYso++JB+vYMg2OXFROAF7G8BNFFPQx
        ' iuS/7y1azZljN2xq+bW3bAou1bW2ij7fxSXWTJYFZMAyndbLyGHM1e3nVmwpgEpx
        ' BHhZzPvwLb55st1wceuKjs2Ontb13J33sUb7bbJMWh0=
        ' </Modulus>
        ' <Exponent>
        ' AQAB
        ' </Exponent>
        ' </RSAKeyValue>

        ' <X509Certificate>MIIEPjCCA6mgAwIBAgIDAgGKMAsGCSqGSIb3DQEBBDCBsTEdMBsGA1UECBQUUmVn
        ' aW9uIE1ldHJvcG9saXRhbmExETAPBgNVBAcUCFNhbnRpYWdvMSIwIAYDVQQDFBlF
        ' LUNlcnRjaGlsZSBDQSBJbnRlcm1lZGlhMTYwNAYDVQQLFC1FbXByZXNhIE5hY2lv
        ' bmFsIGRlIENlcnRpZmljYWNpb24gRWxlY3Ryb25pY2ExFDASBgNVBAoUC0UtQ0VS
        ' VENISUxFMQswCQYDVQQGEwJDTDAeFw0wMjEwMDIxOTExNTlaFw0wMzEwMDIwMDAw
        ' MDBaMIHXMR0wGwYDVQQIFBRSZWdpb24gTWV0cm9wb2xpdGFuYTEnMCUGA1UECxQe
        ' U2VydmljaW8gZGUgSW1wdWVzdG9zIEludGVybm9zMScwJQYDVQQKFB5TZXJ2aWNp
        ' byBkZSBJbXB1ZXN0b3MgSW50ZXJub3MxETAPBgNVBAcUCFNhbnRpYWdvMR8wHQYJ
        ' KoZIhvcNAQkBFhB3Z29uemFsZXpAc2lpLmNsMSMwIQYDVQQDFBpXaWxpYmFsZG8g
        ' R29uemFsZXogQ2FicmVyYTELMAkGA1UEBhMCQ0wwXDANBgkqhkiG9w0BAQEFAANL
        ' ADBIAkEAvNQyaLPd3cQlBr0fQWooAKXSFan/WbaFtD5P7QDzcE1pBIvKY2Uv6uid
        ' ur/mGVB9IS4Fq/1xRIXy13FFmxLwTQIDAQABo4IBgjCCAX4wIwYDVR0RBBwwGqAY
        ' BggrBgEEAcNSAaAMFgowNzg4MDQ0Mi00MDwGA1UdHwQ1MDMwMaAvoC2GK2h0dHA6
        ' Ly9jcmwuZS1jZXJ0Y2hpbGUuY2wvRWNlcnRjaGlsZUNBSS5jcmwwIwYDVR0SBBww
        ' GqAYBggrBgEEAcEBAqAMFgo5NjkyODE4MC01MIHmBgNVHSAEgd4wgdswgdgGCCsG
        ' AQQBw1IAMIHLMDYGCCsGAQUFBwIBFipodHRwOi8vd3d3LmUtY2VydGNoaWxlLmNs
        ' L3BvbGl0aWNhL2Nwcy5odG0wgZAGCCsGAQUFBwICMIGDGoGARWwgdGl0dWxhciBo
        ' YSBzaWRvIHZhbGlkYWRvIGVuIGZvcm1hIHByZXNlbmNpYWwsIHF1ZWRhbmRvIGhh
        ' YmlsaXRhZG8gZWwgQ2VydGlmaWNhZG8gcGFyYSB1c28gdHJpYnV0YXJpbywgcGFn
        ' b3MsIGNvbWVyY2lvIHUgb3Ryb3MwCwYDVR0PBAQDAgTwMAsGCSqGSIb3DQEBBAOB
        ' gQB2V4cTj7jo1RawmsRQUSnnvJjMCrZstcHY+Ss3IghVPO9eGoYzu5Q63vzt0Pi8
        ' CS91SBc7xo+LDoljaUyjOzj7zvU7TpWoFndiTQF3aCOtTkV+vjCMWW3sVHes4UCM
        ' DkF3VYK+rDTAadiaeDArTwsx4eNEpxFuA/TJwcXpLQRCDg==</X509Certificate>

        Dim strCert64 As String
        Dim strXmlKey As String

        strCert64 = "MIIEPjCCA6mgAwIBAgIDAgGKMAsGCSqGSIb3DQEBBDCBsTEdMBsGA1UECBQUUmVnaW9uIE1ldHJvcG9saXRhbmExETAPBgNVBAcUCFNhbnRpYWdvMSIwIAYDVQQDFBlFLUNlcnRjaGlsZSBDQSBJbnRlcm1lZGlhMTYwNAYDVQQLFC1FbXByZXNhIE5hY2lvbmFsIGRlIENlcnRpZmljYWNpb24gRWx" & _
    "lY3Ryb25pY2ExFDASBgNVBAoUC0UtQ0VSVENISUxFMQswCQYDVQQGEwJDTDAeFw0wMjEwMDIxOTExNTlaFw0wMzEwMDIwMDAwMDBaMIHXMR0wGwYDVQQIFBRSZWdpb24gTWV0cm9wb2xpdGFuYTEnMCUGA1UECxQeU2VydmljaW8gZGUgSW1wdWVzdG9zIEludGVybm9zMScwJQYDVQQKFB5TZXJ2aWNpbyBkZSBJbXB1ZXN" & _
    "0b3MgSW50ZXJub3MxETAPBgNVBAcUCFNhbnRpYWdvMR8wHQYJKoZIhvcNAQkBFhB3Z29uemFsZXpAc2lpLmNsMSMwIQYDVQQDFBpXaWxpYmFsZG8gR29uemFsZXogQ2FicmVyYTELMAkGA1UEBhMCQ0wwXDANBgkqhkiG9w0BAQEFAANLADBIAkEAvNQyaLPd3cQlBr0fQWooAKXSFan/WbaFtD5P7QDzcE1pBIvKY2Uv6ui" & _
    "dur/mGVB9IS4Fq/1xRIXy13FFmxLwTQIDAQABo4IBgjCCAX4wIwYDVR0RBBwwGqAYBggrBgEEAcNSAaAMFgowNzg4MDQ0Mi00MDwGA1UdHwQ1MDMwMaAvoC2GK2h0dHA6Ly9jcmwuZS1jZXJ0Y2hpbGUuY2wvRWNlcnRjaGlsZUNBSS5jcmwwIwYDVR0SBBwwGqAYBggrBgEEAcEBAqAMFgo5NjkyODE4MC01MIHmBgNVHSA" & _
    "Egd4wgdswgdgGCCsGAQQBw1IAMIHLMDYGCCsGAQUFBwIBFipodHRwOi8vd3d3LmUtY2VydGNoaWxlLmNsL3BvbGl0aWNhL2Nwcy5odG0wgZAGCCsGAQUFBwICMIGDGoGARWwgdGl0dWxhciBoYSBzaWRvIHZhbGlkYWRvIGVuIGZvcm1hIHByZXNlbmNpYWwsIHF1ZWRhbmRvIGhhYmlsaXRhZG8gZWwgQ2VydGlmaWNhZG8" & _
    "gcGFyYSB1c28gdHJpYnV0YXJpbywgcGFnb3MsIGNvbWVyY2lvIHUgb3Ryb3MwCwYDVR0PBAQDAgTwMAsGCSqGSIb3DQEBBAOBgQB2V4cTj7jo1RawmsRQUSnnvJjMCrZstcHY+Ss3IghVPO9eGoYzu5Q63vzt0Pi8CS91SBc7xo+LDoljaUyjOzj7zvU7TpWoFndiTQF3aCOtTkV+vjCMWW3sVHes4UCMDkF3VYK+rDTAadi" & _
    "aeDArTwsx4eNEpxFuA/TJwcXpLQRCDg=="

        strXmlKey = "<RSAKeyValue><Modulus>" & _
            "tNEknkb1kHiD1OOAWlLKkcH/UP5UGa6V6MYso++JB+vYMg2OXFROAF7G8BNFFPQx" & _
            "iuS/7y1azZljN2xq+bW3bAou1bW2ij7fxSXWTJYFZMAyndbLyGHM1e3nVmwpgEpx" & _
            "BHhZzPvwLb55st1wceuKjs2Ontb13J33sUb7bbJMWh0=</Modulus>" & _
            "<Exponent>AQAB</Exponent></RSAKeyValue>"

        Console.WriteLine(IsCertAndKeyValueMatched(strCert64, strXmlKey))

    End Sub

    Public Function Hash_String_SHA1(ByVal strMessage As String, Optional ByVal ShowDebug As Boolean = False) As String
        ' $GENERIC-FUNCTION$
        ' INPUT:  Message as an ANSI string
        ' OUTPUT: SHA-1 message digest in hex format
        Dim abMessage() As Byte
        Dim nmLen As Integer
        Dim strDigest As String

        ' Convert ANSI text to bytes
        abMessage = System.Text.Encoding.Default.GetBytes(strMessage)
        nmLen = abMessage.Length

        If ShowDebug Then
            Console.WriteLine("M (ansi):" & vbCrLf & "'" & System.Text.Encoding.Default.GetString(abMessage) & "'")
            Console.WriteLine("M (hex):  " & Cnv.ToHex(abMessage))
            Console.WriteLine("Message is " & nmLen & " bytes long")
        End If

        strDigest = Hash.HexFromBytes(abMessage, HashAlgorithm.Sha1)
        If strDigest.Length = 0 Then
            Console.WriteLine("FAILED to create message digest")
        End If

        Hash_String_SHA1 = strDigest

    End Function

    Public Function Hash_File_SHA1(ByVal strFileName As String) As String
        ' $GENERIC-FUNCTION$
        ' INPUT:  Full path to file
        ' OUTPUT: SHA-1 message digest in hex format
        Dim strDigest As String

        strDigest = Hash.HexFromFile(strFileName, HashAlgorithm.Sha1)
        If strDigest.Length = 0 Then
            Console.WriteLine("FAILED to create message digest")
        End If

        Hash_File_SHA1 = strDigest

    End Function

    Public Sub Test_Make_Hash_of_File()

        Console.WriteLine("DIGEST=" & Hash_File_SHA1("data.canon.ok.txt"))

    End Sub

    Public Function MakeDigestValueOfSignedInfo(ByVal strDigestValue64 As String, ByVal strReference As String, ByVal fIncludeXMLSchema As Boolean, Optional ByVal ShowDebug As Boolean = False) As String
        ' $GENERIC-FUNCTION$
        ' INPUT:  DigestValue of data in base64 format
        '         Reference as in <Reference URI="#...">
        '         Flag to include XMLSchema-instance attribute
        ' OUTPUT: SHA-1 digest of canonicalized <SignedInfo> element in HEX format
        ' REMARKS: This is for the specific form with no whitespace before any element

        Dim strSignedInfoCanonic As String
        Dim strDigest As String
        Dim strFirstLine As String

        'SPECIFIC FORM (no whitespace before elements):
        ' <SignedInfo>
        ' <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
        ' <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
        ' <Reference URI="#...">
        ' <Transforms>
        ' <Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
        ' </Transforms>
        ' <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
        ' <DigestValue>...</DigestValue>
        ' </Reference>
        ' </SignedInfo>

        ' To canonicalize the SignedInfo, do the following:-
        ' 1. Replace any CR-LF pairs with single LF char
        ' 2. Add the xmlns attributes to the SignedInfo tag
        ' 3. Convert the empty 'Method' elements to start-end tag pairs
        ' 4. Use double-quotes (") around attribute values
        ' 5. Do NOT change any other whitespace chars outside the tags
        ' -- assumes all other c14n aspects are dealt with in the hard-coding

        ' We can hard-code all of the above directly; well, almost...
        If fIncludeXMLSchema Then
            strFirstLine = "<SignedInfo xmlns=""http://www.w3.org/2000/09/xmldsig#"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"">"
        Else
            strFirstLine = "<SignedInfo xmlns=""http://www.w3.org/2000/09/xmldsig#"">"
        End If

        strSignedInfoCanonic = _
            strFirstLine & vbLf & _
            "<CanonicalizationMethod Algorithm=""http://www.w3.org/TR/2001/REC-xml-c14n-20010315""></CanonicalizationMethod>" & vbLf & _
            "<SignatureMethod Algorithm=""http://www.w3.org/2000/09/xmldsig#rsa-sha1""></SignatureMethod>" & vbLf & _
            "<Reference URI=""#" & strReference & """>" & vbLf & _
            "<Transforms>" & vbLf & _
            "<Transform Algorithm=""http://www.w3.org/TR/2001/REC-xml-c14n-20010315""></Transform>" & vbLf & _
            "</Transforms>" & vbLf & _
            "<DigestMethod Algorithm=""http://www.w3.org/2000/09/xmldsig#sha1""></DigestMethod>" & vbLf & _
            "<DigestValue>" & strDigestValue64 & "</DigestValue>" & vbLf & _
            "</Reference>" & vbLf & _
            "</SignedInfo>"

        If ShowDebug Then
            Console.WriteLine(strSignedInfoCanonic)
        End If
        strDigest = Hash_String_SHA1(strSignedInfoCanonic)
        MakeDigestValueOfSignedInfo = strDigest

    End Function

    Public Sub Test_DigestSignedInfo()
        Dim strComputed As String
        Dim strCorrect As String

        Console.WriteLine()
        Console.WriteLine("F60T33 Outer XML-Dsig:")
        strCorrect = "98B466FFE6A5E73B85962BC7300841C5F1693D3A"
        strComputed = MakeDigestValueOfSignedInfo("4OTWXyRl5fw3htjTyZXQtYEsC3E=", "SetDoc", fIncludeXMLSchema:=True)
        Console.WriteLine("COMPUTED=" & strComputed)
        Console.WriteLine("CORRECT= " & strCorrect)

        Console.WriteLine("F60T33 Inner XML-Dsig:")
        strCorrect = "353CABFE369AAD9BEA21F5FA06CB367960FFB7D4"
        strComputed = MakeDigestValueOfSignedInfo("hlmQtu/AyjUjTDhM3852wvRCr8w=", "F60T33", fIncludeXMLSchema:=False)
        Console.WriteLine("COMPUTED=" & strComputed)
        Console.WriteLine("CORRECT= " & strCorrect)

    End Sub

    Public Function XMLDSIG_VerifySigUsingRSAKeyValue(ByVal strSig64 As String, ByVal strXmlKey As String) As String
        ' $GENERIC-FUNCTION$
        ' INPUT:  strSig64  = <SignatureValue> in base64 excluding XML tags
        '         strXmlKey = <RSAKeyValue> in XMLSIG format including XML tags
        ' OUTPUT: DigestValue in hex format
        Dim nRet As Integer
        Dim abData() As Byte
        Dim nDataLen As Integer
        Dim strPublicKey As String
        Dim nKeyLen As Integer
        Dim abDigest() As Byte
        Dim nDigLen As Integer

        XMLDSIG_VerifySigUsingRSAKeyValue = ""
        Console.WriteLine("SigBase64=" & strSig64)
        ' Convert XML key form to our internal format
        strPublicKey = Rsa.FromXMLString(strXmlKey, false)
        If strPublicKey.Length = 0 Then
            Console.WriteLine("ERROR: Unable to read XML key string")
            Exit Function
        End If
        Console.WriteLine("Key length is " & Rsa.KeyBits(strPublicKey) & " bits")

        ' Convert signatureValue to byte format
        abData = System.Convert.FromBase64String(strSig64)
        Console.WriteLine("SIGNATURE=" & Cnv.ToHex(abData))
        nDataLen = UBound(abData) - LBound(abData) + 1
        Console.WriteLine("Signature is " & nDataLen & " bytes long")
        ' Verify the key - this should return 1
        nRet = Rsa.CheckKey(strPublicKey)
        Console.WriteLine("RSA_CheckKey returns " & nRet & " (expecting 1)")
        ' Check the length
        nKeyLen = Rsa.KeyBytes(strPublicKey)
        Console.WriteLine("Key is " & nKeyLen & " bytes long")
        If nKeyLen <> nDataLen Then
            Console.WriteLine("ERROR: Key is the wrong length!")
            Exit Function
        End If
        ' Decrypt the signature
        abData = Rsa.RawPublic(abData, strPublicKey)
        If abData.Length = 0 Then
            Console.WriteLine("ERROR: " & General.LastError())
            Exit Function
        End If
        Console.WriteLine("EMSA BLOCK=" & Cnv.ToHex(abData))

        ' Extract digest from block
        abDigest = Rsa.DecodeDigestForSignature(abData)
        nDigLen = abDigest.Length
        Console.WriteLine("RSA_DecodeMsg returns " & nDigLen & " (expecting 20)")
        If nDigLen <= 0 Then
            Console.WriteLine("ERROR: Cannot extract digest")
            Exit Function
        End If

        ' Display bytes as hex and base64
        Console.WriteLine("digest=" & Cnv.ToHex(abDigest))
        Console.WriteLine("base64=" & System.Convert.ToBase64String(abDigest))
        Console.WriteLine()
        ' Return result
        XMLDSIG_VerifySigUsingRSAKeyValue = Cnv.ToHex(abDigest)

    End Function

    Public Function XMLDSIG_VerifySigUsingCert(ByVal strSig64 As String, ByVal strCert64 As String) As String
        ' $GENERIC-FUNCTION$
        ' INPUT:  strSig64  = <SignatureValue> content in base64 excluding tags
        '         strCert64 = <X509Certificate> content in base64 excluding tags
        ' OUTPUT: digestValue in hex format
        Dim abData() As Byte
        Dim strPublicKey As String
        Dim nRet As Integer
        Dim nDataLen As Integer
        Dim nKeyLen As Integer
        Dim abDigest() As Byte
        Dim strQuery As String
        Dim strOutput As String
        Dim strXmlKey As String

        XMLDSIG_VerifySigUsingCert = ""
        ' Query the certificate for details
        strQuery = "subjectName"
        strOutput = X509.QueryCert(strCert64, strQuery)
        If strOutput.Length = 0 Then
            Console.WriteLine("ERROR: Error reading certificate: " & General.LastError)
            Exit Function ' ERROR
        End If
        Console.WriteLine(strQuery & "=" & strOutput)

        ' Extract public key from X.509 certificate in internal string form
        strPublicKey = Rsa.GetPublicKeyFromCert(strCert64).ToString()
        Console.WriteLine("Chars in internal key = " & strPublicKey.Length)
        If strPublicKey.Length = 0 Then
            Console.WriteLine("ERROR: Error reading certificate key")
            Exit Function ' ERROR
        End If
        Console.WriteLine("PUBLIC KEY (internal)=" & strPublicKey)

        ' While we're here, display the public key in XML format
        strXmlKey = Rsa.ToXMLString(strPublicKey, 0)
        If strXmlKey.Length > 0 Then
            Console.WriteLine(strXmlKey)
        Else
            Console.WriteLine("**Failed to create public key in XML")
        End If

        ' Convert signatureValue to byte format
        abData = System.Convert.FromBase64String(strSig64)
        Console.WriteLine("SIGNATURE=" & Cnv.ToHex(abData))
        nDataLen = abData.Length
        Console.WriteLine("Signature is " & nDataLen & " bytes long")
        ' Verify the key - this should return 1
        nRet = Rsa.CheckKey(strPublicKey)
        Console.WriteLine("RSA_CheckKey returns " & nRet & " (expecting 1)")
        ' Check the length
        nKeyLen = Rsa.KeyBytes(strPublicKey)
        Console.WriteLine("Key is " & nKeyLen & " bytes long")
        If nKeyLen <> nDataLen Then
            Console.WriteLine("ERROR: Key is the wrong length!")
            Exit Function
        End If
        ' Decrypt the signature
        abData = Rsa.RawPublic(abData, strPublicKey)
        Console.WriteLine("RSA_RawPublic returns " & nRet & " (expecting 0)")
        Console.WriteLine("EMSA BLOCK=" & Cnv.ToHex(abData))

        ' Extract digest from block
        abDigest = Rsa.DecodeDigestForSignature(abData)
        Console.WriteLine("RSA_DecodeMsg returns " & abDigest.Length & " (expecting 20)")
        If abDigest.Length = 0 Then
            Console.WriteLine("ERROR: Cannot extract digest")
            Exit Function
        End If

        ' Display bytes as hex and base64
        Console.WriteLine("digest=" & Cnv.ToHex(abDigest))
        Console.WriteLine("base64=" & System.Convert.ToBase64String(abDigest))
        ' Return digest in hex
        XMLDSIG_VerifySigUsingCert = Cnv.ToHex(abDigest)
    End Function

    Public Sub TestReadFRMA()
        Dim strCert64 As String
        Dim strSig64 As String
        Dim strDigestHex As String

        '<FRMA algoritmo="SHA1withRSA">g1AQX0sy8NJugX52k2hTJEZAE9Cuul6pqYBdFxj1N17umW7zG/hAavCALKByHzdYAfZ3LhGTXCai5zNxOo4lDQ==</FRMA>
        strSig64 = "g1AQX0sy8NJugX52k2hTJEZAE9Cuul6pqYBdFxj1N17umW7zG/hAavCALKByHzdYAfZ3LhGTXCai5zNxOo4lDQ=="

        ' [2009-05-07] We have the certificate for the signer of this now...
        strCert64 = "-----BEGIN CERTIFICATE-----" & vbCrLf & _
            "MIICTzCCAfmgAwIBAwIBZDANBgkqhkiG9w0BAQQFADCBrzELMAkGA1UEBhMCQ0wx" & _
            "CzAJBgNVBAgTAkNTMQswCQYDVQQHEwJDczEnMCUGA1UEChMeU2VydmljaW8gZGUg" & _
            "SW1wdWVzdG9zIEludGVybm9zMRkwFwYDVQQLExBPZmljaW5hIEludGVybmV0MScw" & _
            "JQYDVQQDEx5TZXJ2aWNpbyBkZSBJbXB1ZXN0b3MgSW50ZXJub3MxGTAXBgkqhkiG" & _
            "9w0BCQEWCnNpaUBzaWkuY2wwHhcNMDMwNDI5MjAxNDA1WhcNMDQwNDIzMjAxNDA1" & _
            "WjCBrzELMAkGA1UEBhMCQ0wxCzAJBgNVBAgTAkNTMQswCQYDVQQHEwJDczEnMCUG" & _
            "A1UEChMeU2VydmljaW8gZGUgSW1wdWVzdG9zIEludGVybm9zMRkwFwYDVQQLExBP" & _
            "ZmljaW5hIEludGVybmV0MScwJQYDVQQDEx5TZXJ2aWNpbyBkZSBJbXB1ZXN0b3Mg" & _
            "SW50ZXJub3MxGTAXBgkqhkiG9w0BCQEWCnNpaUBzaWkuY2wwXDANBgkqhkiG9w0B" & _
            "AQEFAANLADBIAkEAyPvwDcshpVAApYVSLF3lKKc+DOFswDqx5ep95LKigRHjUvrv" & _
            "jct9UeNJq9SxBdzU9nz54TEVBYyfAVQpG4xxUwIDAQABMA0GCSqGSIb3DQEBBAUA" & _
            "A0EADvJX1C7hUFD2Eq9jNZpeJ/YBOZx1SBmAHSeXud6fTw98+AR4X3YDmzO9D4Kd" & _
            "hEFi3NK4anpjiPOKbA8fBWyyBA==" & _
            "-----END CERTIFICATE-----"

        strDigestHex = XMLDSIG_VerifySigUsingCert(strSig64, strCert64)

    End Sub

    Public Sub MakeFRMAdigest()
        ' This should give the same digest value we obtained above.
        Dim strData As String
        Dim strDigest As String
        ' Put <DA> data into a single string with no spaces between elements
        strData = "<DA><RE>97975000-5</RE><RS>RUT DE PRUEBA</RS><TD>33</TD><RNG><D>1</D><H>200</H></RNG><FA>2003-09-04</FA><RSAPK><M>0a4O6Kbx8Qj3K4iWSP4w7KneZYeJ+g/prihYtIEolKt3cykSxl1zO8vSXu397QhTmsX7SBEudTUx++2zDXBhZw==</M><E>Aw==</E></RSAPK><IDK>100</IDK></DA>"
        ' Create an SHA-1 digest value in hex format
        ''strDigest = String(PKI_SHA1_CHARS, " ")
        strDigest = Hash.HexFromString(strData, HashAlgorithm.Sha1)
        Console.WriteLine("SHA1(DA)=" & strDigest)
        ' Display in base64
        Console.WriteLine("SHA1(DA)=" & System.Convert.ToBase64String(Cnv.FromHex(strDigest)))
    End Sub

    Public Sub TestReadFRMT()
        Dim strXmlKey As String
        Dim strSig64 As String

        ' <FRMT algoritmo="SHA1withRSA">GbmDcS9e/jVC2LsLIe1iRV12Bf6lxsILtbQiCkh6mbjckFCJ7fj/kakFTS06Jo8iS4HXvJj3oYZuey53Krniew==</FRMT>
        strSig64 = "GbmDcS9e/jVC2LsLIe1iRV12Bf6lxsILtbQiCkh6mbjckFCJ7fj/kakFTS06Jo8iS4HXvJj3oYZuey53Krniew=="

        ' Form XML string of public key in proper XMLSIG format using <RSAPK> element in XML file
        ' <RSAPK><M>0a4O6Kbx8Qj3K4iWSP4w7KneZYeJ+g/prihYtIEolKt3cykSxl1zO8vSXu397QhTmsX7SBEudTUx++2zDXBhZw==</M><E>Aw==</E></RSAPK>
        strXmlKey = "<RSAKeyValue><Modulus>0a4O6Kbx8Qj3K4iWSP4w7KneZYeJ+g/prihYtIEolKt3cykSxl1zO8vSXu397QhTmsX7SBEudTUx++2zDXBhZw==</Modulus>" & _
        "<Exponent>Aw==</Exponent></RSAKeyValue>"

        Call XMLDSIG_VerifySigUsingRSAKeyValue(strSig64, strXmlKey)

    End Sub

    Public Sub TestF60T33OuterXmlSigByCert()
        ' THIS DOES NOT WORK! Because the X509 Certificate provided does not correspond to the key used to make the signature.
        Dim strSig64 As String
        Dim strCert64 As String

        strCert64 = "MIIEgjCCA+ugAwIBAgIEAQAApzANBgkqhkiG9w0BAQUFADCBtTELMAkGA1UEBhMCQ0wxHTAbBgNVBAgUFFJlZ2lvbiBNZXRyb3BvbGl0YW5hMREwDwYDVQQHFAhTYW50aWFnbzEUMBIGA1UEChQLRS1DRVJUQ0hJTEUxIDAeBgNVBAsUF0F1dG9yaWRhZCBDZXJ0aWZpY2Fkb3JhMRcwFQYDVQQDFA5FLUNFUlRDSElMRSBD" & _
    "QTEjMCEGCSqGSIb3DQEJARYUZW1haWxAZS1jZXJ0Y2hpbGUuY2wwHhcNMDMxMDAxMTg1ODE1WhcNMDQwOTMwMDAwMDAwWjCBuDELMAkGA1UEBhMCQ0wxFjAUBgNVBAgUDU1ldHJvcG9saXRhbmExETAPBgNVBAcUCFNhbnRpYWdvMScwJQYDVQQKFB5TZXJ2aWNpbyBkZSBJbXB1ZXN0b3MgSW50ZXJub3MxDzANBgNVBAsU" & _
    "BlBpc28gNDEjMCEGA1UEAxQaV2lsaWJhbGRvIEdvbnphbGV6IENhYnJlcmExHzAdBgkqhkiG9w0BCQEWEHdnb256YWxlekBzaWkuY2wwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALxZlVh1xr9sKQIBDF/6Va+lsHQSG5AAmCWvtNTIOXN3E9EQCy7pOPHrDg6EusvoHyesZSKJbc0TnIFXZp78q7mbdHijzKqvMmyv" & _
    "wbdP7KK8LQfwf84W4v9O8MJeUHlbJGlo5nFACrPAeTtONbHaReyzeMDv2EganNEDJc9c+UNfAgMBAAGjggGYMIIBlDAjBgNVHREEHDAaoBgGCCsGAQQBwQEBoAwWCjA3ODgwNDQyLTQwCQYDVR0TBAIwADA8BgNVHR8ENTAzMDGgL6AthitodHRwOi8vY3JsLmUtY2VydGNoaWxlLmNsL2UtY2VydGNoaWxlY2EuY3JsMCMG" & _
    "A1UdEgQcMBqgGAYIKwYBBAHBAQKgDBYKOTY5MjgxODAtNTAfBgNVHSMEGDAWgBTgKP3S4GBPs0brGsz1CJEHcjodCDCB0AYDVR0gBIHIMIHFMIHCBggrBgEEAcNSBTCBtTAvBggrBgEFBQcCARYjaHR0cDovL3d3dy5lLWNlcnRjaGlsZS5jbC8yMDAwL0NQUy8wgYEGCCsGAQUFBwICMHUac0VsIHRpdHVsYXIgaGEgc2lk" & _
    "byB2YWxpZG8gZW4gZm9ybWEgcHJlc2VuY2lhbCwgcXVlZGFuZG8gZWwgQ2VydGlmaWNhZG8gcGFyYSB1c28gdHJpYnV0YXJpbywgcGFnb3MsIGNvbWVyY2lvIHkgb3Ryb3MwCwYDVR0PBAQDAgTwMA0GCSqGSIb3DQEBBQUAA4GBABMfCyJF0mNXcov8iEWvjGFyyPTsXwvsYbbkOJ41wjaGOFMCInb4WY0ngM8BsDV22bGM" & _
    "s8oLyX7rVy16bGA8Z7WDUtYhoOM7mqXw/Hrpqjh3JgAf8zqdzBdH/q6mAbdvq/yb04JHKWPC7fMFuBoeyVWAnhmuMZfReWQiMUEHGGIW"
        strSig64 = "sBnr8Yq14vVAcrN/pKLD/BrqUFczKMW3y1t3JOrdsxhhq6IxvS13SgyMXbIN/T9ciRaFgNabs3pi732XhcpeiSmD1ktzbRctEbSIszYkFJY49k0eB+TVzq3eVaQr4INrymfuOnWj78BZcwKuXvDy4iAcx6/TBbAAkPFwMP9ql2s="

        Call XMLDSIG_VerifySigUsingCert(strSig64, strCert64)

    End Sub

    Public Sub TestF60T33OuterXmlSigByRSA()
        ' THIS WORKS...
        Dim strSig64 As String
        Dim strXmlKey As String

        strXmlKey = "<RSAKeyValue><Modulus>" & _
            "tNEknkb1kHiD1OOAWlLKkcH/UP5UGa6V6MYso++JB+vYMg2OXFROAF7G8BNFFPQx" & _
            "iuS/7y1azZljN2xq+bW3bAou1bW2ij7fxSXWTJYFZMAyndbLyGHM1e3nVmwpgEpx" & _
            "BHhZzPvwLb55st1wceuKjs2Ontb13J33sUb7bbJMWh0=</Modulus>" & _
            "<Exponent>AQAB</Exponent></RSAKeyValue>"
        strSig64 = "sBnr8Yq14vVAcrN/pKLD/BrqUFczKMW3y1t3JOrdsxhhq6IxvS13SgyMXbIN/T9ciRaFgNabs3pi732XhcpeiSmD1ktzbRctEbSIszYkFJY49k0eB+TVzq3eVaQr4INrymfuOnWj78BZcwKuXvDy4iAcx6/TBbAAkPFwMP9ql2s="

        Call XMLDSIG_VerifySigUsingRSAKeyValue(strSig64, strXmlKey)

    End Sub

    Public Sub TestF60T33InnerXmlSigByRSA()
        ' THIS WORKS...
        Dim strSig64 As String
        Dim strXmlKey As String

        strXmlKey = "<RSAKeyValue><Modulus>" & _
            "tNEknkb1kHiD1OOAWlLKkcH/UP5UGa6V6MYso++JB+vYMg2OXFROAF7G8BNFFPQx" & _
            "iuS/7y1azZljN2xq+bW3bAou1bW2ij7fxSXWTJYFZMAyndbLyGHM1e3nVmwpgEpx" & _
            "BHhZzPvwLb55st1wceuKjs2Ontb13J33sUb7bbJMWh0=</Modulus>" & _
            "<Exponent>AQAB</Exponent></RSAKeyValue>"
        strSig64 = "JG1Ig0pvSIH85kIKGRZUjkyX6CNaY08Y94j4UegTgDe8+wl61GzqjdR1rfOK9BGn93AMOo6aiAgolW0k/XklNVtM/ZzpNNS3d/fYVa1q509mAMSXbelxSM3bjoa7H6Wzd/mV1PpQ8zK5gw7mgMMP4IKxHyS92G81GEguSmzcQmA="

        Call XMLDSIG_VerifySigUsingRSAKeyValue(strSig64, strXmlKey)

    End Sub

    Public Sub TestF60T33FRMTSigByRSA()
        Dim strSig64 As String
        Dim strXmlKey As String

        strXmlKey = "<RSAKeyValue><Modulus>" & _
            "0a4O6Kbx8Qj3K4iWSP4w7KneZYeJ+g/prihYtIEolKt3cykSxl1zO8vSXu397QhTmsX7SBEudTUx++2zDXBhZw==</Modulus>" & _
            "<Exponent>Aw==</Exponent></RSAKeyValue>"
        strSig64 = "GbmDcS9e/jVC2LsLIe1iRV12Bf6lxsILtbQiCkh6mbjckFCJ7fj/kakFTS06Jo8iS4HXvJj3oYZuey53Krniew=="

        Call XMLDSIG_VerifySigUsingRSAKeyValue(strSig64, strXmlKey)

    End Sub



    Sub Main()

        Console.WriteLine("DOING ALL TESTS...")

        Console.WriteLine("\n Read_SmallerKeys() \n")
        Read_SmallerKeys()

        Console.WriteLine("\n MakeFRMTdigest() \n")
        MakeFRMTdigest()

        Console.WriteLine("\n SignDDtoMakeFRMTsig() \n")
        SignDDtoMakeFRMTsig()

        Console.WriteLine("\n CheckExampleCertAndRSAKey() \n")
        CheckExampleCertAndRSAKey()

        Console.WriteLine("\n CheckManualCertAndRSAKey() \n")
        CheckManualCertAndRSAKey()

        Console.WriteLine("\n Test_Make_Hash_of_File() \n")
        Test_Make_Hash_of_File()

        Console.WriteLine("\n Test_DigestSignedInfo() \n")
        Test_DigestSignedInfo()

        Console.WriteLine("\n TestReadFRMA() \n")
        TestReadFRMA()

        Console.WriteLine("\n MakeFRMAdigest() \n")
        MakeFRMAdigest()

        Console.WriteLine("\n TestReadFRMT() \n")
        TestReadFRMT()

        Console.WriteLine("\n TestF60T33OuterXmlSigByCert() \n")
        TestF60T33OuterXmlSigByCert()

        Console.WriteLine("\n TestF60T33OuterXmlSigByRSA() \n")
        TestF60T33OuterXmlSigByRSA()

        Console.WriteLine("\n TestF60T33InnerXmlSigByRSA() \n")
        TestF60T33InnerXmlSigByRSA()

        Console.WriteLine("\n TestF60T33FRMTSigByRSA() \n")
        TestF60T33FRMTSigByRSA()

    End Sub

End Module