/*
' $Id: MakeDigestValue.cs $
' $Date: 2013-09-04 14:34 $
' $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 MakeDigestValue
{
    class MakeDigestValue
    {
        static void Main(string[] args)
        {
            Test_DigestSignedInfo();
        }

        static void Test_DigestSignedInfo()
        {
            string strComputed, strCorrect;
            Console.WriteLine("\n" + "F60T33 Outer XML-Dsig:");
            strCorrect = "98B466FFE6A5E73B85962BC7300841C5F1693D3A";
            strComputed = MakeDigestValueOfSignedInfo("4OTWXyRl5fw3htjTyZXQtYEsC3E=", "SetDoc", true);
            Console.WriteLine("COMPUTED={0}", strComputed);
            Console.WriteLine("CORRECT= {0}", strCorrect);

            Console.WriteLine("\n" + "F60T33 Inner XML-Dsig:");
            strCorrect = "353CABFE369AAD9BEA21F5FA06CB367960FFB7D4";
            strComputed = MakeDigestValueOfSignedInfo("hlmQtu/AyjUjTDhM3852wvRCr8w=", "F60T33", false);
            Console.WriteLine("COMPUTED={0}", strComputed);
            Console.WriteLine("CORRECT= {0}", strCorrect);

        }

/*
    '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
*/


        /// <summary>
        /// Create digest value of SignedInfo
        /// </summary>
        /// <param name="strDigestValue64">DigestValue of data in base64 format</param>
        /// <param name="strReference">Reference as in &lt;Reference URI="#..."&gt;</param>
        /// <param name="fIncludeXMLSchema">Flag to include XMLSchema-instance attribute</param>
        /// <param name="ShowDebug">[Optional] Show debugging output</param>
        /// <returns>SHA-1 digest of canonicalized &lt;SignedInfo&gt; element in HEX format</returns>
        static string MakeDigestValueOfSignedInfo(string strDigestValue64, string strReference,
            bool fIncludeXMLSchema, bool ShowDebug)
        {
            string signedInfoCanonic, digestHex, firstLine;

            // Create a hard-coded version of the canonicalized SignedInfo
            // Note that "\n" is just a single newline character (ASCII 10)
            if (fIncludeXMLSchema) {
                firstLine = @"<SignedInfo xmlns=""http://www.w3.org/2000/09/xmldsig#"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"">";
            } else {
                firstLine = @"<SignedInfo xmlns=""http://www.w3.org/2000/09/xmldsig#"">";
            }
            signedInfoCanonic = firstLine + "\n" +
                @"<CanonicalizationMethod Algorithm=""http://www.w3.org/TR/2001/REC-xml-c14n-20010315""></CanonicalizationMethod>" + "\n" +
                @"<SignatureMethod Algorithm=""http://www.w3.org/2000/09/xmldsig#rsa-sha1""></SignatureMethod>" + "\n" +
                @"<Reference URI=""#" + strReference + @""">" + "\n" +
                @"<Transforms>" + "\n" +
                @"<Transform Algorithm=""http://www.w3.org/TR/2001/REC-xml-c14n-20010315""></Transform>" + "\n" +
                @"</Transforms>" + "\n" +
                @"<DigestMethod Algorithm=""http://www.w3.org/2000/09/xmldsig#sha1""></DigestMethod>" + "\n" +
                @"<DigestValue>" + strDigestValue64 + "</DigestValue>" + "\n" +
                @"</Reference>" + "\n" +
                @"</SignedInfo>";
            if (ShowDebug)
            {
                int cols = 0;
                for (int i = 0; i < signedInfoCanonic.Length; i++)
                {
                    char c = signedInfoCanonic[i];
                    
                    byte b = (byte)c;
                    if (' ' <= b && b <= '~')
                        Console.Write(c);
                    else
                        Console.Write('.');
                    cols++;
                    if (cols >= 79)
                    {
                        Console.Write('\n');
                        cols = 0;
                    }
                }
                Console.Write('\n');
           }
            // Compute the digest in hex form
            digestHex = Hash.HexFromString(signedInfoCanonic, HashAlgorithm.Sha1);

            return digestHex;
        }
        // Overload...
        static string MakeDigestValueOfSignedInfo(string strDigestValue64, string strReference,
            bool fIncludeXMLSchema)
        {
            return MakeDigestValueOfSignedInfo(strDigestValue64, strReference, fIncludeXMLSchema, false);
        }
    }
}