using System;
using System.Text;
using System.Diagnostics;
using CryptoSysPKI;

/*
$Id: Xmldsig2.cs $
$Date: 2017/03/20 22:01 $

Copyright (C) 2017 DI Management Services Pty Ltd. All rights reserved.
http://www.di-mgt.com.au/contact/

References: 
  http://www.di-mgt.com.au/xmldsig2.html Signing an XML document using XMLDSIG (Part 2)
  http://www.cryptosys.net/pki/output-for-xml-docs.html Creating output for secure XML documents

*/

namespace Xmldsig2
{
    class Xmldsig2
    {
        static void Main(string[] args)
        {
            string digval, sigval, keyval;
            string pfxfile, keyfile, certfile;
            string pubkey;
            StringBuilder sbPassword, sbPrikey;
            int keyhash1, keyhash2;
            int r;

            Console.WriteLine("PKI Version={0}", General.Version());

            // All data files assumed to be in current working directory

            // Store password in StringBuilder so we can erase it later
            sbPassword = new StringBuilder("password");

            // 0. Extract PKCS#8 private key file and X.509 certificate from PFX file
            pfxfile = "alice.pfx";
            keyfile = "alice.key";
            r = Rsa.GetPrivateKeyFromPFX(keyfile, pfxfile);
            Debug.Assert(r > 0, "PFX file is invalid or missing");
            Console.WriteLine("Extracted keyfile '{0}' from PFX", keyfile);
            certfile = "alice.cer";
            r = X509.GetCertFromPFX(certfile, pfxfile, sbPassword.ToString());
            Debug.Assert(r > 0, "PFX file or its password is invalid");
            Console.WriteLine("Extracted certfile '{0}' from PFX", certfile);

            Console.WriteLine("Show we can read the two files we just extracted...");
            pubkey = Rsa.ReadPublicKey(certfile).ToString();
            keyhash1 = Rsa.KeyHashCode(pubkey);
            Console.WriteLine("Public key is  {0} bits long with key hashcode {1,8:X}", Rsa.KeyBits(pubkey), keyhash1);
            sbPrikey = Rsa.ReadPrivateKey(keyfile, sbPassword.ToString());
            keyhash2 = Rsa.KeyHashCode(sbPrikey.ToString());
            Console.WriteLine("Private key is {0} bits long with key hashcode {1,8:X}", Rsa.KeyBits(sbPrikey.ToString()), keyhash2);


            // 1. Compute SHA-1 digest value of canonicalized XML
            // Ref: http://www.di-mgt.com.au/xmldsig2.html#c14nit
            Console.WriteLine("\nCompute digest value of c14n'd document:");
            digval = Cnv.ToBase64(Hash.BytesFromFile("enveloped-c14n.xml", HashAlgorithm.Sha1));
            Console.WriteLine("DigestValue: " + digval);


            // 2. Compute signature value of canonicalized SignedInfo
            Console.WriteLine("\nCompute signature value from c14n'd SignedInfo:");
            sigval = Sig.SignFile("enveloped-signedinfo.xml", keyfile, sbPassword.ToString(), SigAlgorithm.Rsa_Sha1);
            Console.WriteLine(sigval);


            // 3. Extract RSAKeyValue from X.509 certificate via internal key string
            Console.WriteLine("\nExtract RSAKeyValue from X.509 certificate:");
            pubkey = Rsa.ReadPublicKey(certfile).ToString();
            Debug.Assert(pubkey.Length > 0);
            keyval = Rsa.ToXMLString(pubkey, 0);
            Console.WriteLine(keyval);


            // 4. Clean up sensitive data
            Wipe.String(sbPassword);
            Wipe.String(sbPrikey);

        }
    }
}