Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit 78357cf

Browse files
bartonjsjoshfree
authored andcommitted
Make TripleDESCryptoServiceProvider CreateTransform behave like netfx
.NET Framework's TripleDESCryptoServiceProvider rejects small inputs, but accepts oversized IVs (effectively truncating them to the block size). This change makes the .NET Core type behave the same way, and adds a test to codify all of the oversized IV relationships with the CryptoServiceProvider compat types. (DES and RC2 apparently already allowed it)
1 parent 2d39212 commit 78357cf

File tree

3 files changed

+92
-2
lines changed

3 files changed

+92
-2
lines changed

src/System.Security.Cryptography.Csp/src/System/Security/Cryptography/TripleDESCryptoServiceProvider.cs

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,34 @@ public override PaddingMode Padding
6363
public override KeySizes[] LegalBlockSizes => _impl.LegalBlockSizes;
6464
public override KeySizes[] LegalKeySizes => _impl.LegalKeySizes;
6565
public override ICryptoTransform CreateEncryptor() => _impl.CreateEncryptor();
66-
public override ICryptoTransform CreateEncryptor(byte[] rgbKey, byte[] rgbIV) => _impl.CreateEncryptor(rgbKey, rgbIV);
6766
public override ICryptoTransform CreateDecryptor() => _impl.CreateDecryptor();
68-
public override ICryptoTransform CreateDecryptor(byte[] rgbKey, byte[] rgbIV) => _impl.CreateDecryptor(rgbKey, rgbIV);
6967
public override void GenerateIV() => _impl.GenerateIV();
7068
public override void GenerateKey() => _impl.GenerateKey();
7169

70+
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA5350", Justification = "This is the implementation of TripleDES")]
71+
public override ICryptoTransform CreateEncryptor(byte[] rgbKey, byte[] rgbIV) =>
72+
_impl.CreateEncryptor(rgbKey, TrimLargeIV(rgbIV));
73+
74+
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA5350", Justification = "This is the implementation of TripleDES")]
75+
public override ICryptoTransform CreateDecryptor(byte[] rgbKey, byte[] rgbIV) =>
76+
_impl.CreateDecryptor(rgbKey, TrimLargeIV(rgbIV));
77+
78+
private byte[] TrimLargeIV(byte[] iv)
79+
{
80+
// The BlockSize for 3DES is 64, so this is always 8, but let's use
81+
// the formula anyways.
82+
int blockSizeBytes = (BlockSize + 7) / 8;
83+
84+
if (iv?.Length > blockSizeBytes)
85+
{
86+
byte[] tmp = new byte[blockSizeBytes];
87+
Buffer.BlockCopy(iv, 0, tmp, 0, tmp.Length);
88+
return tmp;
89+
}
90+
91+
return iv;
92+
}
93+
7294
protected override void Dispose(bool disposing)
7395
{
7496
if (disposing)
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using Xunit;
6+
7+
namespace System.Security.Cryptography.Csp.Tests
8+
{
9+
public static class CreateTransformCompat
10+
{
11+
[Theory]
12+
[InlineData(typeof(AesCryptoServiceProvider), null)]
13+
[InlineData(typeof(DESCryptoServiceProvider), 9)]
14+
[InlineData(typeof(DESCryptoServiceProvider), 13)]
15+
[InlineData(typeof(RC2CryptoServiceProvider), 9)]
16+
[InlineData(typeof(RC2CryptoServiceProvider), 17)]
17+
[InlineData(typeof(TripleDESCryptoServiceProvider), 9)]
18+
[InlineData(typeof(TripleDESCryptoServiceProvider), 24)]
19+
[InlineData(typeof(TripleDESCryptoServiceProvider), 31)]
20+
public static void CreateTransform_IVTooBig(Type t, int? ivSizeBytes)
21+
{
22+
using (SymmetricAlgorithm alg = (SymmetricAlgorithm)Activator.CreateInstance(t))
23+
{
24+
alg.Mode = CipherMode.CBC;
25+
byte[] key = alg.Key;
26+
27+
// If it isn't supposed to work
28+
if (ivSizeBytes == null)
29+
{
30+
// badSize is in bytes, BlockSize is in bits.
31+
// So badSize is 8 times as big as it should be.
32+
int badSize = alg.BlockSize;
33+
Assert.Throws<ArgumentException>(() => alg.CreateEncryptor(key, new byte[badSize]));
34+
Assert.Throws<ArgumentException>(() => alg.CreateDecryptor(key, new byte[badSize]));
35+
36+
return;
37+
}
38+
39+
int correctSize = alg.BlockSize / 8;
40+
byte[] data = { 1, 2, 3, 4, 5 };
41+
42+
byte[] iv = new byte[ivSizeBytes.Value];
43+
44+
for (int i = 0; i < iv.Length; i++)
45+
{
46+
iv[i] = (byte)((byte.MaxValue - i) ^ correctSize);
47+
}
48+
49+
byte[] correctIV = iv.AsSpan(0, correctSize).ToArray();
50+
51+
using (ICryptoTransform correctEnc = alg.CreateEncryptor(key, correctIV))
52+
using (ICryptoTransform badIvEnc = alg.CreateEncryptor(key, iv))
53+
using (ICryptoTransform badIvDec = alg.CreateDecryptor(key, iv))
54+
{
55+
byte[] encrypted = badIvEnc.TransformFinalBlock(data, 0, data.Length);
56+
byte[] correctEncrypted = correctEnc.TransformFinalBlock(data, 0, data.Length);
57+
58+
Assert.Equal(correctEncrypted, encrypted);
59+
60+
byte[] decrypted1 = badIvDec.TransformFinalBlock(correctEncrypted, 0, correctEncrypted.Length);
61+
62+
Assert.Equal(data, decrypted1);
63+
}
64+
}
65+
}
66+
}
67+
}

src/System.Security.Cryptography.Csp/tests/System.Security.Cryptography.Csp.Tests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Windows_NT-Debug|AnyCPU'" />
1414
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Windows_NT-Release|AnyCPU'" />
1515
<ItemGroup>
16+
<Compile Include="CreateTransformCompat.cs" />
1617
<Compile Include="CspParametersTests.cs" />
1718
<Compile Include="RSAImportExportCspBlobTests.cs" />
1819
<Compile Include="RSACryptoServiceProviderBackCompat.cs" />

0 commit comments

Comments
 (0)