/*
' $Id: TestChileSign.cs $
' $Date: 2013-09-04 20:05 $
' $Author: dai $

' This module uses methods from the CryptoSys (tm) PKI Toolkit available from
' <www.cryptosys.net/pki/>.
' Add a reference to `diCrSysPKINet.dll` in your project.

' *************************** COPYRIGHT NOTICE ******************************
' This code was originally written by David Ireland and is copyright
' (C) 2013 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 **************************
*/

using System;
using System.Text;
using CryptoSysPKI;

namespace TestChileSign
{
    class TestChileSign
    {
        static void Main(string[] args)
        {
            string strDigestHex, strPriKeyFile, strSigValue64;
            StringBuilder sbPassword;

            // A quick check to show we have correct reference to the CryptoSys PKI library...
            Console.WriteLine("PKI Version={0}", General.Version());

            // OUR TEST INPUT DATA:
            // The digest value we made earlier...
            strDigestHex = "353CABFE369AAD9BEA21F5FA06CB367960FFB7D4";
            // We do not have the signing key used in the SII example. We use a test private key...
            strPriKeyFile = "AlicePrivRSASign.key";
            // CAUTION: do not hardcode password in production code...
            // NB we use a StringBuilder for security reasons
            sbPassword = new StringBuilder("password");

            Console.WriteLine("SHA-1 message digest of <SignedInfo> = {0}", strDigestHex);
            strSigValue64 = SignSignedInfo(strDigestHex, strPriKeyFile, sbPassword.ToString());
            Console.WriteLine("SignatureValue={0}", strSigValue64);

            Wipe.String(sbPassword);

        }

        /// <summary>
        /// Creates SignatureValue suitable for XML file
        /// </summary>
        /// <param name="strDigestHex">SHA-1 digest of canonicalized <SignedInfo> element in HEX format</param>
        /// <param name="strPriKeyFile">Signer's encrypted private key file</param>
        /// <param name="strPassword">Password for private key file</param>
        /// <returns>Signature value in base64 form</returns>
        static string SignSignedInfo(string strDigestHex, string strPriKeyFile, string strPassword)
        {
            StringBuilder sbPrivateKey;
            byte[] digest;
            byte[] block;
            int nkLen;
            string sigVal64;

            // Read in private key from key file
            sbPrivateKey = Rsa.ReadEncPrivateKey(strPriKeyFile, strPassword);
            if (sbPrivateKey.Length == 0)
            {
                Console.WriteLine("ERROR: reading private key file");
                return "";
            }
            // Get length of key in bytes (expecting 128)
            nkLen = Rsa.KeyBytes(sbPrivateKey);
            Console.WriteLine("  Key is {0} bytes long", nkLen);

            // Convert digest value from Hex form to Byte array
            // -- expecting exactly 20 bytes = 40 hex chars, padded on the left with '0's if necessary
            if (strDigestHex.Length != 40)
            {
                Console.WriteLine("ERROR: expecting exactly 40 hex chars in strDigestHex");
                return "";
            }
            digest = Cnv.FromHex(strDigestHex);
            Console.WriteLine("  Digest={0}", Cnv.ToHex(digest));

            // Encode digest value for signature
            block = Rsa.EncodeDigestForSignature(nkLen, digest, HashAlgorithm.Sha1);
            Console.WriteLine("  EM: {0}", Cnv.ToHex(block));

            // Sign using RSA private key
            block = Rsa.RawPrivate(block, sbPrivateKey.ToString());
            Console.WriteLine("  SG: {0}", Cnv.ToHex(block));

            // Convert the byte array to base64 encoding
            sigVal64 = Cnv.ToBase64(block);

            // Clean up private key data
            Wipe.String(sbPrivateKey);

            // Return base64-encoded signature value
            return sigVal64;
        }
    }
}