using System; using System.Diagnostics; using System.Text; using CryptoSysPKI; namespace TestChile { class TestChile { // $Id: TestChile.cs $ // $Date: 2010-06-24 06:10 $ // $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 static void Read_SmallerKeys() { // From manual_certificacion.pdf, 2003-11-26, p25 string strKeyPem = null; int nRet = 0; string strPrivateKey = null; string strPublicKey = null; string strXmlKey = null; string strSig64 = null; byte[] abData = null; int nDataLen = 0; int nKeyLen = 0; byte[] abDigest = null; // 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-----" + "\n" + "MIIBOwIBAAJBANGuDuim8fEI9yuIlkj+MOyp3mWHifoP6a4oWLSBKJSrd3MpEsZd" + "czvL0l7t/e0IU5rF+0gRLnU1Mfvtsw1wYWcCAQMCQQCLyV9FxKFLW09yWw7bVCCd" + "xpRDr7FRX/EexZB4VhsNxm/vtJfDZyYle0Lfy42LlcsXxPm1w6Q6NnjuW+AeBy67" + "AiEA7iMi5q5xjswqq+49RP55o//jqdZL/pC9rdnUKxsNRMMCIQDhaHdIctErN2hC" + "IP9knS3+9zra4R+5jSXOvI+3xVhWjQIhAJ7CF0R0S7SIHHKe04NUURf/7RvkMqm1" + "08k74sdnXi3XAiEAlkWk2vc2HM+a1sCqQxNz/098ketqe7NuidMKeoOQObMCIQCk" + "FAMS9IcPcMjk7zI2r/4EEW63PSXyN7MFAX7TYe25mw==" + "\n" + "-----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) { Console.WriteLine("ERROR: Key is the wrong length!"); return; } // Decrypt the signature abData = Rsa.RawPublic(abData, strPublicKey); if (nRet != 0) { Console.WriteLine("ERROR: " + General.ErrorLookup(nRet)); return; } 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)); } public static void MakeFRMTdigest() { // This should give the same digest value we obtained above. string strData = null; string strDigest = null; // 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))); } public static void 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 string strKeyPem = null; string strData = null; string strPrivateKey = null; int nKeyBytes = 0; byte[] abBlock = null; byte[] abData = null; int nDataLen = 0; string strSigVal64 = null; // 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-----" + "\n" + "MIIBOwIBAAJBANGuDuim8fEI9yuIlkj+MOyp3mWHifoP6a4oWLSBKJSrd3MpEsZd" + "czvL0l7t/e0IU5rF+0gRLnU1Mfvtsw1wYWcCAQMCQQCLyV9FxKFLW09yWw7bVCCd" + "xpRDr7FRX/EexZB4VhsNxm/vtJfDZyYle0Lfy42LlcsXxPm1w6Q6NnjuW+AeBy67" + "AiEA7iMi5q5xjswqq+49RP55o//jqdZL/pC9rdnUKxsNRMMCIQDhaHdIctErN2hC" + "IP9knS3+9zra4R+5jSXOvI+3xVhWjQIhAJ7CF0R0S7SIHHKe04NUURf/7RvkMqm1" + "08k74sdnXi3XAiEAlkWk2vc2HM+a1sCqQxNz/098ketqe7NuidMKeoOQObMCIQCk" + "FAMS9IcPcMjk7zI2r/4EEW63PSXyN7MFAX7TYe25mw==" + "\n" + "-----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 = abData.Length; 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) { Console.WriteLine("ERROR: RSA_EncodeMsg failed. Error: " + General.LastError()); return; } 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) { Console.WriteLine("ERROR: RSA_RawPrivate failed. Error: " + General.LastError()); return; } Console.WriteLine("SIGNATURE= " + Cnv.ToHex(abBlock)); // Convert byte array to base64 strSigVal64 = System.Convert.ToBase64String(abBlock); Console.WriteLine("SignatureValue=" + strSigVal64); } public static string XmlHexFromInternalKey(string strKey) { string functionReturnValue = null; // $GENERIC-FUNCTION$ // INPUT: Public or private RSA key in internal format // OUTPUT: String containing RSAKeyValue in XML format string strXmlKey = null; Rsa.XmlOptions nOptions = default(Rsa.XmlOptions); nOptions = Rsa.XmlOptions.HexBinaryFormat | Rsa.XmlOptions.ExcludePrivateParams | Rsa.XmlOptions.ForceRSAKeyValue; strXmlKey = Rsa.ToXMLString(strKey, nOptions); if (strXmlKey.Length > 0) { functionReturnValue = strXmlKey; } else { functionReturnValue = "**Failed to create public key in XML"; } return functionReturnValue; } public static bool IsCertAndKeyValueMatched(string strCert64, string strXmlKey) { // $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. string strPublicKey = null; string strQuery = null; string strOutput = null; int nHashCode1 = 0; int nHashCode2 = 0; bool result = false; // Query the certificate for details... strQuery = "issuerName"; strOutput = X509.QueryCert(strCert64, strQuery); if (strOutput.Length == 0) { Console.WriteLine("ERROR: Error reading certificate: " + General.LastError()); return result; // ERROR } Console.WriteLine(strQuery + "=" + strOutput); strQuery = "serialNumber"; strOutput = X509.QueryCert(strCert64, strQuery); if (strOutput.Length == 0) { Console.WriteLine("ERROR: Error reading certificate: " + General.LastError()); return result; // ERROR } Console.WriteLine(strQuery + "=" + strOutput); strQuery = "subjectName"; strOutput = X509.QueryCert(strCert64, strQuery); if (strOutput.Length == 0) { Console.WriteLine("ERROR: Error reading certificate: " + General.LastError()); return result; // ERROR } Console.WriteLine(strQuery + "=" + strOutput); strQuery = "notBefore"; strOutput = X509.QueryCert(strCert64, strQuery); if (strOutput.Length == 0) { Console.WriteLine("ERROR: Error reading certificate: " + General.LastError()); return result; // ERROR } Console.WriteLine(strQuery + "=" + strOutput); strQuery = "signatureAlgorithm"; strOutput = X509.QueryCert(strCert64, strQuery); if (strOutput.Length == 0) { Console.WriteLine("ERROR: Error reading certificate: " + General.LastError()); return result; // ERROR } Console.WriteLine(strQuery + "=" + strOutput); // Extract public key from X.509 certificate strPublicKey = Rsa.GetPublicKeyFromCert(strCert64).ToString(); if (strPublicKey.Length == 0) { Console.WriteLine("ERROR: Error reading certificate key: " + General.LastError()); return result; // ERROR } 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, true); if (strPublicKey.Length == 0) { Console.WriteLine("ERROR: Unable to read XML key string"); return result; } 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) { result = true; Console.WriteLine("OK, public keys match."); } else { result = false; Console.WriteLine("ERROR: public keys do not match."); } return result; } public static void 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> string strCert64 = null; string strXmlKey = null; 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)); } public static void 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> string strCert64 = null; string strXmlKey = null; 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)); } public static string Hash_String_SHA1(string strMessage, bool ShowDebug) { // $GENERIC-FUNCTION$ // INPUT: Message as an ANSI string // OUTPUT: SHA-1 message digest in hex format byte[] abMessage = null; int nmLen = 0; string strDigest = null; // Convert ANSI text to bytes abMessage = System.Text.Encoding.Default.GetBytes(strMessage); nmLen = abMessage.Length; if (ShowDebug) { Console.WriteLine("M (ansi):" + "\n" + "'" + System.Text.Encoding.Default.GetString(abMessage) + "'"); Console.WriteLine("M (hex): " + Cnv.ToHex(abMessage)); Console.WriteLine("Message is " + nmLen + " bytes long"); } strDigest = Hash.HexFromBytes(abMessage, HashAlgorithm.Sha1); if (strDigest.Length == 0) { Console.WriteLine("FAILED to create message digest"); } return strDigest; } public static string Hash_File_SHA1(string strFileName) { // $GENERIC-FUNCTION$ // INPUT: Full path to file // OUTPUT: SHA-1 message digest in hex format string strDigest = null; strDigest = Hash.HexFromFile(strFileName, HashAlgorithm.Sha1); if (strDigest.Length == 0) { Console.WriteLine("FAILED to create message digest"); } return strDigest; } public static void Test_Make_Hash_of_File() { Console.WriteLine("DIGEST=" + Hash_File_SHA1("data.canon.ok.txt")); } public static string MakeDigestValueOfSignedInfo(string strDigestValue64, string strReference, bool fIncludeXMLSchema, bool ShowDebug) { // $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 string strSignedInfoCanonic = null; string strDigest = null; string strFirstLine = null; string chLf = String.Format("\n"); // String with single LF char //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) { 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#\">"; } strSignedInfoCanonic = strFirstLine + chLf + "<CanonicalizationMethod Algorithm=\"http://www.w3.org/TR/2001/REC-xml-c14n-20010315\"></CanonicalizationMethod>" + chLf + "<SignatureMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#rsa-sha1\"></SignatureMethod>" + chLf + "<Reference URI=\"#" + strReference + "\">" + chLf + "<Transforms>" + chLf + "<Transform Algorithm=\"http://www.w3.org/TR/2001/REC-xml-c14n-20010315\"></Transform>" + chLf + "</Transforms>" + chLf + "<DigestMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#sha1\"></DigestMethod>" + chLf + "<DigestValue>" + strDigestValue64 + "</DigestValue>" + chLf + "</Reference>" + chLf + "</SignedInfo>"; if (ShowDebug) { Console.WriteLine(strSignedInfoCanonic); } strDigest = Hash_String_SHA1(strSignedInfoCanonic, false); return strDigest; } public static void Test_DigestSignedInfo() { string strComputed = null; string strCorrect = null; Console.WriteLine(); Console.WriteLine("F60T33 Outer XML-Dsig:"); strCorrect = "98B466FFE6A5E73B85962BC7300841C5F1693D3A"; strComputed = MakeDigestValueOfSignedInfo("4OTWXyRl5fw3htjTyZXQtYEsC3E=", "SetDoc", true, false); Console.WriteLine("COMPUTED=" + strComputed); Console.WriteLine("CORRECT= " + strCorrect); Console.WriteLine("F60T33 Inner XML-Dsig:"); strCorrect = "353CABFE369AAD9BEA21F5FA06CB367960FFB7D4"; strComputed = MakeDigestValueOfSignedInfo("hlmQtu/AyjUjTDhM3852wvRCr8w=", "F60T33", false, false); Console.WriteLine("COMPUTED=" + strComputed); Console.WriteLine("CORRECT= " + strCorrect); } public static string XMLDSIG_VerifySigUsingRSAKeyValue(string strSig64, string strXmlKey) { // $GENERIC-FUNCTION$ // INPUT: strSig64 = <SignatureValue> in base64 excluding XML tags // strXmlKey = <RSAKeyValue> in XMLSIG format including XML tags // OUTPUT: DigestValue in hex format int nRet = 0; byte[] abData = null; int nDataLen = 0; string strPublicKey = null; int nKeyLen = 0; byte[] abDigest = null; int nDigLen = 0; string result = ""; Console.WriteLine("SigBase64=" + strSig64); // Convert XML key form to our internal format strPublicKey = Rsa.FromXMLString(strXmlKey, false); if (strPublicKey.Length == 0) { Console.WriteLine("ERROR: Unable to read XML key string"); return result; } 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 = 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) { Console.WriteLine("ERROR: Key is the wrong length!"); return result; } // Decrypt the signature abData = Rsa.RawPublic(abData, strPublicKey); if (abData.Length == 0) { Console.WriteLine("ERROR: " + General.LastError()); return result; } 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) { Console.WriteLine("ERROR: Cannot extract digest"); return result; } // Display bytes as hex and base64 Console.WriteLine("digest=" + Cnv.ToHex(abDigest)); Console.WriteLine("base64=" + System.Convert.ToBase64String(abDigest)); Console.WriteLine(); // Return result return Cnv.ToHex(abDigest); } public static string XMLDSIG_VerifySigUsingCert(string strSig64, string strCert64) { // $GENERIC-FUNCTION$ // INPUT: strSig64 = <SignatureValue> content in base64 excluding tags // strCert64 = <X509Certificate> content in base64 excluding tags // OUTPUT: digestValue in hex format byte[] abData = null; string strPublicKey = null; int nCheck = 0; int nDataLen = 0; int nKeyLen = 0; byte[] abDigest = null; string strQuery = null; string strOutput = null; string strXmlKey = null; string result = ""; // Query the certificate for details strQuery = "subjectName"; strOutput = X509.QueryCert(strCert64, strQuery); if (strOutput.Length == 0) { Console.WriteLine("ERROR: Error reading certificate: " + General.LastError()); return result; // ERROR } 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) { Console.WriteLine("ERROR: Error reading certificate key"); return result; // ERROR } //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) { Console.WriteLine(strXmlKey); } else { Console.WriteLine("**Failed to create public key in XML"); } // 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 nCheck = Rsa.CheckKey(strPublicKey); Console.WriteLine("RSA_CheckKey returns " + nCheck + " (expecting 1)"); // Check the length nKeyLen = Rsa.KeyBytes(strPublicKey); Console.WriteLine("Key is " + nKeyLen + " bytes long"); if (nKeyLen != nDataLen) { Console.WriteLine("ERROR: Key is the wrong length!"); return result; } // Decrypt the signature abData = Rsa.RawPublic(abData, strPublicKey); 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) { Console.WriteLine("ERROR: Cannot extract digest"); return result; } // Display bytes as hex and base64 Console.WriteLine("digest=" + Cnv.ToHex(abDigest)); Console.WriteLine("base64=" + System.Convert.ToBase64String(abDigest)); // Return digest in hex return Cnv.ToHex(abDigest); } public static void TestReadFRMA() { string strCert64 = null; string strSig64 = null; string strDigestHex = null; //<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-----" + "\n" + "MIICTzCCAfmgAwIBAwIBZDANBgkqhkiG9w0BAQQFADCBrzELMAkGA1UEBhMCQ0wx" + "CzAJBgNVBAgTAkNTMQswCQYDVQQHEwJDczEnMCUGA1UEChMeU2VydmljaW8gZGUg" + "SW1wdWVzdG9zIEludGVybm9zMRkwFwYDVQQLExBPZmljaW5hIEludGVybmV0MScw" + "JQYDVQQDEx5TZXJ2aWNpbyBkZSBJbXB1ZXN0b3MgSW50ZXJub3MxGTAXBgkqhkiG" + "9w0BCQEWCnNpaUBzaWkuY2wwHhcNMDMwNDI5MjAxNDA1WhcNMDQwNDIzMjAxNDA1" + "WjCBrzELMAkGA1UEBhMCQ0wxCzAJBgNVBAgTAkNTMQswCQYDVQQHEwJDczEnMCUG" + "A1UEChMeU2VydmljaW8gZGUgSW1wdWVzdG9zIEludGVybm9zMRkwFwYDVQQLExBP" + "ZmljaW5hIEludGVybmV0MScwJQYDVQQDEx5TZXJ2aWNpbyBkZSBJbXB1ZXN0b3Mg" + "SW50ZXJub3MxGTAXBgkqhkiG9w0BCQEWCnNpaUBzaWkuY2wwXDANBgkqhkiG9w0B" + "AQEFAANLADBIAkEAyPvwDcshpVAApYVSLF3lKKc+DOFswDqx5ep95LKigRHjUvrv" + "jct9UeNJq9SxBdzU9nz54TEVBYyfAVQpG4xxUwIDAQABMA0GCSqGSIb3DQEBBAUA" + "A0EADvJX1C7hUFD2Eq9jNZpeJ/YBOZx1SBmAHSeXud6fTw98+AR4X3YDmzO9D4Kd" + "hEFi3NK4anpjiPOKbA8fBWyyBA==" + "-----END CERTIFICATE-----"; strDigestHex = XMLDSIG_VerifySigUsingCert(strSig64, strCert64); } public static void MakeFRMAdigest() { // This should give the same digest value we obtained above. string strData = null; string strDigest = null; // 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))); } public static void TestReadFRMT() { string strXmlKey = null; string strSig64 = null; // <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>"; XMLDSIG_VerifySigUsingRSAKeyValue(strSig64, strXmlKey); } public static void TestF60T33OuterXmlSigByCert() { // THIS DOES NOT WORK! Because the X509 Certificate provided does not correspond to the key used to make the signature. string strSig64 = null; string strCert64 = null; strCert64 = "MIIEgjCCA+ugAwIBAgIEAQAApzANBgkqhkiG9w0BAQUFADCBtTELMAkGA1UEBhMCQ0wxHTAbBgNVBAgUFFJlZ2lvbiBNZXRyb3BvbGl0YW5hMREwDwYDVQQHFAhTYW50aWFnbzEUMBIGA1UEChQLRS1DRVJUQ0hJTEUxIDAeBgNVBAsUF0F1dG9yaWRhZCBDZXJ0aWZpY2Fkb3JhMRcwFQYDVQQDFA5FLUNFUlRDSElMRSBD" + "QTEjMCEGCSqGSIb3DQEJARYUZW1haWxAZS1jZXJ0Y2hpbGUuY2wwHhcNMDMxMDAxMTg1ODE1WhcNMDQwOTMwMDAwMDAwWjCBuDELMAkGA1UEBhMCQ0wxFjAUBgNVBAgUDU1ldHJvcG9saXRhbmExETAPBgNVBAcUCFNhbnRpYWdvMScwJQYDVQQKFB5TZXJ2aWNpbyBkZSBJbXB1ZXN0b3MgSW50ZXJub3MxDzANBgNVBAsU" + "BlBpc28gNDEjMCEGA1UEAxQaV2lsaWJhbGRvIEdvbnphbGV6IENhYnJlcmExHzAdBgkqhkiG9w0BCQEWEHdnb256YWxlekBzaWkuY2wwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALxZlVh1xr9sKQIBDF/6Va+lsHQSG5AAmCWvtNTIOXN3E9EQCy7pOPHrDg6EusvoHyesZSKJbc0TnIFXZp78q7mbdHijzKqvMmyv" + "wbdP7KK8LQfwf84W4v9O8MJeUHlbJGlo5nFACrPAeTtONbHaReyzeMDv2EganNEDJc9c+UNfAgMBAAGjggGYMIIBlDAjBgNVHREEHDAaoBgGCCsGAQQBwQEBoAwWCjA3ODgwNDQyLTQwCQYDVR0TBAIwADA8BgNVHR8ENTAzMDGgL6AthitodHRwOi8vY3JsLmUtY2VydGNoaWxlLmNsL2UtY2VydGNoaWxlY2EuY3JsMCMG" + "A1UdEgQcMBqgGAYIKwYBBAHBAQKgDBYKOTY5MjgxODAtNTAfBgNVHSMEGDAWgBTgKP3S4GBPs0brGsz1CJEHcjodCDCB0AYDVR0gBIHIMIHFMIHCBggrBgEEAcNSBTCBtTAvBggrBgEFBQcCARYjaHR0cDovL3d3dy5lLWNlcnRjaGlsZS5jbC8yMDAwL0NQUy8wgYEGCCsGAQUFBwICMHUac0VsIHRpdHVsYXIgaGEgc2lk" + "byB2YWxpZG8gZW4gZm9ybWEgcHJlc2VuY2lhbCwgcXVlZGFuZG8gZWwgQ2VydGlmaWNhZG8gcGFyYSB1c28gdHJpYnV0YXJpbywgcGFnb3MsIGNvbWVyY2lvIHkgb3Ryb3MwCwYDVR0PBAQDAgTwMA0GCSqGSIb3DQEBBQUAA4GBABMfCyJF0mNXcov8iEWvjGFyyPTsXwvsYbbkOJ41wjaGOFMCInb4WY0ngM8BsDV22bGM" + "s8oLyX7rVy16bGA8Z7WDUtYhoOM7mqXw/Hrpqjh3JgAf8zqdzBdH/q6mAbdvq/yb04JHKWPC7fMFuBoeyVWAnhmuMZfReWQiMUEHGGIW"; strSig64 = "sBnr8Yq14vVAcrN/pKLD/BrqUFczKMW3y1t3JOrdsxhhq6IxvS13SgyMXbIN/T9ciRaFgNabs3pi732XhcpeiSmD1ktzbRctEbSIszYkFJY49k0eB+TVzq3eVaQr4INrymfuOnWj78BZcwKuXvDy4iAcx6/TBbAAkPFwMP9ql2s="; XMLDSIG_VerifySigUsingCert(strSig64, strCert64); } public static void TestF60T33OuterXmlSigByRSA() { // THIS WORKS... string strSig64 = null; string strXmlKey = null; strXmlKey = "<RSAKeyValue><Modulus>" + "tNEknkb1kHiD1OOAWlLKkcH/UP5UGa6V6MYso++JB+vYMg2OXFROAF7G8BNFFPQx" + "iuS/7y1azZljN2xq+bW3bAou1bW2ij7fxSXWTJYFZMAyndbLyGHM1e3nVmwpgEpx" + "BHhZzPvwLb55st1wceuKjs2Ontb13J33sUb7bbJMWh0=</Modulus>" + "<Exponent>AQAB</Exponent></RSAKeyValue>"; strSig64 = "sBnr8Yq14vVAcrN/pKLD/BrqUFczKMW3y1t3JOrdsxhhq6IxvS13SgyMXbIN/T9ciRaFgNabs3pi732XhcpeiSmD1ktzbRctEbSIszYkFJY49k0eB+TVzq3eVaQr4INrymfuOnWj78BZcwKuXvDy4iAcx6/TBbAAkPFwMP9ql2s="; XMLDSIG_VerifySigUsingRSAKeyValue(strSig64, strXmlKey); } public static void TestF60T33InnerXmlSigByRSA() { // THIS WORKS... string strSig64 = null; string strXmlKey = null; strXmlKey = "<RSAKeyValue><Modulus>" + "tNEknkb1kHiD1OOAWlLKkcH/UP5UGa6V6MYso++JB+vYMg2OXFROAF7G8BNFFPQx" + "iuS/7y1azZljN2xq+bW3bAou1bW2ij7fxSXWTJYFZMAyndbLyGHM1e3nVmwpgEpx" + "BHhZzPvwLb55st1wceuKjs2Ontb13J33sUb7bbJMWh0=</Modulus>" + "<Exponent>AQAB</Exponent></RSAKeyValue>"; strSig64 = "JG1Ig0pvSIH85kIKGRZUjkyX6CNaY08Y94j4UegTgDe8+wl61GzqjdR1rfOK9BGn93AMOo6aiAgolW0k/XklNVtM/ZzpNNS3d/fYVa1q509mAMSXbelxSM3bjoa7H6Wzd/mV1PpQ8zK5gw7mgMMP4IKxHyS92G81GEguSmzcQmA="; XMLDSIG_VerifySigUsingRSAKeyValue(strSig64, strXmlKey); } public static void TestF60T33FRMTSigByRSA() { string strSig64 = null; string strXmlKey = null; strXmlKey = "<RSAKeyValue><Modulus>" + "0a4O6Kbx8Qj3K4iWSP4w7KneZYeJ+g/prihYtIEolKt3cykSxl1zO8vSXu397QhTmsX7SBEudTUx++2zDXBhZw==</Modulus>" + "<Exponent>Aw==</Exponent></RSAKeyValue>"; strSig64 = "GbmDcS9e/jVC2LsLIe1iRV12Bf6lxsILtbQiCkh6mbjckFCJ7fj/kakFTS06Jo8iS4HXvJj3oYZuey53Krniew=="; XMLDSIG_VerifySigUsingRSAKeyValue(strSig64, strXmlKey); } public static void 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(); } } }