diff --git a/DataProtection.sln b/DataProtection.sln
index 3437c905a7..5d906c25f6 100644
--- a/DataProtection.sln
+++ b/DataProtection.sln
@@ -21,6 +21,8 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Cryptograp
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Cryptography.KeyDerivation.Test", "test\Microsoft.AspNet.Cryptography.KeyDerivation.Test\Microsoft.AspNet.Cryptography.KeyDerivation.Test.kproj", "{42C97F52-8D56-46BD-A712-4F22BED157A7}"
EndProject
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Cryptography.Internal.Test", "test\Microsoft.AspNet.Cryptography.Internal.Test\Microsoft.AspNet.Cryptography.Internal.Test.kproj", "{37053D5F-5B61-47CE-8B72-298CE007FFB0}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -77,6 +79,14 @@ Global
{42C97F52-8D56-46BD-A712-4F22BED157A7}.Release|Any CPU.Build.0 = Release|Any CPU
{42C97F52-8D56-46BD-A712-4F22BED157A7}.Release|x86.ActiveCfg = Release|Any CPU
{42C97F52-8D56-46BD-A712-4F22BED157A7}.Release|x86.Build.0 = Release|Any CPU
+ {37053D5F-5B61-47CE-8B72-298CE007FFB0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {37053D5F-5B61-47CE-8B72-298CE007FFB0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {37053D5F-5B61-47CE-8B72-298CE007FFB0}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {37053D5F-5B61-47CE-8B72-298CE007FFB0}.Debug|x86.Build.0 = Debug|Any CPU
+ {37053D5F-5B61-47CE-8B72-298CE007FFB0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {37053D5F-5B61-47CE-8B72-298CE007FFB0}.Release|Any CPU.Build.0 = Release|Any CPU
+ {37053D5F-5B61-47CE-8B72-298CE007FFB0}.Release|x86.ActiveCfg = Release|Any CPU
+ {37053D5F-5B61-47CE-8B72-298CE007FFB0}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -89,5 +99,6 @@ Global
{E2779976-A28C-4365-A4BB-4AD854FAF23E} = {5FCB2DA3-5395-47F5-BCEE-E0EA319448EA}
{421F0383-34B1-402D-807B-A94542513ABA} = {5FCB2DA3-5395-47F5-BCEE-E0EA319448EA}
{42C97F52-8D56-46BD-A712-4F22BED157A7} = {60336AB3-948D-4D15-A5FB-F32A2B91E814}
+ {37053D5F-5B61-47CE-8B72-298CE007FFB0} = {60336AB3-948D-4D15-A5FB-F32A2B91E814}
EndGlobalSection
EndGlobal
diff --git a/src/Microsoft.AspNet.Cryptography.Internal/Properties/AssemblyInfo.cs b/src/Microsoft.AspNet.Cryptography.Internal/Properties/AssemblyInfo.cs
index 3f612d6db3..65c143563c 100644
--- a/src/Microsoft.AspNet.Cryptography.Internal/Properties/AssemblyInfo.cs
+++ b/src/Microsoft.AspNet.Cryptography.Internal/Properties/AssemblyInfo.cs
@@ -8,6 +8,7 @@ using System.Runtime.InteropServices;
// we only ever p/invoke into DLLs known to be in the System32 folder
[assembly: DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
+[assembly: InternalsVisibleTo("Microsoft.AspNet.Cryptography.Internal.Test")]
[assembly: InternalsVisibleTo("Microsoft.AspNet.Cryptography.KeyDerivation")]
[assembly: InternalsVisibleTo("Microsoft.AspNet.Cryptography.KeyDerivation.Test")]
[assembly: InternalsVisibleTo("Microsoft.AspNet.Security.DataProtection")]
diff --git a/src/Microsoft.AspNet.Security.DataProtection/AuthenticatedEncryption/IOptimizedAuthenticatedEncryptor.cs b/src/Microsoft.AspNet.Security.DataProtection/AuthenticatedEncryption/IOptimizedAuthenticatedEncryptor.cs
index aa8d7c72fb..6535cb146b 100644
--- a/src/Microsoft.AspNet.Security.DataProtection/AuthenticatedEncryption/IOptimizedAuthenticatedEncryptor.cs
+++ b/src/Microsoft.AspNet.Security.DataProtection/AuthenticatedEncryption/IOptimizedAuthenticatedEncryptor.cs
@@ -18,18 +18,25 @@ namespace Microsoft.AspNet.Security.DataProtection.AuthenticatedEncryption
/// the returned ciphertext but which will still be covered by the authentication tag.
/// This input may be zero bytes in length. The same AAD must be specified in the corresponding
/// call to Decrypt.
- /// The number of bytes to include before the ciphertext in the return value.
- /// The number of bytes to include after the ciphertext in the return value.
+ /// The number of bytes to pad before the ciphertext in the output.
+ /// The number of bytes to pad after the ciphertext in the output.
///
- /// A buffer containing the ciphertext and authentication tag.
- /// If a non-zero pre-buffer or post-buffer size is specified, the returned buffer will contain appropriate padding
- /// on either side of the ciphertext and authentication tag. For instance, if a pre-buffer size of 4 and a post-buffer
- /// size of 7 are specified, and if the ciphertext and tag are a combined 48 bytes, then the returned buffer will
- /// be a total 59 bytes in length. The first four bytes will be undefined, the next 48 bytes will contain the
- /// ciphertext and tag, and the last seven bytes will be undefined. The intent is that the caller can overwrite the
- /// pre-buffer or post-buffer with a header or footer without needing to allocate an additional buffer object.
+ /// The ciphertext blob, including authentication tag. The ciphertext blob will be surrounded by
+ /// the number of padding bytes requested. For instance, if the given (plaintext, AAD) input results
+ /// in a (ciphertext, auth tag) output of 0x0102030405, and if 'preBufferSize' is 3 and
+ /// 'postBufferSize' is 5, then the return value will be 0xYYYYYY0102030405ZZZZZZZZZZ, where bytes
+ /// YY and ZZ are undefined.
///
- /// All cryptography-related exceptions should be homogenized to CryptographicException.
+ ///
+ /// This method allows for a slight performance improvement over IAuthenticatedEncryptor.Encrypt
+ /// in the case where the caller needs to prepend or append some data to the resulting ciphertext.
+ /// For instance, if the caller needs to append a 32-bit header to the resulting ciphertext, then
+ /// he can specify 4 for 'preBufferSize' and overwrite the first 32 bits of the buffer returned
+ /// by this function. This saves the caller from having to allocate a new buffer to hold the final
+ /// transformed result.
+ ///
+ /// All cryptography-related exceptions should be homogenized to CryptographicException.
+ ///
byte[] Encrypt(ArraySegment plaintext, ArraySegment additionalAuthenticatedData, uint preBufferSize, uint postBufferSize);
}
}
diff --git a/test/Microsoft.AspNet.Cryptography.Internal.Test/Microsoft.AspNet.Cryptography.Internal.Test.kproj b/test/Microsoft.AspNet.Cryptography.Internal.Test/Microsoft.AspNet.Cryptography.Internal.Test.kproj
new file mode 100644
index 0000000000..bf71fe331c
--- /dev/null
+++ b/test/Microsoft.AspNet.Cryptography.Internal.Test/Microsoft.AspNet.Cryptography.Internal.Test.kproj
@@ -0,0 +1,17 @@
+
+
+
+ 14.0
+ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
+
+
+
+ 37053d5f-5b61-47ce-8b72-298ce007ffb0
+ ..\..\artifacts\obj\$(MSBuildProjectName)
+ ..\..\artifacts\bin\$(MSBuildProjectName)\
+
+
+ 2.0
+
+
+
diff --git a/test/Microsoft.AspNet.Cryptography.Internal.Test/Properties/AssemblyInfo.cs b/test/Microsoft.AspNet.Cryptography.Internal.Test/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..3f8188a594
--- /dev/null
+++ b/test/Microsoft.AspNet.Cryptography.Internal.Test/Properties/AssemblyInfo.cs
@@ -0,0 +1,8 @@
+// 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.Runtime.CompilerServices;
+
+// for unit testing
+[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
diff --git a/test/Microsoft.AspNet.Cryptography.Internal.Test/WeakReferenceHelpersTests.cs b/test/Microsoft.AspNet.Cryptography.Internal.Test/WeakReferenceHelpersTests.cs
new file mode 100644
index 0000000000..9b34dacd6d
--- /dev/null
+++ b/test/Microsoft.AspNet.Cryptography.Internal.Test/WeakReferenceHelpersTests.cs
@@ -0,0 +1,87 @@
+// 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 Xunit;
+
+namespace Microsoft.AspNet.Cryptography
+{
+ public class WeakReferenceHelpersTests
+ {
+ [Fact]
+ public void GetSharedInstance_ExistingWeakRefHasBeenGCed_CreatesNew()
+ {
+ // Arrange
+ WeakReference wrOriginal = new WeakReference(null);
+ WeakReference wr = wrOriginal;
+ MyDisposable newInstance = new MyDisposable();
+
+ // Act
+ var retVal = WeakReferenceHelpers.GetSharedInstance(ref wr, () => newInstance);
+
+ // Assert
+ MyDisposable target;
+ Assert.NotNull(wr);
+ Assert.NotSame(wrOriginal, wr);
+ Assert.True(wr.TryGetTarget(out target));
+ Assert.Same(newInstance, target);
+ Assert.Same(newInstance, retVal);
+ Assert.False(newInstance.HasBeenDisposed);
+ }
+
+ [Fact]
+ public void GetSharedInstance_ExistingWeakRefIsNull_CreatesNew()
+ {
+ // Arrange
+ WeakReference wr = null;
+ MyDisposable newInstance = new MyDisposable();
+
+ // Act
+ var retVal = WeakReferenceHelpers.GetSharedInstance(ref wr, () => newInstance);
+
+ // Assert
+ MyDisposable target;
+ Assert.NotNull(wr);
+ Assert.True(wr.TryGetTarget(out target));
+ Assert.Same(newInstance, target);
+ Assert.Same(newInstance, retVal);
+ Assert.False(newInstance.HasBeenDisposed);
+ }
+
+ [Fact]
+ public void GetSharedInstance_ExistingWeakRefIsNull_AnotherThreadCreatesInstanceWhileOurFactoryRuns_ReturnsExistingInstanceAndDisposesNewInstance()
+ {
+ // Arrange
+ WeakReference wr = null;
+ MyDisposable instanceThatWillBeCreatedFirst = new MyDisposable();
+ MyDisposable instanceThatWillBeCreatedSecond = new MyDisposable();
+
+ // Act
+ var retVal = WeakReferenceHelpers.GetSharedInstance(ref wr, () =>
+ {
+ // mimic another thread creating the instance while our factory is being invoked
+ WeakReferenceHelpers.GetSharedInstance(ref wr, () => instanceThatWillBeCreatedFirst);
+ return instanceThatWillBeCreatedSecond;
+ });
+
+ // Assert
+ MyDisposable target;
+ Assert.NotNull(wr);
+ Assert.True(wr.TryGetTarget(out target));
+ Assert.Same(instanceThatWillBeCreatedFirst, target);
+ Assert.Same(instanceThatWillBeCreatedFirst, retVal);
+ Assert.False(instanceThatWillBeCreatedFirst.HasBeenDisposed);
+ Assert.True(instanceThatWillBeCreatedSecond.HasBeenDisposed);
+ }
+
+ private sealed class MyDisposable : IDisposable
+ {
+ public bool HasBeenDisposed { get; private set; }
+
+ public void Dispose()
+ {
+ HasBeenDisposed = true;
+ }
+ }
+ }
+}
diff --git a/test/Microsoft.AspNet.Cryptography.Internal.Test/project.json b/test/Microsoft.AspNet.Cryptography.Internal.Test/project.json
new file mode 100644
index 0000000000..8f1a47255e
--- /dev/null
+++ b/test/Microsoft.AspNet.Cryptography.Internal.Test/project.json
@@ -0,0 +1,13 @@
+{
+ "dependencies": {
+ "Microsoft.AspNet.Cryptography.Internal": "1.0.0-*",
+ "Microsoft.AspNet.Testing": "1.0.0-*",
+ "xunit.runner.kre": "1.0.0-*"
+ },
+ "frameworks": {
+ "aspnet50": { }
+ },
+ "commands": {
+ "test": "xunit.runner.kre"
+ }
+}