Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.
/ corefx Public archive

Commit

Permalink
Make derived types of SymmetricAlgorithm use field assignment in ctors.
Browse files Browse the repository at this point in the history
Aes and TripleDES both did assignments via virtual property setters in their ctor,
which were field assignments in .NET Framework.  3rd party implementations
may have written properties which assumed that the ctor had run to completion,
and they are broken by that behavioral change.

This change makes the ctors look like they do in net462, aside from when
net462 sets fields which don't exist.

It also makes the tests fail if virtual setter dispatch was utilized (for any currently
defined property, at least).

cherry-pick of 5345525 and
207e52e to the release/1.1.0 branch,
with master-only TODO comments removed.
  • Loading branch information
bartonjs committed Oct 20, 2016
1 parent d2f3cf7 commit 69ebf34
Show file tree
Hide file tree
Showing 5 changed files with 281 additions and 44 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.Diagnostics;

using Internal.Cryptography;

namespace System.Security.Cryptography
Expand All @@ -12,34 +10,19 @@ public abstract class Aes : SymmetricAlgorithm
{
protected Aes()
{
this.BlockSize = 128;
this.KeySize = 256;
this.Mode = CipherMode.CBC;
}

public override KeySizes[] LegalBlockSizes
{
get
{
return s_legalBlockSizes.CloneKeySizesArray();
}
}
LegalBlockSizesValue = s_legalBlockSizes.CloneKeySizesArray();
LegalKeySizesValue = s_legalKeySizes.CloneKeySizesArray();

public override KeySizes[] LegalKeySizes
{
get
{
return s_legalKeySizes.CloneKeySizesArray();
}
BlockSizeValue = 128;
KeySizeValue = 256;
ModeValue = CipherMode.CBC;
}

public static Aes Create()
{
return new AesImplementation();
}



private static readonly KeySizes[] s_legalBlockSizes = { new KeySizes(128, 128, 0) };
private static readonly KeySizes[] s_legalKeySizes = { new KeySizes(128, 256, 64) };
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,31 +13,17 @@ public abstract class TripleDES : SymmetricAlgorithm
{
protected TripleDES()
{
KeySize = 3*64;
BlockSize = 64;
KeySizeValue = 3*64;
BlockSizeValue = 64;
LegalBlockSizesValue = s_legalBlockSizes.CloneKeySizesArray();
LegalKeySizesValue = s_legalKeySizes.CloneKeySizesArray();
}

public static TripleDES Create()
{
return new TripleDesImplementation();
}

public override KeySizes[] LegalKeySizes
{
get
{
return s_legalKeySizes.CloneKeySizesArray();
}
}

public override KeySizes[] LegalBlockSizes
{
get
{
return s_legalBlockSizes.CloneKeySizesArray();
}
}

public override byte[] Key
{
get
Expand Down
157 changes: 157 additions & 0 deletions src/System.Security.Cryptography.Algorithms/tests/AesTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using Xunit;

namespace System.Security.Cryptography.Algorithms.Tests
{
public partial class AesTests
{
[Fact]
public static void AesDefaultCtor()
{
using (Aes aes = new AesMinimal())
{
Assert.Equal(256, aes.KeySize);
Assert.Equal(128, aes.BlockSize);
Assert.Equal(CipherMode.CBC, aes.Mode);
Assert.Equal(PaddingMode.PKCS7, aes.Padding);
}
}

[Fact]
public static void EnsureLegalSizesValuesIsolated()
{
new AesLegalSizesBreaker().Dispose();

using (Aes aes = Aes.Create())
{
Assert.Equal(128, aes.LegalKeySizes[0].MinSize);
Assert.Equal(128, aes.LegalBlockSizes[0].MinSize);

aes.Key = new byte[16];
}
}

private class AesLegalSizesBreaker : AesMinimal
{
public AesLegalSizesBreaker()
{
LegalKeySizesValue[0] = new KeySizes(1, 1, 0);
LegalBlockSizesValue[0] = new KeySizes(1, 1, 0);
}
}

private class AesMinimal : Aes
{
// If the constructor uses a virtual call to any of the property setters
// they will fail.
private readonly bool _ready;

public AesMinimal()
{
// Don't set this as a field initializer, otherwise it runs before the base ctor.
_ready = true;
}

public override int KeySize
{
set
{
if (!_ready)
{
throw new InvalidOperationException();
}

base.KeySize = value;
}
}

public override int BlockSize
{
set
{
if (!_ready)
{
throw new InvalidOperationException();
}

base.BlockSize = value;
}
}

public override byte[] IV
{
set
{
if (!_ready)
{
throw new InvalidOperationException();
}

base.IV = value;
}
}

public override byte[] Key
{
set
{
if (!_ready)
{
throw new InvalidOperationException();
}

base.Key = value;
}
}

public override CipherMode Mode
{
set
{
if (!_ready)
{
throw new InvalidOperationException();
}

base.Mode = value;
}
}

public override PaddingMode Padding
{
set
{
if (!_ready)
{
throw new InvalidOperationException();
}

base.Padding = value;
}
}

public override ICryptoTransform CreateDecryptor(byte[] rgbKey, byte[] rgbIV)
{
throw new NotImplementedException();
}

public override ICryptoTransform CreateEncryptor(byte[] rgbKey, byte[] rgbIV)
{
throw new NotImplementedException();
}

public override void GenerateIV()
{
throw new NotImplementedException();
}

public override void GenerateKey()
{
throw new NotImplementedException();
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@
<Link>CommonTest\System\RandomDataGenerator.cs</Link>
</Compile>
<Compile Include="AesProvider.cs" />
<Compile Include="AesTests.cs" />
<Compile Include="DefaultECDsaProvider.cs" />
<Compile Include="DefaultRSAProvider.cs" />
<Compile Include="HashAlgorithmTest.cs" />
Expand Down
118 changes: 114 additions & 4 deletions src/System.Security.Cryptography.Algorithms/tests/TripleDesTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@

using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using Test.Cryptography;
using Xunit;
Expand All @@ -16,7 +14,7 @@ namespace System.Security.Cryptography.Encryption.TripleDes.Tests
public static partial class TripleDesTests
{
[Fact]
public static void DesDefaultCtor()
public static void TripleDesDefaultCtor()
{
using (TripleDES tdes = new TripleDESMinimal())
{
Expand Down Expand Up @@ -78,6 +76,25 @@ public static void TripleDesCreate()
Assert.Equal(inputBytes, decryptedBytes);
}

[Fact]
public static void EnsureLegalSizesValuesIsolated()
{
new TripleDESLegalSizesBreaker().Dispose();

using (TripleDES tripleDes = TripleDES.Create())
{
Assert.Equal(3 * 64, tripleDes.LegalKeySizes[0].MaxSize);
Assert.Equal(64, tripleDes.LegalBlockSizes[0].MaxSize);

tripleDes.Key = new byte[]
{
/* k1 */ 0, 1, 2, 3, 4, 5, 6, 7,
/* k2 */ 0, 0, 0, 2, 4, 6, 0, 1,
/* k3 */ 0, 1, 2, 3, 4, 5, 6, 7,
};
}
}

private static IEnumerable<byte[]> BadKeys()
{
foreach (byte[] key in _weakKeys)
Expand All @@ -104,10 +121,103 @@ private static byte[] RemoveDesParityBits(this byte[] key)
"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb0000000000000000".HexToByteArray(),
};

private sealed class TripleDESMinimal : TripleDES
private class TripleDESLegalSizesBreaker : TripleDESMinimal
{
public TripleDESLegalSizesBreaker()
{
LegalKeySizesValue[0] = new KeySizes(1, 1, 0);
LegalBlockSizesValue[0] = new KeySizes(1, 1, 0);
}
}

private class TripleDESMinimal : TripleDES
{
// If the constructor uses a virtual call to any of the property setters
// they will fail.
private readonly bool _ready;

public TripleDESMinimal()
{
// Don't set this as a field initializer, otherwise it runs before the base ctor.
_ready = true;
}

public override int KeySize
{
set
{
if (!_ready)
{
throw new InvalidOperationException();
}

base.KeySize = value;
}
}

public override int BlockSize
{
set
{
if (!_ready)
{
throw new InvalidOperationException();
}

base.BlockSize = value;
}
}

public override byte[] IV
{
set
{
if (!_ready)
{
throw new InvalidOperationException();
}

base.IV = value;
}
}

public override byte[] Key
{
set
{
if (!_ready)
{
throw new InvalidOperationException();
}

base.Key = value;
}
}

public override CipherMode Mode
{
set
{
if (!_ready)
{
throw new InvalidOperationException();
}

base.Mode = value;
}
}

public override PaddingMode Padding
{
set
{
if (!_ready)
{
throw new InvalidOperationException();
}

base.Padding = value;
}
}

public sealed override void GenerateIV()
Expand Down

0 comments on commit 69ebf34

Please sign in to comment.