Skip to content

Commit

Permalink
3. Data Streams : Cryptography Basics #118
Browse files Browse the repository at this point in the history
- [x] review existing code
- [x] add a placeholder to the project
- [x] add code example  - consider merging with type compatibility
- [x] add unit tests
- UT 👍
  • Loading branch information
mpostol committed Aug 15, 2018
1 parent a98423f commit 925b5b3
Show file tree
Hide file tree
Showing 9 changed files with 314 additions and 5 deletions.
1 change: 1 addition & 0 deletions Lecture/Lecture.sln.GhostDoc.user.dic
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
Crypto
csharp
Globalization
Hermetization
Expand Down
Original file line number Diff line number Diff line change
@@ -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<string>("D9CBFBB0AD87D8CE0CC0D2FF1BCFF67C6933D2B4B4CC4C6FA60CE29F73322CD8", HexString);
Assert.AreEqual<int>(256/4, HexString.Length);
Assert.AreEqual<string>("2cv7sK2H2M4MwNL/G8/2fGkz0rS0zExvpgzin3MyLNg=", Base64);
Assert.AreEqual<int>(44, Base64.Length);
}
[TestMethod]
public void CalculateSHA256LongTest()
{
const string _pasword = "UAXflAoVz8wcR1VkxUgTO8HAMBYK83yQvcHI9nqsQUiI4mx6jLlCAFGPrHj99XHi3uOoUfqe7wF7JkX2wBwwPADpn9f8s2Q0CfaA";
(string HexString, string Base64) = _pasword.CalculateSHA256();
Assert.AreEqual<string>("B77B064339A0D98C722F54A7B055539BD63BAFC07EBD2B9342EA247EAA86FB18", HexString);
Assert.AreEqual<int>(256 / 4, HexString.Length);
Assert.AreEqual<string>("t3sGQzmg2YxyL1SnsFVTm9Y7r8B+vSuTQuokfqqG+xg=", Base64);
Assert.AreEqual<int>(44, Base64.Length);
}
[TestMethod]
public void XmlSignatureTestMethod1()
{
(RSAParameters parameters, string publicKey, string privatePublicKeys) = CreateRSACryptoServiceKeys();
Assert.IsNotNull(parameters);
Assert.AreNotEqual<string>(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<string>(_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);
}
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="FileStreamUnitTest.cs" />
<Compile Include="ReflectionUnitTest.cs" />
<Compile Include="CryptographyHelpersUnitTest.cs" />
</ItemGroup>
<ItemGroup>
<None Include="Instrumentation\Catalog.xsd">
Expand All @@ -78,13 +79,25 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="Instrumentation\catalog.example.xml" />
<None Include="Instrumentation\catalog.example.xml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<None Include="Instrumentation\Catalog.xslt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<Content Include="Instrumentation\PubliKey.xml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<SubType>Designer</SubType>
</Content>
<Content Include="Instrumentation\PubliPrivateKeys.xml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<SubType>Designer</SubType>
</Content>
</ItemGroup>
<Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8" ?>
<RSAKeyValue>
<Modulus>2oFiov7xnJGWf++WBHOdkzp1IHzNZRXhFL0MDFxBIJQvlm3p80WwhoxUQVawJTGRbdGMutOHHOTj+uxFAFlmKrvcaltfRV/rq0Z43LeIbfeX8uwsr10lnxqLhONlP+kY9+RiAartXP3nTG88gFah9j7WrSmlrJWvSCD0lZvUxcuFioXXZw8UQ43046SWhXMYABkZ+1RYKsSjfz80/TITuR0kkY3wIwHiIWhZUjWwNxEh0CLmM06oFLjSKgZwe4UyhCRlg3iXNK3CeMC+ToSyo+lehGnWD226uNECvB3SWC4YN7r96u0xrQcf0//x6nzSdEArohFVyGgB3yb6rlFLjw==</Modulus>
<Exponent>AQAB</Exponent>
</RSAKeyValue>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8" ?>
<RSAKeyValue>
<Modulus>2oFiov7xnJGWf++WBHOdkzp1IHzNZRXhFL0MDFxBIJQvlm3p80WwhoxUQVawJTGRbdGMutOHHOTj+uxFAFlmKrvcaltfRV/rq0Z43LeIbfeX8uwsr10lnxqLhONlP+kY9+RiAartXP3nTG88gFah9j7WrSmlrJWvSCD0lZvUxcuFioXXZw8UQ43046SWhXMYABkZ+1RYKsSjfz80/TITuR0kkY3wIwHiIWhZUjWwNxEh0CLmM06oFLjSKgZwe4UyhCRlg3iXNK3CeMC+ToSyo+lehGnWD226uNECvB3SWC4YN7r96u0xrQcf0//x6nzSdEArohFVyGgB3yb6rlFLjw==</Modulus>
<Exponent>AQAB</Exponent>
<P>9A0KwiudcPWDrwVIq+2ANkuu7IILGf9D94U+qViZAKclqxc9+7UcCeP1a0LCmTiJCVLvNam4ISvU3I7rBnE46cFvJ7c+9SIQZTfb9HOFB78Q5+ulx9k9lv8VKypfuBynoV15f3OHkr2FddSsyKf4EuF20UVWsV8YSJ+iJ5gCc8M=</P>
<Q>5TQnMXCb2DjgY1sGfQgaOtVOakjemhkGUeKNJ+4ptcTUHp/hZWPtZw53kFdje1fZprDdMqKIxM2XQI+NDm2WIDnBOsXQK+K1LAh+4XXEBS+0HcPqqMW8itttOXLeoiNDXWwYWQ5/6UOLUC1ZGyjynE89FQKpyp2i6pHWhocuCEU=</Q>
<DP>xoXhbYfLH7snrnSu4+RjukcgeRVj8Hbck/mYumrus0BEfQOAEUQHFeiQl/sLj1YU6zfCjLWNqbYdBnlfp7LsaAJI6FbA6OkXyy6ARz69RUrgdrgS+Bm4Zx8C2kUy7fKpTbNbBRk2fGCcsvgYwXUZcEplu+AaoFhJybHJV0npHL8=</DP>
<DQ>LH4tRYmolxajaGYZIlhaTyVtLXCr1ZoaAfdKk3/GFQT6cF9076uwQBss1pZAN4dcNuGKbvPiPOH0BJJZPX3EcMkFW5VezcYaiUu05atou+EAw+5uNQj9iq8Byu8jjLHvt8juCQuphOyZtJy4+W6/edxf7R4xO6XSJFrfHApNw0k=</DQ>
<InverseQ>0op7bysIJnOESr0FO8JxVh85wK0dX4vC89prAzUPc2YBsrf4aW/tSewcHDtGvx0fuUZEiJcyzunho+cuuC3SzMZK2CXTJWIvR/qTuD5bjzWm3CNKP+AdvLTaCQ78M/fx7D96bhPECsy2rkwh3iBCNs0YytrGkmeij9V6Pe0ZYRk=</InverseQ>
<D>QkBexuskGQPvrQTY6KqhiYV9BAezQ0YaA+66G3lRae5ka2kSOWfU+UbNOS5upCheXvzdfbwrSHCCS4+d8Fgq6SQi1cC0p1VJIJpyhQHFBQrAcLB5cAZ/JLmoufc0uOcVYfxGVxkbdUmq+vrzTjp2SzKMZt6s1CJiji0n28DvB7V5XpZoCBVAyT705jtdx/K5zgYd7a036D5e2KNtBWDI2l2w63AAQNaqgsNGjEt3N1fHO1yyOf9q7loYvtNAJcj5i2TpEeWiJy5w1hfYGfG28bB+mrL71dfG7wjJWrUJNdoKeONS63ZS2jwMyeTWp5wuwwlh8cgQMXhJBlJF9lPNeQ==</D>
</RSAKeyValue>

Original file line number Diff line number Diff line change
Expand Up @@ -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<Catalog>(_catalog2Write, _fileName, FileMode.Create);
Catalog _recoveredCatalog = XmlFile.ReadXmlFile<Catalog>(_fileName);
Assert.IsNotNull(_recoveredCatalog);
Expand Down
Original file line number Diff line number Diff line change
@@ -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<long> 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);
}
}
}
}
}
/// <summary>
/// Sign and save an XML document.
/// </summary>
/// <param name="document">Document to be signed</param>
/// <param name="rsa">The keys ro be used by the <see cref="RSACryptoServiceProvider"/> RSA algorithm implementation.</param>
/// <remarks>
/// This document cannot be verified unless the verifying code has the public key with which it was signed.
/// </remarks>
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);
}
/// <summary>
/// Load and verify the signature of an XML file against an asymmetric RSA algorithm and return the document.
/// </summary>
/// <param name="rsaKeys">The RSA keys as the xml document.</param>
/// <param name="fileName">Name of the file.</param>
/// <returns>An instance of the <see cref="XmlDocument"/> capturing the xml file.</returns>
/// <exception cref="ArgumentException">
/// rsaKeys
/// or
/// fileName
/// </exception>
/// <exception cref="System.Security.Cryptography.CryptographicException"></exception>
/// <remarks>There must be only one signature.</remarks>
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 <signature> node.
return (_document, _signedXml);
}
}
}
24 changes: 21 additions & 3 deletions Lecture/P03.DataStreams/DataStreams/DataStreams.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,31 @@
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Data.OracleClient" />
<Reference Include="System.Drawing" />
<Reference Include="System.Net" />
<Reference Include="System.Security" />
<Reference Include="System.Security.AccessControl, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\..\packages\System.Security.AccessControl.4.5.0\lib\net461\System.Security.AccessControl.dll</HintPath>
</Reference>
<Reference Include="System.Security.Cryptography.Xml, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\..\packages\System.Security.Cryptography.Xml.4.5.0\lib\net461\System.Security.Cryptography.Xml.dll</HintPath>
</Reference>
<Reference Include="System.Security.Permissions, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\..\packages\System.Security.Permissions.4.5.0\lib\net461\System.Security.Permissions.dll</HintPath>
</Reference>
<Reference Include="System.Security.Principal.Windows, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\..\packages\System.Security.Principal.Windows.4.5.0\lib\net461\System.Security.Principal.Windows.dll</HintPath>
</Reference>
<Reference Include="System.ServiceProcess" />
<Reference Include="System.Transactions" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Cryptography\CryptographyHelpers.cs" />
<Compile Include="FileAndStream\FileExample.cs" />
<Compile Include="GlobalSuppressions.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
Expand All @@ -82,6 +101,7 @@
<ItemGroup>
<None Include="FileAndStream\README.md" />
<None Include="Key.snk" />
<None Include="packages.config" />
<None Include="Reflection\README.MD" />
</ItemGroup>
<ItemGroup>
Expand All @@ -96,9 +116,7 @@
<Install>true</Install>
</BootstrapperPackage>
</ItemGroup>
<ItemGroup>
<Folder Include="Cryptography\" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
Expand Down
7 changes: 7 additions & 0 deletions Lecture/P03.DataStreams/DataStreams/packages.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="System.Security.AccessControl" version="4.5.0" targetFramework="net471" />
<package id="System.Security.Cryptography.Xml" version="4.5.0" targetFramework="net471" />
<package id="System.Security.Permissions" version="4.5.0" targetFramework="net471" />
<package id="System.Security.Principal.Windows" version="4.5.0" targetFramework="net471" />
</packages>

0 comments on commit 925b5b3

Please sign in to comment.