From c2778b3b4bd4a256d2441d34370e2936abc6604f Mon Sep 17 00:00:00 2001 From: Val Melamed Date: Thu, 7 Jan 2016 12:43:03 -0500 Subject: [PATCH 1/8] ### Changes to the Ciphers v1.11.0 * Added MAC keyed hashers like HMAC-SHA256 or MAC-3DES. * Added a MAC key importing/exporting utility `MacKey` in the style of `EncryptedKey` or `ProtectedKey`. * Changed the access of the classes `HashAlgorithmFactory`,`KeyedHashAlgorithmFactory`,`SymmetricAlgorithmFactory`, `KeyLocationStrategy` to public. * Added and tested MAC keyed hashers like HMAC-SHA256 or MAC-3DES. * Added and tested a MAC key importing/exporting utility "MacKey" in the style of EncryptedKey or ProtectedKey. * Added interface `ILightCipher` with methods `ReleaseCertificate` and `CloneCipher` to the class `EncryptedKeyCipher` and `ILightHasher` with methods `ReleaseCertificate` and `CloneHasher` to the class `KeyedHasher`. `ReleaseCertificate` strips the public/private keys from the objects and now they can be used only for encryption/hashing. This way the objects become lighter and more suitable for caching and using it in a big numbers of cryptographic operations. `CloneCipher` creates a copy of the current object, without the public/private keys. * Some performance improvements in the classes `Hasher` and `Signer`. --- Aspects/NuGet/vm.Aspects.nuspec | 6 + .../Security/Cryptography/Ciphers/Hasher.cs | 194 +++++++++--------- .../Cryptography/Ciphers/NuGet/Ciphers.nuspec | 10 +- .../Ciphers/Test/ClonedLightHasherTest.cs | 55 +++++ .../Cryptography/Ciphers/Test/HasherTest.cs | 7 +- .../Test/ReleasedCertificateHasherTest.cs | 60 +++++- 6 files changed, 223 insertions(+), 109 deletions(-) diff --git a/Aspects/NuGet/vm.Aspects.nuspec b/Aspects/NuGet/vm.Aspects.nuspec index fe72e11..1f4fd23 100644 --- a/Aspects/NuGet/vm.Aspects.nuspec +++ b/Aspects/NuGet/vm.Aspects.nuspec @@ -14,6 +14,12 @@ * Added and tested MAC keyed hashers like HMAC-SHA256 or MAC-3DES. * Added and tested a MAC key importing/exporting utility "MacKey" in the style of EncryptedKey or ProtectedKey. + * Added interface `ILightCipher` with methods `ReleaseCertificate` and `CloneCipher` to the class `EncryptedKeyCipher` and + `ILightHasher` with methods `ReleaseCertificate` and `CloneHasher` to the class `KeyedHasher`. + `ReleaseCertificate` strips the public/private keys from the objects and now they can be used only for encryption/hashing. + This way the objects become lighter and more suitable for caching and using it in a big numbers of cryptographic operations. + `CloneCipher` creates a copy of the current object, without the public/private keys. + * Some performance improvements in the classes `Hasher` and `Signer`. https://github.com/vmelamed/vm/blob/master/LICENSE https://github.com/vmelamed/vm/tree/master/Aspects diff --git a/Aspects/Security/Cryptography/Ciphers/Hasher.cs b/Aspects/Security/Cryptography/Ciphers/Hasher.cs index 91d2e3a..40b696c 100644 --- a/Aspects/Security/Cryptography/Ciphers/Hasher.cs +++ b/Aspects/Security/Cryptography/Ciphers/Hasher.cs @@ -35,9 +35,9 @@ public class Hasher : IHasherAsync #region Fields /// - /// Caches the hash algorithm factory + /// The underlying hash algorithm. /// - readonly IHashAlgorithmFactory _hashAlgorithmFactory; + readonly HashAlgorithm _hashAlgorithm; /// /// The salt length. /// @@ -62,8 +62,10 @@ public Hasher( { Contract.Requires(saltLength==0 || saltLength>=DefaultSaltLength, "The salt length should be either 0 or not less than 8 bytes."); - _hashAlgorithmFactory = ServiceLocatorWrapper.Default.GetInstance(); - _hashAlgorithmFactory.Initialize(hashAlgorithmName); + var hashAlgorithmFactory = ServiceLocatorWrapper.Default.GetInstance(); + hashAlgorithmFactory.Initialize(hashAlgorithmName); + + _hashAlgorithm = hashAlgorithmFactory.Create(); _saltLength = saltLength; } @@ -71,20 +73,19 @@ public Hasher( #region Properties /// - /// Gets a value indicating whether the hash should be salted. + /// Gets the name of the hash algorithm. /// - public bool ShouldSalt + public string HashAlgorithmName { - get { return SaltLength > 0; } + get { return _hashAlgorithm.GetType().FullName; } } /// - /// Gets the name of the hash algorithm. + /// Gets a value indicating whether the hash should be salted. /// - /// The name of the hash algorithm. - public string HashAlgorithmName + public bool ShouldSalt { - get { return _hashAlgorithmFactory.HashAlgorithmName; } + get { return SaltLength > 0; } } #endregion @@ -116,13 +117,13 @@ public virtual byte[] Hash( if (!dataStream.CanRead) throw new ArgumentException("The data stream cannot be read.", "dataStream"); - using (var hashAlgorithm = _hashAlgorithmFactory.Create()) - using (var hashStream = CreateHashStream(hashAlgorithm)) + _hashAlgorithm.Initialize(); + using (var hashStream = CreateHashStream()) { var salt = WriteSalt(hashStream, null); dataStream.CopyTo(hashStream); - return FinalizeHashing(hashStream, hashAlgorithm, salt); + return FinalizeHashing(hashStream, salt); } } @@ -148,35 +149,38 @@ public virtual bool TryVerifyHash( // save the property value - it may change for this call only depending on the length of the hash var savedSaltLength = SaltLength; - using (var hashAlgorithm = _hashAlgorithmFactory.Create()) - try + try + { + _hashAlgorithm.Initialize(); + + // the parameter hash has the length of the expected product from this algorithm, i.e. there is no salt + if (hash.Length == _hashAlgorithm.HashSize/8) + SaltLength = 0; + else { - // the parameter hash has the length of the expected product from this algorithm, i.e. there is no salt - if (hash.Length == hashAlgorithm.HashSize/8) - SaltLength = 0; - else - // the parameter hash has the length of the expected product from this algorithm + the length of the salt, i.e. there is salt in the parameter salt - if (hash.Length > hashAlgorithm.HashSize/8) - SaltLength = hash.Length - hashAlgorithm.HashSize/8; + // the parameter hash has the length of the expected product from this algorithm + the length of the salt, i.e. there is salt in the parameter salt + if (hash.Length > _hashAlgorithm.HashSize/8) + SaltLength = hash.Length - _hashAlgorithm.HashSize/8; else // this is wrong... return false; + } - using (var hashStream = CreateHashStream(hashAlgorithm)) - { - WriteSalt(hashStream, hash); - dataStream.CopyTo(hashStream); + using (var hashStream = CreateHashStream()) + { + WriteSalt(hashStream, hash); + dataStream.CopyTo(hashStream); - byte[] computedHash = FinalizeHashing(hashStream, hashAlgorithm, hash); + byte[] computedHash = FinalizeHashing(hashStream, hash); - return computedHash.ConstantTimeEquals(hash); - } - } - finally - { - // restore the value of the property - SaltLength = savedSaltLength; + return computedHash.ConstantTimeEquals(hash); } + } + finally + { + // restore the value of the property + SaltLength = savedSaltLength; + } } /// @@ -191,13 +195,13 @@ public virtual byte[] Hash( if (data == null) return null; - using (var hashAlgorithm = _hashAlgorithmFactory.Create()) - using (var hashStream = CreateHashStream(hashAlgorithm)) + _hashAlgorithm.Initialize(); + using (var hashStream = CreateHashStream()) { var salt = WriteSalt(hashStream, null); hashStream.Write(data, 0, data.Length); - return FinalizeHashing(hashStream, hashAlgorithm, salt); + return FinalizeHashing(hashStream, salt); } } @@ -222,35 +226,38 @@ public virtual bool TryVerifyHash( // save the property value - it may change for this call only var savedSaltLength = SaltLength; - using (var hashAlgorithm = _hashAlgorithmFactory.Create()) - try + try + { + _hashAlgorithm.Initialize(); + + // the parameter hash has the length of the expected product from this algorithm, i.e. there is no salt + if (hash.Length == _hashAlgorithm.HashSize/8) + SaltLength = 0; + else { - // the parameter hash has the length of the expected product from this algorithm, i.e. there is no salt - if (hash.Length == hashAlgorithm.HashSize/8) - SaltLength = 0; - else - // the parameter hash has the length of the expected product from this algorithm + the length of the salt, i.e. there is salt in the parameter salt - if (hash.Length > hashAlgorithm.HashSize/8) - SaltLength = hash.Length - hashAlgorithm.HashSize/8; + // the parameter hash has the length of the expected product from this algorithm + the length of the salt, i.e. there is salt in the parameter salt + if (hash.Length > _hashAlgorithm.HashSize/8) + SaltLength = hash.Length - _hashAlgorithm.HashSize/8; else // this is wrong... return false; + } - using (var hashStream = CreateHashStream(hashAlgorithm)) - { - WriteSalt(hashStream, hash); - hashStream.Write(data, 0, data.Length); + using (var hashStream = CreateHashStream()) + { + WriteSalt(hashStream, hash); + hashStream.Write(data, 0, data.Length); - byte[] computedHash = FinalizeHashing(hashStream, hashAlgorithm, hash); + byte[] computedHash = FinalizeHashing(hashStream, hash); - return computedHash.ConstantTimeEquals(hash); - } - } - finally - { - // restore the property value - SaltLength = savedSaltLength; + return computedHash.ConstantTimeEquals(hash); } + } + finally + { + // restore the property value + SaltLength = savedSaltLength; + } } #endregion @@ -269,13 +276,13 @@ public virtual async Task HashAsync( if (dataStream == null) return null; - using (var hashAlgorithm = _hashAlgorithmFactory.Create()) - using (var hashStream = CreateHashStream(hashAlgorithm)) + _hashAlgorithm.Initialize(); + using (var hashStream = CreateHashStream()) { var salt = await WriteSaltAsync(hashStream, null); await dataStream.CopyToAsync(hashStream); - return FinalizeHashing(hashStream, hashAlgorithm, salt); + return FinalizeHashing(hashStream, salt); } } @@ -300,35 +307,38 @@ public virtual async Task TryVerifyHashAsync( // save the property value - it may change for this call only depending on the length of the hash var savedSaltLength = SaltLength; - using (var hashAlgorithm = _hashAlgorithmFactory.Create()) - try + try + { + _hashAlgorithm.Initialize(); + + // the hash has the same length as the length of the key - there is no salt + if (hash.Length == _hashAlgorithm.HashSize/8) + SaltLength = 0; + else { - // the hash has the same length as the length of the key - there is no salt - if (hash.Length == hashAlgorithm.HashSize/8) - SaltLength = 0; - else - // the hash has the same length as the length of the key + the length of the salt - there is salt in the parameter salt - if (hash.Length > hashAlgorithm.HashSize/8) - SaltLength = hash.Length - hashAlgorithm.HashSize/8; + // the hash has the same length as the length of the key + the length of the salt - there is salt in the parameter salt + if (hash.Length > _hashAlgorithm.HashSize/8) + SaltLength = hash.Length - _hashAlgorithm.HashSize/8; else // this is wrong... return false; + } - using (var hashStream = CreateHashStream(hashAlgorithm)) - { - await WriteSaltAsync(hashStream, hash); - await dataStream.CopyToAsync(hashStream); + using (var hashStream = CreateHashStream()) + { + await WriteSaltAsync(hashStream, hash); + await dataStream.CopyToAsync(hashStream); - byte[] computedHash = FinalizeHashing(hashStream, hashAlgorithm, hash); + byte[] computedHash = FinalizeHashing(hashStream, hash); - return computedHash.ConstantTimeEquals(hash); - } - } - finally - { - // restore the value of the property - SaltLength = savedSaltLength; + return computedHash.ConstantTimeEquals(hash); } + } + finally + { + // restore the value of the property + SaltLength = savedSaltLength; + } } #endregion @@ -338,12 +348,9 @@ public virtual async Task TryVerifyHashAsync( /// /// CryptoStream. [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "It will be disposed by the calling code.")] - protected virtual CryptoStream CreateHashStream( - HashAlgorithm hashAlgorithm) + protected virtual CryptoStream CreateHashStream() { - Contract.Requires(hashAlgorithm != null, "hashAlgorithm"); - - return new CryptoStream(new NullStream(), hashAlgorithm, CryptoStreamMode.Write); + return new CryptoStream(new NullStream(), _hashAlgorithm, CryptoStreamMode.Write); } /// @@ -377,7 +384,6 @@ protected virtual byte[] WriteSalt( /// Finalizes the hashing. /// /// The hash stream. - /// The hash algorithm. /// The salt. /// The hash. /// Thrown when is . @@ -386,23 +392,21 @@ protected virtual byte[] WriteSalt( [SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "2", Justification = "salt is conditionally validated.")] protected virtual byte[] FinalizeHashing( CryptoStream hashStream, - HashAlgorithm hashAlgorithm, byte[] salt) { Contract.Requires(hashStream != null, "hashStream"); Contract.Requires(hashStream.CanWrite, "The argument \"hashStream\" cannot be written to."); - Contract.Requires(hashAlgorithm != null, "hashAlgorithm"); Contract.Requires(!ShouldSalt || salt != null, "salt"); if (!hashStream.HasFlushedFinalBlock) hashStream.FlushFinalBlock(); - var hash = new byte[SaltLength + hashAlgorithm.HashSize/8]; + var hash = new byte[SaltLength + _hashAlgorithm.HashSize/8]; if (SaltLength > 0) salt.CopyTo(hash, 0); - hashAlgorithm.Hash.CopyTo(hash, SaltLength); + _hashAlgorithm.Hash.CopyTo(hash, SaltLength); return hash; } @@ -497,14 +501,14 @@ public void Dispose() protected virtual void Dispose(bool disposing) { if (disposing) - _hashAlgorithmFactory.Dispose(); + _hashAlgorithm.Dispose(); } #endregion [ContractInvariantMethod] void Invariant() { - Contract.Invariant(_hashAlgorithmFactory != null, "The hash algorithm factory cannot be null."); + Contract.Invariant(_hashAlgorithm != null, "The hash algorithm factory cannot be null."); Contract.Invariant(_saltLength==0 || _saltLength>=DefaultSaltLength, "Invalid salt length."); } } diff --git a/Aspects/Security/Cryptography/Ciphers/NuGet/Ciphers.nuspec b/Aspects/Security/Cryptography/Ciphers/NuGet/Ciphers.nuspec index 6525278..59feebd 100644 --- a/Aspects/Security/Cryptography/Ciphers/NuGet/Ciphers.nuspec +++ b/Aspects/Security/Cryptography/Ciphers/NuGet/Ciphers.nuspec @@ -18,10 +18,12 @@ * Built and tested with .NET v4.6. - Added public methods `ResetAsymmetricKeys` and `Duplicate` to the classes `EncryptedKeyCipher` and `KeyedHasher`. - `ResetAsymmetricKeyes` strips the public/private keys from the objects and now they can be used only for encryption/hashing. - This way the objects become lighter and more suitable for caching and using in a big numbers of cryptographic operations. - `Duplicate` creates a copy of the current object, without the public/private keys. + Added interface `ILightCipher` with methods `ReleaseCertificate` and `CloneCipher` to the class `EncryptedKeyCipher` and + `ILightHasher` with methods `ReleaseCertificate` and `CloneHasher` to the class `KeyedHasher`. + `ReleaseCertificate` strips the public/private keys from the objects and now they can be used only for encryption/hashing. + This way the objects become lighter and more suitable for caching and using it in a big numbers of cryptographic operations. + `CloneCipher` creates a copy of the current object, without the public/private keys. + Some performance improvements in the classes `Hasher` and `Signer`. https://github.com/vmelamed/vm/blob/master/LICENSE https://github.com/vmelamed/vm/tree/master/Aspects/Security/Cryptography/Ciphers diff --git a/Aspects/Security/Cryptography/Ciphers/Test/ClonedLightHasherTest.cs b/Aspects/Security/Cryptography/Ciphers/Test/ClonedLightHasherTest.cs index d30a171..00b1c12 100644 --- a/Aspects/Security/Cryptography/Ciphers/Test/ClonedLightHasherTest.cs +++ b/Aspects/Security/Cryptography/Ciphers/Test/ClonedLightHasherTest.cs @@ -48,6 +48,61 @@ public static void ClassCleanup() File.Delete(keyManagement.KeyLocation); } + [TestMethod] + public void CloneCanVerifyOriginal() + { + const string expected = "The quick fox jumps over the lazy dog."; + + using (var hasher = new KeyedHasher(CertificateFactory.GetDecryptingCertificate(), null, keyFileName)) + { + var hash = hasher.Hash(expected); + + using (var clone = hasher.CloneLightHasher()) + Assert.IsTrue(clone.TryVerifyHash(expected, hash)); + } + } + + [TestMethod] + public void OriginalCanVerifyClone() + { + const string expected = "The quick fox jumps over the lazy dog."; + + using (var hasher = new KeyedHasher(CertificateFactory.GetDecryptingCertificate(), null, keyFileName)) + using (var clone = hasher.CloneLightHasher()) + { + var hash = clone.Hash(expected); + + Assert.IsTrue(hasher.TryVerifyHash(expected, hash)); + } + } + [TestMethod] + public void CloneCanVerifyClone() + { + const string expected = "The quick fox jumps over the lazy dog."; + + using (var hasher = new KeyedHasher(CertificateFactory.GetDecryptingCertificate(), null, keyFileName)) + using (var clone = hasher.CloneLightHasher()) + using (var clone2 = hasher.CloneLightHasher()) + { + var hash = clone.Hash(expected); + + Assert.IsTrue(clone2.TryVerifyHash(expected, hash)); + } + } + + [TestMethod] + public void CloneCanVerifyItsOwn() + { + const string expected = "The quick fox jumps over the lazy dog."; + + using (var hasher = new KeyedHasher(CertificateFactory.GetDecryptingCertificate(), null, keyFileName)) + using (var clone = hasher.CloneLightHasher()) + { + var hash = clone.Hash(expected); + + Assert.IsTrue(clone.TryVerifyHash(expected, hash)); + } + } } } diff --git a/Aspects/Security/Cryptography/Ciphers/Test/HasherTest.cs b/Aspects/Security/Cryptography/Ciphers/Test/HasherTest.cs index c729558..0ad264d 100644 --- a/Aspects/Security/Cryptography/Ciphers/Test/HasherTest.cs +++ b/Aspects/Security/Cryptography/Ciphers/Test/HasherTest.cs @@ -65,10 +65,9 @@ public async Task PublicWriteSaltAsync( public byte[] PublicFinalizeHashing( CryptoStream hashStream, - HashAlgorithm hashAlgorithm, byte[] salt) { - return base.FinalizeHashing(hashStream, hashAlgorithm, salt); + return base.FinalizeHashing(hashStream, salt); } } @@ -134,7 +133,7 @@ public void WriteSaltNonWritableStreamAsyncTest() public void FinalizeHashingNonWritableCryptoStreamTest() { using (var hasher = GetInheritedHasher()) - hasher.PublicFinalizeHashing(GetCryptoStream(hasher), HashAlgorithm.Create(Algorithms.Hash.Sha256), new byte[8]); + hasher.PublicFinalizeHashing(GetCryptoStream(hasher), new byte[8]); } [TestMethod] @@ -142,7 +141,7 @@ public void FinalizeHashingNonWritableCryptoStreamTest() public void FinalizeHashingNullSaltTest() { using (var hasher = GetInheritedHasher()) - hasher.PublicFinalizeHashing(GetCryptoStream2(hasher), HashAlgorithm.Create(Algorithms.Hash.Sha256), null); + hasher.PublicFinalizeHashing(GetCryptoStream2(hasher), null); } } } diff --git a/Aspects/Security/Cryptography/Ciphers/Test/ReleasedCertificateHasherTest.cs b/Aspects/Security/Cryptography/Ciphers/Test/ReleasedCertificateHasherTest.cs index 8bdbe3c..0b3148f 100644 --- a/Aspects/Security/Cryptography/Ciphers/Test/ReleasedCertificateHasherTest.cs +++ b/Aspects/Security/Cryptography/Ciphers/Test/ReleasedCertificateHasherTest.cs @@ -12,12 +12,6 @@ public class ReleasedCertificateHasherTest : GenericHasherTest { const string keyFileName = "releasedCertificateHash.key"; - /// - ///Gets or sets the test context which provides - ///information about and functionality for the current test run. - /// - //public TestContext TestContext { get; set; } - public override IHasherAsync GetHasher() { return new KeyedHasher(CertificateFactory.GetDecryptingCertificate(), null, keyFileName).ReleaseCertificate(); @@ -45,6 +39,60 @@ public static void ClassCleanup() File.Delete(keyManagement.KeyLocation); } + [TestMethod] + public void OriginalCanVerifyStripped() + { + const string expected = "The quick fox jumps over the lazy dog."; + + using (var stripped = new KeyedHasher(CertificateFactory.GetDecryptingCertificate(), null, keyFileName).ReleaseCertificate()) + using (var original = new KeyedHasher(CertificateFactory.GetDecryptingCertificate(), null, keyFileName)) + { + var hash = stripped.Hash(expected); + + Assert.IsTrue(original.TryVerifyHash(expected, hash)); + } + } + + [TestMethod] + public void StrippedCanVerifyOriginal() + { + const string expected = "The quick fox jumps over the lazy dog."; + + using (var original = new KeyedHasher(CertificateFactory.GetDecryptingCertificate(), null, keyFileName)) + { + var hash = original.Hash(expected); + + var stripped = ((KeyedHasher)original).ReleaseCertificate(); + + Assert.IsTrue(stripped.TryVerifyHash(expected, hash)); + } + } + + [TestMethod] + public void StrippedCanVerifyStripped() + { + const string expected = "The quick fox jumps over the lazy dog."; + + using (var stripped = new KeyedHasher(CertificateFactory.GetDecryptingCertificate(), null, keyFileName).ReleaseCertificate()) + using (var stripped2 = new KeyedHasher(CertificateFactory.GetDecryptingCertificate(), null, keyFileName).ReleaseCertificate()) + { + var hash = stripped.Hash(expected); + + Assert.IsTrue(stripped2.TryVerifyHash(expected, hash)); + } + } + + [TestMethod] + public void StrippedCanVerifyItsOwn() + { + const string expected = "The quick fox jumps over the lazy dog."; + + using (var stripped = new KeyedHasher(CertificateFactory.GetDecryptingCertificate(), null, keyFileName).ReleaseCertificate()) + { + var hash = stripped.Hash(expected); + Assert.IsTrue(stripped.TryVerifyHash(expected, hash)); + } + } } } From bdf73c0151eea248b6f81df3c5ab4622caeb15c3 Mon Sep 17 00:00:00 2001 From: Val Melamed Date: Thu, 7 Jan 2016 20:49:48 -0500 Subject: [PATCH 2/8] Ciphers 1.11.2 --- Aspects/Security/Cryptography/Ciphers/KeyedHasher .cs | 4 ++-- Aspects/Security/Cryptography/Ciphers/NuGet/Ciphers.nuspec | 3 ++- .../Cryptography/Ciphers/Properties/AssemblyInfo.cs | 6 +++--- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Aspects/Security/Cryptography/Ciphers/KeyedHasher .cs b/Aspects/Security/Cryptography/Ciphers/KeyedHasher .cs index 8a5f9e0..ae8e027 100644 --- a/Aspects/Security/Cryptography/Ciphers/KeyedHasher .cs +++ b/Aspects/Security/Cryptography/Ciphers/KeyedHasher .cs @@ -612,9 +612,9 @@ public IHasherAsync CloneLightHasher() var hasher = new KeyedHasher(); hasher._hashAlgorithm = KeyedHashAlgorithm.Create(_hashAlgorithm.GetType().FullName); - hasher._hashAlgorithm.Key = _hashAlgorithm.Key; + hasher._hashAlgorithm.Key = (byte[])_hashAlgorithm.Key.Clone(); hasher.IsHashKeyInitialized = true; - + return hasher; } #endregion diff --git a/Aspects/Security/Cryptography/Ciphers/NuGet/Ciphers.nuspec b/Aspects/Security/Cryptography/Ciphers/NuGet/Ciphers.nuspec index 59feebd..aa5cebf 100644 --- a/Aspects/Security/Cryptography/Ciphers/NuGet/Ciphers.nuspec +++ b/Aspects/Security/Cryptography/Ciphers/NuGet/Ciphers.nuspec @@ -2,7 +2,7 @@ Ciphers - 1.11.0 + 1.11.2 Val Melamed Val Melamed @@ -24,6 +24,7 @@ This way the objects become lighter and more suitable for caching and using it in a big numbers of cryptographic operations. `CloneCipher` creates a copy of the current object, without the public/private keys. Some performance improvements in the classes `Hasher` and `Signer`. + Fixed minor bugs. https://github.com/vmelamed/vm/blob/master/LICENSE https://github.com/vmelamed/vm/tree/master/Aspects/Security/Cryptography/Ciphers diff --git a/Aspects/Security/Cryptography/Ciphers/Properties/AssemblyInfo.cs b/Aspects/Security/Cryptography/Ciphers/Properties/AssemblyInfo.cs index 2ca6360..072b16d 100644 --- a/Aspects/Security/Cryptography/Ciphers/Properties/AssemblyInfo.cs +++ b/Aspects/Security/Cryptography/Ciphers/Properties/AssemblyInfo.cs @@ -5,9 +5,9 @@ // associated with an assembly. [assembly: AssemblyTitle("vm.Aspects.Security.Cryptography.Ciphers")] [assembly: AssemblyDescription("A set of cipher classes producing cipher-packages and encrypted and/or signed XML documents and elements.")] -[assembly: AssemblyVersion("1.11.0")] -[assembly: AssemblyFileVersion("1.11.0")] -[assembly: AssemblyInformationalVersion("1.11.0")] +[assembly: AssemblyVersion("1.11.2")] +[assembly: AssemblyFileVersion("1.11.2")] +[assembly: AssemblyInformationalVersion("1.11.2")] [assembly: System.Runtime.CompilerServices.InternalsVisibleTo( "vm.Aspects.Security.Cryptography.Ciphers.Tests, " + From bda21e8a3f80c64018412d7dee7ed55a4ff94ed8 Mon Sep 17 00:00:00 2001 From: Val Melamed Date: Fri, 8 Jan 2016 22:29:56 -0500 Subject: [PATCH 3/8] Merged the contract files into their interface files. --- .../Ciphers/Contracts/ICipherAsyncContract.cs | 71 ----------------- .../Ciphers/Contracts/ICipherContract.cs | 55 ------------- .../IHashAlgorithmFactoryContract.cs | 41 ---------- .../Ciphers/Contracts/IHasherAsyncContract.cs | 77 ------------------- .../Ciphers/Contracts/IHasherContract.cs | 75 ------------------ .../Contracts/IKeyLocationStrategyContract.cs | 18 ----- .../Contracts/IKeyManagementContract.cs | 48 ------------ .../Contracts/IKeyStorageAsyncContract.cs | 62 --------------- .../Ciphers/Contracts/IKeyStorageContract.cs | 48 ------------ .../ISymmetricAlgorithmFactoryContract.cs | 36 --------- .../SymmetricKeyCipherBaseContract.cs | 30 -------- .../Contracts/Xml/IXmlCipherContract.cs | 52 ------------- .../Contracts/Xml/IXmlSignerContract.cs | 68 ---------------- .../Security/Cryptography/Ciphers/Hasher.cs | 7 +- .../Security/Cryptography/Ciphers/ICipher.cs | 50 +++++++++++- .../Cryptography/Ciphers/ICipherAsync.cs | 68 +++++++++++++++- .../Ciphers/IHashAlgorithmFactory.cs | 36 ++++++++- .../Security/Cryptography/Ciphers/IHasher.cs | 70 ++++++++++++++++- .../Cryptography/Ciphers/IHasherAsync.cs | 74 +++++++++++++++++- .../Ciphers/IKeyLocationStrategy.cs | 17 +++- .../Cryptography/Ciphers/IKeyManagement.cs | 44 ++++++++++- .../Cryptography/Ciphers/IKeyStorage.cs | 45 ++++++++++- .../Cryptography/Ciphers/IKeyStorageAsync.cs | 57 +++++++++++++- .../Ciphers/ISymmetricAlgorithmFactory.cs | 31 +++++++- .../Ciphers/SymmetricAlgorithmFactory.cs | 4 +- .../Ciphers/SymmetricKeyCipherBase.cs | 26 ++++++- .../Ciphers/Test/CreateCertificates.ps1 | 1 + .../Cryptography/Ciphers/Xml/IXmlCipher.cs | 50 +++++++++++- .../Cryptography/Ciphers/Xml/IXmlSigner.cs | 66 +++++++++++++++- ...pects.Security.Cryptography.Ciphers.csproj | 13 ---- 30 files changed, 621 insertions(+), 719 deletions(-) delete mode 100644 Aspects/Security/Cryptography/Ciphers/Contracts/ICipherAsyncContract.cs delete mode 100644 Aspects/Security/Cryptography/Ciphers/Contracts/ICipherContract.cs delete mode 100644 Aspects/Security/Cryptography/Ciphers/Contracts/IHashAlgorithmFactoryContract.cs delete mode 100644 Aspects/Security/Cryptography/Ciphers/Contracts/IHasherAsyncContract.cs delete mode 100644 Aspects/Security/Cryptography/Ciphers/Contracts/IHasherContract.cs delete mode 100644 Aspects/Security/Cryptography/Ciphers/Contracts/IKeyLocationStrategyContract.cs delete mode 100644 Aspects/Security/Cryptography/Ciphers/Contracts/IKeyManagementContract.cs delete mode 100644 Aspects/Security/Cryptography/Ciphers/Contracts/IKeyStorageAsyncContract.cs delete mode 100644 Aspects/Security/Cryptography/Ciphers/Contracts/IKeyStorageContract.cs delete mode 100644 Aspects/Security/Cryptography/Ciphers/Contracts/ISymmetricAlgorithmFactoryContract.cs delete mode 100644 Aspects/Security/Cryptography/Ciphers/Contracts/SymmetricKeyCipherBaseContract.cs delete mode 100644 Aspects/Security/Cryptography/Ciphers/Contracts/Xml/IXmlCipherContract.cs delete mode 100644 Aspects/Security/Cryptography/Ciphers/Contracts/Xml/IXmlSignerContract.cs diff --git a/Aspects/Security/Cryptography/Ciphers/Contracts/ICipherAsyncContract.cs b/Aspects/Security/Cryptography/Ciphers/Contracts/ICipherAsyncContract.cs deleted file mode 100644 index 4b0405a..0000000 --- a/Aspects/Security/Cryptography/Ciphers/Contracts/ICipherAsyncContract.cs +++ /dev/null @@ -1,71 +0,0 @@ -using System; -using System.Diagnostics.Contracts; -using System.IO; -using System.Threading.Tasks; - -namespace vm.Aspects.Security.Cryptography.Ciphers.Contracts -{ - [ContractClassFor(typeof(ICipherAsync))] - abstract class ICipherAsyncContract : ICipherAsync - { - #region ICipherAsync Members - public Task EncryptAsync(Stream dataStream, Stream encryptedStream) - { - Contract.Requires(dataStream != null, "dataStream"); - Contract.Requires(encryptedStream != null, "encryptedStream"); - Contract.Requires(dataStream.CanRead, "The argument \"dataStream\" cannot be read from."); - Contract.Requires(encryptedStream.CanWrite, "The argument \"encryptedStream\" cannot be written to."); - - throw new NotImplementedException(); - } - - public Task DecryptAsync(Stream encryptedStream, Stream dataStream) - { - Contract.Requires(encryptedStream != null, "encryptedStream"); - Contract.Requires(dataStream != null, "dataStream"); - Contract.Requires(encryptedStream.CanRead, "The argument \"dataStream\" cannot be read from."); - Contract.Requires(dataStream.CanWrite, "The argument \"encryptedStream\" cannot be written to."); - - throw new NotImplementedException(); - } - #endregion - - #region ICipher Members - public bool Base64Encoded { get; set; } - - public void Encrypt( - Stream dataStream, - Stream encryptedStream) - { - throw new NotImplementedException(); - } - - public void Decrypt( - Stream encryptedStream, - Stream dataStream) - { - throw new NotImplementedException(); - } - - public byte[] Encrypt(byte[] data) - { - throw new NotImplementedException(); - } - - public byte[] Decrypt(byte[] encryptedData) - { - throw new NotImplementedException(); - } - - #endregion - - #region IDisposable Members - - public void Dispose() - { - throw new NotImplementedException(); - } - - #endregion - } -} diff --git a/Aspects/Security/Cryptography/Ciphers/Contracts/ICipherContract.cs b/Aspects/Security/Cryptography/Ciphers/Contracts/ICipherContract.cs deleted file mode 100644 index fb4b1ac..0000000 --- a/Aspects/Security/Cryptography/Ciphers/Contracts/ICipherContract.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System; -using System.Diagnostics.Contracts; -using System.IO; - -namespace vm.Aspects.Security.Cryptography.Ciphers.Contracts -{ - [ContractClassFor(typeof(ICipher))] - abstract class ICipherContract : ICipher - { - #region ICipher Members - public bool Base64Encoded { get; set; } - - public void Encrypt(Stream dataStream, Stream encryptedStream) - { - Contract.Requires(dataStream != null, "dataStream"); - Contract.Requires(encryptedStream != null, "encryptedStream"); - Contract.Requires(dataStream.CanRead, "The argument \"dataStream\" cannot be read from."); - Contract.Requires(encryptedStream.CanWrite, "The argument \"encryptedStream\" cannot be written to."); - - throw new NotImplementedException(); - } - - public void Decrypt(Stream encryptedStream, Stream dataStream) - { - Contract.Requires(encryptedStream != null, "encryptedStream"); - Contract.Requires(dataStream != null, "dataStream"); - Contract.Requires(encryptedStream.CanRead, "The argument \"dataStream\" cannot be read from."); - Contract.Requires(dataStream.CanWrite, "The argument \"encryptedStream\" cannot be written to."); - - throw new NotImplementedException(); - } - - public byte[] Encrypt(byte[] data) - { - Contract.Ensures(!(data==null ^ Contract.Result()==null)); - - throw new NotImplementedException(); - } - - public byte[] Decrypt(byte[] encryptedData) - { - Contract.Ensures(!(encryptedData==null ^ Contract.Result()==null)); - - throw new NotImplementedException(); - } - #endregion - - #region IDisposable Members - public void Dispose() - { - throw new NotImplementedException(); - } - #endregion - } -} diff --git a/Aspects/Security/Cryptography/Ciphers/Contracts/IHashAlgorithmFactoryContract.cs b/Aspects/Security/Cryptography/Ciphers/Contracts/IHashAlgorithmFactoryContract.cs deleted file mode 100644 index 76754c2..0000000 --- a/Aspects/Security/Cryptography/Ciphers/Contracts/IHashAlgorithmFactoryContract.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; -using System.Diagnostics.Contracts; -using System.Security.Cryptography; - -namespace vm.Aspects.Security.Cryptography.Ciphers.Contracts -{ - [ContractClassFor(typeof(IHashAlgorithmFactory))] - abstract class IHashAlgorithmFactoryContract : IHashAlgorithmFactory - { - #region IHashAlgorithmFactory Members - - public void Initialize( - string hashAlgorithmName) - { - throw new NotImplementedException(); - } - - public HashAlgorithm Create() - { - Contract.Ensures(Contract.Result() != null, "Could not create a hash algorithm."); - - throw new NotImplementedException(); - } - - public string HashAlgorithmName - { - get { throw new NotImplementedException(); } - } - - #endregion - - #region IDisposable Members - - public void Dispose() - { - throw new NotImplementedException(); - } - - #endregion - } -} diff --git a/Aspects/Security/Cryptography/Ciphers/Contracts/IHasherAsyncContract.cs b/Aspects/Security/Cryptography/Ciphers/Contracts/IHasherAsyncContract.cs deleted file mode 100644 index 476fcfe..0000000 --- a/Aspects/Security/Cryptography/Ciphers/Contracts/IHasherAsyncContract.cs +++ /dev/null @@ -1,77 +0,0 @@ -using System; -using System.Diagnostics.Contracts; -using System.IO; -using System.Threading.Tasks; - -namespace vm.Aspects.Security.Cryptography.Ciphers.Contracts -{ - [ContractClassFor(typeof(IHasherAsync))] - abstract class IHasherAsyncContract : IHasherAsync - { - #region IHasherAsync Members - - public Task HashAsync(Stream dataStream) - { - Contract.Requires(dataStream==null || dataStream.CanRead, "The \"dataStream\" cannot be read from."); - Contract.Ensures(!(dataStream==null ^ Contract.Result()==null), "The returned value is invalid."); - - throw new NotImplementedException(); - } - - public Task TryVerifyHashAsync(Stream dataStream, byte[] hash) - { - Contract.Requires(dataStream==null || dataStream.CanRead, "The \"dataStream\" cannot be read from."); - Contract.Requires(dataStream==null || hash!=null, "hash"); - Contract.Ensures(dataStream!=null || Contract.Result()==(hash==null), "Invalid return value."); - - throw new NotImplementedException(); - } - - #endregion - - #region IHasher Members - - public int SaltLength - { - get - { - throw new NotImplementedException(); - } - set - { - throw new NotImplementedException(); - } - } - - public byte[] Hash(System.IO.Stream dataStream) - { - throw new NotImplementedException(); - } - - public bool TryVerifyHash(System.IO.Stream dataStream, byte[] hash) - { - throw new NotImplementedException(); - } - - public byte[] Hash(byte[] data) - { - throw new NotImplementedException(); - } - - public bool TryVerifyHash(byte[] data, byte[] hash) - { - throw new NotImplementedException(); - } - - #endregion - - #region IDisposable Members - - public void Dispose() - { - throw new NotImplementedException(); - } - - #endregion - } -} diff --git a/Aspects/Security/Cryptography/Ciphers/Contracts/IHasherContract.cs b/Aspects/Security/Cryptography/Ciphers/Contracts/IHasherContract.cs deleted file mode 100644 index c1d6e93..0000000 --- a/Aspects/Security/Cryptography/Ciphers/Contracts/IHasherContract.cs +++ /dev/null @@ -1,75 +0,0 @@ -using System; -using System.Diagnostics.Contracts; -using System.IO; - -namespace vm.Aspects.Security.Cryptography.Ciphers.Contracts -{ - [ContractClassFor(typeof(IHasher))] - abstract class IHasherContract : IHasher - { - #region IHasher Members - - public int SaltLength - { - get - { - Contract.Ensures(Contract.Result()==0 || Contract.Result()>=Hasher.DefaultSaltLength, "The salt length should be either 0 or not less than 8 bytes."); - - throw new NotImplementedException(); - } - set - { - Contract.Requires(value==0 || value>=8, "The salt length should be either 0 or not less than 8 bytes."); - - throw new NotImplementedException(); - } - } - - public byte[] Hash( - Stream dataStream) - { - Contract.Requires(dataStream==null || dataStream.CanRead, "The \"dataStream\" cannot be read from."); - Contract.Ensures(!(dataStream==null ^ Contract.Result()==null), "The returned value is invalid."); - - throw new NotImplementedException(); - } - - public bool TryVerifyHash( - Stream dataStream, - byte[] hash) - { - Contract.Requires(dataStream==null || dataStream.CanRead, "The \"dataStream\" cannot be read from."); - Contract.Requires(dataStream==null || hash!=null, "hash"); - Contract.Ensures(dataStream!=null || Contract.Result()==(hash==null), "Invalid return value."); - - throw new NotImplementedException(); - } - - public byte[] Hash( - byte[] data) - { - Contract.Ensures(!(data==null ^ Contract.Result()==null), "Invalid return value."); - - throw new NotImplementedException(); - } - - public bool TryVerifyHash(byte[] data, byte[] hash) - { - Contract.Requires(data==null || hash!=null, "hash"); - Contract.Ensures(data!=null || Contract.Result()==(hash==null), "Invalid return value."); - - throw new NotImplementedException(); - } - - #endregion - - #region IDisposable Members - - public void Dispose() - { - throw new NotImplementedException(); - } - - #endregion - } -} diff --git a/Aspects/Security/Cryptography/Ciphers/Contracts/IKeyLocationStrategyContract.cs b/Aspects/Security/Cryptography/Ciphers/Contracts/IKeyLocationStrategyContract.cs deleted file mode 100644 index 7e06599..0000000 --- a/Aspects/Security/Cryptography/Ciphers/Contracts/IKeyLocationStrategyContract.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Diagnostics.Contracts; - -namespace vm.Aspects.Security.Cryptography.Ciphers.Contracts -{ - [ContractClassFor(typeof(IKeyLocationStrategy))] - abstract class IKeyLocationStrategyContract : IKeyLocationStrategy - { - #region IKeyLocationStrategy Members - public string GetKeyLocation(string keyLocation) - { - Contract.Ensures(!string.IsNullOrWhiteSpace(Contract.Result()), "The key location cannot be null, empty or consist of whitespace characters only."); - - throw new NotImplementedException(); - } - #endregion - } -} diff --git a/Aspects/Security/Cryptography/Ciphers/Contracts/IKeyManagementContract.cs b/Aspects/Security/Cryptography/Ciphers/Contracts/IKeyManagementContract.cs deleted file mode 100644 index 991af43..0000000 --- a/Aspects/Security/Cryptography/Ciphers/Contracts/IKeyManagementContract.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using System.Diagnostics.Contracts; -using System.Threading.Tasks; - -namespace vm.Aspects.Security.Cryptography.Ciphers.Contracts -{ - [ContractClassFor(typeof(IKeyManagement))] - abstract class IKeyManagementContract : IKeyManagement - { - #region IKeyManagement Members - public string KeyLocation - { - get - { - Contract.Ensures(!String.IsNullOrEmpty(Contract.Result()), "The key location cannot be null, empty or consist of whitespace characters only."); - - throw new NotImplementedException(); - } - } - - public byte[] ExportSymmetricKey() - { - throw new NotImplementedException(); - } - - public Task ExportSymmetricKeyAsync() - { - throw new NotImplementedException(); - } - - public void ImportSymmetricKey(byte[] key) - { - Contract.Requires(key != null, "key"); - Contract.Requires(key.Length > 0, "The length of the imported key is 0"); - - throw new NotImplementedException(); - } - - public Task ImportSymmetricKeyAsync(byte[] key) - { - Contract.Requires(key != null, "key"); - Contract.Requires(key.Length > 0, "The length of the imported key is 0"); - - throw new NotImplementedException(); - } - #endregion - } -} diff --git a/Aspects/Security/Cryptography/Ciphers/Contracts/IKeyStorageAsyncContract.cs b/Aspects/Security/Cryptography/Ciphers/Contracts/IKeyStorageAsyncContract.cs deleted file mode 100644 index c3e1661..0000000 --- a/Aspects/Security/Cryptography/Ciphers/Contracts/IKeyStorageAsyncContract.cs +++ /dev/null @@ -1,62 +0,0 @@ -using System; -using System.Diagnostics.CodeAnalysis; -using System.Diagnostics.Contracts; -using System.Threading.Tasks; - -namespace vm.Aspects.Security.Cryptography.Ciphers.Contracts -{ - [ContractClassFor(typeof(IKeyStorageAsync))] - abstract class IKeyStorageAsyncContract : IKeyStorageAsync - { - #region IKeyStorage Members - public bool KeyLocationExists( - string keyLocation) - { - throw new NotImplementedException(); - } - - [SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId="0")] - public void PutKey( - byte[] key, - string keyLocation) - { - throw new NotImplementedException(); - } - - public byte[] GetKey( - string keyLocation) - { - throw new NotImplementedException(); - } - - public void DeleteKeyLocation( - string keyLocation) - { - throw new NotImplementedException(); - } - #endregion - - #region IKeyStorageAsync Members - [SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId="0")] - public Task PutKeyAsync(byte[] key, string keyLocation) - { - Contract.Requires(key != null, "key"); - Contract.Requires(key.Length != 0, "The length of the array in the argument \"key\" cannot be 0."); - Contract.Requires(keyLocation != null, "keyLocation"); - Contract.Requires(!string.IsNullOrWhiteSpace(keyLocation), "The argument \"keyLocation\" cannot be empty or consist of whitespace characters only."); - - throw new NotImplementedException(); - } - - public Task GetKeyAsync(string keyLocation) - { - Contract.Requires(keyLocation != null, "keyLocation"); - Contract.Requires(!string.IsNullOrWhiteSpace(keyLocation), "The argument \"keyLocation\" cannot be empty or consist of whitespace characters only."); - Contract.Ensures(Contract.Result() != null, "The returned value is null."); - Contract.Ensures(Contract.Result().Length != 0, "The returned value has 0 length."); - - throw new NotImplementedException(); - } - #endregion - } -} diff --git a/Aspects/Security/Cryptography/Ciphers/Contracts/IKeyStorageContract.cs b/Aspects/Security/Cryptography/Ciphers/Contracts/IKeyStorageContract.cs deleted file mode 100644 index c7083b9..0000000 --- a/Aspects/Security/Cryptography/Ciphers/Contracts/IKeyStorageContract.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using System.Diagnostics.CodeAnalysis; -using System.Diagnostics.Contracts; - -namespace vm.Aspects.Security.Cryptography.Ciphers.Contracts -{ - [ContractClassFor(typeof(IKeyStorage))] - abstract class IKeyStorageContract : IKeyStorage - { - #region IKeyStorage Members - - public bool KeyLocationExists(string keyLocation) - { - Contract.Requires(keyLocation != null, "keyLocation"); - Contract.Requires(!string.IsNullOrWhiteSpace(keyLocation), "The argument \"keyLocation\" cannot be empty or consist of whitespace characters only."); - - throw new NotImplementedException(); - } - - [SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId="0")] - public void PutKey(byte[] key, string keyLocation) - { - Contract.Requires(key != null, "key"); - Contract.Requires(key.Length != 0, "The length of the array in the argument \"key\" cannot be 0."); - Contract.Requires(keyLocation != null, "keyLocation"); - Contract.Requires(!string.IsNullOrWhiteSpace(keyLocation), "The argument \"keyLocation\" cannot be empty or consist of whitespace characters only."); - - throw new NotImplementedException(); - } - - public byte[] GetKey(string keyLocation) - { - Contract.Requires(keyLocation != null, "keyLocation"); - Contract.Requires(!string.IsNullOrWhiteSpace(keyLocation), "The argument \"keyLocation\" cannot be empty or consist of whitespace characters only."); - Contract.Ensures(Contract.Result() != null, "The returned key is null."); - Contract.Ensures(Contract.Result().Length != 0, "The returned key has 0 length."); - - throw new NotImplementedException(); - } - - public void DeleteKeyLocation(string keyLocation) - { - throw new NotImplementedException(); - } - - #endregion - } -} diff --git a/Aspects/Security/Cryptography/Ciphers/Contracts/ISymmetricAlgorithmFactoryContract.cs b/Aspects/Security/Cryptography/Ciphers/Contracts/ISymmetricAlgorithmFactoryContract.cs deleted file mode 100644 index da79404..0000000 --- a/Aspects/Security/Cryptography/Ciphers/Contracts/ISymmetricAlgorithmFactoryContract.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; -using System.Diagnostics.Contracts; -using System.Security.Cryptography; - -namespace vm.Aspects.Security.Cryptography.Ciphers.Contracts -{ - [ContractClassFor(typeof(ISymmetricAlgorithmFactory))] - abstract class ISymmetricAlgorithmFactoryContract : ISymmetricAlgorithmFactory - { - #region ISymmetricAlgorithmFactory Members - public void Initialize( - string symmetricAlgorithmName) - { - } - - public SymmetricAlgorithm Create() - { - Contract.Ensures(Contract.Result() != null, "Could not create a symmetric algorithm."); - - throw new NotImplementedException(); - } - - public string SymmetricAlgorithmName - { - get { throw new NotImplementedException(); } - } - #endregion - - #region IDisposable Members - public void Dispose() - { - throw new NotImplementedException(); - } - #endregion - } -} diff --git a/Aspects/Security/Cryptography/Ciphers/Contracts/SymmetricKeyCipherBaseContract.cs b/Aspects/Security/Cryptography/Ciphers/Contracts/SymmetricKeyCipherBaseContract.cs deleted file mode 100644 index 60d0294..0000000 --- a/Aspects/Security/Cryptography/Ciphers/Contracts/SymmetricKeyCipherBaseContract.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using System.Diagnostics.Contracts; - -namespace vm.Aspects.Security.Cryptography.Ciphers.Contracts -{ - [ContractClassFor(typeof(SymmetricKeyCipherBase))] - abstract class SymmetricKeyCipherBaseContract : SymmetricKeyCipherBase - { - protected SymmetricKeyCipherBaseContract() - : base(null) - { - } - - protected override byte[] EncryptSymmetricKey() - { - Contract.Ensures(Contract.Result() != null && Contract.Result().Length > 0, "The method returned null or empty encrypted key."); - - throw new NotImplementedException(); - } - - protected override void DecryptSymmetricKey( - byte[] encryptedKey) - { - Contract.Requires(encryptedKey != null, "encryptedKey"); - Contract.Requires(encryptedKey.Length > 0, "The argument \"encryptedKey\" cannot be empty."); - - throw new NotImplementedException(); - } - } -} diff --git a/Aspects/Security/Cryptography/Ciphers/Contracts/Xml/IXmlCipherContract.cs b/Aspects/Security/Cryptography/Ciphers/Contracts/Xml/IXmlCipherContract.cs deleted file mode 100644 index eef1e3d..0000000 --- a/Aspects/Security/Cryptography/Ciphers/Contracts/Xml/IXmlCipherContract.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System; -using System.Diagnostics.Contracts; -using System.Xml; -using vm.Aspects.Security.Cryptography.Ciphers.Xml; - -namespace vm.Aspects.Security.Cryptography.Ciphers.Contracts.Xml -{ - [ContractClassFor(typeof(IXmlCipher))] - abstract class IXmlCipherContract : IXmlCipher - { - #region IXmlCipher Members - - public bool ContentOnly - { - get - { - throw new NotImplementedException(); - } - set - { - throw new NotImplementedException(); - } - } - - public void Encrypt( - XmlDocument document, - string xmlPath = null, - XmlNamespaceManager namespaceManager = null) - { - Contract.Requires(document != null, "document"); - throw new NotImplementedException(); - } - - public void Decrypt( - XmlDocument document) - { - Contract.Requires(document != null, "document"); - throw new NotImplementedException(); - } - - #endregion - - #region IDisposable Members - - public void Dispose() - { - throw new NotImplementedException(); - } - - #endregion - } -} diff --git a/Aspects/Security/Cryptography/Ciphers/Contracts/Xml/IXmlSignerContract.cs b/Aspects/Security/Cryptography/Ciphers/Contracts/Xml/IXmlSignerContract.cs deleted file mode 100644 index 7144454..0000000 --- a/Aspects/Security/Cryptography/Ciphers/Contracts/Xml/IXmlSignerContract.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System; -using System.Diagnostics.Contracts; -using System.Xml; -using vm.Aspects.Security.Cryptography.Ciphers.Xml; - -namespace vm.Aspects.Security.Cryptography.Ciphers.Contracts.Xml -{ - [ContractClassFor(typeof(IXmlSigner))] - abstract class IXmlSignerContract : IXmlSigner - { - #region IXmlSigner Members - - public SignatureLocation SignatureLocation - { - get - { - Contract.Ensures(Enum.IsDefined(typeof(SignatureLocation), Contract.Result()), "The value of the property is not a valid SignatureLocation value."); - throw new NotImplementedException(); - } - set - { - Contract.Requires(Enum.IsDefined(typeof(SignatureLocation), value), "The value is not a valid SignatureLocation value."); - throw new NotImplementedException(); - } - } - - public bool IncludeKeyInfo - { - get - { - throw new NotImplementedException(); - } - set - { - throw new NotImplementedException(); - } - } - - public XmlDocument Sign( - XmlDocument document, - string xmlPath = null, - XmlNamespaceManager namespaceManager = null, - Uri documentLocation = null) - { - Contract.Requires(document != null, "document"); - throw new NotImplementedException(); - } - - public bool TryVerifySignature( - XmlDocument document, - XmlDocument signature = null) - { - Contract.Requires(document != null, "document"); - throw new NotImplementedException(); - } - - #endregion - - #region IDisposable Members - - public void Dispose() - { - throw new NotImplementedException(); - } - - #endregion - } -} diff --git a/Aspects/Security/Cryptography/Ciphers/Hasher.cs b/Aspects/Security/Cryptography/Ciphers/Hasher.cs index 40b696c..3f216ac 100644 --- a/Aspects/Security/Cryptography/Ciphers/Hasher.cs +++ b/Aspects/Security/Cryptography/Ciphers/Hasher.cs @@ -77,7 +77,12 @@ public Hasher( /// public string HashAlgorithmName { - get { return _hashAlgorithm.GetType().FullName; } + get + { + Contract.Ensures(!string.IsNullOrWhiteSpace(Contract.Result())); + + return _hashAlgorithm.GetType().FullName; + } } /// diff --git a/Aspects/Security/Cryptography/Ciphers/ICipher.cs b/Aspects/Security/Cryptography/Ciphers/ICipher.cs index 49bb6e6..71b294a 100644 --- a/Aspects/Security/Cryptography/Ciphers/ICipher.cs +++ b/Aspects/Security/Cryptography/Ciphers/ICipher.cs @@ -1,7 +1,6 @@ using System; using System.Diagnostics.Contracts; using System.IO; -using vm.Aspects.Security.Cryptography.Ciphers.Contracts; namespace vm.Aspects.Security.Cryptography.Ciphers { @@ -112,4 +111,53 @@ byte[] Encrypt( byte[] Decrypt( byte[] encryptedData); } + + [ContractClassFor(typeof(ICipher))] + abstract class ICipherContract : ICipher + { + #region ICipher Members + public bool Base64Encoded { get; set; } + + public void Encrypt(Stream dataStream, Stream encryptedStream) + { + Contract.Requires(dataStream != null, "dataStream"); + Contract.Requires(encryptedStream != null, "encryptedStream"); + Contract.Requires(dataStream.CanRead, "The argument \"dataStream\" cannot be read from."); + Contract.Requires(encryptedStream.CanWrite, "The argument \"encryptedStream\" cannot be written to."); + + throw new NotImplementedException(); + } + + public void Decrypt(Stream encryptedStream, Stream dataStream) + { + Contract.Requires(encryptedStream != null, "encryptedStream"); + Contract.Requires(dataStream != null, "dataStream"); + Contract.Requires(encryptedStream.CanRead, "The argument \"dataStream\" cannot be read from."); + Contract.Requires(dataStream.CanWrite, "The argument \"encryptedStream\" cannot be written to."); + + throw new NotImplementedException(); + } + + public byte[] Encrypt(byte[] data) + { + Contract.Ensures(!(data==null ^ Contract.Result()==null)); + + throw new NotImplementedException(); + } + + public byte[] Decrypt(byte[] encryptedData) + { + Contract.Ensures(!(encryptedData==null ^ Contract.Result()==null)); + + throw new NotImplementedException(); + } + #endregion + + #region IDisposable Members + public void Dispose() + { + throw new NotImplementedException(); + } + #endregion + } } diff --git a/Aspects/Security/Cryptography/Ciphers/ICipherAsync.cs b/Aspects/Security/Cryptography/Ciphers/ICipherAsync.cs index 91e7542..f685d63 100644 --- a/Aspects/Security/Cryptography/Ciphers/ICipherAsync.cs +++ b/Aspects/Security/Cryptography/Ciphers/ICipherAsync.cs @@ -1,7 +1,7 @@ -using System.Diagnostics.Contracts; +using System; +using System.Diagnostics.Contracts; using System.IO; using System.Threading.Tasks; -using vm.Aspects.Security.Cryptography.Ciphers.Contracts; namespace vm.Aspects.Security.Cryptography.Ciphers { @@ -74,4 +74,68 @@ Task DecryptAsync( Stream encryptedStream, Stream dataStream); } + + [ContractClassFor(typeof(ICipherAsync))] + abstract class ICipherAsyncContract : ICipherAsync + { + #region ICipherAsync Members + public Task EncryptAsync(Stream dataStream, Stream encryptedStream) + { + Contract.Requires(dataStream != null, "dataStream"); + Contract.Requires(encryptedStream != null, "encryptedStream"); + Contract.Requires(dataStream.CanRead, "The argument \"dataStream\" cannot be read from."); + Contract.Requires(encryptedStream.CanWrite, "The argument \"encryptedStream\" cannot be written to."); + + throw new NotImplementedException(); + } + + public Task DecryptAsync(Stream encryptedStream, Stream dataStream) + { + Contract.Requires(encryptedStream != null, "encryptedStream"); + Contract.Requires(dataStream != null, "dataStream"); + Contract.Requires(encryptedStream.CanRead, "The argument \"dataStream\" cannot be read from."); + Contract.Requires(dataStream.CanWrite, "The argument \"encryptedStream\" cannot be written to."); + + throw new NotImplementedException(); + } + #endregion + + #region ICipher Members + public bool Base64Encoded { get; set; } + + public void Encrypt( + Stream dataStream, + Stream encryptedStream) + { + throw new NotImplementedException(); + } + + public void Decrypt( + Stream encryptedStream, + Stream dataStream) + { + throw new NotImplementedException(); + } + + public byte[] Encrypt(byte[] data) + { + throw new NotImplementedException(); + } + + public byte[] Decrypt(byte[] encryptedData) + { + throw new NotImplementedException(); + } + + #endregion + + #region IDisposable Members + + public void Dispose() + { + throw new NotImplementedException(); + } + + #endregion + } } diff --git a/Aspects/Security/Cryptography/Ciphers/IHashAlgorithmFactory.cs b/Aspects/Security/Cryptography/Ciphers/IHashAlgorithmFactory.cs index c904116..1d824db 100644 --- a/Aspects/Security/Cryptography/Ciphers/IHashAlgorithmFactory.cs +++ b/Aspects/Security/Cryptography/Ciphers/IHashAlgorithmFactory.cs @@ -1,7 +1,6 @@ using System; using System.Diagnostics.Contracts; using System.Security.Cryptography; -using vm.Aspects.Security.Cryptography.Ciphers.Contracts; namespace vm.Aspects.Security.Cryptography.Ciphers { @@ -34,4 +33,39 @@ public interface IHashAlgorithmFactory : IDisposable /// The name of the hash algorithm. string HashAlgorithmName { get; } } + + [ContractClassFor(typeof(IHashAlgorithmFactory))] + abstract class IHashAlgorithmFactoryContract : IHashAlgorithmFactory + { + #region IHashAlgorithmFactory Members + + public void Initialize( + string hashAlgorithmName) + { + throw new NotImplementedException(); + } + + public HashAlgorithm Create() + { + Contract.Ensures(Contract.Result() != null, "Could not create a hash algorithm."); + + throw new NotImplementedException(); + } + + public string HashAlgorithmName + { + get { throw new NotImplementedException(); } + } + + #endregion + + #region IDisposable Members + + public void Dispose() + { + throw new NotImplementedException(); + } + + #endregion + } } diff --git a/Aspects/Security/Cryptography/Ciphers/IHasher.cs b/Aspects/Security/Cryptography/Ciphers/IHasher.cs index b504ff5..7b010d5 100644 --- a/Aspects/Security/Cryptography/Ciphers/IHasher.cs +++ b/Aspects/Security/Cryptography/Ciphers/IHasher.cs @@ -1,7 +1,6 @@ using System; using System.Diagnostics.Contracts; using System.IO; -using vm.Aspects.Security.Cryptography.Ciphers.Contracts; namespace vm.Aspects.Security.Cryptography.Ciphers { @@ -77,4 +76,73 @@ public interface IHasher : IDisposable /// The hash or the encryption failed. bool TryVerifyHash(byte[] data, byte[] hash); } + + [ContractClassFor(typeof(IHasher))] + abstract class IHasherContract : IHasher + { + #region IHasher Members + + public int SaltLength + { + get + { + Contract.Ensures(Contract.Result()==0 || Contract.Result()>=Hasher.DefaultSaltLength, "The salt length should be either 0 or not less than 8 bytes."); + + throw new NotImplementedException(); + } + set + { + Contract.Requires(value==0 || value>=8, "The salt length should be either 0 or not less than 8 bytes."); + + throw new NotImplementedException(); + } + } + + public byte[] Hash( + Stream dataStream) + { + Contract.Requires(dataStream==null || dataStream.CanRead, "The \"dataStream\" cannot be read from."); + Contract.Ensures(!(dataStream==null ^ Contract.Result()==null), "The returned value is invalid."); + + throw new NotImplementedException(); + } + + public bool TryVerifyHash( + Stream dataStream, + byte[] hash) + { + Contract.Requires(dataStream==null || dataStream.CanRead, "The \"dataStream\" cannot be read from."); + Contract.Requires(dataStream==null || hash!=null, "hash"); + Contract.Ensures(dataStream!=null || Contract.Result()==(hash==null), "Invalid return value."); + + throw new NotImplementedException(); + } + + public byte[] Hash( + byte[] data) + { + Contract.Ensures(!(data==null ^ Contract.Result()==null), "Invalid return value."); + + throw new NotImplementedException(); + } + + public bool TryVerifyHash(byte[] data, byte[] hash) + { + Contract.Requires(data==null || hash!=null, "hash"); + Contract.Ensures(data!=null || Contract.Result()==(hash==null), "Invalid return value."); + + throw new NotImplementedException(); + } + + #endregion + + #region IDisposable Members + + public void Dispose() + { + throw new NotImplementedException(); + } + + #endregion + } } diff --git a/Aspects/Security/Cryptography/Ciphers/IHasherAsync.cs b/Aspects/Security/Cryptography/Ciphers/IHasherAsync.cs index 3a3ca09..b8f83c7 100644 --- a/Aspects/Security/Cryptography/Ciphers/IHasherAsync.cs +++ b/Aspects/Security/Cryptography/Ciphers/IHasherAsync.cs @@ -1,7 +1,7 @@ -using System.Diagnostics.Contracts; +using System; +using System.Diagnostics.Contracts; using System.IO; using System.Threading.Tasks; -using vm.Aspects.Security.Cryptography.Ciphers.Contracts; namespace vm.Aspects.Security.Cryptography.Ciphers { @@ -52,4 +52,74 @@ public interface IHasherAsync : IHasher /// The hash or the encryption failed. Task TryVerifyHashAsync(Stream dataStream, byte[] hash); } + + [ContractClassFor(typeof(IHasherAsync))] + abstract class IHasherAsyncContract : IHasherAsync + { + #region IHasherAsync Members + + public Task HashAsync(Stream dataStream) + { + Contract.Requires(dataStream==null || dataStream.CanRead, "The \"dataStream\" cannot be read from."); + Contract.Ensures(!(dataStream==null ^ Contract.Result()==null), "The returned value is invalid."); + + throw new NotImplementedException(); + } + + public Task TryVerifyHashAsync(Stream dataStream, byte[] hash) + { + Contract.Requires(dataStream==null || dataStream.CanRead, "The \"dataStream\" cannot be read from."); + Contract.Requires(dataStream==null || hash!=null, "hash"); + Contract.Ensures(dataStream!=null || Contract.Result()==(hash==null), "Invalid return value."); + + throw new NotImplementedException(); + } + + #endregion + + #region IHasher Members + + public int SaltLength + { + get + { + throw new NotImplementedException(); + } + set + { + throw new NotImplementedException(); + } + } + + public byte[] Hash(System.IO.Stream dataStream) + { + throw new NotImplementedException(); + } + + public bool TryVerifyHash(System.IO.Stream dataStream, byte[] hash) + { + throw new NotImplementedException(); + } + + public byte[] Hash(byte[] data) + { + throw new NotImplementedException(); + } + + public bool TryVerifyHash(byte[] data, byte[] hash) + { + throw new NotImplementedException(); + } + + #endregion + + #region IDisposable Members + + public void Dispose() + { + throw new NotImplementedException(); + } + + #endregion + } } diff --git a/Aspects/Security/Cryptography/Ciphers/IKeyLocationStrategy.cs b/Aspects/Security/Cryptography/Ciphers/IKeyLocationStrategy.cs index 0e385e4..487416d 100644 --- a/Aspects/Security/Cryptography/Ciphers/IKeyLocationStrategy.cs +++ b/Aspects/Security/Cryptography/Ciphers/IKeyLocationStrategy.cs @@ -1,5 +1,5 @@ -using System.Diagnostics.Contracts; -using vm.Aspects.Security.Cryptography.Ciphers.Contracts; +using System; +using System.Diagnostics.Contracts; namespace vm.Aspects.Security.Cryptography.Ciphers { @@ -36,4 +36,17 @@ public interface IKeyLocationStrategy /// string GetKeyLocation(string keyLocation); } + + [ContractClassFor(typeof(IKeyLocationStrategy))] + abstract class IKeyLocationStrategyContract : IKeyLocationStrategy + { + #region IKeyLocationStrategy Members + public string GetKeyLocation(string keyLocation) + { + Contract.Ensures(!string.IsNullOrWhiteSpace(Contract.Result()), "The key location cannot be null, empty or consist of whitespace characters only."); + + throw new NotImplementedException(); + } + #endregion + } } diff --git a/Aspects/Security/Cryptography/Ciphers/IKeyManagement.cs b/Aspects/Security/Cryptography/Ciphers/IKeyManagement.cs index de71035..b31c74d 100644 --- a/Aspects/Security/Cryptography/Ciphers/IKeyManagement.cs +++ b/Aspects/Security/Cryptography/Ciphers/IKeyManagement.cs @@ -1,7 +1,7 @@  +using System; using System.Diagnostics.Contracts; using System.Threading.Tasks; -using vm.Aspects.Security.Cryptography.Ciphers.Contracts; namespace vm.Aspects.Security.Cryptography.Ciphers { @@ -46,4 +46,46 @@ public interface IKeyManagement /// Task ImportSymmetricKeyAsync(byte[] key); } + + [ContractClassFor(typeof(IKeyManagement))] + abstract class IKeyManagementContract : IKeyManagement + { + #region IKeyManagement Members + public string KeyLocation + { + get + { + Contract.Ensures(!string.IsNullOrEmpty(Contract.Result()), "The key location cannot be null, empty or consist of whitespace characters only."); + + throw new NotImplementedException(); + } + } + + public byte[] ExportSymmetricKey() + { + throw new NotImplementedException(); + } + + public Task ExportSymmetricKeyAsync() + { + throw new NotImplementedException(); + } + + public void ImportSymmetricKey(byte[] key) + { + Contract.Requires(key != null, "key"); + Contract.Requires(key.Length > 0, "The length of the imported key is 0"); + + throw new NotImplementedException(); + } + + public Task ImportSymmetricKeyAsync(byte[] key) + { + Contract.Requires(key != null, "key"); + Contract.Requires(key.Length > 0, "The length of the imported key is 0"); + + throw new NotImplementedException(); + } + #endregion + } } diff --git a/Aspects/Security/Cryptography/Ciphers/IKeyStorage.cs b/Aspects/Security/Cryptography/Ciphers/IKeyStorage.cs index ae75357..2a37101 100644 --- a/Aspects/Security/Cryptography/Ciphers/IKeyStorage.cs +++ b/Aspects/Security/Cryptography/Ciphers/IKeyStorage.cs @@ -1,5 +1,5 @@ -using System.Diagnostics.Contracts; -using vm.Aspects.Security.Cryptography.Ciphers.Contracts; +using System; +using System.Diagnostics.Contracts; namespace vm.Aspects.Security.Cryptography.Ciphers { @@ -37,4 +37,45 @@ public interface IKeyStorage /// The key location name to be deleted. void DeleteKeyLocation(string keyLocation); } + + [ContractClassFor(typeof(IKeyStorage))] + abstract class IKeyStorageContract : IKeyStorage + { + #region IKeyStorage Members + + public bool KeyLocationExists(string keyLocation) + { + Contract.Requires(keyLocation != null, "keyLocation"); + Contract.Requires(!string.IsNullOrWhiteSpace(keyLocation), "The argument \"keyLocation\" cannot be empty or consist of whitespace characters only."); + + throw new NotImplementedException(); + } + + public void PutKey(byte[] key, string keyLocation) + { + Contract.Requires(key != null, "key"); + Contract.Requires(key.Length != 0, "The length of the array in the argument \"key\" cannot be 0."); + Contract.Requires(keyLocation != null, "keyLocation"); + Contract.Requires(!string.IsNullOrWhiteSpace(keyLocation), "The argument \"keyLocation\" cannot be empty or consist of whitespace characters only."); + + throw new NotImplementedException(); + } + + public byte[] GetKey(string keyLocation) + { + Contract.Requires(keyLocation != null, "keyLocation"); + Contract.Requires(!string.IsNullOrWhiteSpace(keyLocation), "The argument \"keyLocation\" cannot be empty or consist of whitespace characters only."); + Contract.Ensures(Contract.Result() != null, "The returned key is null."); + Contract.Ensures(Contract.Result().Length != 0, "The returned key has 0 length."); + + throw new NotImplementedException(); + } + + public void DeleteKeyLocation(string keyLocation) + { + throw new NotImplementedException(); + } + + #endregion + } } diff --git a/Aspects/Security/Cryptography/Ciphers/IKeyStorageAsync.cs b/Aspects/Security/Cryptography/Ciphers/IKeyStorageAsync.cs index 6e2d199..51ed3f6 100644 --- a/Aspects/Security/Cryptography/Ciphers/IKeyStorageAsync.cs +++ b/Aspects/Security/Cryptography/Ciphers/IKeyStorageAsync.cs @@ -1,6 +1,6 @@ -using System.Diagnostics.Contracts; +using System; +using System.Diagnostics.Contracts; using System.Threading.Tasks; -using vm.Aspects.Security.Cryptography.Ciphers.Contracts; namespace vm.Aspects.Security.Cryptography.Ciphers { @@ -26,4 +26,57 @@ public interface IKeyStorageAsync : IKeyStorage /// A object representing the process of getting the encrypted symmetric key from the storage. Task GetKeyAsync(string keyLocation); } + + [ContractClassFor(typeof(IKeyStorageAsync))] + abstract class IKeyStorageAsyncContract : IKeyStorageAsync + { + #region IKeyStorage Members + public bool KeyLocationExists( + string keyLocation) + { + throw new NotImplementedException(); + } + + public void PutKey( + byte[] key, + string keyLocation) + { + throw new NotImplementedException(); + } + + public byte[] GetKey( + string keyLocation) + { + throw new NotImplementedException(); + } + + public void DeleteKeyLocation( + string keyLocation) + { + throw new NotImplementedException(); + } + #endregion + + #region IKeyStorageAsync Members + public Task PutKeyAsync(byte[] key, string keyLocation) + { + Contract.Requires(key != null, "key"); + Contract.Requires(key.Length != 0, "The length of the array in the argument \"key\" cannot be 0."); + Contract.Requires(keyLocation != null, "keyLocation"); + Contract.Requires(!string.IsNullOrWhiteSpace(keyLocation), "The argument \"keyLocation\" cannot be empty or consist of whitespace characters only."); + + throw new NotImplementedException(); + } + + public Task GetKeyAsync(string keyLocation) + { + Contract.Requires(keyLocation != null, "keyLocation"); + Contract.Requires(!string.IsNullOrWhiteSpace(keyLocation), "The argument \"keyLocation\" cannot be empty or consist of whitespace characters only."); + Contract.Ensures(Contract.Result() != null, "The returned value is null."); + Contract.Ensures(Contract.Result().Length != 0, "The returned value has 0 length."); + + throw new NotImplementedException(); + } + #endregion + } } diff --git a/Aspects/Security/Cryptography/Ciphers/ISymmetricAlgorithmFactory.cs b/Aspects/Security/Cryptography/Ciphers/ISymmetricAlgorithmFactory.cs index 0bca206..f11750d 100644 --- a/Aspects/Security/Cryptography/Ciphers/ISymmetricAlgorithmFactory.cs +++ b/Aspects/Security/Cryptography/Ciphers/ISymmetricAlgorithmFactory.cs @@ -1,7 +1,6 @@ using System; using System.Diagnostics.Contracts; using System.Security.Cryptography; -using vm.Aspects.Security.Cryptography.Ciphers.Contracts; namespace vm.Aspects.Security.Cryptography.Ciphers { @@ -34,4 +33,34 @@ public interface ISymmetricAlgorithmFactory : IDisposable /// The name of the symmetric algorithm. string SymmetricAlgorithmName { get; } } + + [ContractClassFor(typeof(ISymmetricAlgorithmFactory))] + abstract class ISymmetricAlgorithmFactoryContract : ISymmetricAlgorithmFactory + { + #region ISymmetricAlgorithmFactory Members + public void Initialize( + string symmetricAlgorithmName) + { + } + + public SymmetricAlgorithm Create() + { + Contract.Ensures(Contract.Result() != null, "Could not create a symmetric algorithm."); + + throw new NotImplementedException(); + } + + public string SymmetricAlgorithmName + { + get { throw new NotImplementedException(); } + } + #endregion + + #region IDisposable Members + public void Dispose() + { + throw new NotImplementedException(); + } + #endregion + } } diff --git a/Aspects/Security/Cryptography/Ciphers/SymmetricAlgorithmFactory.cs b/Aspects/Security/Cryptography/Ciphers/SymmetricAlgorithmFactory.cs index 24cd64e..6957141 100644 --- a/Aspects/Security/Cryptography/Ciphers/SymmetricAlgorithmFactory.cs +++ b/Aspects/Security/Cryptography/Ciphers/SymmetricAlgorithmFactory.cs @@ -86,9 +86,9 @@ public void Initialize( } /// - /// Creates a instance. + /// Creates a instance. /// - /// instance. + /// instance. /// public SymmetricAlgorithm Create() { diff --git a/Aspects/Security/Cryptography/Ciphers/SymmetricKeyCipherBase.cs b/Aspects/Security/Cryptography/Ciphers/SymmetricKeyCipherBase.cs index ca6184c..6294c0d 100644 --- a/Aspects/Security/Cryptography/Ciphers/SymmetricKeyCipherBase.cs +++ b/Aspects/Security/Cryptography/Ciphers/SymmetricKeyCipherBase.cs @@ -5,7 +5,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Practices.ServiceLocation; -using vm.Aspects.Security.Cryptography.Ciphers.Contracts; namespace vm.Aspects.Security.Cryptography.Ciphers { @@ -351,4 +350,29 @@ protected virtual void CopyTo( cipher.ShouldEncryptIV = ShouldEncryptIV; } } + + [ContractClassFor(typeof(SymmetricKeyCipherBase))] + abstract class SymmetricKeyCipherBaseContract : SymmetricKeyCipherBase + { + protected SymmetricKeyCipherBaseContract() + : base(null) + { + } + + protected override byte[] EncryptSymmetricKey() + { + Contract.Ensures(Contract.Result() != null && Contract.Result().Length > 0, "The method returned null or empty encrypted key."); + + throw new NotImplementedException(); + } + + protected override void DecryptSymmetricKey( + byte[] encryptedKey) + { + Contract.Requires(encryptedKey != null, "encryptedKey"); + Contract.Requires(encryptedKey.Length > 0, "The argument \"encryptedKey\" cannot be empty."); + + throw new NotImplementedException(); + } + } } diff --git a/Aspects/Security/Cryptography/Ciphers/Test/CreateCertificates.ps1 b/Aspects/Security/Cryptography/Ciphers/Test/CreateCertificates.ps1 index 13516fc..601cdbe 100644 --- a/Aspects/Security/Cryptography/Ciphers/Test/CreateCertificates.ps1 +++ b/Aspects/Security/Cryptography/Ciphers/Test/CreateCertificates.ps1 @@ -32,3 +32,4 @@ if ($Host.Name -eq "ConsoleHost") $Host.UI.RawUI.FlushInputBuffer(); $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyUp") > $null; } + \ No newline at end of file diff --git a/Aspects/Security/Cryptography/Ciphers/Xml/IXmlCipher.cs b/Aspects/Security/Cryptography/Ciphers/Xml/IXmlCipher.cs index 0593abe..5227e49 100644 --- a/Aspects/Security/Cryptography/Ciphers/Xml/IXmlCipher.cs +++ b/Aspects/Security/Cryptography/Ciphers/Xml/IXmlCipher.cs @@ -2,7 +2,6 @@ using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Contracts; using System.Xml; -using vm.Aspects.Security.Cryptography.Ciphers.Contracts.Xml; namespace vm.Aspects.Security.Cryptography.Ciphers.Xml { @@ -39,7 +38,7 @@ public interface IXmlCipher : IDisposable /// /// The specified symmetric algorithm is not supported. Only the TripleDES, DES, AES-128, AES-192 and AES-256 algorithms are supported. /// - [SuppressMessage("Microsoft.Design", "CA1059:MembersShouldNotExposeCertainConcreteTypes", MessageId="System.Xml.XmlNode", Justification="We need here the whole document.")] + [SuppressMessage("Microsoft.Design", "CA1059:MembersShouldNotExposeCertainConcreteTypes", MessageId = "System.Xml.XmlNode", Justification = "We need here the whole document.")] void Encrypt(XmlDocument document, string xmlPath = null, XmlNamespaceManager namespaceManager = null); /// @@ -49,7 +48,52 @@ public interface IXmlCipher : IDisposable /// /// The is . /// - [SuppressMessage("Microsoft.Design", "CA1059:MembersShouldNotExposeCertainConcreteTypes", MessageId="System.Xml.XmlNode", Justification="We need here the whole document.")] + [SuppressMessage("Microsoft.Design", "CA1059:MembersShouldNotExposeCertainConcreteTypes", MessageId = "System.Xml.XmlNode", Justification = "We need here the whole document.")] void Decrypt(XmlDocument document); } + + [ContractClassFor(typeof(IXmlCipher))] + abstract class IXmlCipherContract : IXmlCipher + { + #region IXmlCipher Members + + public bool ContentOnly + { + get + { + throw new NotImplementedException(); + } + set + { + throw new NotImplementedException(); + } + } + + public void Encrypt( + XmlDocument document, + string xmlPath = null, + XmlNamespaceManager namespaceManager = null) + { + Contract.Requires(document != null, "document"); + throw new NotImplementedException(); + } + + public void Decrypt( + XmlDocument document) + { + Contract.Requires(document != null, "document"); + throw new NotImplementedException(); + } + + #endregion + + #region IDisposable Members + + public void Dispose() + { + throw new NotImplementedException(); + } + + #endregion + } } diff --git a/Aspects/Security/Cryptography/Ciphers/Xml/IXmlSigner.cs b/Aspects/Security/Cryptography/Ciphers/Xml/IXmlSigner.cs index a85c7f9..f59148c 100644 --- a/Aspects/Security/Cryptography/Ciphers/Xml/IXmlSigner.cs +++ b/Aspects/Security/Cryptography/Ciphers/Xml/IXmlSigner.cs @@ -2,7 +2,6 @@ using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Contracts; using System.Xml; -using vm.Aspects.Security.Cryptography.Ciphers.Contracts.Xml; namespace vm.Aspects.Security.Cryptography.Ciphers.Xml { @@ -110,7 +109,7 @@ public interface IXmlSigner : IDisposable /// respective elements of the . /// /// - [SuppressMessage("Microsoft.Design", "CA1059:MembersShouldNotExposeCertainConcreteTypes", MessageId="System.Xml.XmlNode", Justification="We need here the whole document.")] + [SuppressMessage("Microsoft.Design", "CA1059:MembersShouldNotExposeCertainConcreteTypes", MessageId = "System.Xml.XmlNode", Justification = "We need here the whole document.")] XmlDocument Sign( XmlDocument document, string xmlPath = null, @@ -141,9 +140,70 @@ XmlDocument Sign( /// /// /// - [SuppressMessage("Microsoft.Design", "CA1059:MembersShouldNotExposeCertainConcreteTypes", MessageId="System.Xml.XmlNode", Justification="We need here the whole document.")] + [SuppressMessage("Microsoft.Design", "CA1059:MembersShouldNotExposeCertainConcreteTypes", MessageId = "System.Xml.XmlNode", Justification = "We need here the whole document.")] bool TryVerifySignature( XmlDocument document, XmlDocument signature = null); } + + [ContractClassFor(typeof(IXmlSigner))] + abstract class IXmlSignerContract : IXmlSigner + { + #region IXmlSigner Members + + public SignatureLocation SignatureLocation + { + get + { + Contract.Ensures(Enum.IsDefined(typeof(SignatureLocation), Contract.Result()), "The value of the property is not a valid SignatureLocation value."); + throw new NotImplementedException(); + } + set + { + Contract.Requires(Enum.IsDefined(typeof(SignatureLocation), value), "The value is not a valid SignatureLocation value."); + throw new NotImplementedException(); + } + } + + public bool IncludeKeyInfo + { + get + { + throw new NotImplementedException(); + } + set + { + throw new NotImplementedException(); + } + } + + public XmlDocument Sign( + XmlDocument document, + string xmlPath = null, + XmlNamespaceManager namespaceManager = null, + Uri documentLocation = null) + { + Contract.Requires(document != null, "document"); + throw new NotImplementedException(); + } + + public bool TryVerifySignature( + XmlDocument document, + XmlDocument signature = null) + { + Contract.Requires(document != null, "document"); + throw new NotImplementedException(); + } + + #endregion + + #region IDisposable Members + + public void Dispose() + { + throw new NotImplementedException(); + } + + #endregion + } } diff --git a/Aspects/Security/Cryptography/Ciphers/vm.Aspects.Security.Cryptography.Ciphers.csproj b/Aspects/Security/Cryptography/Ciphers/vm.Aspects.Security.Cryptography.Ciphers.csproj index 9a11b7f..842cb6e 100644 --- a/Aspects/Security/Cryptography/Ciphers/vm.Aspects.Security.Cryptography.Ciphers.csproj +++ b/Aspects/Security/Cryptography/Ciphers/vm.Aspects.Security.Cryptography.Ciphers.csproj @@ -209,19 +209,6 @@ - - - - - - - - - - - - - From 64ae4c20acc3d74b7cc7ae6815ef42877b68ce29 Mon Sep 17 00:00:00 2001 From: vmelamed Date: Sat, 9 Jan 2016 16:06:12 -0500 Subject: [PATCH 4/8] Marked a bunch of tests with [TestCategory("IntegrationTest")]. Rewrote the cert creation script to use 100% PS. --- .../Tests/EFRepository/EFSpecificsTests.cs | 8 +++ Aspects/Model/Tests/IOrmSpecificsTests.cs | 1 + Aspects/Model/Tests/IRepositoryTest.cs | 21 +++++++ .../Ciphers/Test/CreateCertificates.ps1 | 56 ++++++++++++------- 4 files changed, 65 insertions(+), 21 deletions(-) diff --git a/Aspects/Model/Tests/EFRepository/EFSpecificsTests.cs b/Aspects/Model/Tests/EFRepository/EFSpecificsTests.cs index 4488883..c1b99a1 100644 --- a/Aspects/Model/Tests/EFRepository/EFSpecificsTests.cs +++ b/Aspects/Model/Tests/EFRepository/EFSpecificsTests.cs @@ -54,6 +54,7 @@ protected override IOrmSpecifics GetSpecifics() } [TestMethod] + [TestCategory("IntegrationTest")] public void EnlistInAmbientTransactionRolledBack() { var specifics = GetSpecifics(); @@ -90,6 +91,7 @@ public void EnlistInAmbientTransactionRolledBack() } [TestMethod] + [TestCategory("IntegrationTest")] public override void EnlistInAmbientTransaction() { var specifics = GetSpecifics(); @@ -126,6 +128,7 @@ public override void EnlistInAmbientTransaction() } [TestMethod] + [TestCategory("IntegrationTest")] public override void ObjectIsProxyTest() { try @@ -195,6 +198,7 @@ public override void ObjectIsProxyTest() } [TestMethod] + [TestCategory("IntegrationTest")] public override void ObjectIsLoadedTest() { long id; @@ -249,6 +253,7 @@ public override void ObjectIsLoadedTest() } [TestMethod] + [TestCategory("IntegrationTest")] public override void ObjectIsChangeTrackingTest() { var specifics = GetSpecifics(); @@ -281,6 +286,7 @@ public override void ObjectIsChangeTrackingTest() } [TestMethod] + [TestCategory("IntegrationTest")] public override void ExceptionIsOptimisticConcurrencyTest() { var specifics = GetSpecifics(); @@ -291,6 +297,7 @@ public override void ExceptionIsOptimisticConcurrencyTest() } [TestMethod] + [TestCategory("IntegrationTest")] public override void ExceptionIsConnectionRelatedTest() { // SqlException-s cannot be instantiated or mocked. @@ -298,6 +305,7 @@ public override void ExceptionIsConnectionRelatedTest() } [TestMethod] + [TestCategory("IntegrationTest")] public override void ExceptionIsTransientTest() { var specifics = GetSpecifics(); diff --git a/Aspects/Model/Tests/IOrmSpecificsTests.cs b/Aspects/Model/Tests/IOrmSpecificsTests.cs index 07c0b87..59321a4 100644 --- a/Aspects/Model/Tests/IOrmSpecificsTests.cs +++ b/Aspects/Model/Tests/IOrmSpecificsTests.cs @@ -35,6 +35,7 @@ protected IRepository GetInitializedRepository() protected abstract IOrmSpecifics GetSpecifics(); [TestMethod] + [TestCategory("IntegrationTest")] public void FetchTest() { IRepository target; diff --git a/Aspects/Model/Tests/IRepositoryTest.cs b/Aspects/Model/Tests/IRepositoryTest.cs index 4a25fe3..4d6efb0 100644 --- a/Aspects/Model/Tests/IRepositoryTest.cs +++ b/Aspects/Model/Tests/IRepositoryTest.cs @@ -39,6 +39,7 @@ protected IRepository GetInitializedRepository() } [TestMethod] + [TestCategory("IntegrationTest")] public virtual void InitializeTest() { try @@ -66,6 +67,7 @@ public virtual void InitializeTest() } [TestMethod] + [TestCategory("IntegrationTest")] public virtual void GetGenericStoreIdTest() { var target = GetInitializedRepository(); @@ -85,6 +87,7 @@ public virtual void GetGenericStoreIdTest() } [TestMethod] + [TestCategory("IntegrationTest")] public virtual void CreateEntityTest() { var target = GetInitializedRepository(); @@ -97,6 +100,7 @@ public virtual void CreateEntityTest() } [TestMethod] + [TestCategory("IntegrationTest")] public virtual void CreateValueTest() { var target = GetInitializedRepository(); @@ -109,6 +113,7 @@ public virtual void CreateValueTest() } [TestMethod] + [TestCategory("IntegrationTest")] public virtual void AddTest() { long id; @@ -137,6 +142,7 @@ public virtual void AddTest() } [TestMethod] + [TestCategory("IntegrationTest")] public virtual void AddDerivedTest() { long id, id1; @@ -180,6 +186,7 @@ public virtual void AddDerivedTest() } [TestMethod] + [TestCategory("IntegrationTest")] public virtual void AddBaseTest() { long id2, id1; @@ -223,6 +230,7 @@ public virtual void AddBaseTest() } [TestMethod] + [TestCategory("IntegrationTest")] public virtual void AttachTest() { long id; @@ -253,6 +261,7 @@ public virtual void AttachTest() } [TestMethod] + [TestCategory("IntegrationTest")] public virtual void AttachModifiedTest() { long id; @@ -285,6 +294,7 @@ public virtual void AttachModifiedTest() } [TestMethod] + [TestCategory("IntegrationTest")] public virtual void AttachAddedExistingTest() { long id; @@ -339,6 +349,7 @@ public virtual void AttachAddedExistingTest() } [TestMethod] + [TestCategory("IntegrationTest")] public virtual void AttachAddedNonExistingTest() { long id; @@ -386,6 +397,7 @@ public virtual void AttachAddedNonExistingTest() } [TestMethod] + [TestCategory("IntegrationTest")] public virtual void AttachDeletedExistingTest() { long id; @@ -418,6 +430,7 @@ public virtual void AttachDeletedExistingTest() } [TestMethod] + [TestCategory("IntegrationTest")] public virtual void AttachDeletedNonExistingTest() { long id; @@ -478,6 +491,7 @@ public virtual void AttachDeletedNonExistingTest() } [TestMethod] + [TestCategory("IntegrationTest")] public virtual void DetachTest() { long id; @@ -510,6 +524,7 @@ public virtual void DetachTest() } [TestMethod] + [TestCategory("IntegrationTest")] public virtual void GetByStoreIdExistingTest() { long id; @@ -542,6 +557,7 @@ public virtual void GetByStoreIdExistingTest() } [TestMethod] + [TestCategory("IntegrationTest")] public virtual void GetByStoreIdNotExistingTest() { long id; @@ -559,6 +575,7 @@ public virtual void GetByStoreIdNotExistingTest() } [TestMethod] + [TestCategory("IntegrationTest")] public virtual void DeleteExistingFromContextTest() { long id; @@ -589,6 +606,7 @@ public virtual void DeleteExistingFromContextTest() } [TestMethod] + [TestCategory("IntegrationTest")] public virtual void DeleteExistingTest() { long id; @@ -629,6 +647,7 @@ public virtual void DeleteExistingTest() } [TestMethod] + [TestCategory("IntegrationTest")] public virtual void DeleteNotExistingTest() { long id; @@ -658,6 +677,7 @@ public virtual void DeleteNotExistingTest() } [TestMethod] + [TestCategory("IntegrationTest")] public virtual void EntitiesTest() { IRepository target; @@ -713,6 +733,7 @@ public virtual void EntitiesTest() } [TestMethod] + [TestCategory("IntegrationTest")] public virtual void DetachedEntitiesTest() { IRepository target; diff --git a/Aspects/Security/Cryptography/Ciphers/Test/CreateCertificates.ps1 b/Aspects/Security/Cryptography/Ciphers/Test/CreateCertificates.ps1 index 601cdbe..44498c6 100644 --- a/Aspects/Security/Cryptography/Ciphers/Test/CreateCertificates.ps1 +++ b/Aspects/Security/Cryptography/Ciphers/Test/CreateCertificates.ps1 @@ -1,35 +1,49 @@ +# ------------------------------------------------------------------------------------------------------------------------------- +# Delete all previously created certificates if needed: +# ------------------------------------------------------------------------------------------------------------------------------- +foreach ($c in Get-ChildItem Cert:\CurrentUser\my | + Where-Object {$_.Subject -imatch "vm\..*UnitTest"}) + { Remove-Item ("Cert:\CurrentUser\my\"+$c.Thumbprint); } + +foreach ($c in Get-ChildItem cert:\CurrentUser\TrustedPublisher | + Where-Object {$_.Subject -imatch "vm\..*UnitTest"}) + { Remove-Item ("cert:\CurrentUser\TrustedPublisher\"+$c.Thumbprint); } + # ------------------------------------------------------------------------------------------------------------------------------- # To test SHA1 only signatures use the following commands to create SHA1 only signing certificates (SHA256 will fail with these): # ------------------------------------------------------------------------------------------------------------------------------- -makecert -r -pe -n "CN=vm.SignatureCipherUnitTest" -m 12 -sky signature -ss my -makecert -r -pe -n "CN=vm.EncryptionCipherUnitTest" -m 12 -sky exchange -ss my +#makecert -r -ss my -pe -n "CN=vm.SignatureCipherUnitTest" -m 12 -sky signature +#makecert -r -pe -n "CN=vm.EncryptionCipherUnitTest" -m 12 -sky exchange -ss my +New-SelfSignedCertificate -CertStoreLocation Cert:\CurrentUser\my -KeyExportPolicy Exportable -Subject "CN=vm.SignatureCipherUnitTest" -KeyUsage DigitalSignature -KeyUsageProperty Sign -HashAlgorithm sha1 -Provider "Microsoft Enhanced RSA and AES Cryptographic Provider" -KeyLength 2048 > $null; +New-SelfSignedCertificate -CertStoreLocation Cert:\CurrentUser\my -KeyExportPolicy Exportable -Subject "CN=vm.EncryptionCipherUnitTest" -KeyUsage DataEncipherment -KeyUsageProperty Decrypt -HashAlgorithm sha1 -Provider "Microsoft Enhanced RSA and AES Cryptographic Provider" -KeyLength 2048 > $null; # ---------------------------------------------------------------------------------------------------- # To test SHA1 and SHA256 signatures use the following commands to create SHA256 signing certificates: # ---------------------------------------------------------------------------------------------------- -makecert -r -pe -n "CN=vm.Sha256SignatureCipherUnitTest" -m 12 -sky signature -ss my -a sha256 -sp "Microsoft Enhanced RSA and AES Cryptographic Provider" -sy 24 -makecert -r -pe -n "CN=vm.Sha256EncryptionCipherUnitTest" -m 12 -sky exchange -ss my -a sha256 -sp "Microsoft Enhanced RSA and AES Cryptographic Provider" -sy 24 +#makecert -r -pe -n "CN=vm.Sha256SignatureCipherUnitTest" -m 12 -sky signature -ss my -a sha256 -sp "Microsoft Enhanced RSA and AES Cryptographic Provider" -sy 24 +#makecert -r -pe -n "CN=vm.Sha256EncryptionCipherUnitTest" -m 12 -sky exchange -ss my -a sha256 -sp "Microsoft Enhanced RSA and AES Cryptographic Provider" -sy 24 +New-SelfSignedCertificate -CertStoreLocation Cert:\CurrentUser\my -KeyExportPolicy Exportable -Subject "CN=vm.Sha256SignatureCipherUnitTest" -KeyUsage DigitalSignature -KeyUsageProperty Sign -HashAlgorithm sha256 -Provider "Microsoft Enhanced RSA and AES Cryptographic Provider" -KeyLength 2048 > $null; +New-SelfSignedCertificate -CertStoreLocation Cert:\CurrentUser\my -KeyExportPolicy Exportable -Subject "CN=vm.Sha256EncryptionCipherUnitTest" -KeyUsage DataEncipherment -KeyUsageProperty Decrypt -HashAlgorithm sha256 -Provider "Microsoft Enhanced RSA and AES Cryptographic Provider" -KeyLength 2048 > $null; # export the created certificates into files, without the private keys -dir cert:\CurrentUser\My | - where-object { $_.Subject -like 'CN=vm.*'} | - foreach-object { - $path = $_.Subject -replace "cn=", ""; - $path = "$($path).cer"; - export-certificate -cert $_ -filepath $path - }; +Get-ChildItem cert:\CurrentUser\My | + where-object { $_.Subject -like 'CN=vm.*'} | + ForEach-Object { + $path = $_.Subject -replace "cn=", ""; + $path = "$($path).cer"; + Export-Certificate -Cert $_ -FilePath $path + }; # import them to "Other People" -dir vm.*.cer | - foreach { - import-certificate $_ -certstorelocation cert:\CurrentUser\TrustedPublisher - } > $null; -# clean-up -del vm.*.cer; +Get-ChildItem vm.*.cer | + foreach { + Import-Certificate $_ -CertStoreLocation cert:\CurrentUser\TrustedPublisher; + } > $null; +# clean-updir +Remove-Item vm.*.cer; if ($Host.Name -eq "ConsoleHost") { - Write-Host "Press any key to continue..."; - $Host.UI.RawUI.FlushInputBuffer(); - $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyUp") > $null; + Write-Host "Press any key to continue..."; + $Host.UI.RawUI.FlushInputBuffer(); + $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyUp") > $null; } - \ No newline at end of file From 3bb8484a82ff09da83d4263cdd37ca527429f32b Mon Sep 17 00:00:00 2001 From: vmelamed Date: Sat, 9 Jan 2016 19:08:13 -0500 Subject: [PATCH 5/8] Simplified the algorithm factories. --- .../Ciphers/HashAlgorithmFactory.cs | 101 ++--------------- .../Ciphers/IHashAlgorithmFactory.cs | 11 +- .../Ciphers/ISymmetricAlgorithmFactory.cs | 9 +- .../Ciphers/KeyedHashAlgorithmFactory.cs | 98 ++--------------- .../Ciphers/SymmetricAlgorithmFactory.cs | 103 +++--------------- 5 files changed, 39 insertions(+), 283 deletions(-) diff --git a/Aspects/Security/Cryptography/Ciphers/HashAlgorithmFactory.cs b/Aspects/Security/Cryptography/Ciphers/HashAlgorithmFactory.cs index a3b3557..f0d02c7 100644 --- a/Aspects/Security/Cryptography/Ciphers/HashAlgorithmFactory.cs +++ b/Aspects/Security/Cryptography/Ciphers/HashAlgorithmFactory.cs @@ -1,8 +1,6 @@ using System; -using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Security.Cryptography; -using System.Threading; using Microsoft.Practices.ServiceLocation; namespace vm.Aspects.Security.Cryptography.Ciphers @@ -20,10 +18,6 @@ public sealed class HashAlgorithmFactory : IHashAlgorithmFactory /// The generated hash factory /// Func _hashFactory; - /// - /// A temporary hash algorithm object. - /// - HashAlgorithm _hashAlgorithm; #region IHashAlgorithmFactory members /// @@ -64,9 +58,9 @@ public void Initialize( { // 2. try to resolve the hash algorithm object directly from the CSL _hashFactory = () => ServiceLocatorWrapper.Default.GetInstance(); - _hashAlgorithm = _hashFactory(); - // if we are here, we've got our factory. - return; + using (var hashAlgorithm = _hashFactory()) + // if we are here, we've got our factory. + return; } catch (ActivationException) { @@ -92,14 +86,14 @@ public void Initialize( _hashFactory = () => HashAlgorithm.Create(_hashAlgorithmName); // try it - _hashAlgorithm = _hashFactory(); - if (_hashAlgorithm == null) - // if unsuccessful - throw an exception. - throw new ActivationException( - string.Format( - CultureInfo.InvariantCulture, - "The name \"{0}\" was not recognized as a valid hash algorithm.", - _hashAlgorithmName)); + using (var hashAlgorithm = _hashFactory()) + if (hashAlgorithm == null) + // if unsuccessful - throw an exception. + throw new ActivationException( + string.Format( + CultureInfo.InvariantCulture, + "The name \"{0}\" was not recognized as a valid hash algorithm.", + _hashAlgorithmName)); } /// @@ -114,13 +108,7 @@ public HashAlgorithm Create() if (_hashFactory == null) throw new InvalidOperationException("The factory was not initialized properly. Call Initialize first."); - if (_hashAlgorithm == null) - return _hashFactory(); - - var hashAlgorithm = _hashAlgorithm; - - _hashAlgorithm = null; - return hashAlgorithm; + return _hashFactory(); } /// @@ -132,70 +120,5 @@ public string HashAlgorithmName get { return _hashAlgorithmName; } } #endregion - - #region IDisposable pattern implementation - /// - /// The flag will be set just before the object is disposed. - /// - /// 0 - if the object is not disposed yet, any other value - the object is already disposed. - /// - /// Do not test or manipulate this flag outside of the property or the method . - /// The type of this field is Int32 so that it can be easily passed to the members of the class . - /// - int _disposed; - - /// - /// Returns true if the object has already been disposed, otherwise false. - /// - public bool IsDisposed - { - get { return Volatile.Read(ref _disposed) != 0; } - } - - /// - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// - /// Invokes the protected virtual . - [SuppressMessage("Microsoft.Design", "CA1063:ImplementIDisposableCorrectly", Justification = "It is correct.")] - public void Dispose() - { - // if it is disposed or in a process of disposing - return. - if (Interlocked.Exchange(ref _disposed, 1) != 0) - return; - - // these will be called only if the instance is not disposed yet or is not in a process of disposing. - Dispose(true); - GC.SuppressFinalize(this); - } - - /// - /// Allows the object to attempt to free resources and perform other cleanup operations before it is reclaimed by garbage collection. - /// - /// Invokes the protected virtual . - ~HashAlgorithmFactory() - { - Dispose(false); - } - - /// - /// Performs the actual job of disposing the object. - /// - /// - /// Passes the information whether this method is called by (explicitly or - /// implicitly at the end of a using statement), or by the . - /// - /// - /// If the method is called with ==true, i.e. from , - /// it will try to release all managed resources (usually aggregated objects which implement as well) - /// and then it will release all unmanaged resources if any. If the parameter is false then - /// the method will only try to release the unmanaged resources. - /// - /*protected virtual*/ - void Dispose(bool disposing) - { - if (disposing && _hashAlgorithm != null) - _hashAlgorithm.Dispose(); - } - #endregion } } diff --git a/Aspects/Security/Cryptography/Ciphers/IHashAlgorithmFactory.cs b/Aspects/Security/Cryptography/Ciphers/IHashAlgorithmFactory.cs index 1d824db..44357fe 100644 --- a/Aspects/Security/Cryptography/Ciphers/IHashAlgorithmFactory.cs +++ b/Aspects/Security/Cryptography/Ciphers/IHashAlgorithmFactory.cs @@ -10,7 +10,7 @@ namespace vm.Aspects.Security.Cryptography.Ciphers /// hash algorithm given choices like, parameters, Common Service Locator registrations, default values, etc. /// [ContractClass(typeof(IHashAlgorithmFactoryContract))] - public interface IHashAlgorithmFactory : IDisposable + public interface IHashAlgorithmFactory { /// /// Initializes the factory with an optional hash algorithm name. @@ -58,14 +58,5 @@ public string HashAlgorithmName } #endregion - - #region IDisposable Members - - public void Dispose() - { - throw new NotImplementedException(); - } - - #endregion } } diff --git a/Aspects/Security/Cryptography/Ciphers/ISymmetricAlgorithmFactory.cs b/Aspects/Security/Cryptography/Ciphers/ISymmetricAlgorithmFactory.cs index f11750d..b5381a3 100644 --- a/Aspects/Security/Cryptography/Ciphers/ISymmetricAlgorithmFactory.cs +++ b/Aspects/Security/Cryptography/Ciphers/ISymmetricAlgorithmFactory.cs @@ -10,7 +10,7 @@ namespace vm.Aspects.Security.Cryptography.Ciphers /// symmetric algorithm given choices like, parameters, Common Service Locator registrations, default values, etc. /// [ContractClass(typeof(ISymmetricAlgorithmFactoryContract))] - public interface ISymmetricAlgorithmFactory : IDisposable + public interface ISymmetricAlgorithmFactory { /// /// Initializes the factory with an optional symmetric algorithm name. @@ -55,12 +55,5 @@ public string SymmetricAlgorithmName get { throw new NotImplementedException(); } } #endregion - - #region IDisposable Members - public void Dispose() - { - throw new NotImplementedException(); - } - #endregion } } diff --git a/Aspects/Security/Cryptography/Ciphers/KeyedHashAlgorithmFactory.cs b/Aspects/Security/Cryptography/Ciphers/KeyedHashAlgorithmFactory.cs index d04e081..9e6ebb0 100644 --- a/Aspects/Security/Cryptography/Ciphers/KeyedHashAlgorithmFactory.cs +++ b/Aspects/Security/Cryptography/Ciphers/KeyedHashAlgorithmFactory.cs @@ -20,10 +20,6 @@ public sealed class KeyedHashAlgorithmFactory : IHashAlgorithmFactory /// The generated keyed hash factory /// Func _hashFactory; - /// - /// A temporary keyed hash algorithm object. - /// - KeyedHashAlgorithm _hashAlgorithm; #region IHashAlgorithmFactory members /// @@ -64,9 +60,9 @@ public void Initialize( { // 2. try to resolve the keyed hash algorithm object directly from the CSL _hashFactory = () => ServiceLocatorWrapper.Default.GetInstance(); - _hashAlgorithm = _hashFactory(); - // if we are here, we've got our factory. - return; + using (var hashAlgorithm = _hashFactory()) + // if we are here, we've got our factory. + return; } catch (ActivationException) { @@ -92,14 +88,14 @@ public void Initialize( _hashFactory = () => KeyedHashAlgorithm.Create(_hashAlgorithmName); // try it - _hashAlgorithm = _hashFactory(); - if (_hashAlgorithm == null) - // if unsuccessful - throw an exception. - throw new ActivationException( - string.Format( - CultureInfo.InvariantCulture, - "The name \"{0}\" was not recognized as a valid keyed hash algorithm.", - _hashAlgorithmName)); + using (var hashAlgorithm = _hashFactory()) + if (hashAlgorithm == null) + // if unsuccessful - throw an exception. + throw new ActivationException( + string.Format( + CultureInfo.InvariantCulture, + "The name \"{0}\" was not recognized as a valid keyed hash algorithm.", + _hashAlgorithmName)); } /// @@ -114,13 +110,7 @@ public HashAlgorithm Create() if (_hashFactory == null) throw new InvalidOperationException("The factory was not initialized properly. Call Initialize first."); - if (_hashAlgorithm == null) - return _hashFactory(); - - var hashAlgorithm = _hashAlgorithm; - - _hashAlgorithm = null; - return hashAlgorithm; + return _hashFactory(); } /// @@ -132,69 +122,5 @@ public string HashAlgorithmName get { return _hashAlgorithmName; } } #endregion - - #region IDisposable pattern implementation - /// - /// The flag will be set just before the object is disposed. - /// - /// 0 - if the object is not disposed yet, any other value - the object is already disposed. - /// - /// Do not test or manipulate this flag outside of the property or the method . - /// The type of this field is Int32 so that it can be easily passed to the members of the class . - /// - int _disposed; - - /// - /// Returns true if the object has already been disposed, otherwise false. - /// - public bool IsDisposed - { - get { return Volatile.Read(ref _disposed) != 0; } - } - - /// - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// - /// Invokes the protected virtual . - [SuppressMessage("Microsoft.Design", "CA1063:ImplementIDisposableCorrectly", Justification = "It is correct.")] - public void Dispose() - { - // if it is disposed or in a process of disposing - return. - if (Interlocked.Exchange(ref _disposed, 1) != 0) - return; - - // these will be called only if the instance is not disposed yet or is not in a process of disposing. - Dispose(true); - GC.SuppressFinalize(this); - } - - /// - /// Allows the object to attempt to free resources and perform other cleanup operations before it is reclaimed by garbage collection. - /// - /// Invokes the protected virtual . - ~KeyedHashAlgorithmFactory() - { - Dispose(false); - } - - /// - /// Performs the actual job of disposing the object. - /// - /// - /// Passes the information whether this method is called by (explicitly or - /// implicitly at the end of a using statement), or by the . - /// - /// - /// If the method is called with ==true, i.e. from , - /// it will try to release all managed resources (usually aggregated objects which implement as well) - /// and then it will release all unmanaged resources if any. If the parameter is false then - /// the method will only try to release the unmanaged resources. - /// - void Dispose(bool disposing) - { - if (disposing && _hashAlgorithm != null) - _hashAlgorithm.Dispose(); - } - #endregion } } diff --git a/Aspects/Security/Cryptography/Ciphers/SymmetricAlgorithmFactory.cs b/Aspects/Security/Cryptography/Ciphers/SymmetricAlgorithmFactory.cs index 6957141..1ef7fd8 100644 --- a/Aspects/Security/Cryptography/Ciphers/SymmetricAlgorithmFactory.cs +++ b/Aspects/Security/Cryptography/Ciphers/SymmetricAlgorithmFactory.cs @@ -1,8 +1,6 @@ using System; -using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Security.Cryptography; -using System.Threading; using Microsoft.Practices.ServiceLocation; namespace vm.Aspects.Security.Cryptography.Ciphers @@ -20,10 +18,6 @@ public sealed class SymmetricAlgorithmFactory : ISymmetricAlgorithmFactory /// The generated symmetric factory /// Func _symmetricAlgorithmFactory; - /// - /// A temporary symmetric algorithm object. - /// - SymmetricAlgorithm _symmetricAlgorithm; #region ISymmetricAlgorithmFactory Members @@ -46,9 +40,10 @@ public void Initialize( { // 2. try to resolve the symmetric algorithm object directly from the CSL _symmetricAlgorithmFactory = () => ServiceLocatorWrapper.Default.GetInstance(); - _symmetricAlgorithm = _symmetricAlgorithmFactory(); - // if we are here, we've got our factory. - return; + + using (var symmetricAlgorithm = _symmetricAlgorithmFactory()) + // if we are here, we've got our factory. + return; } catch (ActivationException) { @@ -74,15 +69,14 @@ public void Initialize( _symmetricAlgorithmFactory = () => SymmetricAlgorithm.Create(_symmetricAlgorithmName); // try it, if successful we'll store it and return it in the first call to Create() - _symmetricAlgorithm = _symmetricAlgorithmFactory(); - - if (_symmetricAlgorithm == null) - // if unsuccessful - throw an exception. - throw new ActivationException( - string.Format( - CultureInfo.InvariantCulture, - "The name \"{0}\" was not recognized as a valid symmetric algorithm.", - _symmetricAlgorithmName)); + using (var symmetricAlgorithm = _symmetricAlgorithmFactory()) + if (symmetricAlgorithm == null) + // if unsuccessful - throw an exception. + throw new ActivationException( + string.Format( + CultureInfo.InvariantCulture, + "The name \"{0}\" was not recognized as a valid symmetric algorithm.", + _symmetricAlgorithmName)); } /// @@ -95,13 +89,7 @@ public SymmetricAlgorithm Create() if (_symmetricAlgorithmFactory == null) throw new InvalidOperationException("The factory was not initialized properly. Call Initialize first."); - if (_symmetricAlgorithm == null) - return _symmetricAlgorithmFactory(); - - var symmetricAlgorithm = _symmetricAlgorithm; - - _symmetricAlgorithm = null; - return symmetricAlgorithm; + return _symmetricAlgorithmFactory(); } /// @@ -115,70 +103,5 @@ public string SymmetricAlgorithmName } #endregion - - #region IDisposable pattern implementation - /// - /// The flag will be set just before the object is disposed. - /// - /// 0 - if the object is not disposed yet, any other value - the object is already disposed. - /// - /// Do not test or manipulate this flag outside of the property or the method . - /// The type of this field is Int32 so that it can be easily passed to the members of the class . - /// - int _disposed; - - /// - /// Returns true if the object has already been disposed, otherwise false. - /// - public bool IsDisposed - { - get { return Volatile.Read(ref _disposed) != 0; } - } - - /// - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// - /// Invokes the protected virtual . - [SuppressMessage("Microsoft.Design", "CA1063:ImplementIDisposableCorrectly", Justification = "It is correct.")] - public void Dispose() - { - // if it is disposed or in a process of disposing - return. - if (Interlocked.Exchange(ref _disposed, 1) != 0) - return; - - // these will be called only if the instance is not disposed and is not in a process of disposing. - Dispose(true); - GC.SuppressFinalize(this); - } - - /// - /// Allows the object to attempt to free resources and perform other cleanup operations before it is reclaimed by garbage collection. - /// - /// Invokes the protected virtual . - ~SymmetricAlgorithmFactory() - { - Dispose(false); - } - - /// - /// Performs the actual job of disposing the object. - /// - /// - /// Passes the information whether this method is called by (explicitly or - /// implicitly at the end of a using statement), or by the . - /// - /// - /// If the method is called with ==true, i.e. from , - /// it will try to release all managed resources (usually aggregated objects which implement as well) - /// and then it will release all unmanaged resources if any. If the parameter is false then - /// the method will only try to release the unmanaged resources. - /// - /*protected virtual*/ - void Dispose(bool disposing) - { - if (disposing && _symmetricAlgorithm != null) - _symmetricAlgorithm.Dispose(); - } - #endregion } } From c7f5e7f5eab7bbf257baea00baefa33c647ac19e Mon Sep 17 00:00:00 2001 From: vmelamed Date: Sat, 9 Jan 2016 19:34:08 -0500 Subject: [PATCH 6/8] Added documentation text for the KeyedHasher. --- .../Ciphers/Documents/Ciphers.docx | Bin 39486 -> 40579 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/Aspects/Security/Cryptography/Ciphers/Documents/Ciphers.docx b/Aspects/Security/Cryptography/Ciphers/Documents/Ciphers.docx index 9778279ae60b94477bfa9b9736678e001bc30f9e..a882f1e001647d86dc5b56abdff33faa070cdfe8 100644 GIT binary patch delta 34375 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 Date: Sat, 9 Jan 2016 21:51:03 -0500 Subject: [PATCH 7/8] vm.Aspects.Model: Fixed a bug in the DomainEntity. vm.Aspects.Security.Cryptography.Ciphers: Performance improvements in the algorithm factories. Released v1.11.3 --- .../NuGet/ExpressionSerialization.nuspec | 2 +- .../Serialization/Properties/AssemblyInfo.cs | 6 +- Aspects/Model/DomainEntity.cs | 2 +- Aspects/Model/Properties/AssemblyInfo.cs | 6 +- Aspects/NuGet/vm.Aspects.nuspec | 11 +--- Aspects/Parsers/Properties/AssemblyInfo.cs | 6 +- Aspects/Properties/AssemblyInfo.cs | 6 +- .../Cryptography/Ciphers/NuGet/Ciphers.nuspec | 10 +-- .../Ciphers/Properties/AssemblyInfo.cs | 6 +- .../Ciphers/Test/HashAlgorithmFactoryTest.cs | 62 ------------------- .../Test/SymmetricAlgorithmFactoryTest.cs | 48 -------------- Aspects/Wcf/Properties/AssemblyInfo.cs | 6 +- 12 files changed, 24 insertions(+), 147 deletions(-) diff --git a/Aspects/Linq/Expressions/Serialization/NuGet/ExpressionSerialization.nuspec b/Aspects/Linq/Expressions/Serialization/NuGet/ExpressionSerialization.nuspec index 9786e90..bf7b2a6 100644 --- a/Aspects/Linq/Expressions/Serialization/NuGet/ExpressionSerialization.nuspec +++ b/Aspects/Linq/Expressions/Serialization/NuGet/ExpressionSerialization.nuspec @@ -2,7 +2,7 @@ AspectExpressionSerialization - 1.0.23 + 1.0.24 Val Melamed Val Melamed diff --git a/Aspects/Linq/Expressions/Serialization/Properties/AssemblyInfo.cs b/Aspects/Linq/Expressions/Serialization/Properties/AssemblyInfo.cs index 37c134c..e7c4c93 100644 --- a/Aspects/Linq/Expressions/Serialization/Properties/AssemblyInfo.cs +++ b/Aspects/Linq/Expressions/Serialization/Properties/AssemblyInfo.cs @@ -4,9 +4,9 @@ [assembly: AssemblyTitle("vm.Aspects.Linq.Expressions.Serialization")] [assembly: AssemblyDescription("Serializes and deserializes LINQ expression trees to and from XML documents.")] -[assembly: AssemblyVersion("1.0.23")] -[assembly: AssemblyFileVersion("1.0.23")] -[assembly: AssemblyInformationalVersion("1.0.23")] +[assembly: AssemblyVersion("1.0.24")] +[assembly: AssemblyFileVersion("1.0.24")] +[assembly: AssemblyInformationalVersion("1.0.24")] [assembly: InternalsVisibleTo( "vm.Aspects.Linq.Expressions.Serialization.Test, " + diff --git a/Aspects/Model/DomainEntity.cs b/Aspects/Model/DomainEntity.cs index 6673f17..45af3cc 100644 --- a/Aspects/Model/DomainEntity.cs +++ b/Aspects/Model/DomainEntity.cs @@ -144,7 +144,7 @@ public override bool Equals( /// A hash code for the current instance. public override int GetHashCode() { - return Key.GetHashCode(); ; + return HasIdentity ? Key.GetHashCode() : 0; } /// diff --git a/Aspects/Model/Properties/AssemblyInfo.cs b/Aspects/Model/Properties/AssemblyInfo.cs index ad35228..a1b10c8 100644 --- a/Aspects/Model/Properties/AssemblyInfo.cs +++ b/Aspects/Model/Properties/AssemblyInfo.cs @@ -3,9 +3,9 @@ [assembly: AssemblyTitle("vm.Aspect.Model")] [assembly: AssemblyDescription("Defines the IRepository and related base classes and utilities - a framework of building domain object model.")] -[assembly: AssemblyVersion("1.0.23")] -[assembly: AssemblyFileVersion("1.0.23")] -[assembly: AssemblyInformationalVersion("1.0.23")] +[assembly: AssemblyVersion("1.0.24")] +[assembly: AssemblyFileVersion("1.0.24")] +[assembly: AssemblyInformationalVersion("1.0.24")] [assembly: System.Runtime.CompilerServices.InternalsVisibleTo( "vm.Aspects.Model.Tests, " + diff --git a/Aspects/NuGet/vm.Aspects.nuspec b/Aspects/NuGet/vm.Aspects.nuspec index 1f4fd23..af910d6 100644 --- a/Aspects/NuGet/vm.Aspects.nuspec +++ b/Aspects/NuGet/vm.Aspects.nuspec @@ -2,7 +2,7 @@ vm.Aspects - 1.0.23-beta + 1.0.24-beta Val Melamed Val Melamed @@ -12,14 +12,7 @@ A set of classes, utilities, etc. addressing various common cross-cutting concerns or extending existing similar libraries like Enterprise Library, Unity, etc. - * Added and tested MAC keyed hashers like HMAC-SHA256 or MAC-3DES. - * Added and tested a MAC key importing/exporting utility "MacKey" in the style of EncryptedKey or ProtectedKey. - * Added interface `ILightCipher` with methods `ReleaseCertificate` and `CloneCipher` to the class `EncryptedKeyCipher` and - `ILightHasher` with methods `ReleaseCertificate` and `CloneHasher` to the class `KeyedHasher`. - `ReleaseCertificate` strips the public/private keys from the objects and now they can be used only for encryption/hashing. - This way the objects become lighter and more suitable for caching and using it in a big numbers of cryptographic operations. - `CloneCipher` creates a copy of the current object, without the public/private keys. - * Some performance improvements in the classes `Hasher` and `Signer`. + vm.Aspects.Model: Fixed a bug in the DomainEntity. https://github.com/vmelamed/vm/blob/master/LICENSE https://github.com/vmelamed/vm/tree/master/Aspects diff --git a/Aspects/Parsers/Properties/AssemblyInfo.cs b/Aspects/Parsers/Properties/AssemblyInfo.cs index ba38105..af60286 100644 --- a/Aspects/Parsers/Properties/AssemblyInfo.cs +++ b/Aspects/Parsers/Properties/AssemblyInfo.cs @@ -6,9 +6,9 @@ [assembly: AssemblyTitle("vm.Aspects.Parser")] [assembly: AssemblyDescription("Text parsing readers, e.g. CSV/TSV reader.")] -[assembly: AssemblyVersion("1.0.23")] -[assembly: AssemblyFileVersion("1.0.23")] -[assembly: AssemblyInformationalVersion("1.0.23")] +[assembly: AssemblyVersion("1.0.24")] +[assembly: AssemblyFileVersion("1.0.24")] +[assembly: AssemblyInformationalVersion("1.0.24")] [assembly: System.Runtime.CompilerServices.InternalsVisibleTo( "vm.Aspects.Parsers.Tests, " + diff --git a/Aspects/Properties/AssemblyInfo.cs b/Aspects/Properties/AssemblyInfo.cs index 6461f4e..f5ee43d 100644 --- a/Aspects/Properties/AssemblyInfo.cs +++ b/Aspects/Properties/AssemblyInfo.cs @@ -2,9 +2,9 @@ [assembly: AssemblyTitle("vm.Aspects")] [assembly: AssemblyDescription("A set of classes addressing various common cross-cutting concerns.")] -[assembly: AssemblyVersion("1.0.23")] -[assembly: AssemblyFileVersion("1.0.23")] -[assembly: AssemblyInformationalVersion("1.0.23")] +[assembly: AssemblyVersion("1.0.24")] +[assembly: AssemblyFileVersion("1.0.24")] +[assembly: AssemblyInformationalVersion("1.0.24")] [assembly: System.Runtime.CompilerServices.InternalsVisibleTo( diff --git a/Aspects/Security/Cryptography/Ciphers/NuGet/Ciphers.nuspec b/Aspects/Security/Cryptography/Ciphers/NuGet/Ciphers.nuspec index aa5cebf..7e83d4c 100644 --- a/Aspects/Security/Cryptography/Ciphers/NuGet/Ciphers.nuspec +++ b/Aspects/Security/Cryptography/Ciphers/NuGet/Ciphers.nuspec @@ -2,7 +2,7 @@ Ciphers - 1.11.2 + 1.11.3 Val Melamed Val Melamed @@ -18,13 +18,7 @@ * Built and tested with .NET v4.6. - Added interface `ILightCipher` with methods `ReleaseCertificate` and `CloneCipher` to the class `EncryptedKeyCipher` and - `ILightHasher` with methods `ReleaseCertificate` and `CloneHasher` to the class `KeyedHasher`. - `ReleaseCertificate` strips the public/private keys from the objects and now they can be used only for encryption/hashing. - This way the objects become lighter and more suitable for caching and using it in a big numbers of cryptographic operations. - `CloneCipher` creates a copy of the current object, without the public/private keys. - Some performance improvements in the classes `Hasher` and `Signer`. - Fixed minor bugs. + Performance improvements in the algorithm factories. https://github.com/vmelamed/vm/blob/master/LICENSE https://github.com/vmelamed/vm/tree/master/Aspects/Security/Cryptography/Ciphers diff --git a/Aspects/Security/Cryptography/Ciphers/Properties/AssemblyInfo.cs b/Aspects/Security/Cryptography/Ciphers/Properties/AssemblyInfo.cs index 072b16d..271220f 100644 --- a/Aspects/Security/Cryptography/Ciphers/Properties/AssemblyInfo.cs +++ b/Aspects/Security/Cryptography/Ciphers/Properties/AssemblyInfo.cs @@ -5,9 +5,9 @@ // associated with an assembly. [assembly: AssemblyTitle("vm.Aspects.Security.Cryptography.Ciphers")] [assembly: AssemblyDescription("A set of cipher classes producing cipher-packages and encrypted and/or signed XML documents and elements.")] -[assembly: AssemblyVersion("1.11.2")] -[assembly: AssemblyFileVersion("1.11.2")] -[assembly: AssemblyInformationalVersion("1.11.2")] +[assembly: AssemblyVersion("1.11.3")] +[assembly: AssemblyFileVersion("1.11.3")] +[assembly: AssemblyInformationalVersion("1.11.3")] [assembly: System.Runtime.CompilerServices.InternalsVisibleTo( "vm.Aspects.Security.Cryptography.Ciphers.Tests, " + diff --git a/Aspects/Security/Cryptography/Ciphers/Test/HashAlgorithmFactoryTest.cs b/Aspects/Security/Cryptography/Ciphers/Test/HashAlgorithmFactoryTest.cs index 6c14a45..387bb62 100644 --- a/Aspects/Security/Cryptography/Ciphers/Test/HashAlgorithmFactoryTest.cs +++ b/Aspects/Security/Cryptography/Ciphers/Test/HashAlgorithmFactoryTest.cs @@ -49,68 +49,6 @@ public static void CleanupTest() } #endregion - #region IsDisposed tests - [TestMethod] - public void IsDisposedTest() - { - try - { - var target = new HashAlgorithmFactory(); - - Assert.IsNotNull(target); - - using (target as IDisposable) - Assert.IsFalse(target.IsDisposed); - Assert.IsTrue(target.IsDisposed); - - // should do nothing: - target.Dispose(); - } - finally - { - CleanupTest(); - } - } - - [TestMethod] - public void IsDisposedTest2() - { - try - { - var target = new HashAlgorithmFactory(); - - Assert.IsNotNull(target); - - target.Initialize("SHA1"); - - using (target as IDisposable) - Assert.IsFalse(target.IsDisposed); - Assert.IsTrue(target.IsDisposed); - - // should do nothing: - target.Dispose(); - } - finally - { - CleanupTest(); - } - } - - [TestMethod] - [TestCategory("SlowTest")] - public void FinalizerTest() - { - var target = new WeakReference(new HashAlgorithmFactory()); - - Thread.Sleep(1000); - GC.Collect(); - - HashAlgorithmFactory collected; - - Assert.IsFalse(target.TryGetTarget(out collected)); - } - #endregion - [TestMethod] [ExpectedException(typeof(InvalidOperationException))] public void UninitializedTest() diff --git a/Aspects/Security/Cryptography/Ciphers/Test/SymmetricAlgorithmFactoryTest.cs b/Aspects/Security/Cryptography/Ciphers/Test/SymmetricAlgorithmFactoryTest.cs index ca977b2..b24dd36 100644 --- a/Aspects/Security/Cryptography/Ciphers/Test/SymmetricAlgorithmFactoryTest.cs +++ b/Aspects/Security/Cryptography/Ciphers/Test/SymmetricAlgorithmFactoryTest.cs @@ -50,54 +50,6 @@ public static void CleanupTest() } #endregion - #region IsDisposed tests - [TestMethod] - public void IsDisposedTest() - { - try - { - var target = new SymmetricAlgorithmFactory(); - - Assert.IsNotNull(target); - - using (target as IDisposable) - Assert.IsFalse(target.IsDisposed); - Assert.IsTrue(target.IsDisposed); - - // should do nothing: - target.Dispose(); - } - finally - { - CleanupTest(); - } - } - - [TestMethod] - public void IsDisposedTest2() - { - try - { - var target = new SymmetricAlgorithmFactory(); - - Assert.IsNotNull(target); - - target.Initialize("DES"); - - using (target as IDisposable) - Assert.IsFalse(target.IsDisposed); - Assert.IsTrue(target.IsDisposed); - - // should do nothing: - target.Dispose(); - } - finally - { - CleanupTest(); - } - } - #endregion - [TestMethod] [ExpectedException(typeof(InvalidOperationException))] public void UninitializedTest() diff --git a/Aspects/Wcf/Properties/AssemblyInfo.cs b/Aspects/Wcf/Properties/AssemblyInfo.cs index 2f233af..71d89d1 100644 --- a/Aspects/Wcf/Properties/AssemblyInfo.cs +++ b/Aspects/Wcf/Properties/AssemblyInfo.cs @@ -3,9 +3,9 @@ [assembly: AssemblyTitle("Wcf")] [assembly: AssemblyDescription("A set of classes and generics simplifying the initial configuration work of creating WCF services.")] -[assembly: AssemblyVersion("1.0.23")] -[assembly: AssemblyFileVersion("1.0.23")] -[assembly: AssemblyInformationalVersion("1.0.23")] +[assembly: AssemblyVersion("1.0.24")] +[assembly: AssemblyFileVersion("1.0.24")] +[assembly: AssemblyInformationalVersion("1.0.24")] [assembly: System.Runtime.CompilerServices.InternalsVisibleTo( "vm.Aspects.Wcf.Test, " + From 3a19102014628bded710859a34948081780531e6 Mon Sep 17 00:00:00 2001 From: vmelamed Date: Sun, 10 Jan 2016 18:58:20 -0500 Subject: [PATCH 8/8] v1.0.25-beta: vm.Aspects.Model: Fixed a bug in the DomainEntity and in the resolution of the HiLoStoreIdProvider. --- Aspects/DIContainer.cs | 15 ++- .../NuGet/ExpressionSerialization.nuspec | 2 +- .../Serialization/Properties/AssemblyInfo.cs | 6 +- Aspects/Model/DomainEntity.cs | 2 +- .../EFRepositoryBase.IRepository.cs | 4 +- .../HiLoIdentity/HiLoIdentityGenerator.cs | 122 +++++++++++++++++- .../HiLoIdentityGeneratorConfiguration.cs | 2 +- .../HiLoIdentity/HiLoStoreIdProvider.cs | 17 ++- .../PerCallContextRepositoryCallHandler.cs | 34 +++-- Aspects/Model/Properties/AssemblyInfo.cs | 6 +- Aspects/Model/packages.config | 1 + Aspects/Model/vm.Aspects.Model.csproj | 5 + Aspects/NuGet/vm.Aspects.nuspec | 4 +- Aspects/Parsers/Properties/AssemblyInfo.cs | 6 +- Aspects/Properties/AssemblyInfo.cs | 6 +- Aspects/Wcf/Properties/AssemblyInfo.cs | 6 +- 16 files changed, 182 insertions(+), 56 deletions(-) diff --git a/Aspects/DIContainer.cs b/Aspects/DIContainer.cs index b4a6fca..f55623f 100644 --- a/Aspects/DIContainer.cs +++ b/Aspects/DIContainer.cs @@ -325,7 +325,6 @@ public static void Dump( /// /// The container. /// - [Conditional("DEBUG")] public static void DebugDump( this IUnityContainer container) { @@ -334,12 +333,14 @@ public static void DebugDump( using (var writer = new StringWriter(CultureInfo.InvariantCulture)) { container.Dump(writer); - Debug.WriteLine( - "==============================={1}"+ - "{0}{1}"+ - "==============================={1}", - writer.GetStringBuilder(), - writer.NewLine); + Debug.Print( +@"=============================== + +{0} + +=============================== +", + writer.GetStringBuilder()); } } } diff --git a/Aspects/Linq/Expressions/Serialization/NuGet/ExpressionSerialization.nuspec b/Aspects/Linq/Expressions/Serialization/NuGet/ExpressionSerialization.nuspec index bf7b2a6..c8985df 100644 --- a/Aspects/Linq/Expressions/Serialization/NuGet/ExpressionSerialization.nuspec +++ b/Aspects/Linq/Expressions/Serialization/NuGet/ExpressionSerialization.nuspec @@ -2,7 +2,7 @@ AspectExpressionSerialization - 1.0.24 + 1.0.25 Val Melamed Val Melamed diff --git a/Aspects/Linq/Expressions/Serialization/Properties/AssemblyInfo.cs b/Aspects/Linq/Expressions/Serialization/Properties/AssemblyInfo.cs index e7c4c93..85836cc 100644 --- a/Aspects/Linq/Expressions/Serialization/Properties/AssemblyInfo.cs +++ b/Aspects/Linq/Expressions/Serialization/Properties/AssemblyInfo.cs @@ -4,9 +4,9 @@ [assembly: AssemblyTitle("vm.Aspects.Linq.Expressions.Serialization")] [assembly: AssemblyDescription("Serializes and deserializes LINQ expression trees to and from XML documents.")] -[assembly: AssemblyVersion("1.0.24")] -[assembly: AssemblyFileVersion("1.0.24")] -[assembly: AssemblyInformationalVersion("1.0.24")] +[assembly: AssemblyVersion("1.0.25")] +[assembly: AssemblyFileVersion("1.0.25")] +[assembly: AssemblyInformationalVersion("1.0.25")] [assembly: InternalsVisibleTo( "vm.Aspects.Linq.Expressions.Serialization.Test, " + diff --git a/Aspects/Model/DomainEntity.cs b/Aspects/Model/DomainEntity.cs index 45af3cc..e4d83ff 100644 --- a/Aspects/Model/DomainEntity.cs +++ b/Aspects/Model/DomainEntity.cs @@ -30,7 +30,7 @@ public abstract partial class DomainEntity : BaseDomainEntity, /// public override bool HasIdentity { - get { return !Key.Equals(default(TKey)); } + get { return !(ReferenceEquals(Key, null) || Key.Equals(default(TKey))); } } #region IHasStoreId Members diff --git a/Aspects/Model/EFRepository/EFRepositoryBase.IRepository.cs b/Aspects/Model/EFRepository/EFRepositoryBase.IRepository.cs index 3279a97..de5981e 100644 --- a/Aspects/Model/EFRepository/EFRepositoryBase.IRepository.cs +++ b/Aspects/Model/EFRepository/EFRepositoryBase.IRepository.cs @@ -92,9 +92,9 @@ public virtual void SetDatabaseInitializer() if (initializer != null) // Database.SetInitializer(initializer); typeof(Database) - .GetMethod("SetInitializer") + .GetMethod(nameof(Database.SetInitializer)) .MakeGenericMethod(GetType()) - .Invoke((object)null, new object[] { initializer }); + .Invoke(null, new object[] { initializer }); } /// diff --git a/Aspects/Model/EFRepository/HiLoIdentity/HiLoIdentityGenerator.cs b/Aspects/Model/EFRepository/HiLoIdentity/HiLoIdentityGenerator.cs index 26ddbd8..72d0708 100644 --- a/Aspects/Model/EFRepository/HiLoIdentity/HiLoIdentityGenerator.cs +++ b/Aspects/Model/EFRepository/HiLoIdentity/HiLoIdentityGenerator.cs @@ -8,7 +8,7 @@ namespace vm.Aspects.Model.EFRepository.HiLoIdentity /// /// Class HiLoIdentityGenerator. Implements the Hi-Lo algorithm for generating unique ID-s. /// - public class HiLoIdentityGenerator + public class HiLoIdentityGenerator : BaseDomainEntity, IEquatable { #region Constants /// @@ -75,6 +75,14 @@ public HiLoIdentityGenerator( public int MaxLowValue { get; protected internal set; } #endregion + /// + /// Gets a value indicating whether this instance is already associated with an entity set. + /// + public override bool HasIdentity + { + get { return !string.IsNullOrWhiteSpace(EntitySetName); } + } + #region Methods /// /// Increments the high value and initializes the low value. @@ -100,7 +108,7 @@ internal void IncrementHighValue() /// Gets the next available value for an entity id. If the low values are exhausted the method will return -1L. /// /// The next available value for an entity id. - [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification="n/a")] + [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification = "n/a")] public long GetId() { if (HighValue < 1L || LowValue >= MaxLowValue) @@ -109,5 +117,115 @@ public long GetId() return unchecked(((long)(HighValue-1) * MaxLowValue) + ++LowValue); } #endregion + + + #region Identity rules implementation. + #region IEquatable Members + /// + /// Indicates whether the current object is equal to a reference to another object of the same type. + /// + /// A reference to another object of type to compare with the current object. + /// + /// + /// if is equal to , otherwise + /// if refers to this object, otherwise + /// if is not the same type as this object, otherwise + /// if the current object and the are considered to be equal, + /// e.g. their business identities are equal; otherwise, . + /// + /// + /// + /// The and methods and + /// the overloaded operator== and operator!= test for business identity, + /// i.e. they test for business same-ness by comparing the types and the business keys. + /// + public virtual bool Equals(HiLoIdentityGenerator other) + { + if (ReferenceEquals(other, null)) + return false; + if (ReferenceEquals(this, other)) + return true; + if (GetType() != other.GetType()) + return false; + + return EntitySetName == other.EntitySetName; + } + #endregion + + /// + /// Determines whether this instance is equal to the specified reference. + /// + /// The reference to compare with this object. + /// + /// + /// if cannot be cast to , otherwise + /// if is equal to , otherwise + /// if refers to this object, otherwise + /// if is not the same type as this object, otherwise + /// if the current object and the are considered to be equal, + /// e.g. their business identities are equal; otherwise, . + /// + /// + /// + /// The and methods and + /// the overloaded operator== and operator!= test for business identity, + /// i.e. they test for business same-ness by comparing the types and the business keys. + /// + public override bool Equals(object obj) => Equals(obj as HiLoIdentityGenerator); + + /// + /// Serves as a hash function for the objects of and its derived types. + /// + /// A hash code for the current instance. + public override int GetHashCode() + { + var hashCode = Constants.HashInitializer; + + hashCode = Constants.HashMultiplier * hashCode + EntitySetName.GetHashCode(); + + return hashCode; + } + + /// + /// Compares two objects. + /// + /// The left operand. + /// The right operand. + /// + /// if the objects are considered to be equal (); + /// otherwise . + /// + public static bool operator ==(HiLoIdentityGenerator left, HiLoIdentityGenerator right) => ReferenceEquals(left, null) ? ReferenceEquals(right, null) : left.Equals(right); + + /// + /// Compares two objects. + /// + /// The left operand. + /// The right operand. + /// + /// if the objects are not considered to be equal (); + /// otherwise . + /// + public static bool operator !=(HiLoIdentityGenerator left, HiLoIdentityGenerator right) => !(left==right); + #endregion + + /// + /// Indicates whether the current object is equal to a reference to another object of the same type. + /// + /// A reference to another object of type to compare with this object. + /// + /// if is equal to , otherwise + /// if refers to this object, otherwise + /// if the business identities of the current object and the are equal by value, + /// e.g. BusinessKeyProperty == other.BusinessKeyProperty; otherwise, . + /// + /// + /// The method and its overloads as well as the overloaded operator== and operator!= test for business identity, + /// i.e. they test for business same-ness by comparing the business keys. + /// + public override bool Equals(BaseDomainEntity other) + { + return Equals(other as HiLoIdentityGenerator); + } } } diff --git a/Aspects/Model/EFRepository/HiLoIdentity/HiLoIdentityGeneratorConfiguration.cs b/Aspects/Model/EFRepository/HiLoIdentity/HiLoIdentityGeneratorConfiguration.cs index a8140f4..e9bd4b0 100644 --- a/Aspects/Model/EFRepository/HiLoIdentity/HiLoIdentityGeneratorConfiguration.cs +++ b/Aspects/Model/EFRepository/HiLoIdentity/HiLoIdentityGeneratorConfiguration.cs @@ -7,7 +7,7 @@ class HiLoIdentityGeneratorConfiguration : EntityTypeConfiguration g.EntitySetName); diff --git a/Aspects/Model/EFRepository/HiLoIdentity/HiLoStoreIdProvider.cs b/Aspects/Model/EFRepository/HiLoIdentity/HiLoStoreIdProvider.cs index bad19d2..9993bf6 100644 --- a/Aspects/Model/EFRepository/HiLoIdentity/HiLoStoreIdProvider.cs +++ b/Aspects/Model/EFRepository/HiLoIdentity/HiLoStoreIdProvider.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Transactions; using Microsoft.Practices.ServiceLocation; +using Microsoft.Practices.Unity; using vm.Aspects.Facilities; using vm.Aspects.Model.Repository; @@ -98,7 +99,7 @@ Guid IStoreUniqueId.GetNewId(IRepository repository) /// public const string DefaultEntitySetName = "_"; - readonly Func _generatorsRepositoryFactory; + readonly Func _generatorsRepositoryFactory; /// /// Initializes a new instance of the class. @@ -108,10 +109,11 @@ Guid IStoreUniqueId.GetNewId(IRepository repository) /// the constructor will try to resolve it from the service locator with resolve name /// public HiLoStoreIdProvider( - Func generatorsRepositoryFactory) + [Dependency(HiLoGeneratorsRepositoryResolveName)] + Func generatorsRepositoryFactory) { _generatorsRepositoryFactory = generatorsRepositoryFactory ?? - (() => ServiceLocator.Current.GetInstance(HiLoGeneratorsRepositoryResolveName) as EFRepositoryBase); + (() => ServiceLocator.Current.GetInstance(HiLoGeneratorsRepositoryResolveName)); } #region Transaction scope defaults: @@ -177,16 +179,17 @@ HiLoIdentityGenerator CreateOrGetFreshGenerator( // get a fresh generator object from the DB generator = localRepository - .Set() - .FirstOrDefault(g => g.EntitySetName == entitySetName); + .Entities() + .FirstOrDefault(g => g.EntitySetName == entitySetName) + ; if (generator == null) { // create a new generator generator = new HiLoIdentityGenerator(entitySetName, HiLoIdentityGenerator.DefaultMaxLowValue); localRepository - .Set() - .Add(generator); + .Add(generator) + ; } generator.IncrementHighValue(); diff --git a/Aspects/Model/PerCallContextRepositoryCallHandler.cs b/Aspects/Model/PerCallContextRepositoryCallHandler.cs index e5fea24..60f98e9 100644 --- a/Aspects/Model/PerCallContextRepositoryCallHandler.cs +++ b/Aspects/Model/PerCallContextRepositoryCallHandler.cs @@ -1,20 +1,18 @@ using System; +using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; -using System.Linq; +using System.Diagnostics.Contracts; using System.Threading.Tasks; -using vm.Aspects; -using vm.Aspects.Exceptions; using Microsoft.Practices.Unity; using Microsoft.Practices.Unity.InterceptionExtension; -using System.Diagnostics.Contracts; +using vm.Aspects.Exceptions; using vm.Aspects.Model.Repository; -using System.Collections.Generic; namespace vm.Aspects.Model { /// /// The class PerCallContextRepositoryCallHandler is meant to be used as a policy (AOP aspect) in the call context of a WCF call. - /// It is assumed that the repository is resolved from the DI container and has , i.e. all + /// It is assumed that the repository is resolved from the DI container and has , i.e. all /// resolutions for with the same resolve name in the same WCF call context will return one and the same repository object. /// This handler implements two post-call actions: if there are no exceptions, it commits the unit of work, otherwise rolls back the current transaction /// and then removes the repository's lifetime manager from the container. In other words the application developer does not need to worry about @@ -39,7 +37,7 @@ public class PerCallContextRepositoryCallHandler : ICallHandler /// chain. /// Return value from the target. /// Thrown when either or are -s. - [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification="It's OK here.")] + [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "It's OK here.")] public IMethodReturn Invoke( IMethodInvocation input, GetNextHandlerDelegate getNext) @@ -47,9 +45,9 @@ public IMethodReturn Invoke( Contract.Ensures(Contract.Result() != null); if (input == null) - throw new ArgumentNullException("input"); + throw new ArgumentNullException(nameof(input)); if (getNext == null) - throw new ArgumentNullException("getNext"); + throw new ArgumentNullException(nameof(getNext)); var result = getNext().Invoke(input, getNext); @@ -70,13 +68,13 @@ public IMethodReturn Invoke( #endregion - [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification="It is re-thrown.")] + [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "It is re-thrown.")] IMethodReturn CommitWork( IMethodInvocation input, IMethodReturn result) { IDictionary registrations; - + lock (DIContainer.Root) registrations = DIContainer.Root.GetRegistrationsSnapshot(); @@ -86,7 +84,7 @@ IMethodReturn CommitWork( if (!registrations.TryGetValue(new RegistrationLookup(typeof(IRepository), RepositoryResolveName), out registration) || !(registration.LifetimeManager is PerCallContextLifetimeManager)) return result; - + try { var repository = registration.LifetimeManager.GetValue() as IRepository; @@ -127,7 +125,7 @@ IMethodReturn CommitWorkAsync( { Contract.Requires(input != null, nameof(input)); Contract.Requires(result != null, nameof(result)); - + var parameters = new DoCommitWorkAsyncParameters { Input = input, @@ -144,22 +142,22 @@ IMethodReturn CommitWorkAsync( var commitWorkAsyncGeneric = typeof(Func<,>).MakeGenericType(typeof(DoCommitWorkAsyncParameters), returnType); // create a delegate out of an instantiated DoCommitWorkAsync - var doCommitWorkAsyncDelegate = GetType().GetMethod("DoCommitWorkAsync") + var doCommitWorkAsyncDelegate = GetType().GetMethod(nameof(DoCommitWorkAsync)) .MakeGenericMethod(returnType) .CreateDelegate(commitWorkAsyncGeneric); // pass the delegate to a Task c-tor var wrappedTask = typeof(Task).MakeGenericType(returnType) .GetConstructor(new Type[] { commitWorkAsyncGeneric }) - .Invoke(new object[] - { - doCommitWorkAsyncDelegate, + .Invoke(new object[] + { + doCommitWorkAsyncDelegate, parameters, }) as Task; wrappedTask.Start(); return input.CreateMethodReturn(wrappedTask); } - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification="Called via reflection.")] + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called via reflection.")] async Task DoCommitWorkAsync( DoCommitWorkAsyncParameters parameters) { diff --git a/Aspects/Model/Properties/AssemblyInfo.cs b/Aspects/Model/Properties/AssemblyInfo.cs index a1b10c8..f7e9f20 100644 --- a/Aspects/Model/Properties/AssemblyInfo.cs +++ b/Aspects/Model/Properties/AssemblyInfo.cs @@ -3,9 +3,9 @@ [assembly: AssemblyTitle("vm.Aspect.Model")] [assembly: AssemblyDescription("Defines the IRepository and related base classes and utilities - a framework of building domain object model.")] -[assembly: AssemblyVersion("1.0.24")] -[assembly: AssemblyFileVersion("1.0.24")] -[assembly: AssemblyInformationalVersion("1.0.24")] +[assembly: AssemblyVersion("1.0.25")] +[assembly: AssemblyFileVersion("1.0.25")] +[assembly: AssemblyInformationalVersion("1.0.25")] [assembly: System.Runtime.CompilerServices.InternalsVisibleTo( "vm.Aspects.Model.Tests, " + diff --git a/Aspects/Model/packages.config b/Aspects/Model/packages.config index b0add85..caf8468 100644 --- a/Aspects/Model/packages.config +++ b/Aspects/Model/packages.config @@ -5,6 +5,7 @@ + diff --git a/Aspects/Model/vm.Aspects.Model.csproj b/Aspects/Model/vm.Aspects.Model.csproj index e07e1e3..d64bf80 100644 --- a/Aspects/Model/vm.Aspects.Model.csproj +++ b/Aspects/Model/vm.Aspects.Model.csproj @@ -200,6 +200,10 @@ ..\..\packages\EnterpriseLibrary.ExceptionHandling.Logging.6.0.1304.0\lib\NET45\Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Logging.dll True + + ..\..\..\Almond Bank Core Services\Services\packages\EnterpriseLibrary.ExceptionHandling.WCF.6.0.1304.0\lib\NET45\Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.WCF.dll + True + ..\..\packages\EnterpriseLibrary.Logging.6.0.1304.0\lib\NET45\Microsoft.Practices.EnterpriseLibrary.Logging.dll True @@ -240,6 +244,7 @@ + diff --git a/Aspects/NuGet/vm.Aspects.nuspec b/Aspects/NuGet/vm.Aspects.nuspec index af910d6..3d61270 100644 --- a/Aspects/NuGet/vm.Aspects.nuspec +++ b/Aspects/NuGet/vm.Aspects.nuspec @@ -2,7 +2,7 @@ vm.Aspects - 1.0.24-beta + 1.0.25-beta Val Melamed Val Melamed @@ -12,7 +12,7 @@ A set of classes, utilities, etc. addressing various common cross-cutting concerns or extending existing similar libraries like Enterprise Library, Unity, etc. - vm.Aspects.Model: Fixed a bug in the DomainEntity. + vm.Aspects.Model: Fixed a bug in the DomainEntity and in the resolution of the HiLoStoreIdProvider. https://github.com/vmelamed/vm/blob/master/LICENSE https://github.com/vmelamed/vm/tree/master/Aspects diff --git a/Aspects/Parsers/Properties/AssemblyInfo.cs b/Aspects/Parsers/Properties/AssemblyInfo.cs index af60286..af00d27 100644 --- a/Aspects/Parsers/Properties/AssemblyInfo.cs +++ b/Aspects/Parsers/Properties/AssemblyInfo.cs @@ -6,9 +6,9 @@ [assembly: AssemblyTitle("vm.Aspects.Parser")] [assembly: AssemblyDescription("Text parsing readers, e.g. CSV/TSV reader.")] -[assembly: AssemblyVersion("1.0.24")] -[assembly: AssemblyFileVersion("1.0.24")] -[assembly: AssemblyInformationalVersion("1.0.24")] +[assembly: AssemblyVersion("1.0.25")] +[assembly: AssemblyFileVersion("1.0.25")] +[assembly: AssemblyInformationalVersion("1.0.25")] [assembly: System.Runtime.CompilerServices.InternalsVisibleTo( "vm.Aspects.Parsers.Tests, " + diff --git a/Aspects/Properties/AssemblyInfo.cs b/Aspects/Properties/AssemblyInfo.cs index f5ee43d..eba99b7 100644 --- a/Aspects/Properties/AssemblyInfo.cs +++ b/Aspects/Properties/AssemblyInfo.cs @@ -2,9 +2,9 @@ [assembly: AssemblyTitle("vm.Aspects")] [assembly: AssemblyDescription("A set of classes addressing various common cross-cutting concerns.")] -[assembly: AssemblyVersion("1.0.24")] -[assembly: AssemblyFileVersion("1.0.24")] -[assembly: AssemblyInformationalVersion("1.0.24")] +[assembly: AssemblyVersion("1.0.25")] +[assembly: AssemblyFileVersion("1.0.25")] +[assembly: AssemblyInformationalVersion("1.0.25")] [assembly: System.Runtime.CompilerServices.InternalsVisibleTo( diff --git a/Aspects/Wcf/Properties/AssemblyInfo.cs b/Aspects/Wcf/Properties/AssemblyInfo.cs index 71d89d1..8d0cefe 100644 --- a/Aspects/Wcf/Properties/AssemblyInfo.cs +++ b/Aspects/Wcf/Properties/AssemblyInfo.cs @@ -3,9 +3,9 @@ [assembly: AssemblyTitle("Wcf")] [assembly: AssemblyDescription("A set of classes and generics simplifying the initial configuration work of creating WCF services.")] -[assembly: AssemblyVersion("1.0.24")] -[assembly: AssemblyFileVersion("1.0.24")] -[assembly: AssemblyInformationalVersion("1.0.24")] +[assembly: AssemblyVersion("1.0.25")] +[assembly: AssemblyFileVersion("1.0.25")] +[assembly: AssemblyInformationalVersion("1.0.25")] [assembly: System.Runtime.CompilerServices.InternalsVisibleTo( "vm.Aspects.Wcf.Test, " +