diff --git a/Lecture/Lecture.sln.GhostDoc.user.dic b/Lecture/Lecture.sln.GhostDoc.user.dic index 320f3457..fae487ca 100644 --- a/Lecture/Lecture.sln.GhostDoc.user.dic +++ b/Lecture/Lecture.sln.GhostDoc.user.dic @@ -1,3 +1,4 @@ +Crypto csharp Globalization Hermetization diff --git a/Lecture/P03.DataStreams/DataStreams.UnitTest/CryptographyHelpersUnitTest.cs b/Lecture/P03.DataStreams/DataStreams.UnitTest/CryptographyHelpersUnitTest.cs new file mode 100644 index 00000000..7bbb010b --- /dev/null +++ b/Lecture/P03.DataStreams/DataStreams.UnitTest/CryptographyHelpersUnitTest.cs @@ -0,0 +1,89 @@ +//____________________________________________________________________________ +// +// Copyright (C) 2018, Mariusz Postol LODZ POLAND. +// +// To be in touch join the community at GITTER: https://gitter.im/mpostol/TP +//____________________________________________________________________________ + +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Diagnostics; +using System.IO; +using System.Security.Cryptography; +using System.Xml; + +namespace TP.DataStreams.Cryptography +{ + [TestClass] + public class CryptographyHelpersUnitTest + { + [TestMethod] + public void CalculateSHA256Test() + { + const string _pasword = "Fe4ZFH2VgpOOwBdM9dkI"; + (string HexString, string Base64) = _pasword.CalculateSHA256(); + Assert.AreEqual("D9CBFBB0AD87D8CE0CC0D2FF1BCFF67C6933D2B4B4CC4C6FA60CE29F73322CD8", HexString); + Assert.AreEqual(256/4, HexString.Length); + Assert.AreEqual("2cv7sK2H2M4MwNL/G8/2fGkz0rS0zExvpgzin3MyLNg=", Base64); + Assert.AreEqual(44, Base64.Length); + } + [TestMethod] + public void CalculateSHA256LongTest() + { + const string _pasword = "UAXflAoVz8wcR1VkxUgTO8HAMBYK83yQvcHI9nqsQUiI4mx6jLlCAFGPrHj99XHi3uOoUfqe7wF7JkX2wBwwPADpn9f8s2Q0CfaA"; + (string HexString, string Base64) = _pasword.CalculateSHA256(); + Assert.AreEqual("B77B064339A0D98C722F54A7B055539BD63BAFC07EBD2B9342EA247EAA86FB18", HexString); + Assert.AreEqual(256 / 4, HexString.Length); + Assert.AreEqual("t3sGQzmg2YxyL1SnsFVTm9Y7r8B+vSuTQuokfqqG+xg=", Base64); + Assert.AreEqual(44, Base64.Length); + } + [TestMethod] + public void XmlSignatureTestMethod1() + { + (RSAParameters parameters, string publicKey, string privatePublicKeys) = CreateRSACryptoServiceKeys(); + Assert.IsNotNull(parameters); + Assert.AreNotEqual(publicKey, privatePublicKeys); + Debug.WriteLine(publicKey); + Debug.WriteLine(string.Empty); + Debug.WriteLine(privatePublicKeys); + } + [TestMethod] + [DeploymentItem("Instrumentation")] + public void XmlSignatureTest() + { + const string _xmlFile = @"catalog.example.xml"; + Assert.IsTrue(File.Exists(_xmlFile)); + const string _publiKey = @"PubliKey.xml"; + Assert.IsTrue(File.Exists(_publiKey)); + const string _publiPrivateKeys = @"PubliPrivateKeys.xml"; + Assert.IsTrue(File.Exists(_publiPrivateKeys)); + XmlDocument _documentToSign = new XmlDocument(); + _documentToSign.Load(_xmlFile); + const string _signedFileName = "SignedXmlFile.xml"; + string _rsaKeys = null; + if (File.Exists(_signedFileName)) + File.Delete(_signedFileName); + using (StreamReader _reader = new StreamReader(_publiPrivateKeys, System.Text.Encoding.UTF8)) + _rsaKeys = _reader.ReadToEnd(); + CryptographyHelpers.SignSaveXml(_documentToSign, _rsaKeys, _signedFileName); + Assert.IsTrue(File.Exists(_signedFileName)); + XmlDocument _signedXmlDocument1 = CryptographyHelpers.LoadVerifyXml(_signedFileName); + Assert.IsNotNull(_signedXmlDocument1); + using (StreamReader _reader = new StreamReader(_publiKey, System.Text.Encoding.UTF8)) + _rsaKeys = _reader.ReadToEnd(); + XmlDocument _signedXmlDocument2 = CryptographyHelpers.LoadVerifyXml(_rsaKeys, _signedFileName); + Assert.IsNotNull(_signedXmlDocument2); + Assert.AreEqual(_signedXmlDocument1.ToString(), _signedXmlDocument2.ToString()); + } + private (RSAParameters parameters, string publicKey, string privatePublicKeys) CreateRSACryptoServiceKeys() + { + using (RSACryptoServiceProvider _rsa = new RSACryptoServiceProvider(2048)) + { + RSAParameters _parameters = _rsa.ExportParameters(true); + string _public = _rsa.ToXmlString(false); + string _both = _rsa.ToXmlString(true); + return (_parameters, _public, _both); + } + } + } +} + diff --git a/Lecture/P03.DataStreams/DataStreams.UnitTest/DataStreams.UnitTest.csproj b/Lecture/P03.DataStreams/DataStreams.UnitTest/DataStreams.UnitTest.csproj index 8514464c..60349934 100644 --- a/Lecture/P03.DataStreams/DataStreams.UnitTest/DataStreams.UnitTest.csproj +++ b/Lecture/P03.DataStreams/DataStreams.UnitTest/DataStreams.UnitTest.csproj @@ -62,6 +62,7 @@ + @@ -78,13 +79,25 @@ - + + Always + Always + + + Always + Designer + + + Always + Designer + + diff --git a/Lecture/P03.DataStreams/DataStreams.UnitTest/Instrumentation/PubliKey.xml b/Lecture/P03.DataStreams/DataStreams.UnitTest/Instrumentation/PubliKey.xml new file mode 100644 index 00000000..0aa2021b --- /dev/null +++ b/Lecture/P03.DataStreams/DataStreams.UnitTest/Instrumentation/PubliKey.xml @@ -0,0 +1,5 @@ + + + 2oFiov7xnJGWf++WBHOdkzp1IHzNZRXhFL0MDFxBIJQvlm3p80WwhoxUQVawJTGRbdGMutOHHOTj+uxFAFlmKrvcaltfRV/rq0Z43LeIbfeX8uwsr10lnxqLhONlP+kY9+RiAartXP3nTG88gFah9j7WrSmlrJWvSCD0lZvUxcuFioXXZw8UQ43046SWhXMYABkZ+1RYKsSjfz80/TITuR0kkY3wIwHiIWhZUjWwNxEh0CLmM06oFLjSKgZwe4UyhCRlg3iXNK3CeMC+ToSyo+lehGnWD226uNECvB3SWC4YN7r96u0xrQcf0//x6nzSdEArohFVyGgB3yb6rlFLjw== + AQAB + \ No newline at end of file diff --git a/Lecture/P03.DataStreams/DataStreams.UnitTest/Instrumentation/PubliPrivateKeys.xml b/Lecture/P03.DataStreams/DataStreams.UnitTest/Instrumentation/PubliPrivateKeys.xml new file mode 100644 index 00000000..cf36930d --- /dev/null +++ b/Lecture/P03.DataStreams/DataStreams.UnitTest/Instrumentation/PubliPrivateKeys.xml @@ -0,0 +1,12 @@ + + + 2oFiov7xnJGWf++WBHOdkzp1IHzNZRXhFL0MDFxBIJQvlm3p80WwhoxUQVawJTGRbdGMutOHHOTj+uxFAFlmKrvcaltfRV/rq0Z43LeIbfeX8uwsr10lnxqLhONlP+kY9+RiAartXP3nTG88gFah9j7WrSmlrJWvSCD0lZvUxcuFioXXZw8UQ43046SWhXMYABkZ+1RYKsSjfz80/TITuR0kkY3wIwHiIWhZUjWwNxEh0CLmM06oFLjSKgZwe4UyhCRlg3iXNK3CeMC+ToSyo+lehGnWD226uNECvB3SWC4YN7r96u0xrQcf0//x6nzSdEArohFVyGgB3yb6rlFLjw== + AQAB +

9A0KwiudcPWDrwVIq+2ANkuu7IILGf9D94U+qViZAKclqxc9+7UcCeP1a0LCmTiJCVLvNam4ISvU3I7rBnE46cFvJ7c+9SIQZTfb9HOFB78Q5+ulx9k9lv8VKypfuBynoV15f3OHkr2FddSsyKf4EuF20UVWsV8YSJ+iJ5gCc8M=

+ 5TQnMXCb2DjgY1sGfQgaOtVOakjemhkGUeKNJ+4ptcTUHp/hZWPtZw53kFdje1fZprDdMqKIxM2XQI+NDm2WIDnBOsXQK+K1LAh+4XXEBS+0HcPqqMW8itttOXLeoiNDXWwYWQ5/6UOLUC1ZGyjynE89FQKpyp2i6pHWhocuCEU= + xoXhbYfLH7snrnSu4+RjukcgeRVj8Hbck/mYumrus0BEfQOAEUQHFeiQl/sLj1YU6zfCjLWNqbYdBnlfp7LsaAJI6FbA6OkXyy6ARz69RUrgdrgS+Bm4Zx8C2kUy7fKpTbNbBRk2fGCcsvgYwXUZcEplu+AaoFhJybHJV0npHL8= + LH4tRYmolxajaGYZIlhaTyVtLXCr1ZoaAfdKk3/GFQT6cF9076uwQBss1pZAN4dcNuGKbvPiPOH0BJJZPX3EcMkFW5VezcYaiUu05atou+EAw+5uNQj9iq8Byu8jjLHvt8juCQuphOyZtJy4+W6/edxf7R4xO6XSJFrfHApNw0k= + 0op7bysIJnOESr0FO8JxVh85wK0dX4vC89prAzUPc2YBsrf4aW/tSewcHDtGvx0fuUZEiJcyzunho+cuuC3SzMZK2CXTJWIvR/qTuD5bjzWm3CNKP+AdvLTaCQ78M/fx7D96bhPECsy2rkwh3iBCNs0YytrGkmeij9V6Pe0ZYRk= + QkBexuskGQPvrQTY6KqhiYV9BAezQ0YaA+66G3lRae5ka2kSOWfU+UbNOS5upCheXvzdfbwrSHCCS4+d8Fgq6SQi1cC0p1VJIJpyhQHFBQrAcLB5cAZ/JLmoufc0uOcVYfxGVxkbdUmq+vrzTjp2SzKMZt6s1CJiji0n28DvB7V5XpZoCBVAyT705jtdx/K5zgYd7a036D5e2KNtBWDI2l2w63AAQNaqgsNGjEt3N1fHO1yyOf9q7loYvtNAJcj5i2TpEeWiJy5w1hfYGfG28bB+mrL71dfG7wjJWrUJNdoKeONS63ZS2jwMyeTWp5wuwwlh8cgQMXhJBlJF9lPNeQ== +
+ diff --git a/Lecture/P03.DataStreams/DataStreams.UnitTest/SerializationUnitTest.cs b/Lecture/P03.DataStreams/DataStreams.UnitTest/SerializationUnitTest.cs index ce6a8ce0..2ae6e7ac 100644 --- a/Lecture/P03.DataStreams/DataStreams.UnitTest/SerializationUnitTest.cs +++ b/Lecture/P03.DataStreams/DataStreams.UnitTest/SerializationUnitTest.cs @@ -42,7 +42,7 @@ public void ReadWRiteTest() Catalog _catalog2Write = new Catalog(); _catalog2Write.AddTestingData(); Assert.IsNotNull(_catalog2Write.CD); - string _fileName = @"Instrumentation\catalog.xml"; + string _fileName = @"catalog.xml"; XmlFile.WriteXmlFile(_catalog2Write, _fileName, FileMode.Create); Catalog _recoveredCatalog = XmlFile.ReadXmlFile(_fileName); Assert.IsNotNull(_recoveredCatalog); diff --git a/Lecture/P03.DataStreams/DataStreams/Cryptography/CryptographyHelpers.cs b/Lecture/P03.DataStreams/DataStreams/Cryptography/CryptographyHelpers.cs new file mode 100644 index 00000000..7447146e --- /dev/null +++ b/Lecture/P03.DataStreams/DataStreams/Cryptography/CryptographyHelpers.cs @@ -0,0 +1,164 @@ +//____________________________________________________________________________ +// +// Copyright (C) 2018, Mariusz Postol LODZ POLAND. +// +// To be in touch join the community at GITTER: https://gitter.im/mpostol/TP +//____________________________________________________________________________ + +using System; +using System.IO; +using System.Security.Cryptography; +using System.Security.Cryptography.Xml; +using System.Text; +using System.Xml; + +namespace TP.DataStreams.Cryptography +{ + + public static class CryptographyHelpers + { + public static (string Hex, string Base64) CalculateSHA256 (this string inputStream) + { + byte[] _inputStreamBytes = Encoding.UTF8.GetBytes(inputStream); + using (SHA256 mySHA256 = SHA256Managed.Create()) + { + byte[] hashValue = mySHA256.ComputeHash(_inputStreamBytes); + return (hashValue.ToHexString(), Convert.ToBase64String(hashValue, Base64FormattingOptions.InsertLineBreaks)); + } + } + public static void EncryptData(string inFileName, string outFileName, byte[] dESKey, byte[] dESIV, IProgress progress) + { + //Create the file streams to handle the input and output files. + using (FileStream _inFileStream = new FileStream(inFileName, FileMode.Open, FileAccess.Read)) + { + using (FileStream _outFileStream = new FileStream(outFileName, FileMode.OpenOrCreate, FileAccess.Write)) + { + _outFileStream.SetLength(0); + //Create variables to help with read and write. + byte[] _buffer = new byte[100]; //This is intermediate storage for the encryption. + long _bytesWritten = 0; //This is the total number of bytes written. + long _inFileStreamLength = _inFileStream.Length; //This is the total length of the input file. + int _length; //This is the number of bytes to be written at a time. + TripleDESCryptoServiceProvider _tripleProvider = new TripleDESCryptoServiceProvider(); + using (CryptoStream _outCryptoStream = new CryptoStream(_outFileStream, _tripleProvider.CreateEncryptor(dESKey, dESIV), CryptoStreamMode.Write)) + { + //Read from the input file, then encrypt and write to the output file. + while (_bytesWritten < _inFileStreamLength) + { + _length = _inFileStream.Read(_buffer, 0, 100); + _outCryptoStream.Write(_buffer, 0, _length); + _bytesWritten = _bytesWritten + _length; + progress.Report(_bytesWritten); + } + } + } + } + } + /// + /// Sign and save an XML document. + /// + /// Document to be signed + /// The keys ro be used by the RSA algorithm implementation. + /// + /// This document cannot be verified unless the verifying code has the public key with which it was signed. + /// + public static void SignSaveXml(this XmlDocument document, string rsaKeys, string fileName) + { + #region Check arguments + if (document == null) + throw new ArgumentException($"The {nameof(document)} parameter cannot be null"); + if (string.IsNullOrEmpty(rsaKeys)) + throw new ArgumentException($"The {nameof(rsaKeys)} parameter cannot be null"); + if (string.IsNullOrEmpty(fileName)) + throw new ArgumentException($"The {nameof(fileName)} parameter cannot be null"); + #endregion + using (RSACryptoServiceProvider _rsaProvider = new RSACryptoServiceProvider()) + { + _rsaProvider.FromXmlString(rsaKeys); + KeyInfo _keyInfo = new KeyInfo();// Add an RSAKeyValue KeyInfo (optional; helps recipient find key to validate). + _keyInfo.AddClause(new RSAKeyValue(_rsaProvider)); + SignedXml _signedXml = new SignedXml(document) + { + SigningKey = _rsaProvider, // Add the key to the SignedXml document. + KeyInfo = _keyInfo + }; + Reference _reference = new Reference // Create a reference to be signed. + { + Uri = "" //An entire XML document is to be signed using an enveloped signature. + }; + XmlDsigEnvelopedSignatureTransform _envelope = new XmlDsigEnvelopedSignatureTransform(); // Add an enveloped transformation to the reference. + _reference.AddTransform(_envelope); + _signedXml.AddReference(_reference); // Add the reference to the SignedXml object. + _signedXml.ComputeSignature(); // Compute the signature. + XmlElement _xmlDigitalSignature = _signedXml.GetXml(); // Get the XML representation of the signature and save it to an XmlElement object. + document.DocumentElement.AppendChild(document.ImportNode(_xmlDigitalSignature, true));// Append the element to the XML document. + } + document.Save(fileName); + } + /// + /// Load and verify the signature of an XML file against an asymmetric RSA algorithm and return the document. + /// + /// The RSA keys as the xml document. + /// Name of the file. + /// An instance of the capturing the xml file. + /// + /// rsaKeys + /// or + /// fileName + /// + /// + /// There must be only one signature. + public static XmlDocument LoadVerifyXml(string rsaKeys, string fileName) + { + #region Check arguments + if (string.IsNullOrEmpty(rsaKeys)) + throw new ArgumentException($"The {nameof(rsaKeys)} parameter cannot be null"); + if (string.IsNullOrEmpty(fileName)) + throw new ArgumentException($"The {nameof(fileName)} parameter cannot be null"); + #endregion + (XmlDocument _document, SignedXml _signedXml) = LoadsIGNEDXmlFile(fileName); + using (RSACryptoServiceProvider _provider = new RSACryptoServiceProvider()) + { + _provider.FromXmlString(rsaKeys); + if (!_signedXml.CheckSignature(_provider))// Check the signature and return the result. + throw new CryptographicException($"Wrong signature of the document."); + } + return _document; + } + public static XmlDocument LoadVerifyXml(string fileName) + { + #region Check arguments + if (string.IsNullOrEmpty(fileName)) + throw new ArgumentException($"The {nameof(fileName)} parameter cannot be null"); + #endregion + (XmlDocument _document, SignedXml _signedXml) = LoadsIGNEDXmlFile(fileName); + if (!_signedXml.CheckSignature())// Check the signature and return the result. + throw new System.Security.Cryptography.CryptographicException($"Wrong signature of the document."); + return _document; + } + private static string ToHexString(this byte[] bytes) + { + char[] c = new char[bytes.Length * 2]; + int b; + for (int i = 0; i < bytes.Length; i++) + { + b = bytes[i] >> 4; + c[i * 2] = (char)(55 + b + (((b - 10) >> 31) & -7)); + b = bytes[i] & 0xF; + c[i * 2 + 1] = (char)(55 + b + (((b - 10) >> 31) & -7)); + } + return new string(c); + } + private static (XmlDocument document, SignedXml signedXml) LoadsIGNEDXmlFile(string fileName) + { + XmlDocument _document = new XmlDocument(); + _document.Load(fileName); + SignedXml _signedXml = new SignedXml(_document); + XmlNodeList _nodeList = _document.GetElementsByTagName("Signature");// Find the "Signature" node and create a new XmlNodeList object. + if (_nodeList.Count != 1) // There must be only one signature. Return false if 0 or more than one signatures was found. + throw new CryptographicException($"Expected exactly one signature but the file contaons {_nodeList.Count}."); + _signedXml.LoadXml((XmlElement)_nodeList[0]);// Load the first node. + return (_document, _signedXml); + } + } +} \ No newline at end of file diff --git a/Lecture/P03.DataStreams/DataStreams/DataStreams.csproj b/Lecture/P03.DataStreams/DataStreams/DataStreams.csproj index d1c9c93d..7b3458e7 100644 --- a/Lecture/P03.DataStreams/DataStreams/DataStreams.csproj +++ b/Lecture/P03.DataStreams/DataStreams/DataStreams.csproj @@ -64,12 +64,31 @@ + + + + + + ..\..\packages\System.Security.AccessControl.4.5.0\lib\net461\System.Security.AccessControl.dll + + + ..\..\packages\System.Security.Cryptography.Xml.4.5.0\lib\net461\System.Security.Cryptography.Xml.dll + + + ..\..\packages\System.Security.Permissions.4.5.0\lib\net461\System.Security.Permissions.dll + + + ..\..\packages\System.Security.Principal.Windows.4.5.0\lib\net461\System.Security.Principal.Windows.dll + + + + @@ -82,6 +101,7 @@ + @@ -96,9 +116,7 @@ true - - - +