Skip to content

Commit

Permalink
Add one-shot CFB encrypt/decrypt to SymmetricAlgorithm
Browse files Browse the repository at this point in the history
Adds the CFB versions similar to the already-added ECB and CBC versions.

Co-authored-by: Jeremy Barton <jbarton@microsoft.com>
  • Loading branch information
vcsjones and bartonjs authored Jul 13, 2021
1 parent 59ab54c commit 2d3acc6
Show file tree
Hide file tree
Showing 28 changed files with 2,857 additions and 176 deletions.
9 changes: 2 additions & 7 deletions src/libraries/Common/src/Internal/Cryptography/Helpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,9 @@ internal static partial class Helpers
return (byte[])(src.Clone());
}

public static int GetPaddingSize(this SymmetricAlgorithm algorithm, CipherMode mode, int feedbackSizeBits)
public static int GetPaddingSize(this SymmetricAlgorithm algorithm, CipherMode mode, int feedbackSizeInBits)
{
// CFB8 does not require any padding at all
// otherwise, it is always required to pad for block size
if (mode == CipherMode.CFB && feedbackSizeBits == 8)
return 1;

return algorithm.BlockSize / 8;
return (mode == CipherMode.CFB ? feedbackSizeInBits : algorithm.BlockSize) / 8;
}

internal static bool TryCopyToDestination(ReadOnlySpan<byte> source, Span<byte> destination, out int bytesWritten)
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -1124,6 +1124,7 @@ private static void TestAesTransformDirectKey(
{
aes.Mode = cipherMode;
aes.Padding = paddingMode;
aes.Key = key;

if (feedbackSize.HasValue)
{
Expand All @@ -1135,16 +1136,19 @@ private static void TestAesTransformDirectKey(

if (cipherMode == CipherMode.ECB)
{
aes.Key = key;
liveOneShotDecryptBytes = aes.DecryptEcb(cipherBytes, paddingMode);
liveOneShotEncryptBytes = aes.EncryptEcb(plainBytes, paddingMode);
}
else if (cipherMode == CipherMode.CBC)
{
aes.Key = key;
liveOneShotDecryptBytes = aes.DecryptCbc(cipherBytes, iv, paddingMode);
liveOneShotEncryptBytes = aes.EncryptCbc(plainBytes, iv, paddingMode);
}
else if (cipherMode == CipherMode.CFB)
{
liveOneShotDecryptBytes = aes.DecryptCfb(cipherBytes, iv, paddingMode, feedbackSizeInBits: feedbackSize.Value);
liveOneShotEncryptBytes = aes.EncryptCfb(plainBytes, iv, paddingMode, feedbackSizeInBits: feedbackSize.Value);
}
}

Assert.Equal(cipherBytes, liveEncryptBytes);
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,7 @@ private static void TestDESTransformDirectKey(
{
des.Mode = cipherMode;
des.Padding = paddingMode;
des.Key = key;

if (feedbackSize.HasValue)
{
Expand All @@ -540,17 +541,23 @@ private static void TestDESTransformDirectKey(
liveEncryptBytes = DESEncryptDirectKey(des, key, iv, plainBytes);
liveDecryptBytes = DESDecryptDirectKey(des, key, iv, cipherBytes);

if (cipherMode == CipherMode.ECB)
{
des.Key = key;
liveOneShotDecryptBytes = des.DecryptEcb(cipherBytes, paddingMode);
liveOneShotEncryptBytes = des.EncryptEcb(plainBytes, paddingMode);
}
else if (cipherMode == CipherMode.CBC)
if (DESFactory.OneShotSupported)
{
des.Key = key;
liveOneShotDecryptBytes = des.DecryptCbc(cipherBytes, iv, paddingMode);
liveOneShotEncryptBytes = des.EncryptCbc(plainBytes, iv, paddingMode);
if (cipherMode == CipherMode.ECB)
{
liveOneShotDecryptBytes = des.DecryptEcb(cipherBytes, paddingMode);
liveOneShotEncryptBytes = des.EncryptEcb(plainBytes, paddingMode);
}
else if (cipherMode == CipherMode.CBC)
{
liveOneShotDecryptBytes = des.DecryptCbc(cipherBytes, iv, paddingMode);
liveOneShotEncryptBytes = des.EncryptCbc(plainBytes, iv, paddingMode);
}
else if (cipherMode == CipherMode.CFB)
{
liveOneShotDecryptBytes = des.DecryptCfb(cipherBytes, iv, paddingMode, feedbackSizeInBits: feedbackSize.Value);
liveOneShotEncryptBytes = des.EncryptCfb(plainBytes, iv, paddingMode, feedbackSizeInBits: feedbackSize.Value);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,12 @@ namespace System.Security.Cryptography.Encryption.Des.Tests
public interface IDESProvider
{
DES Create();
bool OneShotSupported { get; }
}

public static partial class DESFactory
{
public static DES Create()
{
return s_provider.Create();
}
public static DES Create() => s_provider.Create();
public static bool OneShotSupported => s_provider.OneShotSupported;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,26 @@ public void DecryptOneShot_Array(byte[] plaintext, byte[] ciphertext, PaddingMod
public void EncryptOneShot_Array(byte[] plaintext, byte[] ciphertext, PaddingMode padding, CipherMode mode) =>
EncryptOneShot_ArrayTest(plaintext, ciphertext, padding, mode);

[Fact]
public void EncryptOneShot_CfbNotSupported()
{
using (SymmetricAlgorithm alg = CreateAlgorithm())
{
Assert.ThrowsAny<CryptographicException>(() =>
alg.TryEncryptCfb(ReadOnlySpan<byte>.Empty, IV, Span<byte>.Empty, out _));
}
}

[Fact]
public void DecryptOneShot_CfbNotSupported()
{
using (SymmetricAlgorithm alg = CreateAlgorithm())
{
Assert.ThrowsAny<CryptographicException>(() =>
alg.TryDecryptCfb(ReadOnlySpan<byte>.Empty, IV, Span<byte>.Empty, out _));
}
}

public static IEnumerable<object[]> TestCases
{
get
Expand Down
Loading

0 comments on commit 2d3acc6

Please sign in to comment.