diff --git a/test/Microsoft.AspNet.Security.DataProtection.Test/Cng/CbcAuthenticatedEncryptorTests.cs b/test/Microsoft.AspNet.Security.DataProtection.Test/Cng/CbcAuthenticatedEncryptorTests.cs index 7e2027e78a..c7c1acee95 100644 --- a/test/Microsoft.AspNet.Security.DataProtection.Test/Cng/CbcAuthenticatedEncryptorTests.cs +++ b/test/Microsoft.AspNet.Security.DataProtection.Test/Cng/CbcAuthenticatedEncryptorTests.cs @@ -6,13 +6,15 @@ using System.Linq; using System.Security.Cryptography; using System.Text; using Microsoft.AspNet.Security.DataProtection.Cng; +using Microsoft.AspNet.Testing.xunit; using Xunit; namespace Microsoft.AspNet.Security.DataProtection.Test.Cng { public class CbcAuthenticatedEncryptorTests { - [Fact] + [ConditionalFact] + [ConditionalRunTestOnlyIfBcryptAvailable] public void Encrypt_Decrypt_RoundTrips() { // Arrange @@ -32,7 +34,8 @@ namespace Microsoft.AspNet.Security.DataProtection.Test.Cng Assert.Equal(plaintext, decipheredtext); } - [Fact] + [ConditionalFact] + [ConditionalRunTestOnlyIfBcryptAvailable] public void Encrypt_Decrypt_Tampering_Fails() { // Arrange @@ -78,7 +81,8 @@ namespace Microsoft.AspNet.Security.DataProtection.Test.Cng }); } - [Fact] + [ConditionalFact] + [ConditionalRunTestOnlyIfBcryptAvailable] public void Encrypt_KnownKey() { // Arrange diff --git a/test/Microsoft.AspNet.Security.DataProtection.Test/Cng/CngAuthenticatedEncryptorBaseTests.cs b/test/Microsoft.AspNet.Security.DataProtection.Test/Cng/CngAuthenticatedEncryptorBaseTests.cs index 603186a009..1ccabfc429 100644 --- a/test/Microsoft.AspNet.Security.DataProtection.Test/Cng/CngAuthenticatedEncryptorBaseTests.cs +++ b/test/Microsoft.AspNet.Security.DataProtection.Test/Cng/CngAuthenticatedEncryptorBaseTests.cs @@ -3,6 +3,7 @@ using System; using Microsoft.AspNet.Security.DataProtection.Cng; +using Microsoft.AspNet.Testing.xunit; using Moq; using Xunit; @@ -10,7 +11,8 @@ namespace Microsoft.AspNet.Security.DataProtection.Test.Cng { public unsafe class CngAuthenticatedEncryptorBaseTests { - [Fact] + [ConditionalFact] + [ConditionalRunTestOnlyIfBcryptAvailable] public void Decrypt_ForwardsArraySegment() { // Arrange @@ -35,7 +37,8 @@ namespace Microsoft.AspNet.Security.DataProtection.Test.Cng Assert.Equal(new byte[] { 0x20, 0x21, 0x22 }, retVal); } - [Fact] + [ConditionalFact] + [ConditionalRunTestOnlyIfBcryptAvailable] public void Decrypt_HandlesEmptyAADPointerFixup() { // Arrange @@ -60,7 +63,8 @@ namespace Microsoft.AspNet.Security.DataProtection.Test.Cng Assert.Equal(new byte[] { 0x20, 0x21, 0x22 }, retVal); } - [Fact] + [ConditionalFact] + [ConditionalRunTestOnlyIfBcryptAvailable] public void Decrypt_HandlesEmptyCiphertextPointerFixup() { // Arrange diff --git a/test/Microsoft.AspNet.Security.DataProtection.Test/Cng/GcmAuthenticatedEncryptorTests.cs b/test/Microsoft.AspNet.Security.DataProtection.Test/Cng/GcmAuthenticatedEncryptorTests.cs index b1eae351d7..681de03f38 100644 --- a/test/Microsoft.AspNet.Security.DataProtection.Test/Cng/GcmAuthenticatedEncryptorTests.cs +++ b/test/Microsoft.AspNet.Security.DataProtection.Test/Cng/GcmAuthenticatedEncryptorTests.cs @@ -6,13 +6,15 @@ using System.Linq; using System.Security.Cryptography; using System.Text; using Microsoft.AspNet.Security.DataProtection.Cng; +using Microsoft.AspNet.Testing.xunit; using Xunit; namespace Microsoft.AspNet.Security.DataProtection.Test.Cng { public class GcmAuthenticatedEncryptorTests { - [Fact] + [ConditionalFact] + [ConditionalRunTestOnlyIfBcryptAvailable] public void Encrypt_Decrypt_RoundTrips() { // Arrange @@ -29,7 +31,8 @@ namespace Microsoft.AspNet.Security.DataProtection.Test.Cng Assert.Equal(plaintext, decipheredtext); } - [Fact] + [ConditionalFact] + [ConditionalRunTestOnlyIfBcryptAvailable] public void Encrypt_Decrypt_Tampering_Fails() { // Arrange @@ -72,7 +75,8 @@ namespace Microsoft.AspNet.Security.DataProtection.Test.Cng }); } - [Fact] + [ConditionalFact] + [ConditionalRunTestOnlyIfBcryptAvailable] public void Encrypt_KnownKey() { // Arrange diff --git a/test/Microsoft.AspNet.Security.DataProtection.Test/ConditionalRunTestOnlyIfBcryptAvailableAttribute.cs b/test/Microsoft.AspNet.Security.DataProtection.Test/ConditionalRunTestOnlyIfBcryptAvailableAttribute.cs new file mode 100644 index 0000000000..eb6cc86e0e --- /dev/null +++ b/test/Microsoft.AspNet.Security.DataProtection.Test/ConditionalRunTestOnlyIfBcryptAvailableAttribute.cs @@ -0,0 +1,58 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Globalization; +using Microsoft.AspNet.Security.DataProtection.SafeHandles; +using Microsoft.AspNet.Testing.xunit; + +namespace Microsoft.AspNet.Security.DataProtection.Test +{ + public class ConditionalRunTestOnlyIfBcryptAvailableAttribute : Attribute, ITestCondition + { + private static readonly SafeLibraryHandle _bcryptLibHandle = GetBcryptLibHandle(); + + private readonly string _requiredExportFunction; + + public ConditionalRunTestOnlyIfBcryptAvailableAttribute(string requiredExportFunction = null) + { + _requiredExportFunction = requiredExportFunction; + } + + public bool IsMet + { + get + { + if (_bcryptLibHandle == null) + { + return false; // no bcrypt.dll available + } + + return (_requiredExportFunction == null || _bcryptLibHandle.DoesProcExist(_requiredExportFunction)); + } + } + + public string SkipReason + { + get + { + return (_bcryptLibHandle != null) + ? String.Format(CultureInfo.InvariantCulture, "Export {0} not found in bcrypt.dll", _requiredExportFunction) + : "bcrypt.dll not found on this platform."; + } + } + + private static SafeLibraryHandle GetBcryptLibHandle() + { + try + { + return SafeLibraryHandle.Open("bcrypt.dll"); + } + catch + { + // If we're not on an OS with BCRYPT.DLL, just bail. + return null; + } + } + } +} diff --git a/test/Microsoft.AspNet.Security.DataProtection.Test/PBKDF2/Pbkdf2Tests.cs b/test/Microsoft.AspNet.Security.DataProtection.Test/PBKDF2/Pbkdf2Tests.cs index 501f759a89..6fed8294d7 100644 --- a/test/Microsoft.AspNet.Security.DataProtection.Test/PBKDF2/Pbkdf2Tests.cs +++ b/test/Microsoft.AspNet.Security.DataProtection.Test/PBKDF2/Pbkdf2Tests.cs @@ -4,6 +4,7 @@ using System; using System.Text; using Microsoft.AspNet.Security.DataProtection.PBKDF2; +using Microsoft.AspNet.Testing.xunit; using Xunit; namespace Microsoft.AspNet.Security.DataProtection.Test.PBKDF2 @@ -23,7 +24,7 @@ namespace Microsoft.AspNet.Security.DataProtection.Test.PBKDF2 [InlineData("my-password", KeyDerivationPrf.Sha512, 5, 512 / 8 - 1, "ZTallQJrFn0279xIzaiA1XqatVTGei+ZjKngA7bIMtKMDUw6YJeGUQpFG8iGTgN+ri3LNDktNbzwfcSyZmm9")] [InlineData("my-password", KeyDerivationPrf.Sha512, 5, 512 / 8 + 0, "ZTallQJrFn0279xIzaiA1XqatVTGei+ZjKngA7bIMtKMDUw6YJeGUQpFG8iGTgN+ri3LNDktNbzwfcSyZmm90Q==")] [InlineData("my-password", KeyDerivationPrf.Sha512, 5, 512 / 8 + 1, "ZTallQJrFn0279xIzaiA1XqatVTGei+ZjKngA7bIMtKMDUw6YJeGUQpFG8iGTgN+ri3LNDktNbzwfcSyZmm90Wk=")] - public void RunTest_Normal(string password, KeyDerivationPrf prf, int iterationCount, int numBytesRequested, string expectedValueAsBase64) + public void RunTest_Normal_Managed(string password, KeyDerivationPrf prf, int iterationCount, int numBytesRequested, string expectedValueAsBase64) { // Arrange byte[] salt = new byte[256]; @@ -32,14 +33,86 @@ namespace Microsoft.AspNet.Security.DataProtection.Test.PBKDF2 salt[i] = (byte)i; } - // Act & assert - fully managed, Win7, and Win8 + // Act & assert TestProvider(password, salt, prf, iterationCount, numBytesRequested, expectedValueAsBase64); + } + + // The 'numBytesRequested' parameters below are chosen to exercise code paths where + // this value straddles the digest length of the PRF. We only use 5 iterations so + // that our unit tests are fast. + [ConditionalTheory] + [ConditionalRunTestOnlyIfBcryptAvailable("BCryptDeriveKeyPBKDF2")] + [InlineData("my-password", KeyDerivationPrf.Sha1, 5, 160 / 8 - 1, "efmxNcKD/U1urTEDGvsThlPnHA==")] + [InlineData("my-password", KeyDerivationPrf.Sha1, 5, 160 / 8 + 0, "efmxNcKD/U1urTEDGvsThlPnHDI=")] + [InlineData("my-password", KeyDerivationPrf.Sha1, 5, 160 / 8 + 1, "efmxNcKD/U1urTEDGvsThlPnHDLk")] + [InlineData("my-password", KeyDerivationPrf.Sha256, 5, 256 / 8 - 1, "JRNz8bPKS02EG1vf7eWjA64IeeI+TI8gBEwb1oVvRA==")] + [InlineData("my-password", KeyDerivationPrf.Sha256, 5, 256 / 8 + 0, "JRNz8bPKS02EG1vf7eWjA64IeeI+TI8gBEwb1oVvRLo=")] + [InlineData("my-password", KeyDerivationPrf.Sha256, 5, 256 / 8 + 1, "JRNz8bPKS02EG1vf7eWjA64IeeI+TI8gBEwb1oVvRLpk")] + [InlineData("my-password", KeyDerivationPrf.Sha512, 5, 512 / 8 - 1, "ZTallQJrFn0279xIzaiA1XqatVTGei+ZjKngA7bIMtKMDUw6YJeGUQpFG8iGTgN+ri3LNDktNbzwfcSyZmm9")] + [InlineData("my-password", KeyDerivationPrf.Sha512, 5, 512 / 8 + 0, "ZTallQJrFn0279xIzaiA1XqatVTGei+ZjKngA7bIMtKMDUw6YJeGUQpFG8iGTgN+ri3LNDktNbzwfcSyZmm90Q==")] + [InlineData("my-password", KeyDerivationPrf.Sha512, 5, 512 / 8 + 1, "ZTallQJrFn0279xIzaiA1XqatVTGei+ZjKngA7bIMtKMDUw6YJeGUQpFG8iGTgN+ri3LNDktNbzwfcSyZmm90Wk=")] + public void RunTest_Normal_Win7(string password, KeyDerivationPrf prf, int iterationCount, int numBytesRequested, string expectedValueAsBase64) + { + // Arrange + byte[] salt = new byte[256]; + for (int i = 0; i < salt.Length; i++) + { + salt[i] = (byte)i; + } + + // Act & assert TestProvider(password, salt, prf, iterationCount, numBytesRequested, expectedValueAsBase64); + } + + // The 'numBytesRequested' parameters below are chosen to exercise code paths where + // this value straddles the digest length of the PRF. We only use 5 iterations so + // that our unit tests are fast. + [ConditionalTheory] + [ConditionalRunTestOnlyIfBcryptAvailable("BCryptKeyDerivation")] + [InlineData("my-password", KeyDerivationPrf.Sha1, 5, 160 / 8 - 1, "efmxNcKD/U1urTEDGvsThlPnHA==")] + [InlineData("my-password", KeyDerivationPrf.Sha1, 5, 160 / 8 + 0, "efmxNcKD/U1urTEDGvsThlPnHDI=")] + [InlineData("my-password", KeyDerivationPrf.Sha1, 5, 160 / 8 + 1, "efmxNcKD/U1urTEDGvsThlPnHDLk")] + [InlineData("my-password", KeyDerivationPrf.Sha256, 5, 256 / 8 - 1, "JRNz8bPKS02EG1vf7eWjA64IeeI+TI8gBEwb1oVvRA==")] + [InlineData("my-password", KeyDerivationPrf.Sha256, 5, 256 / 8 + 0, "JRNz8bPKS02EG1vf7eWjA64IeeI+TI8gBEwb1oVvRLo=")] + [InlineData("my-password", KeyDerivationPrf.Sha256, 5, 256 / 8 + 1, "JRNz8bPKS02EG1vf7eWjA64IeeI+TI8gBEwb1oVvRLpk")] + [InlineData("my-password", KeyDerivationPrf.Sha512, 5, 512 / 8 - 1, "ZTallQJrFn0279xIzaiA1XqatVTGei+ZjKngA7bIMtKMDUw6YJeGUQpFG8iGTgN+ri3LNDktNbzwfcSyZmm9")] + [InlineData("my-password", KeyDerivationPrf.Sha512, 5, 512 / 8 + 0, "ZTallQJrFn0279xIzaiA1XqatVTGei+ZjKngA7bIMtKMDUw6YJeGUQpFG8iGTgN+ri3LNDktNbzwfcSyZmm90Q==")] + [InlineData("my-password", KeyDerivationPrf.Sha512, 5, 512 / 8 + 1, "ZTallQJrFn0279xIzaiA1XqatVTGei+ZjKngA7bIMtKMDUw6YJeGUQpFG8iGTgN+ri3LNDktNbzwfcSyZmm90Wk=")] + public void RunTest_Normal_Win8(string password, KeyDerivationPrf prf, int iterationCount, int numBytesRequested, string expectedValueAsBase64) + { + // Arrange + byte[] salt = new byte[256]; + for (int i = 0; i < salt.Length; i++) + { + salt[i] = (byte)i; + } + + // Act & assert TestProvider(password, salt, prf, iterationCount, numBytesRequested, expectedValueAsBase64); } [Fact] - public void RunTest_WithLongPassword() + public void RunTest_WithLongPassword_Managed() + { + RunTest_WithLongPassword_Impl(); + } + + [ConditionalFact] + [ConditionalRunTestOnlyIfBcryptAvailable("BCryptDeriveKeyPBKDF2")] + public void RunTest_WithLongPassword_Win7() + { + RunTest_WithLongPassword_Impl(); + } + + [ConditionalFact] + [ConditionalRunTestOnlyIfBcryptAvailable("BCryptKeyDerivation")] + public void RunTest_WithLongPassword_Win8() + { + RunTest_WithLongPassword_Impl(); + } + + private static void RunTest_WithLongPassword_Impl() + where TProvider : IPbkdf2Provider, new() { // Arrange string password = new String('x', 50000); // 50,000 char password @@ -49,10 +122,8 @@ namespace Microsoft.AspNet.Security.DataProtection.Test.PBKDF2 const int iterationCount = 5; const int numBytesRequested = 128; - // Act & assert - fully managed, Win7, and Win8 - TestProvider(password, salt, prf, iterationCount, numBytesRequested, expectedDerivedKeyBase64); - TestProvider(password, salt, prf, iterationCount, numBytesRequested, expectedDerivedKeyBase64); - TestProvider(password, salt, prf, iterationCount, numBytesRequested, expectedDerivedKeyBase64); + // Act & assert + TestProvider(password, salt, prf, iterationCount, numBytesRequested, expectedDerivedKeyBase64); } private static void TestProvider(string password, byte[] salt, KeyDerivationPrf prf, int iterationCount, int numBytesRequested, string expectedDerivedKeyAsBase64) diff --git a/test/Microsoft.AspNet.Security.DataProtection.Test/SP800_108/SP800_108Tests.cs b/test/Microsoft.AspNet.Security.DataProtection.Test/SP800_108/SP800_108Tests.cs index 9feb26b816..2705296ed1 100644 --- a/test/Microsoft.AspNet.Security.DataProtection.Test/SP800_108/SP800_108Tests.cs +++ b/test/Microsoft.AspNet.Security.DataProtection.Test/SP800_108/SP800_108Tests.cs @@ -5,6 +5,7 @@ using System; using System.Security.Cryptography; using System.Text; using Microsoft.AspNet.Security.DataProtection.SP800_108; +using Microsoft.AspNet.Testing.xunit; using Xunit; namespace Microsoft.AspNet.Security.DataProtection.Test.SP800_108 @@ -19,7 +20,7 @@ namespace Microsoft.AspNet.Security.DataProtection.Test.SP800_108 [InlineData(512 / 8 - 1, "V47WmHzPSkdC2vkLAomIjCzZlDOAetll3yJLcSvon7LJFjJpEN+KnSNp+gIpeydKMsENkflbrIZ/3s6GkEaH")] [InlineData(512 / 8 + 0, "mVaFM4deXLl610CmnCteNzxgbM/VkmKznAlPauHcDBn0le06uOjAKLHx0LfoU2/Ttq9nd78Y6Nk6wArmdwJgJg==")] [InlineData(512 / 8 + 1, "GaHPeqdUxriFpjRtkYQYWr5/iqneD/+hPhVJQt4rXblxSpB1UUqGqL00DMU/FJkX0iMCfqUjQXtXyfks+p++Ev4=")] - public void DeriveKeyWithContextHeader_Normal(int numDerivedBytes, string expectedDerivedSubkeyAsBase64) + public void DeriveKeyWithContextHeader_Normal_Managed(int numDerivedBytes, string expectedDerivedSubkeyAsBase64) { // Arrange byte[] kdk = Encoding.UTF8.GetBytes("kdk"); @@ -27,9 +28,45 @@ namespace Microsoft.AspNet.Security.DataProtection.Test.SP800_108 byte[] contextHeader = Encoding.UTF8.GetBytes("contextHeader"); byte[] context = Encoding.UTF8.GetBytes("context"); - // Act & assert - managed, Win7, Win8 + // Act & assert TestManagedKeyDerivation(kdk, label, contextHeader, context, numDerivedBytes, expectedDerivedSubkeyAsBase64); + } + + // The 'numBytesRequested' parameters below are chosen to exercise code paths where + // this value straddles the digest length of the PRF (which is hardcoded to HMACSHA512). + [ConditionalTheory] + [ConditionalRunTestOnlyIfBcryptAvailable] + [InlineData(512 / 8 - 1, "V47WmHzPSkdC2vkLAomIjCzZlDOAetll3yJLcSvon7LJFjJpEN+KnSNp+gIpeydKMsENkflbrIZ/3s6GkEaH")] + [InlineData(512 / 8 + 0, "mVaFM4deXLl610CmnCteNzxgbM/VkmKznAlPauHcDBn0le06uOjAKLHx0LfoU2/Ttq9nd78Y6Nk6wArmdwJgJg==")] + [InlineData(512 / 8 + 1, "GaHPeqdUxriFpjRtkYQYWr5/iqneD/+hPhVJQt4rXblxSpB1UUqGqL00DMU/FJkX0iMCfqUjQXtXyfks+p++Ev4=")] + public void DeriveKeyWithContextHeader_Normal_Win7(int numDerivedBytes, string expectedDerivedSubkeyAsBase64) + { + // Arrange + byte[] kdk = Encoding.UTF8.GetBytes("kdk"); + byte[] label = Encoding.UTF8.GetBytes("label"); + byte[] contextHeader = Encoding.UTF8.GetBytes("contextHeader"); + byte[] context = Encoding.UTF8.GetBytes("context"); + + // Act & assert TestCngKeyDerivation((pbKdk, cbKdk) => new Win7SP800_108_CTR_HMACSHA512Provider(pbKdk, cbKdk), kdk, label, contextHeader, context, numDerivedBytes, expectedDerivedSubkeyAsBase64); + } + + // The 'numBytesRequested' parameters below are chosen to exercise code paths where + // this value straddles the digest length of the PRF (which is hardcoded to HMACSHA512). + [ConditionalTheory] + [ConditionalRunTestOnlyIfBcryptAvailable("BCryptKeyDerivation")] + [InlineData(512 / 8 - 1, "V47WmHzPSkdC2vkLAomIjCzZlDOAetll3yJLcSvon7LJFjJpEN+KnSNp+gIpeydKMsENkflbrIZ/3s6GkEaH")] + [InlineData(512 / 8 + 0, "mVaFM4deXLl610CmnCteNzxgbM/VkmKznAlPauHcDBn0le06uOjAKLHx0LfoU2/Ttq9nd78Y6Nk6wArmdwJgJg==")] + [InlineData(512 / 8 + 1, "GaHPeqdUxriFpjRtkYQYWr5/iqneD/+hPhVJQt4rXblxSpB1UUqGqL00DMU/FJkX0iMCfqUjQXtXyfks+p++Ev4=")] + public void DeriveKeyWithContextHeader_Normal_Win8(int numDerivedBytes, string expectedDerivedSubkeyAsBase64) + { + // Arrange + byte[] kdk = Encoding.UTF8.GetBytes("kdk"); + byte[] label = Encoding.UTF8.GetBytes("label"); + byte[] contextHeader = Encoding.UTF8.GetBytes("contextHeader"); + byte[] context = Encoding.UTF8.GetBytes("context"); + + // Act & assert TestCngKeyDerivation((pbKdk, cbKdk) => new Win8SP800_108_CTR_HMACSHA512Provider(pbKdk, cbKdk), kdk, label, contextHeader, context, numDerivedBytes, expectedDerivedSubkeyAsBase64); } @@ -39,7 +76,7 @@ namespace Microsoft.AspNet.Security.DataProtection.Test.SP800_108 [InlineData(512 / 8 - 1, "rt2hM6kkQ8hAXmkHx0TU4o3Q+S7fie6b3S1LAq107k++P9v8uSYA2G+WX3pJf9ZkpYrTKD7WUIoLkgA1R9lk")] [InlineData(512 / 8 + 0, "RKiXmHSrWq5gkiRSyNZWNJrMR0jDyYHJMt9odOayRAE5wLSX2caINpQmfzTH7voJQi3tbn5MmD//dcspghfBiw==")] [InlineData(512 / 8 + 1, "KedXO0zAIZ3AfnPqY1NnXxpC3HDHIxefG4bwD3g6nWYEc5+q7pjbam71Yqj0zgHMNC9Z7BX3wS1/tajFocRWZUk=")] - public void DeriveKeyWithContextHeader_LongKey(int numDerivedBytes, string expectedDerivedSubkeyAsBase64) + public void DeriveKeyWithContextHeader_LongKey_Managed(int numDerivedBytes, string expectedDerivedSubkeyAsBase64) { // Arrange byte[] kdk = new byte[50000]; // CNG can't normally handle a 50,000 byte KDK, but we coerce it into working :) @@ -52,9 +89,55 @@ namespace Microsoft.AspNet.Security.DataProtection.Test.SP800_108 byte[] contextHeader = Encoding.UTF8.GetBytes("contextHeader"); byte[] context = Encoding.UTF8.GetBytes("context"); - // Act & assert - managed, Win7, Win8 + // Act & assert TestManagedKeyDerivation(kdk, label, contextHeader, context, numDerivedBytes, expectedDerivedSubkeyAsBase64); + } + + // The 'numBytesRequested' parameters below are chosen to exercise code paths where + // this value straddles the digest length of the PRF (which is hardcoded to HMACSHA512). + [ConditionalTheory] + [ConditionalRunTestOnlyIfBcryptAvailable] + [InlineData(512 / 8 - 1, "rt2hM6kkQ8hAXmkHx0TU4o3Q+S7fie6b3S1LAq107k++P9v8uSYA2G+WX3pJf9ZkpYrTKD7WUIoLkgA1R9lk")] + [InlineData(512 / 8 + 0, "RKiXmHSrWq5gkiRSyNZWNJrMR0jDyYHJMt9odOayRAE5wLSX2caINpQmfzTH7voJQi3tbn5MmD//dcspghfBiw==")] + [InlineData(512 / 8 + 1, "KedXO0zAIZ3AfnPqY1NnXxpC3HDHIxefG4bwD3g6nWYEc5+q7pjbam71Yqj0zgHMNC9Z7BX3wS1/tajFocRWZUk=")] + public void DeriveKeyWithContextHeader_LongKey_Win7(int numDerivedBytes, string expectedDerivedSubkeyAsBase64) + { + // Arrange + byte[] kdk = new byte[50000]; // CNG can't normally handle a 50,000 byte KDK, but we coerce it into working :) + for (int i = 0; i < kdk.Length; i++) + { + kdk[i] = (byte)i; + } + + byte[] label = Encoding.UTF8.GetBytes("label"); + byte[] contextHeader = Encoding.UTF8.GetBytes("contextHeader"); + byte[] context = Encoding.UTF8.GetBytes("context"); + + // Act & assert TestCngKeyDerivation((pbKdk, cbKdk) => new Win7SP800_108_CTR_HMACSHA512Provider(pbKdk, cbKdk), kdk, label, contextHeader, context, numDerivedBytes, expectedDerivedSubkeyAsBase64); + } + + // The 'numBytesRequested' parameters below are chosen to exercise code paths where + // this value straddles the digest length of the PRF (which is hardcoded to HMACSHA512). + [ConditionalTheory] + [ConditionalRunTestOnlyIfBcryptAvailable("BCryptKeyDerivation")] + [InlineData(512 / 8 - 1, "rt2hM6kkQ8hAXmkHx0TU4o3Q+S7fie6b3S1LAq107k++P9v8uSYA2G+WX3pJf9ZkpYrTKD7WUIoLkgA1R9lk")] + [InlineData(512 / 8 + 0, "RKiXmHSrWq5gkiRSyNZWNJrMR0jDyYHJMt9odOayRAE5wLSX2caINpQmfzTH7voJQi3tbn5MmD//dcspghfBiw==")] + [InlineData(512 / 8 + 1, "KedXO0zAIZ3AfnPqY1NnXxpC3HDHIxefG4bwD3g6nWYEc5+q7pjbam71Yqj0zgHMNC9Z7BX3wS1/tajFocRWZUk=")] + public void DeriveKeyWithContextHeader_LongKey_Win8(int numDerivedBytes, string expectedDerivedSubkeyAsBase64) + { + // Arrange + byte[] kdk = new byte[50000]; // CNG can't normally handle a 50,000 byte KDK, but we coerce it into working :) + for (int i = 0; i < kdk.Length; i++) + { + kdk[i] = (byte)i; + } + + byte[] label = Encoding.UTF8.GetBytes("label"); + byte[] contextHeader = Encoding.UTF8.GetBytes("contextHeader"); + byte[] context = Encoding.UTF8.GetBytes("context"); + + // Act & assert TestCngKeyDerivation((pbKdk, cbKdk) => new Win8SP800_108_CTR_HMACSHA512Provider(pbKdk, cbKdk), kdk, label, contextHeader, context, numDerivedBytes, expectedDerivedSubkeyAsBase64); } diff --git a/test/Microsoft.AspNet.Security.DataProtection.Test/project.json b/test/Microsoft.AspNet.Security.DataProtection.Test/project.json index af25e55bfe..2ee987c400 100644 --- a/test/Microsoft.AspNet.Security.DataProtection.Test/project.json +++ b/test/Microsoft.AspNet.Security.DataProtection.Test/project.json @@ -1,6 +1,7 @@ { "dependencies": { "Microsoft.AspNet.Security.DataProtection": "1.0.0-*", + "Microsoft.AspNet.Testing": "1.0.0-*", "Moq": "4.2.1312.1622", "xunit.runner.kre": "1.0.0-*" },