using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using System.Diagnostics;
using System.Reflection;
using System.Security.Cryptography;
using Aitex.Core.RT.Log;
namespace Aitex.Core.Util
{
///
/// This class provides a set of static APIs that add digital signature to Xml files and verify if Xml files
/// or Xml memory streams have valid signature.
///
public static class FileSigner
{
/* This API didn't pass unit test. Will be uncommented in the future.
///
/// Checks to see if the memory stream is a valid xml stream with valid signature.
///
///
/// False if the stream is empty or null, or embedded signature doesn't match, or there is no the signature.
public static bool IsValid(Stream stream)
{
bool retVal = false;
try
{
Logger.LogTrace(MethodBase.GetCurrentMethod(), Logger.TraceEntry);
XmlDocument doc = new XmlDocument();
doc.Load(stream);
Debug.Assert(doc != null && doc.DocumentElement != null);
// Get root element
XmlElement elemRoot = doc.DocumentElement;
// Get signature element
XmlElement elemSignature = elemRoot["Signature"];
if (elemSignature == null)
{
return false; // The stream was not signed.
}
// Remove signature element from document
elemRoot.RemoveChild(elemSignature);
// Calculate hash code from file (after removing Signature element)
UnicodeEncoding ue = new UnicodeEncoding();
SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider();
char[] innerXMLArray = elemRoot.InnerXml.ToCharArray();
byte[] bytes = ue.GetBytes(innerXMLArray);
// byte[] signature = sha1.ComputeHash(ue.GetBytes(elemRoot.InnerXml));
byte[] signature = sha1.ComputeHash(bytes);
string strSignature = Convert.ToBase64String(signature);
// Add signature back to document
elemRoot.AppendChild(elemSignature);
// Compare embedded signature to calculated value
if (elemSignature.InnerText == strSignature)
{
retVal = true;
}
}
catch (System.Exception ex)
{
retVal = false;
Logger.LogError(MethodBase.GetCurrentMethod(), ex);
throw;
}
finally
{
Logger.LogTrace(MethodBase.GetCurrentMethod(), Logger.TraceExit);
}
return retVal;
}
*/
///
/// Checks to see if the file is a valid xml file with valid signature.
///
///
/// False if the embedded signature doesn't match, or there is no the signature.
public static bool IsValid(string fileName)
{
bool retVal = false;
try
{
XmlDocument doc = new XmlDocument();
doc.Load(fileName);
Debug.Assert(doc != null && doc.DocumentElement != null);
// Get root element
XmlElement elemRoot = doc.DocumentElement;
// Get signature element
XmlElement elemSignature = elemRoot["Signature"];
if (elemSignature == null)
{
return false; // The file was not signed.
}
// Remove signature element from document
elemRoot.RemoveChild(elemSignature);
// Calculate hash code from file (after removing Signature element)
UnicodeEncoding ue = new UnicodeEncoding();
SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider();
byte[] signature = sha1.ComputeHash(ue.GetBytes(elemRoot.InnerXml));
string strSignature = Convert.ToBase64String(signature);
// Add signature back to document
elemRoot.AppendChild(elemSignature);
// Compare embedded signature to calculated value
if (elemSignature.InnerText == strSignature)
{
retVal = true;
}
}
catch (System.Exception e)
{
retVal = false;
LOG.Write(e);
throw;
}
finally
{
}
return retVal;
}
/* This API didn't pass unit test. Will be uncommented in the future.
///
/// Add signature to the end of the xml memory stream
///
///
///
public static Stream Sign(Stream stream)
{
try
{
Logger.LogTrace(MethodBase.GetCurrentMethod(), Logger.TraceEntry);
XmlDocument doc = new XmlDocument();
if (stream == null || stream.Length == 0)
{
throw new InvalidOperationException("Empty stream, no XML file to Sign");
}
else
{
doc.Load(stream);
XmlElement elemRoot = doc.DocumentElement;
// Remove any existing signature
XmlElement elemSignature = elemRoot["Signature"];
if (elemSignature != null)
{
elemRoot.RemoveChild(elemSignature);
}
// Calculate hash code (after removing Signature element)
UnicodeEncoding ue = new UnicodeEncoding();
SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider();
char[] innerXMLArray = elemRoot.InnerXml.ToCharArray();
byte[] bytes = ue.GetBytes(innerXMLArray);
// byte[] nSignature = sha1.ComputeHash(ue.GetBytes(elemRoot.InnerXml));
byte[] nSignature = sha1.ComputeHash(bytes);
string strSignature = Convert.ToBase64String(nSignature);
// Add signature to XML document
elemSignature = doc.CreateElement("Signature");
elemSignature.InnerText = strSignature;
elemRoot.AppendChild(elemSignature);
// memStream.Flush();
stream.Seek(0, SeekOrigin.Begin);
doc.Save(stream);
return stream;
}
}
catch (Exception ex)
{
Logger.LogError(MethodBase.GetCurrentMethod(), ex);
throw;
}
finally
{
Logger.LogTrace(MethodBase.GetCurrentMethod(), Logger.TraceExit);
}
}
*/
///
/// Add signature to the end of the xml file.
///
///
public static void Sign(string fileName)
{
try
{
XmlDocument doc = new XmlDocument();
bool writeable = true;
if (File.Exists(fileName) && (File.GetAttributes(fileName) & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
{
writeable = false;
File.SetAttributes(fileName, FileAttributes.Normal);
}
doc.Load(fileName);
XmlElement elemRoot = doc.DocumentElement;
// Remove any existing signature
XmlElement elemSignature = elemRoot["Signature"];
if (elemSignature != null)
{
elemRoot.RemoveChild(elemSignature);
}
// Calculate hash code (after removing Signature element)
UnicodeEncoding ue = new UnicodeEncoding();
SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider();
byte[] nSignature = sha1.ComputeHash(ue.GetBytes(elemRoot.InnerXml));
string strSignature = Convert.ToBase64String(nSignature);
// Add signature to XML document
elemSignature = doc.CreateElement("Signature");
elemSignature.InnerText = strSignature;
elemRoot.AppendChild(elemSignature);
doc.Save(fileName);
if (!writeable)
{
File.SetAttributes(fileName, FileAttributes.ReadOnly);
}
}
catch (Exception ex)
{
LOG.Write(ex);
throw;
}
finally
{
}
}
}
}