This change brings the Cipher Feedback (CFB) mode to .NET 5 with the same behaviors as .NET Framework around the non-standard application of PKCS#7 padding based on the feedback block size and decryption the data be algorithm blocksize-aligned.
* AES: CFB8 and CFB128
* TripleDES: CFB8 and CFB64
* DES: CFB8
* RC2: Not supported
Additionally, due to a lack of support in CNG, CFB is not supported on Windows 7.
//
internal abstract class BasicSymmetricCipher : IDisposable
{
- protected BasicSymmetricCipher(byte[]? iv, int blockSizeInBytes)
+ protected BasicSymmetricCipher(byte[]? iv, int blockSizeInBytes, int paddingSizeInBytes)
{
IV = iv;
BlockSizeInBytes = blockSizeInBytes;
+ PaddingSizeInBytes = paddingSizeInBytes > 0 ? paddingSizeInBytes : blockSizeInBytes;
}
public abstract int Transform(ReadOnlySpan<byte> input, Span<byte> output);
public abstract int TransformFinal(ReadOnlySpan<byte> input, Span<byte> output);
public int BlockSizeInBytes { get; private set; }
+ public int PaddingSizeInBytes { get; private set; }
public void Dispose()
{
private byte[]? _currentIv; // CNG mutates this with the updated IV for the next stage on each Encrypt/Decrypt call.
// The base IV holds a copy of the original IV for Reset(), until it is cleared by Dispose().
- public BasicSymmetricCipherBCrypt(SafeAlgorithmHandle algorithm, CipherMode cipherMode, int blockSizeInBytes, byte[] key, bool ownsParentHandle, byte[]? iv, bool encrypting)
- : base(cipherMode.GetCipherIv(iv), blockSizeInBytes)
+ public BasicSymmetricCipherBCrypt(SafeAlgorithmHandle algorithm, CipherMode cipherMode, int blockSizeInBytes, int paddingSizeInBytes, byte[] key, bool ownsParentHandle, byte[]? iv, bool encrypting)
+ : base(cipherMode.GetCipherIv(iv), blockSizeInBytes, paddingSizeInBytes)
{
Debug.Assert(algorithm != null);
public override int Transform(ReadOnlySpan<byte> input, Span<byte> output)
{
Debug.Assert(input.Length > 0);
- Debug.Assert((input.Length % BlockSizeInBytes) == 0);
+ Debug.Assert((input.Length % PaddingSizeInBytes) == 0);
int numBytesWritten;
public override int TransformFinal(ReadOnlySpan<byte> input, Span<byte> output)
{
- Debug.Assert((input.Length % BlockSizeInBytes) == 0);
+ Debug.Assert((input.Length % PaddingSizeInBytes) == 0);
int numBytesWritten = 0;
#nullable enable
using System;
using System.Diagnostics.CodeAnalysis;
+using System.Security.Cryptography;
namespace Internal.Cryptography
{
return (byte[])(src.Clone());
}
+ public static int GetPaddingSize(this SymmetricAlgorithm algorithm)
+ {
+ // CFB8 does not require any padding at all
+ // otherwise, it is always required to pad for block size
+ if (algorithm.Mode == CipherMode.CFB && algorithm.FeedbackSize == 8)
+ return 1;
+
+ return algorithm.BlockSize / 8;
+ }
+
internal static bool TryCopyToDestination(ReadOnlySpan<byte> source, Span<byte> destination, out int bytesWritten)
{
if (source.TryCopyTo(destination))
protected override unsafe int UncheckedTransformFinalBlock(ReadOnlySpan<byte> inputBuffer, Span<byte> outputBuffer)
{
// We can't complete decryption on a partial block
- if (inputBuffer.Length % InputBlockSize != 0)
+ if (inputBuffer.Length % PaddingSizeBytes != 0)
throw new CryptographicException(SR.Cryptography_PartialBlock);
//
Debug.Assert(plaintextLength >= 0);
//divisor and factor are same and won't overflow.
- int wholeBlocks = Math.DivRem(plaintextLength, InputBlockSize, out int remainder) * InputBlockSize;
+ int wholeBlocks = Math.DivRem(plaintextLength, PaddingSizeBytes, out int remainder) * PaddingSizeBytes;
switch (PaddingMode)
{
case PaddingMode.PKCS7:
case PaddingMode.ANSIX923:
case PaddingMode.ISO10126:
- return checked(wholeBlocks + InputBlockSize);
+ return checked(wholeBlocks + PaddingSizeBytes);
default:
Debug.Fail($"Unknown padding mode {PaddingMode}.");
throw new CryptographicException(SR.Cryptography_UnknownPaddingMode);
private int PadBlock(ReadOnlySpan<byte> block, Span<byte> destination)
{
int count = block.Length;
- int paddingRemainder = count % InputBlockSize;
- int padBytes = InputBlockSize - paddingRemainder;
+ int paddingRemainder = count % PaddingSizeBytes;
+ int padBytes = PaddingSizeBytes - paddingRemainder;
switch (PaddingMode)
{
//
internal abstract class UniversalCryptoTransform : ICryptoTransform
{
- public static ICryptoTransform Create(PaddingMode paddingMode, BasicSymmetricCipher cipher, bool encrypting)
+ public static ICryptoTransform Create(
+ PaddingMode paddingMode,
+ BasicSymmetricCipher cipher,
+ bool encrypting)
{
if (encrypting)
return new UniversalCryptoEncryptor(paddingMode, cipher);
get { return true; }
}
+ protected int PaddingSizeBytes
+ {
+ get { return BasicSymmetricCipher.PaddingSizeInBytes; }
+ }
+
public int InputBlockSize
{
get { return BasicSymmetricCipher.BlockSizeInBytes; }
{
ECB = 1,
CBC = 2,
+ CFB = 3,
+ CFB8 = 10,
}
internal enum PAL_SymmetricOptions
[DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpAes128Gcm")]
internal static extern IntPtr EvpAes128Gcm();
+ [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpAes128Cfb8")]
+ internal static extern IntPtr EvpAes128Cfb8();
+
+ [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpAes128Cfb128")]
+ internal static extern IntPtr EvpAes128Cfb128();
+
[DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpAes128Ccm")]
internal static extern IntPtr EvpAes128Ccm();
[DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpAes192Gcm")]
internal static extern IntPtr EvpAes192Gcm();
+ [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpAes192Cfb8")]
+ internal static extern IntPtr EvpAes192Cfb8();
+
+ [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpAes192Cfb128")]
+ internal static extern IntPtr EvpAes192Cfb128();
+
[DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpAes192Ccm")]
internal static extern IntPtr EvpAes192Ccm();
[DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpAes256Gcm")]
internal static extern IntPtr EvpAes256Gcm();
+ [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpAes256Cfb128")]
+ internal static extern IntPtr EvpAes256Cfb128();
+
+ [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpAes256Cfb8")]
+ internal static extern IntPtr EvpAes256Cfb8();
+
[DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpAes256Ccm")]
internal static extern IntPtr EvpAes256Ccm();
[DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpDesEcb")]
internal static extern IntPtr EvpDesEcb();
+ [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpDesCfb8")]
+ internal static extern IntPtr EvpDesCfb8();
+
[DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpDes3Cbc")]
internal static extern IntPtr EvpDes3Cbc();
[DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpDes3Ecb")]
internal static extern IntPtr EvpDes3Ecb();
+ [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpDes3Cfb8")]
+ internal static extern IntPtr EvpDes3Cfb8();
+
+ [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpDes3Cfb64")]
+ internal static extern IntPtr EvpDes3Cfb64();
+
[DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpRC2Cbc")]
internal static extern IntPtr EvpRC2Cbc();
{
internal static class AesBCryptModes
{
- private static readonly SafeAlgorithmHandle s_hAlgCbc = OpenAesAlgorithm(Cng.BCRYPT_CHAIN_MODE_CBC);
- private static readonly SafeAlgorithmHandle s_hAlgEcb = OpenAesAlgorithm(Cng.BCRYPT_CHAIN_MODE_ECB);
+ private static readonly Lazy<SafeAlgorithmHandle> s_hAlgCbc = OpenAesAlgorithm(Cng.BCRYPT_CHAIN_MODE_CBC);
+ private static readonly Lazy<SafeAlgorithmHandle> s_hAlgEcb = OpenAesAlgorithm(Cng.BCRYPT_CHAIN_MODE_ECB);
+ private static readonly Lazy<SafeAlgorithmHandle> s_hAlgCfb128 = OpenAesAlgorithm(Cng.BCRYPT_CHAIN_MODE_CFB, 16);
+ private static readonly Lazy<SafeAlgorithmHandle> s_hAlgCfb8 = OpenAesAlgorithm(Cng.BCRYPT_CHAIN_MODE_CFB, 1);
- internal static SafeAlgorithmHandle GetSharedHandle(CipherMode cipherMode) =>
+ internal static SafeAlgorithmHandle GetSharedHandle(CipherMode cipherMode, int feedback) =>
// Windows 8 added support to set the CipherMode value on a key,
// but Windows 7 requires that it be set on the algorithm before key creation.
- cipherMode switch
+ (cipherMode, feedback) switch
{
- CipherMode.CBC => s_hAlgCbc,
- CipherMode.ECB => s_hAlgEcb,
+ (CipherMode.CBC, _) => s_hAlgCbc.Value,
+ (CipherMode.ECB, _) => s_hAlgEcb.Value,
+ (CipherMode.CFB, 16) => s_hAlgCfb128.Value,
+ (CipherMode.CFB, 1) => s_hAlgCfb8.Value,
_ => throw new NotSupportedException(),
};
- internal static SafeAlgorithmHandle OpenAesAlgorithm(string cipherMode)
+ internal static Lazy<SafeAlgorithmHandle> OpenAesAlgorithm(string cipherMode, int feedback = 0)
{
- SafeAlgorithmHandle hAlg = Cng.BCryptOpenAlgorithmProvider(Cng.BCRYPT_AES_ALGORITHM, null, Cng.OpenAlgorithmProviderFlags.NONE);
- hAlg.SetCipherMode(cipherMode);
+ return new Lazy<SafeAlgorithmHandle>(() =>
+ {
+ SafeAlgorithmHandle hAlg = Cng.BCryptOpenAlgorithmProvider(Cng.BCRYPT_AES_ALGORITHM, null,
+ Cng.OpenAlgorithmProviderFlags.NONE);
+ hAlg.SetCipherMode(cipherMode);
+
+ // feedback is in bytes!
+ if (feedback > 0)
+ {
+ hAlg.SetFeedbackSize(feedback);
+ }
- return hAlg;
+ return hAlg;
+ });
}
}
}
public const string BCRYPT_CHAIN_MODE_CBC = "ChainingModeCBC";
public const string BCRYPT_CHAIN_MODE_ECB = "ChainingModeECB";
public const string BCRYPT_CHAIN_MODE_GCM = "ChainingModeGCM";
+ public const string BCRYPT_CHAIN_MODE_CFB = "ChainingModeCFB";
public const string BCRYPT_CHAIN_MODE_CCM = "ChainingModeCCM";
public static SafeAlgorithmHandle BCryptOpenAlgorithmProvider(string pszAlgId, string? pszImplementation, OpenAlgorithmProviderFlags dwFlags)
return hAlgorithm;
}
+ public static void SetFeedbackSize(this SafeAlgorithmHandle hAlg, int dwFeedbackSize)
+ {
+ NTSTATUS ntStatus = Interop.BCryptSetIntProperty(hAlg, BCryptPropertyStrings.BCRYPT_MESSAGE_BLOCK_LENGTH, ref dwFeedbackSize, 0);
+
+ if (ntStatus != NTSTATUS.STATUS_SUCCESS)
+ {
+ throw CreateCryptographicException(ntStatus);
+ }
+ }
+
public static void SetCipherMode(this SafeAlgorithmHandle hAlg, string cipherMode)
{
NTSTATUS ntStatus = Interop.BCryptSetProperty(hAlg, BCryptPropertyStrings.BCRYPT_CHAINING_MODE, cipherMode, (cipherMode.Length + 1) * 2, 0);
{
internal static class DesBCryptModes
{
- private static readonly SafeAlgorithmHandle s_hAlgCbc = OpenDesAlgorithm(Cng.BCRYPT_CHAIN_MODE_CBC);
- private static readonly SafeAlgorithmHandle s_hAlgEcb = OpenDesAlgorithm(Cng.BCRYPT_CHAIN_MODE_ECB);
+ private static readonly Lazy<SafeAlgorithmHandle> s_hAlgCbc = OpenDesAlgorithm(Cng.BCRYPT_CHAIN_MODE_CBC);
+ private static readonly Lazy<SafeAlgorithmHandle> s_hAlgEcb = OpenDesAlgorithm(Cng.BCRYPT_CHAIN_MODE_ECB);
+ private static readonly Lazy<SafeAlgorithmHandle> s_hAlgCfb8 = OpenDesAlgorithm(Cng.BCRYPT_CHAIN_MODE_CFB, 1);
- internal static SafeAlgorithmHandle GetSharedHandle(CipherMode cipherMode) =>
+ internal static SafeAlgorithmHandle GetSharedHandle(CipherMode cipherMode, int feedback) =>
// Windows 8 added support to set the CipherMode value on a key,
// but Windows 7 requires that it be set on the algorithm before key creation.
- cipherMode switch
+ (cipherMode, feedback) switch
{
- CipherMode.CBC => s_hAlgCbc,
- CipherMode.ECB => s_hAlgEcb,
+ (CipherMode.CBC, _) => s_hAlgCbc.Value,
+ (CipherMode.ECB, _) => s_hAlgEcb.Value,
+ (CipherMode.CFB, 1) => s_hAlgCfb8.Value,
_ => throw new NotSupportedException(),
};
- private static SafeAlgorithmHandle OpenDesAlgorithm(string cipherMode)
+ private static Lazy<SafeAlgorithmHandle> OpenDesAlgorithm(string cipherMode, int feedback = 0)
{
- SafeAlgorithmHandle hAlg = Cng.BCryptOpenAlgorithmProvider(Cng.BCRYPT_DES_ALGORITHM, null, Cng.OpenAlgorithmProviderFlags.NONE);
- hAlg.SetCipherMode(cipherMode);
+ return new Lazy<SafeAlgorithmHandle>(() =>
+ {
+ SafeAlgorithmHandle hAlg = Cng.BCryptOpenAlgorithmProvider(Cng.BCRYPT_DES_ALGORITHM,
+ null,
+ Cng.OpenAlgorithmProviderFlags.NONE);
+ hAlg.SetCipherMode(cipherMode);
+
+ if (feedback > 0)
+ {
+ hAlg.SetFeedbackSize(feedback);
+ }
- return hAlg;
+ return hAlg;
+ });
}
}
}
{
internal const string BCRYPT_CHAIN_MODE_CBC = "ChainingModeCBC";
internal const string BCRYPT_CHAIN_MODE_ECB = "ChainingModeECB";
+ internal const string BCRYPT_CHAIN_MODE_CFB = "ChainingModeCFB";
}
}
internal const string BCRYPT_ECC_PARAMETERS = "ECCParameters";
internal const string BCRYPT_EFFECTIVE_KEY_LENGTH = "EffectiveKeyLength";
internal const string BCRYPT_HASH_LENGTH = "HashDigestLength";
+ internal const string BCRYPT_MESSAGE_BLOCK_LENGTH = "MessageBlockLength";
}
}
}
internal static class TripleDesBCryptModes
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA5350", Justification = "We are providing the implementation for TripleDES, not consuming it")]
- private static readonly SafeAlgorithmHandle s_hAlgCbc = Open3DesAlgorithm(Cng.BCRYPT_CHAIN_MODE_CBC);
+ private static readonly Lazy<SafeAlgorithmHandle> s_hAlgCbc = Open3DesAlgorithm(Cng.BCRYPT_CHAIN_MODE_CBC);
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA5350", Justification = "We are providing the implementation for TripleDES, not consuming it")]
- private static readonly SafeAlgorithmHandle s_hAlgEcb = Open3DesAlgorithm(Cng.BCRYPT_CHAIN_MODE_ECB);
+ private static readonly Lazy<SafeAlgorithmHandle> s_hAlgEcb = Open3DesAlgorithm(Cng.BCRYPT_CHAIN_MODE_ECB);
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA5350", Justification = "We are providing the implementation for TripleDES, not consuming it")]
+ private static readonly Lazy<SafeAlgorithmHandle> s_hAlgCfb8 = Open3DesAlgorithm(Cng.BCRYPT_CHAIN_MODE_CFB, 1);
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA5350", Justification = "We are providing the implementation for TripleDES, not consuming it")]
+ private static readonly Lazy<SafeAlgorithmHandle> s_hAlgCfb64 = Open3DesAlgorithm(Cng.BCRYPT_CHAIN_MODE_CFB, 8);
- internal static SafeAlgorithmHandle GetSharedHandle(CipherMode cipherMode) =>
+ internal static SafeAlgorithmHandle GetSharedHandle(CipherMode cipherMode, int feedback) =>
// Windows 8 added support to set the CipherMode value on a key,
// but Windows 7 requires that it be set on the algorithm before key creation.
- cipherMode switch
+ (cipherMode, feedback) switch
{
- CipherMode.CBC => s_hAlgCbc,
- CipherMode.ECB => s_hAlgEcb,
+ (CipherMode.CBC, _) => s_hAlgCbc.Value,
+ (CipherMode.ECB, _) => s_hAlgEcb.Value,
+ (CipherMode.CFB, 1) => s_hAlgCfb8.Value,
+ (CipherMode.CFB, 8) => s_hAlgCfb64.Value,
_ => throw new NotSupportedException(),
};
- private static SafeAlgorithmHandle Open3DesAlgorithm(string cipherMode)
+ private static Lazy<SafeAlgorithmHandle> Open3DesAlgorithm(string cipherMode, int feedback = 0)
{
- SafeAlgorithmHandle hAlg = Cng.BCryptOpenAlgorithmProvider(Cng.BCRYPT_3DES_ALGORITHM, null, Cng.OpenAlgorithmProviderFlags.NONE);
- hAlg.SetCipherMode(cipherMode);
+ return new Lazy<SafeAlgorithmHandle>(() =>
+ {
+ SafeAlgorithmHandle hAlg = Cng.BCryptOpenAlgorithmProvider(Cng.BCRYPT_3DES_ALGORITHM, null,
+ Cng.OpenAlgorithmProviderFlags.NONE);
+ hAlg.SetCipherMode(cipherMode);
+
+ if (feedback > 0)
+ {
+ // feedback is in bytes!
+ hAlg.SetFeedbackSize(feedback);
+ }
- return hAlg;
+ return hAlg;
+ });
}
}
}
TestAesDecrypt(CipherMode.CBC, s_aes256Key, s_aes256CbcIv, encryptedBytes, s_multiBlockBytes);
}
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void DecryptKnownCFB128_256()
+ {
+ byte[] encryptedBytes = new byte[]
+ {
+ 0x71, 0x67, 0xD7, 0x86, 0xAA, 0xF8, 0xD9, 0x1A,
+ 0x3A, 0xFB, 0xA5, 0x9E, 0x41, 0xCA, 0x39, 0x32,
+ 0x6A, 0x42, 0xA4, 0xD2, 0x26, 0x32, 0x85, 0x05,
+ 0x5A, 0x98, 0xE4, 0x3A, 0xDA, 0xD7, 0x1B, 0x1A,
+ 0x47, 0x08, 0xF7, 0x7F, 0xC7, 0x08, 0xBF, 0x7C,
+ 0x57, 0xE9, 0x13, 0xD5, 0x4F, 0x8F, 0x23, 0x76,
+ 0xAA, 0xB5, 0x83, 0xE1, 0x5C, 0x48, 0x8A, 0x0D,
+ 0x4A, 0xFD, 0x10, 0x7C, 0xF1, 0x1B, 0x86, 0xA8,
+ 0xAB, 0x9D, 0x5B, 0x49, 0x9D, 0xA4, 0x9C, 0x9B,
+ 0x2B, 0xD1, 0xEC, 0xFF, 0xEB, 0xF7, 0x3B, 0x69,
+ 0x80, 0x0F, 0xA6, 0x26, 0x3E, 0xD9, 0x72, 0xB9,
+ 0x72, 0x22, 0x85, 0x50, 0x95, 0x59, 0xFA, 0x5F
+ };
+
+ TestAesDecrypt(CipherMode.CFB, s_aes256Key, s_aes256CbcIv, encryptedBytes, s_multiBlockBytes, 128);
+ }
+
[Fact]
public static void DecryptKnownECB192()
{
TestAesDecrypt(CipherMode.ECB, s_aes192Key, null, encryptedBytes, s_multiBlockBytes);
}
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void DecryptKnownCFB128_192()
+ {
+ byte[] encryptedBytes = new byte[]
+ {
+ 0x7C, 0xC6, 0xEE, 0xD8, 0xED, 0xB5, 0x3F, 0x8A,
+ 0x90, 0x95, 0x12, 0xD2, 0xBC, 0x9A, 0x96, 0x1E,
+ 0x4E, 0xC4, 0xD1, 0x15, 0xA4, 0x7F, 0x32, 0xA4,
+ 0xD1, 0xFD, 0x8E, 0x02, 0x45, 0xE8, 0x93, 0x3C,
+ 0x3C, 0x91, 0x3F, 0xA4, 0x7F, 0x99, 0xF7, 0x3A,
+ 0x53, 0x0C, 0x0B, 0xFD, 0x01, 0xC5, 0xBD, 0x76,
+ 0xB7, 0xCF, 0x2B, 0x52, 0x34, 0xB1, 0xA6, 0xA4,
+ 0x29, 0x2F, 0x7D, 0x1C, 0x97, 0x3A, 0xE2, 0x75,
+ 0x3E, 0xEB, 0xFC, 0xB7, 0xBB, 0x7A, 0xC0, 0x66,
+ 0x34, 0x25, 0xCF, 0x2D, 0xE2, 0x7E, 0x23, 0x06,
+ 0x10, 0xFE, 0xEA, 0xB3, 0x0F, 0x1D, 0x2C, 0xDD,
+ 0x72, 0x64, 0x51, 0x78, 0x1D, 0x75, 0xD2, 0x17
+ };
+
+ TestAesDecrypt(CipherMode.CFB, s_aes192Key, s_aes256CbcIv, encryptedBytes, s_multiBlockBytes, 128);
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void DecryptKnownCFB128_128()
+ {
+ byte[] encryptedBytes = new byte[]
+ {
+ 0x5B, 0x63, 0x3D, 0x1C, 0x0C, 0x8E, 0xD4, 0xF4,
+ 0xE5, 0x5F, 0xA0, 0xAF, 0x2F, 0xF5, 0xAE, 0x59,
+ 0xB9, 0xC4, 0xFA, 0x02, 0x11, 0x37, 0xEB, 0x38,
+ 0x5B, 0x2F, 0x1D, 0xF5, 0x03, 0xD1, 0xFD, 0x85,
+ 0x4B, 0xAA, 0x4F, 0x29, 0x94, 0x09, 0x31, 0x4C,
+ 0x4D, 0xD6, 0x99, 0xE3, 0x4D, 0xC4, 0x3A, 0x40,
+ 0x97, 0x58, 0xA5, 0x26, 0x80, 0xA8, 0xCA, 0xFA,
+ 0x6D, 0x19, 0x3B, 0x6B, 0x6F, 0x75, 0x76, 0x83,
+ 0x90, 0x31, 0x07, 0x86, 0x35, 0xD6, 0xAB, 0xB4,
+ 0x65, 0x07, 0x0A, 0x0A, 0xA3, 0x7A, 0xD7, 0x16,
+ 0xE2, 0xC5, 0x3B, 0xE0, 0x42, 0x5F, 0xFA, 0xEF,
+ 0xE1, 0x2E, 0x40, 0x84, 0x36, 0x66, 0xB1, 0xBA
+ };
+
+ TestAesDecrypt(CipherMode.CFB, s_aes128Key, s_aes256CbcIv, encryptedBytes, s_multiBlockBytes, 128);
+ }
+
[Fact]
public static void VerifyInPlaceEncryption()
{
cipherBytes: new byte[] { 0x6C, 0xD0, 0x25, 0x13, 0xE8, 0xD4, 0xDC, 0x98, 0x6B, 0x4A, 0xFE, 0x08, 0x7A, 0x60, 0xBD, 0x0C });
}
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB128_8_NoPadding()
+ {
+ TestAesTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.None,
+ key: new byte[] { 0x00, 0x01, 0x02, 0x03, 0x05, 0x06, 0x07, 0x08, 0x0A, 0x0B, 0x0C, 0x0D, 0x0F, 0x10, 0x11, 0x12 },
+ iv: new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ plainBytes: new byte[] { 0x50, 0x68, 0x12, 0xA4, 0x5F, 0x08, 0xC8, 0x89, 0xB9, 0x7F, 0x59, 0x80, 0x03, 0x8B, 0x83, 0x59 },
+ cipherBytes: new byte[] { 0xD5, 0x47, 0xC5, 0x23, 0xCF, 0x5D, 0xFF, 0x67, 0x4C, 0xB4, 0xDB, 0x03, 0x96, 0xA3, 0xEB, 0xCF },
+ 8);
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB128_128_NoPadding()
+ {
+ TestAesTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.None,
+ key: new byte[] { 0x00, 0x01, 0x02, 0x03, 0x05, 0x06, 0x07, 0x08, 0x0A, 0x0B, 0x0C, 0x0D, 0x0F, 0x10, 0x11, 0x12 },
+ iv: new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ plainBytes: new byte[] { 0x50, 0x68, 0x12, 0xA4, 0x5F, 0x08, 0xC8, 0x89, 0xB9, 0x7F, 0x59, 0x80, 0x03, 0x8B, 0x83, 0x59 },
+ cipherBytes: new byte[] { 0xD5, 0x91, 0xEE, 0x44, 0xF7, 0xC4, 0x31, 0xFB, 0x40, 0x20, 0x2F, 0x03, 0x6C, 0x14, 0x7C, 0xAC },
+ 128);
+ }
+
[Fact]
public static void VerifyKnownTransform_CBC128_NoPadding()
{
cipherBytes: new byte[] { 0x19, 0x46, 0xDA, 0xBF, 0x6A, 0x03, 0xA2, 0xA2, 0xC3, 0xD0, 0xB0, 0x50, 0x80, 0xAE, 0xD6, 0xFC });
}
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB128_256_NoPadding()
+ {
+ TestAesTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.None,
+ key: new byte[] { 0x00, 0x01, 0x02, 0x03, 0x05, 0x06, 0x07, 0x08, 0x0A, 0x0B, 0x0C, 0x0D, 0x0F, 0x10, 0x11, 0x12, 0x14, 0x15, 0x16, 0x17, 0x19, 0x1A, 0x1B, 0x1C, 0x1E, 0x1F, 0x20, 0x21, 0x23, 0x24, 0x25, 0x26 },
+ iv: new byte[] { 0x83, 0x4E, 0xAD, 0xFC, 0xCA, 0xC7, 0xE1, 0xB3, 0x06, 0x64, 0xB1, 0xAB, 0xA4, 0x48, 0x15, 0xAB },
+ plainBytes: new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ cipherBytes: new byte[] { 0x19, 0x46, 0xDA, 0xBF, 0x6A, 0x03, 0xA2, 0xA2, 0xC3, 0xD0, 0xB0, 0x50, 0x80, 0xAE, 0xD6, 0xFC },
+ 128);
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB8_256_NoPadding()
+ {
+ TestAesTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.None,
+ key: new byte[] { 0x00, 0x01, 0x02, 0x03, 0x05, 0x06, 0x07, 0x08, 0x0A, 0x0B, 0x0C, 0x0D, 0x0F, 0x10, 0x11, 0x12, 0x14, 0x15, 0x16, 0x17, 0x19, 0x1A, 0x1B, 0x1C, 0x1E, 0x1F, 0x20, 0x21, 0x23, 0x24, 0x25, 0x26 },
+ iv: new byte[] { 0x83, 0x4E, 0xAD, 0xFC, 0xCA, 0xC7, 0xE1, 0xB3, 0x06, 0x64, 0xB1, 0xAB, 0xA4, 0x48, 0x15, 0xAB },
+ plainBytes: new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ cipherBytes: new byte[] { 0x19, 0x38, 0x0A, 0x23, 0x92, 0x37, 0xC2, 0x7A, 0xBA, 0xD1, 0x82, 0x62, 0xE0, 0x36, 0x83, 0x0C },
+ 8);
+ }
+
[Fact]
public static void VerifyKnownTransform_CBC128_NoPadding_2()
{
cipherBytes: new byte[] { 0x0E, 0xDD, 0x33, 0xD3, 0xC6, 0x21, 0xE5, 0x46, 0x45, 0x5B, 0xD8, 0xBA, 0x14, 0x18, 0xBE, 0xC8 });
}
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB128_128_NoPadding_2()
+ {
+ TestAesTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.None,
+ key: new byte[] { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ iv: new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6 },
+ plainBytes: new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6 },
+ cipherBytes: new byte[] { 0xC0, 0xB7, 0x81, 0xC8, 0xC9, 0x80, 0x5A, 0x87, 0x61, 0x0E, 0xB4, 0x36, 0x6D, 0xAC, 0xA1, 0x2E },
+ 128);
+ }
+
[Fact]
public static void VerifyKnownTransform_CBC128_NoPadding_3()
{
cipherBytes: new byte[] { 0x3A, 0xD7, 0x8E, 0x72, 0x6C, 0x1E, 0xC0, 0x2B, 0x7E, 0xBF, 0xE9, 0x2B, 0x23, 0xD9, 0xEC, 0x34 });
}
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB128_128_NoPadding_3()
+ {
+ TestAesTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.None,
+ key: new byte[] { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ iv: new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6 },
+ plainBytes: new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6 },
+ cipherBytes: new byte[] { 0xC0, 0xB7, 0x81, 0xC8, 0xC9, 0x80, 0x5A, 0x87, 0x61, 0x0E, 0xB4, 0x36, 0x6D, 0xAC, 0xA1, 0x2E },
+ 128);
+ }
+
[Fact]
public static void VerifyKnownTransform_CBC192_NoPadding()
{
cipherBytes: new byte[] { 0xDE, 0x88, 0x5D, 0xC8, 0x7F, 0x5A, 0x92, 0x59, 0x40, 0x82, 0xD0, 0x2C, 0xC1, 0xE1, 0xB4, 0x2C });
}
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB128_192_NoPadding()
+ {
+ TestAesTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.None,
+ key: new byte[] { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ iv: new byte[] { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ plainBytes: new byte[] { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ cipherBytes: new byte[] { 0xE9, 0x6E, 0xA7, 0xDA, 0x76, 0x90, 0xCB, 0x98, 0x56, 0x54, 0xE8, 0xFB, 0x86, 0xA3, 0xEB, 0x95 },
+ 128);
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB8_192_NoPadding()
+ {
+ TestAesTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.None,
+ key: new byte[] { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ iv: new byte[] { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ plainBytes: new byte[] { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ cipherBytes: new byte[] { 0xE9, 0x3E, 0xE5, 0xBF, 0x29, 0xFF, 0x95, 0x6E, 0x6B, 0xD6, 0xE8, 0x6F, 0x9F, 0x6A, 0x05, 0x62 },
+ 8);
+ }
+
[Fact]
public static void VerifyKnownTransform_CBC192_NoPadding_2()
{
cipherBytes: new byte[] { 0x6C, 0xD0, 0x25, 0x13, 0xE8, 0xD4, 0xDC, 0x98, 0x6B, 0x4A, 0xFE, 0x08, 0x7A, 0x60, 0xBD, 0x0C });
}
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB128_192_NoPadding_2()
+ {
+ TestAesTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.None,
+ key: new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ iv: new byte[] { 0x81, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ plainBytes: new byte[] { 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ cipherBytes: new byte[] { 0xAA, 0xB9, 0xD1, 0x9F, 0x4A, 0x66, 0xEF, 0x3A, 0x9A, 0x60, 0xAF, 0x10, 0xD8, 0x3D, 0x84, 0x10 },
+ 128);
+ }
+
[Fact]
public static void WrongKeyFailDecrypt()
{
}
}
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB8_128_NoPadding_4()
+ {
+ // NIST CAVP AESMMT.ZIP CFB8MMT128.rsp, [ENCRYPT] COUNT=4
+ // plaintext not extended
+ TestAesTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.None,
+ key: "5d5e7f20e0a66d3e09e0e5a9912f8a46".HexToByteArray(),
+ iv: "052d7ea0ad1f2956a23b27afe1d87b6b".HexToByteArray(),
+ plainBytes: "b84a90fc6d".HexToByteArray(),
+ cipherBytes: "1a9a61c307".HexToByteArray(),
+ feedbackSize: 8);
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB128_128_NoPadding_4_Fails()
+ {
+ Assert.Throws<CryptographicException>(() =>
+ TestAesTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.None,
+ key: "5d5e7f20e0a66d3e09e0e5a9912f8a46".HexToByteArray(),
+ iv: "052d7ea0ad1f2956a23b27afe1d87b6b".HexToByteArray(),
+ plainBytes: "b84a90fc6d".HexToByteArray(),
+ cipherBytes: "1a9a61c307".HexToByteArray(),
+ feedbackSize: 128)
+ );
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB128_128_PKCS7_4()
+ {
+ TestAesTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.PKCS7,
+ key: "5d5e7f20e0a66d3e09e0e5a9912f8a46".HexToByteArray(),
+ iv: "052d7ea0ad1f2956a23b27afe1d87b6b".HexToByteArray(),
+ plainBytes: "b84a90fc6d".HexToByteArray(),
+ cipherBytes: "1aae9ac4cd4742f28ed593b48efce7cd".HexToByteArray(),
+ feedbackSize: 128);
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB8_128_PKCS7_4()
+ {
+ TestAesTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.PKCS7,
+ key: "5d5e7f20e0a66d3e09e0e5a9912f8a46".HexToByteArray(),
+ iv: "052d7ea0ad1f2956a23b27afe1d87b6b".HexToByteArray(),
+ plainBytes: "b84a90fc6d".HexToByteArray(),
+ cipherBytes: "1a9a61c307a4".HexToByteArray(),
+ feedbackSize: 8);
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB8_128_NoPadding_0_Extended()
+ {
+ // NIST CAVP AESMMT.ZIP CFB8MMT128.rsp, [ENCRYPT] COUNT=0
+ // plaintext zero-extended to a full block, cipherBytes extended value
+ // provided by .NET Framework
+ TestAesTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.None,
+ key: "c57d699d89df7cfbef71c080a6b10ac3".HexToByteArray(),
+ iv: "fcb2bc4c006b87483978796a2ae2c42e".HexToByteArray(),
+ plainBytes: ("61" + "000000000000000000000000000000").HexToByteArray(),
+ cipherBytes: ("24" + "D89FE413C3D37172D6B577E2F94997").HexToByteArray(),
+ feedbackSize: 8);
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB8_128_NoPadding_9_Extended()
+ {
+ // NIST CAVP AESMMT.ZIP CFB8MMT128.rsp, [ENCRYPT] COUNT=9
+ // plaintext zero-extended to a full block, cipherBytes extended value
+ // provided by .NET Framework
+ TestAesTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.None,
+ key: "3a6f9159263fa6cef2a075caface5817".HexToByteArray(),
+ iv: "0fc23662b7dbf73827f0c7de321ca36e".HexToByteArray(),
+ plainBytes: ("87efeb8d559ed3367728" + "000000000000").HexToByteArray(),
+ cipherBytes: ("8e9c50425614d540ce11" + "7DD85E93D8E0").HexToByteArray(),
+ feedbackSize: 8);
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB8_192_NoPadding_0_Extended()
+ {
+ // NIST CAVP AESMMT.ZIP CFB8MMT192.rsp, [ENCRYPT] COUNT=0
+ // plaintext zero-extended to a full block, cipherBytes extended value
+ // provided by .NET Framework
+ TestAesTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.None,
+ key: "32a1b0e3da368db563d7316b9779d3327e53d9a6d287ed97".HexToByteArray(),
+ iv: "3dd0e7e21f09d5842f3a699da9b57346".HexToByteArray(),
+ plainBytes: ("54" + "000000000000000000000000000000").HexToByteArray(),
+ cipherBytes: ("6d" + "B3F513638A136D73873517AF1A770F").HexToByteArray(),
+ feedbackSize: 8);
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB8_192_NoPadding_9_Extended()
+ {
+ // NIST CAVP AESMMT.ZIP CFB8MMT192.rsp, [ENCRYPT] COUNT=9
+ // plaintext zero-extended to a full block, cipherBytes extended value
+ // provided by .NET Framework
+ TestAesTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.None,
+ key: "537e7bf661fd4024a024613f15b13690f7d0c847c1e18965".HexToByteArray(),
+ iv: "3a81f9d9d3c155b0caad5d73349476fc".HexToByteArray(),
+ plainBytes: ("d3d8b9b984adc24237ee" + "000000000000").HexToByteArray(),
+ cipherBytes: ("3879fea72ac99929e53a" + "39552A575D73").HexToByteArray(),
+ feedbackSize: 8);
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB8_256_NoPadding_0_Extended()
+ {
+ // NIST CAVP AESMMT.ZIP CFB8MMT256.rsp, [ENCRYPT] COUNT=0
+ // plaintext zero-extended to a full block, cipherBytes extended value
+ // provided by .NET Framework
+ TestAesTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.None,
+ key: "34e8091cee09f1bd3ebf1e8f05f51bfbd4899ef2ae006a3a0f7875052cdd46c8".HexToByteArray(),
+ iv: "43eb4dcc4b04a80216a20e4a09a7abb5".HexToByteArray(),
+ plainBytes: ("f9" + "000000000000000000000000000000").HexToByteArray(),
+ cipherBytes: ("28" + "26199F76D20BE53AB4D146CFC6D281").HexToByteArray(),
+ feedbackSize: 8);
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB8_256_NoPadding_9_Extended()
+ {
+ // NIST CAVP AESMMT.ZIP CFB8MMT256.rsp, [ENCRYPT] COUNT=9
+ // plaintext zero-extended to a full block, cipherBytes extended value
+ // provided by .NET Framework
+ TestAesTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.None,
+ key: "ebbb4566b5e182e0f072466b0b311df38f9175bc0213a5530bce2ec4d74f400d".HexToByteArray(),
+ iv: "0956a48e01002c9e16376d6e308dbad1".HexToByteArray(),
+ plainBytes: ("b0fe25ac8d3d28a2f471" + "000000000000").HexToByteArray(),
+ cipherBytes: ("638c6823e7256fb5626e" + "5EE5C1D7FA17").HexToByteArray(),
+ feedbackSize: 8);
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB128_128_NoPadding_0()
+ {
+ // NIST CAVP AESMMT.ZIP CFB128MMT128.rsp, [ENCRYPT] COUNT=0
+ TestAesTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.None,
+ key: "085b8af6788fa6bc1a0b47dcf50fbd35".HexToByteArray(),
+ iv: "58cb2b12bb52c6f14b56da9210524864".HexToByteArray(),
+ plainBytes: "4b5a872260293312eea1a570fd39c788".HexToByteArray(),
+ cipherBytes: "e92c80e0cfb6d8b1c27fd58bc3708b16".HexToByteArray(),
+ feedbackSize: 128);
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB128_128_NoPadding_1_Extended()
+ {
+ // NIST CAVP AESMMT.ZIP CFB128MMT128.rsp, [ENCRYPT] COUNT=1
+ TestAesTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.None,
+ key: "701ccc4c0e36e512ce077f5af6ccb957".HexToByteArray(),
+ iv: "5337ddeaf89a00dd4d58d860de968469".HexToByteArray(),
+ plainBytes: "cc1172f2f80866d0768b25f70fcf6361aab7c627c8488f97525d7d88949beeea".HexToByteArray(),
+ cipherBytes: "cdcf093bb7840df225683b58a479b00d5de5553a7e85eae4b70bf46dc729dd31".HexToByteArray(),
+ feedbackSize: 128);
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB128_192_NoPadding_0_Extended()
+ {
+ // NIST CAVP AESMMT.ZIP CFB128MMT192.rsp, [ENCRYPT] COUNT=0
+ TestAesTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.None,
+ key: "1bbb30016d3a908827693352ece9833415433618b1d97595".HexToByteArray(),
+ iv: "b2b48e8d60240bf2d9fa05cc2f90c161".HexToByteArray(),
+ plainBytes: "b4e499de51e646fad80030da9dc5e7e2".HexToByteArray(),
+ cipherBytes: "8b7ba98982063a55fca3492269bbe437".HexToByteArray(),
+ feedbackSize: 128);
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB128_192_NoPadding_1_Extended()
+ {
+ // NIST CAVP AESMMT.ZIP CFB128MMT192.rsp, [ENCRYPT] COUNT=1
+ TestAesTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.None,
+ key: "69f9d29885743826d7c5afc53637e6b1fa9512a10eea9ca9".HexToByteArray(),
+ iv: "3743793c7144a755768437f4ef5a33c8".HexToByteArray(),
+ plainBytes: "f84ebf42a758971c369949e288f775c9cf6a82ab51b286576b45652cd68c3ce6".HexToByteArray(),
+ cipherBytes: "a3bd28bb817bdb3f6492827f2aa3e6e134c254129d8f20dbc92389b7d89702d6".HexToByteArray(),
+ feedbackSize: 128);
+ }
+
+ [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ [InlineData(CipherMode.CBC, 0)]
+ [InlineData(CipherMode.CFB, 128)]
+ [InlineData(CipherMode.CFB, 8)]
+ [InlineData(CipherMode.ECB, 0)]
+ public static void EncryptorReuse_LeadsToSameResults(CipherMode cipherMode, int feedbackSize)
+ {
+ // AppleCCCryptor does not allow calling Reset on CFB cipher.
+ // this test validates that the behavior is taken into consideration.
+ var input = "b72606c98d8e4fabf08839abf7a0ac61".HexToByteArray();
+
+ using (Aes aes = AesFactory.Create())
+ {
+ aes.Mode = cipherMode;
+
+ if (feedbackSize > 0)
+ {
+ aes.FeedbackSize = feedbackSize;
+ }
+
+ using (ICryptoTransform transform = aes.CreateEncryptor())
+ {
+ byte[] output1 = transform.TransformFinalBlock(input, 0, input.Length);
+ byte[] output2 = transform.TransformFinalBlock(input, 0, input.Length);
+
+ Assert.Equal(output1, output2);
+ }
+ }
+ }
+
+ [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ [InlineData(CipherMode.CBC, 0)]
+ [InlineData(CipherMode.CFB, 128)]
+ [InlineData(CipherMode.CFB, 8)]
+ [InlineData(CipherMode.ECB, 0)]
+ public static void DecryptorReuse_LeadsToSameResults(CipherMode cipherMode, int feedbackSize)
+ {
+ // AppleCCCryptor does not allow calling Reset on CFB cipher.
+ // this test validates that the behavior is taken into consideration.
+ var input = "2981761d979bb1765a28b2dd19125b54".HexToByteArray();
+ var key = "e1c6e6884eee69552dbfee21f22ca92685d5d08ef0e3f37e5b338c533bb8d72c".HexToByteArray();
+ var iv = "cea9f23ae87a637ab0cda6381ecc1202".HexToByteArray();
+
+ using (Aes aes = AesFactory.Create())
+ {
+ aes.Mode = cipherMode;
+ aes.Key = key;
+ aes.IV = iv;
+ aes.Padding = PaddingMode.None;
+
+ if (feedbackSize > 0)
+ {
+ aes.FeedbackSize = feedbackSize;
+ }
+
+ using (ICryptoTransform transform = aes.CreateDecryptor())
+ {
+ byte[] output1 = transform.TransformFinalBlock(input, 0, input.Length);
+ byte[] output2 = transform.TransformFinalBlock(input, 0, input.Length);
+
+ Assert.Equal(output1, output2);
+ }
+ }
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB128_256_NoPadding_0_Extended()
+ {
+ // NIST CAVP AESMMT.ZIP CFB128MMT256.rsp, [ENCRYPT] COUNT=0
+ TestAesTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.None,
+ key: "e1c6e6884eee69552dbfee21f22ca92685d5d08ef0e3f37e5b338c533bb8d72c".HexToByteArray(),
+ iv: "cea9f23ae87a637ab0cda6381ecc1202".HexToByteArray(),
+ plainBytes: "b72606c98d8e4fabf08839abf7a0ac61".HexToByteArray(),
+ cipherBytes: "2981761d979bb1765a28b2dd19125b54".HexToByteArray(),
+ feedbackSize: 128);
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB128_256_NoPadding_1_Extended()
+ {
+ // NIST CAVP AESMMT.ZIP CFB128MMT256.rsp, [ENCRYPT] COUNT=1
+ TestAesTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.None,
+ key: "ae59254c66d8f533e7f5002ced480c33984a421d7816e27be66c34c19bfbc2a8".HexToByteArray(),
+ iv: "821dd21653ece3af675cd25d26017ae3".HexToByteArray(),
+ plainBytes: "3cb4f17e775c2d6d06dd60f15d6c3a103e5131727f9c6cb80d13e00f316eb904".HexToByteArray(),
+ cipherBytes: "ae375db9f28148c460f6c6b6665fcc2ff6b50b8eaf82c64bba8c649efd4731bc".HexToByteArray(),
+ feedbackSize: 128);
+ }
+
[Fact]
public static void AesZeroPad()
{
byte[] key,
byte[] iv,
byte[] encryptedBytes,
- byte[] expectedAnswer)
+ byte[] expectedAnswer,
+ int? feedbackSize = default)
{
byte[] decryptedBytes;
{
aes.Mode = mode;
aes.Key = key;
+
+ if (feedbackSize.HasValue)
+ {
+ aes.FeedbackSize = feedbackSize.Value;
+ }
if (iv != null)
{
byte[] key,
byte[] iv,
byte[] plainBytes,
- byte[] cipherBytes)
+ byte[] cipherBytes,
+ int? feedbackSize = default)
{
byte[] liveEncryptBytes;
byte[] liveDecryptBytes;
aes.Mode = cipherMode;
aes.Padding = paddingMode;
+ if (feedbackSize.HasValue)
+ {
+ aes.FeedbackSize = feedbackSize.Value;
+ }
+
liveEncryptBytes = AesEncryptDirectKey(aes, key, iv, plainBytes);
liveDecryptBytes = AesDecryptDirectKey(aes, key, iv, cipherBytes);
}
- Assert.Equal(plainBytes, liveDecryptBytes);
Assert.Equal(cipherBytes, liveEncryptBytes);
+ Assert.Equal(plainBytes, liveDecryptBytes);
}
private static byte[] AesEncryptDirectKey(Aes aes, byte[] key, byte[] iv, byte[] plainBytes)
}
}
+ [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ [InlineData(0, true)]
+ [InlineData(1, true)]
+ [InlineData(7, true)]
+ [InlineData(9, true)]
+ [InlineData(-1, true)]
+ [InlineData(int.MaxValue, true)]
+ [InlineData(int.MinValue, true)]
+ [InlineData(64, false)]
+ [InlineData(256, true)]
+ [InlineData(127, true)]
+ public static void InvalidCFBFeedbackSizes(int feedbackSize, bool discoverableInSetter)
+ {
+ using (Aes aes = AesFactory.Create())
+ {
+ aes.GenerateKey();
+ aes.Mode = CipherMode.CFB;
+
+ if (discoverableInSetter)
+ {
+ // there are some key sizes that are invalid for any of the modes,
+ // so the exception is thrown in the setter
+ Assert.Throws<CryptographicException>(() =>
+ {
+ aes.FeedbackSize = feedbackSize;
+ });
+ }
+ else
+ {
+ aes.FeedbackSize = feedbackSize;
+
+ // however, for CFB only few sizes are valid. Those should throw in the
+ // actual AES instantiation.
+
+ Assert.Throws<CryptographicException>(() => aes.CreateDecryptor());
+ Assert.Throws<CryptographicException>(() => aes.CreateEncryptor());
+ }
+ }
+ }
+
+ [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ [InlineData(8)]
+ [InlineData(128)]
+ public static void ValidCFBFeedbackSizes(int feedbackSize)
+ {
+ using (Aes aes = AesFactory.Create())
+ {
+ aes.GenerateKey();
+ aes.Mode = CipherMode.CFB;
+
+ aes.FeedbackSize = feedbackSize;
+
+ using var decryptor = aes.CreateDecryptor();
+ using var encryptor = aes.CreateEncryptor();
+ Assert.NotNull(decryptor);
+ Assert.NotNull(encryptor);
+ }
+ }
+
[Theory]
[InlineData(64, false)] // smaller than default BlockSize
[InlineData(129, false)] // larger than default BlockSize
SupportsMode(CipherMode.ECB);
}
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void SupportsCFB()
+ {
+ SupportsMode(CipherMode.CFB);
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsWindows7))]
+ public static void Windows7DoesNotSupportCFB()
+ {
+ DoesNotSupportMode(CipherMode.CFB);
+ }
+
[Fact]
public static void DoesNotSupportCTS()
{
// aes.CreateEncryptor() (with an invalid Mode value)
// transform.Transform[Final]Block() (with an invalid Mode value)
- Assert.Throws<CryptographicException>(
+ Assert.ThrowsAny<CryptographicException>(
() =>
{
aes.Mode = mode;
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections.Generic;
+using System.IO;
using System.Text;
using Test.Cryptography;
using Xunit;
}
}
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB8_NoPadding_0()
+ {
+ // NIST CAVS TDESMMT.ZIP TCFB8MMT2.rsp, [DECRYPT] COUNT=0
+ // used only key1, cipherBytes computed using openssl
+ TestDESTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.None,
+ key: "fb978a0b6dc2c467".HexToByteArray(),
+ iv: "8b97579ea5ac300f".HexToByteArray(),
+ plainBytes: "80".HexToByteArray(),
+ cipherBytes: "82".HexToByteArray(),
+ feedbackSize: 8
+ );
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB8_NoPadding_1()
+ {
+ // NIST CAVS TDESMMT.ZIP TCFB8MMT2.rsp, [DECRYPT] COUNT=1
+ // used only key1, cipherBytes computed using openssl
+ TestDESTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.None,
+ key: "9b04c86dd31a8a58".HexToByteArray(),
+ iv: "52cd77d49fc72347".HexToByteArray(),
+ plainBytes: "2fef".HexToByteArray(),
+ cipherBytes: "0fe4".HexToByteArray(),
+ feedbackSize: 8
+ );
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB8_NoPadding_2()
+ {
+ // NIST CAVS TDESMMT.ZIP TCFB8MMT2.rsp, [DECRYPT] COUNT=2
+ // used only key1, cipherBytes computed using openssl
+ TestDESTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.None,
+ key: "fbb667e340586b5b".HexToByteArray(),
+ iv: "459e8b8736715791".HexToByteArray(),
+ plainBytes: "061704".HexToByteArray(),
+ cipherBytes: "8e9071".HexToByteArray(),
+ feedbackSize: 8
+ );
+ }
+
+ [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ [InlineData(CipherMode.CBC, 0)]
+ [InlineData(CipherMode.CFB, 8)]
+ [InlineData(CipherMode.ECB, 0)]
+ public static void EncryptorReuse_LeadsToSameResults(CipherMode cipherMode, int feedbackSize)
+ {
+ // AppleCCCryptor does not allow calling Reset on CFB cipher.
+ // this test validates that the behavior is taken into consideration.
+ var input = "b72606c98d8e4fabf08839abf7a0ac61".HexToByteArray();
+
+ using (DES des = DESFactory.Create())
+ {
+ des.Mode = cipherMode;
+
+ if (feedbackSize > 0)
+ {
+ des.FeedbackSize = feedbackSize;
+ }
+
+ using (ICryptoTransform transform = des.CreateEncryptor())
+ {
+ byte[] output1 = transform.TransformFinalBlock(input, 0, input.Length);
+ byte[] output2 = transform.TransformFinalBlock(input, 0, input.Length);
+
+ Assert.Equal(output1, output2);
+ }
+ }
+ }
+
+ [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ [InlineData(CipherMode.CBC, 0)]
+ [InlineData(CipherMode.CFB, 8)]
+ [InlineData(CipherMode.ECB, 0)]
+ public static void DecryptorReuse_LeadsToSameResults(CipherMode cipherMode, int feedbackSize)
+ {
+ // AppleCCCryptor does not allow calling Reset on CFB cipher.
+ // this test validates that the behavior is taken into consideration.
+ var input = "4e6f77206973207468652074696d6520666f7220616c6c20".HexToByteArray();
+ var key = "4a575d02515d40b0".HexToByteArray();
+ var iv = "ab27e9f02affa532".HexToByteArray();
+
+ using (DES des = DESFactory.Create())
+ {
+ des.Mode = cipherMode;
+ des.Key = key;
+ des.IV = iv;
+ des.Padding = PaddingMode.None;
+
+ if (feedbackSize > 0)
+ {
+ des.FeedbackSize = feedbackSize;
+ }
+
+ using (ICryptoTransform transform = des.CreateDecryptor())
+ {
+ byte[] output1 = transform.TransformFinalBlock(input, 0, input.Length);
+ byte[] output2 = transform.TransformFinalBlock(input, 0, input.Length);
+
+ Assert.Equal(output1, output2);
+ }
+ }
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB8_NoPadding_3()
+ {
+ // NIST CAVS TDESMMT.ZIP TCFB8MMT2.rsp, [DECRYPT] COUNT=3
+ // used only key1, cipherBytes computed using openssl
+ TestDESTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.None,
+ key: "4a575d02515d40b0".HexToByteArray(),
+ iv: "ab27e9f02affa532".HexToByteArray(),
+ plainBytes: "55f75b95".HexToByteArray(),
+ cipherBytes: "34aa8679".HexToByteArray(),
+ feedbackSize: 8
+ );
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB8_PKCS7_3()
+ {
+ // NIST CAVS TDESMMT.ZIP TCFB8MMT2.rsp, [DECRYPT] COUNT=3
+ // used only key1, cipherBytes computed using openssl
+ TestDESTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.PKCS7,
+ key: "4a575d02515d40b0".HexToByteArray(),
+ iv: "ab27e9f02affa532".HexToByteArray(),
+ plainBytes: "55f75b95".HexToByteArray(),
+ cipherBytes: "34aa8679ca".HexToByteArray(),
+ feedbackSize: 8
+ );
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB8_NoPadding_4()
+ {
+ // NIST CAVS TDESMMT.ZIP TCFB8MMT2.rsp, [DECRYPT] COUNT=4
+ // used only key1, cipherBytes computed using openssl
+ TestDESTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.None,
+ key: "91a834855e6bab31".HexToByteArray(),
+ iv: "7838aaad4e64640b".HexToByteArray(),
+ plainBytes: "c3851c0ab4".HexToByteArray(),
+ cipherBytes: "84844450f0".HexToByteArray(),
+ feedbackSize: 8
+ );
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB8_NoPadding_5()
+ {
+ // NIST CAVS TDESMMT.ZIP TCFB8MMT2.rsp, [DECRYPT] COUNT=5
+ // used only key1, cipherBytes computed using openssl
+ TestDESTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.None,
+ key: "04d923abd9291c3e".HexToByteArray(),
+ iv: "191f8794944e601c".HexToByteArray(),
+ plainBytes: "6fe8f67d2af1".HexToByteArray(),
+ cipherBytes: "6012c9171bb8".HexToByteArray(),
+ feedbackSize: 8
+ );
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB8_NoPadding_6()
+ {
+ // NIST CAVS TDESMMT.ZIP TCFB8MMT2.rsp, [DECRYPT] COUNT=6
+ // used only key1, cipherBytes computed using openssl
+ TestDESTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.None,
+ key: "a7799e7f5dfe54ce".HexToByteArray(),
+ iv: "370184c749d04a20".HexToByteArray(),
+ plainBytes: "2b4228b769795b".HexToByteArray(),
+ cipherBytes: "58d3de76687976".HexToByteArray(),
+ feedbackSize: 8
+ );
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB8_NoPadding_7()
+ {
+ // NIST CAVS TDESMMT.ZIP TCFB8MMT2.rsp, [DECRYPT] COUNT=7
+ // used only key1, cipherBytes computed using openssl
+ TestDESTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.None,
+ key: "6bfe3d3df8c1e0d3".HexToByteArray(),
+ iv: "51e4c5c29e858da6".HexToByteArray(),
+ plainBytes: "4cb3554fd0b9ec82".HexToByteArray(),
+ cipherBytes: "16b3595259693776".HexToByteArray(),
+ feedbackSize: 8
+ );
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB8_NoPadding_8()
+ {
+ // NIST CAVS TDESMMT.ZIP TCFB8MMT2.rsp, [DECRYPT] COUNT=8
+ // used only key1, cipherBytes computed using openssl
+ TestDESTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.None,
+ key: "e0264aec13e63db9".HexToByteArray(),
+ iv: "bd8795dba79930d6".HexToByteArray(),
+ plainBytes: "79068e2943f02914af".HexToByteArray(),
+ cipherBytes: "fe78cb95ce9e4cac2f".HexToByteArray(),
+ feedbackSize: 8
+ );
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB8_NoPadding_9()
+ {
+ // NIST CAVS TDESMMT.ZIP TCFB8MMT2.rsp, [DECRYPT] COUNT=9
+ // used only key1, cipherBytes computed using openssl
+ TestDESTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.None,
+ key: "7ca28938ba6bec1f".HexToByteArray(),
+ iv: "953896586e49d38f".HexToByteArray(),
+ plainBytes: "2ea956d4a211db6859b7".HexToByteArray(),
+ cipherBytes: "81b850bf481db5df0437".HexToByteArray(),
+ feedbackSize: 8
+ );
+ }
+
+ private static void TestDESTransformDirectKey(
+ CipherMode cipherMode,
+ PaddingMode paddingMode,
+ byte[] key,
+ byte[] iv,
+ byte[] plainBytes,
+ byte[] cipherBytes,
+ int? feedbackSize = default)
+ {
+ byte[] liveEncryptBytes;
+ byte[] liveDecryptBytes;
+
+ using (DES des = DESFactory.Create())
+ {
+ des.Mode = cipherMode;
+ des.Padding = paddingMode;
+
+ if (feedbackSize.HasValue)
+ {
+ des.FeedbackSize = feedbackSize.Value;
+ }
+
+ liveEncryptBytes = DESEncryptDirectKey(des, key, iv, plainBytes);
+ liveDecryptBytes = DESDecryptDirectKey(des, key, iv, cipherBytes);
+ }
+
+ Assert.Equal(cipherBytes, liveEncryptBytes);
+ Assert.Equal(plainBytes, liveDecryptBytes);
+ }
+
+ private static byte[] DESEncryptDirectKey(DES des, byte[] key, byte[] iv, byte[] plainBytes)
+ {
+ using (MemoryStream output = new MemoryStream())
+ using (CryptoStream cryptoStream = new CryptoStream(output, des.CreateEncryptor(key, iv), CryptoStreamMode.Write))
+ {
+ cryptoStream.Write(plainBytes, 0, plainBytes.Length);
+ cryptoStream.FlushFinalBlock();
+
+ return output.ToArray();
+ }
+ }
+
+ private static byte[] DESDecryptDirectKey(DES des, byte[] key, byte[] iv, byte[] cipherBytes)
+ {
+ using (MemoryStream output = new MemoryStream())
+ using (CryptoStream cryptoStream = new CryptoStream(output, des.CreateDecryptor(key, iv), CryptoStreamMode.Write))
+ {
+ cryptoStream.Write(cipherBytes, 0, cipherBytes.Length);
+ cryptoStream.FlushFinalBlock();
+
+ return output.ToArray();
+ }
+ }
+
[Theory]
[InlineData(true, true)]
[InlineData(true, false)]
--- /dev/null
+// 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 System.Collections.Generic;
+using System.IO;
+using System.Text;
+using Test.Cryptography;
+using Xunit;
+
+namespace System.Security.Cryptography.Encryption.Des.Tests
+{
+ public static class DesContractTests
+ {
+ // cfb not available on windows 7
+ [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsWindows7))]
+ [InlineData(0, true)]
+ [InlineData(1, true)]
+ [InlineData(7, true)]
+ [InlineData(9, true)]
+ [InlineData(-1, true)]
+ [InlineData(int.MaxValue, true)]
+ [InlineData(int.MinValue, true)]
+ [InlineData(8, false)]
+ [InlineData(64, false)]
+ [InlineData(256, true)]
+ [InlineData(128, true)]
+ [InlineData(127, true)]
+ public static void Windows7DoesNotSupportCFB(int feedbackSize, bool discoverableInSetter)
+ {
+ using (DES des = DESFactory.Create())
+ {
+ des.GenerateKey();
+ des.Mode = CipherMode.CFB;
+
+ if (discoverableInSetter)
+ {
+ // there are some key sizes that are invalid for any of the modes,
+ // so the exception is thrown in the setter
+ Assert.ThrowsAny<CryptographicException>(() =>
+ {
+ des.FeedbackSize = feedbackSize;
+ });
+ }
+ else
+ {
+ des.FeedbackSize = feedbackSize;
+
+ // however, for CFB only few sizes are valid. Those should throw in the
+ // actual DES instantiation.
+
+ Assert.ThrowsAny<CryptographicException>(() =>
+ {
+ return des.CreateDecryptor();
+ });
+ Assert.ThrowsAny<CryptographicException>(() =>
+ {
+ return des.CreateEncryptor();
+ });
+ }
+ }
+ }
+
+ [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ [InlineData(0, true)]
+ [InlineData(1, true)]
+ [InlineData(7, true)]
+ [InlineData(9, true)]
+ [InlineData(-1, true)]
+ [InlineData(int.MaxValue, true)]
+ [InlineData(int.MinValue, true)]
+ [InlineData(64, false)]
+ [InlineData(256, true)]
+ [InlineData(128, true)]
+ [InlineData(127, true)]
+ public static void InvalidCFBFeedbackSizes(int feedbackSize, bool discoverableInSetter)
+ {
+ using (DES des = DESFactory.Create())
+ {
+ des.GenerateKey();
+ des.Mode = CipherMode.CFB;
+
+ if (discoverableInSetter)
+ {
+ // there are some key sizes that are invalid for any of the modes,
+ // so the exception is thrown in the setter
+ Assert.Throws<CryptographicException>(() =>
+ {
+ des.FeedbackSize = feedbackSize;
+ });
+ }
+ else
+ {
+ des.FeedbackSize = feedbackSize;
+
+ // however, for CFB only few sizes are valid. Those should throw in the
+ // actual DES instantiation.
+
+ Assert.Throws<CryptographicException>(() => des.CreateDecryptor());
+ Assert.Throws<CryptographicException>(() => des.CreateEncryptor());
+ }
+ }
+ }
+
+ [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ [InlineData(8)]
+ public static void ValidCFBFeedbackSizes(int feedbackSize)
+ {
+ using (DES des = DESFactory.Create())
+ {
+ des.GenerateKey();
+ des.Mode = CipherMode.CFB;
+
+ des.FeedbackSize = feedbackSize;
+
+ using var decryptor = des.CreateDecryptor();
+ using var encryptor = des.CreateEncryptor();
+ Assert.NotNull(decryptor);
+ Assert.NotNull(encryptor);
+ }
+ }
+ }
+}
}
}
+ [Theory]
+ [InlineData(CipherMode.CBC, 0)]
+ [InlineData(CipherMode.ECB, 0)]
+ public static void EncryptorReuse_LeadsToSameResults(CipherMode cipherMode, int feedbackSize)
+ {
+ // AppleCCCryptor does not allow calling Reset on CFB cipher.
+ // this test validates that the behavior is taken into consideration.
+ var input = "b72606c98d8e4fabf08839abf7a0ac61".HexToByteArray();
+
+ using (RC2 rc2 = RC2Factory.Create())
+ {
+ rc2.Mode = cipherMode;
+
+ if (feedbackSize > 0)
+ {
+ rc2.FeedbackSize = feedbackSize;
+ }
+
+ using (ICryptoTransform transform = rc2.CreateEncryptor())
+ {
+ byte[] output1 = transform.TransformFinalBlock(input, 0, input.Length);
+ byte[] output2 = transform.TransformFinalBlock(input, 0, input.Length);
+
+ Assert.Equal(output1, output2);
+ }
+ }
+ }
+
+ [Theory]
+ [InlineData(CipherMode.CBC, 0)]
+ [InlineData(CipherMode.ECB, 0)]
+ public static void DecryptorReuse_LeadsToSameResults(CipherMode cipherMode, int feedbackSize)
+ {
+ // AppleCCCryptor does not allow calling Reset on CFB cipher.
+ // this test validates that the behavior is taken into consideration.
+ var input = "896072ab28e5fdfc".HexToByteArray();
+ var key = "3000000000000000".HexToByteArray();
+ var iv = "3000000000000000".HexToByteArray();
+
+ using (RC2 rc2 = RC2Factory.Create())
+ {
+ rc2.Mode = cipherMode;
+ rc2.Key = key;
+ rc2.IV = iv;
+ rc2.Padding = PaddingMode.None;
+
+ if (feedbackSize > 0)
+ {
+ rc2.FeedbackSize = feedbackSize;
+ }
+
+ using (ICryptoTransform transform = rc2.CreateDecryptor())
+ {
+ byte[] output1 = transform.TransformFinalBlock(input, 0, input.Length);
+ byte[] output2 = transform.TransformFinalBlock(input, 0, input.Length);
+
+ Assert.Equal(output1, output2);
+ }
+ }
+ }
+
[Fact]
public static void RC2ReuseEncryptorDecryptor()
{
--- /dev/null
+// 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 System.Collections.Generic;
+using System.IO;
+using System.Text;
+using Test.Cryptography;
+using Xunit;
+
+namespace System.Security.Cryptography.Encryption.RC2.Tests
+{
+ using RC2 = System.Security.Cryptography.RC2;
+
+ public static class RC2ContractTests
+ {
+ [Theory]
+ [InlineData(0, true)]
+ [InlineData(1, true)]
+ [InlineData(7, true)]
+ [InlineData(9, true)]
+ [InlineData(-1, true)]
+ [InlineData(int.MaxValue, true)]
+ [InlineData(int.MinValue, true)]
+ [InlineData(8, false)]
+ [InlineData(64, false)]
+ [InlineData(256, true)]
+ [InlineData(128, true)]
+ [InlineData(127, true)]
+ public static void InvalidCFBFeedbackSizes(int feedbackSize, bool discoverableInSetter)
+ {
+ using (RC2 rc2 = RC2Factory.Create())
+ {
+ rc2.GenerateKey();
+ rc2.Mode = CipherMode.CFB;
+
+ if (discoverableInSetter)
+ {
+ // there are some key sizes that are invalid for any of the modes,
+ // so the exception is thrown in the setter
+ Assert.Throws<CryptographicException>(() =>
+ {
+ rc2.FeedbackSize = feedbackSize;
+ });
+ }
+ else
+ {
+ rc2.FeedbackSize = feedbackSize;
+
+ // however, for CFB only few sizes are valid. Those should throw in the
+ // actual RC2 instantiation.
+
+ Assert.Throws<CryptographicException>(() => rc2.CreateDecryptor());
+ Assert.Throws<CryptographicException>(() => rc2.CreateEncryptor());
+ }
+ }
+ }
+ }
+}
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using System.IO;
using System.Text;
using Test.Cryptography;
using Xunit;
}
}
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB8_NoPadding_0()
+ {
+ // NIST CAVS TDESMMT.ZIP TCFB8MMT2.rsp, [DECRYPT] COUNT=0
+ TestTripleDESTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.None,
+ key: "fb978a0b6dc2c467e3cb52329de95161fb978a0b6dc2c467".HexToByteArray(),
+ iv: "8b97579ea5ac300f".HexToByteArray(),
+ plainBytes: "80".HexToByteArray(),
+ cipherBytes: "05".HexToByteArray(),
+ feedbackSize: 8
+ );
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB8_NoPadding_1()
+ {
+ // NIST CAVS TDESMMT.ZIP TCFB8MMT2.rsp, [DECRYPT] COUNT=1
+ TestTripleDESTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.None,
+ key: "9b04c86dd31a8a589876101549d6e0109b04c86dd31a8a58".HexToByteArray(),
+ iv: "52cd77d49fc72347".HexToByteArray(),
+ plainBytes: "2fef".HexToByteArray(),
+ cipherBytes: "5818".HexToByteArray(),
+ feedbackSize: 8
+ );
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB8_NoPadding_2()
+ {
+ // NIST CAVS TDESMMT.ZIP TCFB8MMT2.rsp, [DECRYPT] COUNT=2
+ TestTripleDESTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.None,
+ key: "fbb667e340586b5b5ef7c87049b93257fbb667e340586b5b".HexToByteArray(),
+ iv: "459e8b8736715791".HexToByteArray(),
+ plainBytes: "061704".HexToByteArray(),
+ cipherBytes: "93b378".HexToByteArray(),
+ feedbackSize: 8
+ );
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB8_PKCS7_2()
+ {
+ // NIST CAVS TDESMMT.ZIP TCFB8MMT2.rsp, [DECRYPT] COUNT=2
+ TestTripleDESTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.PKCS7,
+ key: "fbb667e340586b5b5ef7c87049b93257fbb667e340586b5b".HexToByteArray(),
+ iv: "459e8b8736715791".HexToByteArray(),
+ plainBytes: "061704".HexToByteArray(),
+ cipherBytes: "93b37808".HexToByteArray(),
+ feedbackSize: 8
+ );
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB64_PKCS7_2()
+ {
+ // NIST CAVS TDESMMT.ZIP TCFB8MMT2.rsp, [DECRYPT] COUNT=2
+ TestTripleDESTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.PKCS7,
+ key: "fbb667e340586b5b5ef7c87049b93257fbb667e340586b5b".HexToByteArray(),
+ iv: "459e8b8736715791".HexToByteArray(),
+ plainBytes: "061704".HexToByteArray(),
+ cipherBytes: "931f41eccdab4f99".HexToByteArray(),
+ feedbackSize: 64
+ );
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB8_NoPadding_3()
+ {
+ // NIST CAVS TDESMMT.ZIP TCFB8MMT2.rsp, [DECRYPT] COUNT=3
+ TestTripleDESTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.None,
+ key: "4a575d02515d40b0a40d830bd9b315134a575d02515d40b0".HexToByteArray(),
+ iv: "ab27e9f02affa532".HexToByteArray(),
+ plainBytes: "55f75b95".HexToByteArray(),
+ cipherBytes: "2ef5dddc".HexToByteArray(),
+ feedbackSize: 8
+ );
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB8_NoPadding_4()
+ {
+ // NIST CAVS TDESMMT.ZIP TCFB8MMT2.rsp, [DECRYPT] COUNT=4
+ TestTripleDESTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.None,
+ key: "91a834855e6bab31c7fd6be657ceb9ec91a834855e6bab31".HexToByteArray(),
+ iv: "7838aaad4e64640b".HexToByteArray(),
+ plainBytes: "c3851c0ab4".HexToByteArray(),
+ cipherBytes: "fe451f35f1".HexToByteArray(),
+ feedbackSize: 8
+ );
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB8_NoPadding_5()
+ {
+ // NIST CAVS TDESMMT.ZIP TCFB8MMT2.rsp, [DECRYPT] COUNT=5
+ TestTripleDESTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.None,
+ key: "04d923abd9291c3e4954a8b52fdabcc804d923abd9291c3e".HexToByteArray(),
+ iv: "191f8794944e601c".HexToByteArray(),
+ plainBytes: "6fe8f67d2af1".HexToByteArray(),
+ cipherBytes: "3bd78a8d24ad".HexToByteArray(),
+ feedbackSize: 8
+ );
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB8_NoPadding_6()
+ {
+ // NIST CAVS TDESMMT.ZIP TCFB8MMT2.rsp, [DECRYPT] COUNT=6
+ TestTripleDESTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.None,
+ key: "a7799e7f5dfe54ce13376401e96de075a7799e7f5dfe54ce".HexToByteArray(),
+ iv: "370184c749d04a20".HexToByteArray(),
+ plainBytes: "2b4228b769795b".HexToByteArray(),
+ cipherBytes: "6f32e4495e4259".HexToByteArray(),
+ feedbackSize: 8
+ );
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB8_NoPadding_7()
+ {
+ // NIST CAVS TDESMMT.ZIP TCFB8MMT2.rsp, [DECRYPT] COUNT=7
+ TestTripleDESTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.None,
+ key: "6bfe3d3df8c1e0d34ffe0dbf854c940e6bfe3d3df8c1e0d3".HexToByteArray(),
+ iv: "51e4c5c29e858da6".HexToByteArray(),
+ plainBytes: "4cb3554fd0b9ec82".HexToByteArray(),
+ cipherBytes: "72e1738d80d285e2".HexToByteArray(),
+ feedbackSize: 8
+ );
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB8_NoPadding_8()
+ {
+ // NIST CAVS TDESMMT.ZIP TCFB8MMT2.rsp, [DECRYPT] COUNT=8
+ TestTripleDESTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.None,
+ key: "e0264aec13e63db991f8c120c4b9b6dae0264aec13e63db9".HexToByteArray(),
+ iv: "bd8795dba79930d6".HexToByteArray(),
+ plainBytes: "79068e2943f02914af".HexToByteArray(),
+ cipherBytes: "9b78c5636c5965f88e".HexToByteArray(),
+ feedbackSize: 8
+ );
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB8_NoPadding_9()
+ {
+ // NIST CAVS TDESMMT.ZIP TCFB8MMT2.rsp, [DECRYPT] COUNT=9
+ TestTripleDESTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.None,
+ key: "7ca28938ba6bec1ffec78f7cd69761947ca28938ba6bec1f".HexToByteArray(),
+ iv: "953896586e49d38f".HexToByteArray(),
+ plainBytes: "2ea956d4a211db6859b7".HexToByteArray(),
+ cipherBytes: "f20e536674a66fa73805".HexToByteArray(),
+ feedbackSize: 8
+ );
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB64_NoPadding_0()
+ {
+ // NIST CAVS TDESMMT.ZIP TCFB64MMT2.rsp, [DECRYPT] COUNT=0
+ TestTripleDESTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.None,
+ key: "9ee0b59b25865154588551341c4fef9e9ee0b59b25865154".HexToByteArray(),
+ iv: "6e37d197376db595".HexToByteArray(),
+ plainBytes: "dcd3cf9746d6e42b".HexToByteArray(),
+ cipherBytes: "63cad52260e0a1cd".HexToByteArray(),
+ feedbackSize: 64
+ );
+ }
+
+ [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ [InlineData(CipherMode.CBC, 0)]
+ [InlineData(CipherMode.CFB, 8)]
+ [InlineData(CipherMode.CFB, 64)]
+ [InlineData(CipherMode.ECB, 0)]
+ public static void EncryptorReuse_LeadsToSameResults(CipherMode cipherMode, int feedbackSize)
+ {
+ // AppleCCCryptor does not allow calling Reset on CFB cipher.
+ // this test validates that the behavior is taken into consideration.
+ var input = "b72606c98d8e4fabf08839abf7a0ac61".HexToByteArray();
+
+ using (TripleDES tdes = TripleDESFactory.Create())
+ {
+ tdes.Mode = cipherMode;
+
+ if (feedbackSize > 0)
+ {
+ tdes.FeedbackSize = feedbackSize;
+ }
+
+ using (ICryptoTransform transform = tdes.CreateEncryptor())
+ {
+ byte[] output1 = transform.TransformFinalBlock(input, 0, input.Length);
+ byte[] output2 = transform.TransformFinalBlock(input, 0, input.Length);
+
+ Assert.Equal(output1, output2);
+ }
+ }
+ }
+
+ [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ [InlineData(CipherMode.CBC, 0)]
+ [InlineData(CipherMode.CFB, 8)]
+ [InlineData(CipherMode.CFB, 64)]
+ [InlineData(CipherMode.ECB, 0)]
+ public static void DecryptorReuse_LeadsToSameResults(CipherMode cipherMode, int feedbackSize)
+ {
+ // AppleCCCryptor does not allow calling Reset on CFB cipher.
+ // this test validates that the behavior is taken into consideration.
+ var input = "896072ab28e5fdfc9e8b3610627bf27a".HexToByteArray();
+ var key = "c179d0fdd073a1910e51f1d5fe70047ac179d0fdd073a191".HexToByteArray();
+ var iv = "b956d5426d02b247".HexToByteArray();
+
+ using (TripleDES tdes = TripleDESFactory.Create())
+ {
+ tdes.Mode = cipherMode;
+ tdes.Key = key;
+ tdes.IV = iv;
+ tdes.Padding = PaddingMode.None;
+
+ if (feedbackSize > 0)
+ {
+ tdes.FeedbackSize = feedbackSize;
+ }
+
+ using (ICryptoTransform transform = tdes.CreateDecryptor())
+ {
+ byte[] output1 = transform.TransformFinalBlock(input, 0, input.Length);
+ byte[] output2 = transform.TransformFinalBlock(input, 0, input.Length);
+
+ Assert.Equal(output1, output2);
+ }
+ }
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB64_NoPadding_1()
+ {
+ // NIST CAVS TDESMMT.ZIP TCFB64MMT2.rsp, [DECRYPT] COUNT=1
+ TestTripleDESTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.None,
+ key: "c179d0fdd073a1910e51f1d5fe70047ac179d0fdd073a191".HexToByteArray(),
+ iv: "b956d5426d02b247".HexToByteArray(),
+ plainBytes: "32bd529065e26a27643097925e3a726b".HexToByteArray(),
+ cipherBytes: "896072ab28e5fdfc9e8b3610627bf27a".HexToByteArray(),
+ feedbackSize: 64
+ );
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB64_NoPadding_2()
+ {
+ // NIST CAVS TDESMMT.ZIP TCFB64MMT2.rsp, [DECRYPT] COUNT=2
+ TestTripleDESTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.None,
+ key: "a8084a04495bfb45b3575ee03d732967a8084a04495bfb45".HexToByteArray(),
+ iv: "00fd7b4fdb4b3382".HexToByteArray(),
+ plainBytes: "c20c7041007a67de7b4355be7406095496923b75dfb98080".HexToByteArray(),
+ cipherBytes: "9198c138edb037de25d0bcdebe7b9be10ebd7e7ea103edae".HexToByteArray(),
+ feedbackSize: 64
+ );
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB64_NoPadding_3()
+ {
+ // NIST CAVS TDESMMT.ZIP TCFB64MMT2.rsp, [DECRYPT] COUNT=3
+ TestTripleDESTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.None,
+ key: "c1497fdf67cecbab80d543f16d13c8d5c1497fdf67cecbab".HexToByteArray(),
+ iv: "a1241ca0fe9378cd".HexToByteArray(),
+ plainBytes: "157dcfa7ad6758335e561fa7dd7f98dca592e9128e7be30ccd1af7dc5a4536d5".HexToByteArray(),
+ cipherBytes: "08fcace492f82282fb3255884a64a231dd438069ffbcb432bd7ec446f5b8adfd".HexToByteArray(),
+ feedbackSize: 64
+ );
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB64_NoPadding_4()
+ {
+ // NIST CAVS TDESMMT.ZIP TCFB64MMT2.rsp, [DECRYPT] COUNT=4
+ TestTripleDESTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.None,
+ key: "fd0e3262ec38fe5710389d0779c2fb43fd0e3262ec38fe57".HexToByteArray(),
+ iv: "33c9e4adfb4634ac".HexToByteArray(),
+ plainBytes: "37536dda516aab8a992131004134ce48c56fee05261164aae0a88db0f43410617f105e20940cf3e9".HexToByteArray(),
+ cipherBytes: "80e8a96c3fe83857fc738ac7b6639f0d8c28bfa617c56a60fd1b8fbdc36afe9ce3151e161fa5e3a7".HexToByteArray(),
+ feedbackSize: 64
+ );
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB64_NoPadding_5()
+ {
+ // NIST CAVS TDESMMT.ZIP TCFB64MMT2.rsp, [DECRYPT] COUNT=5
+ TestTripleDESTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.None,
+ key: "ae32253be61040157a7c10b6011fcde3ae32253be6104015".HexToByteArray(),
+ iv: "47be2286dbccdfe6".HexToByteArray(),
+ plainBytes: "e579282129c123c914c700ad8c099b593fe83fdef7be7e5ffb36add9c6b91644cc79c1e457212017488963e16198c528".HexToByteArray(),
+ cipherBytes: "7185c5800ca4d5432b50f5b7920e26296c2913e7e3f847a1ef639e156ba4f9ec6e4b36ded885601d2b9d22f19dc3829f".HexToByteArray(),
+ feedbackSize: 64
+ );
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB64_NoPadding_6()
+ {
+ // NIST CAVS TDESMMT.ZIP TCFB64MMT2.rsp, [DECRYPT] COUNT=6
+ TestTripleDESTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.None,
+ key: "df83498cec83084acb7aaef26e58f1e0df83498cec83084a".HexToByteArray(),
+ iv: "158d2ca6e70b18f6".HexToByteArray(),
+ plainBytes: "4fb7cf2a244ff20beddf8719b2d9c78ab0710703036f804f08bc1f7927ea9906ba1ef57afd1553c5304c0b72694cd88bb6cb1289772dfff0".HexToByteArray(),
+ cipherBytes: "158b396cd1969a07042e808d0c875d74166ce77291df233fe300c29c5a30b1946575ec02042093537dae3f8d51ed96906e601d9da6e34e14".HexToByteArray(),
+ feedbackSize: 64
+ );
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB64_NoPadding_7()
+ {
+ // NIST CAVS TDESMMT.ZIP TCFB64MMT2.rsp, [DECRYPT] COUNT=7
+ TestTripleDESTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.None,
+ key: "ce31cd2067c157199bfb3b8ad9ef9223ce31cd2067c15719".HexToByteArray(),
+ iv: "d31741512b6a7471".HexToByteArray(),
+ plainBytes: "a0447f5abebf8623db81b600699ce8373353442908fefe8c63f5e29e22ba1057f759635505ed0ac059887def2d31f6996128d4fbe2df6534429744d7f6496768".HexToByteArray(),
+ cipherBytes: "b3a791b128f003bc28cd17bbb5c68990faec73f88c10b664f1349b045f3fba24c5f51bbb10259c41a72492c2377bb331b6dd34fea25c2eea8adc461bd0c78d6b".HexToByteArray(),
+ feedbackSize: 64
+ );
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB64_NoPadding_8()
+ {
+ // NIST CAVS TDESMMT.ZIP TCFB64MMT2.rsp, [DECRYPT] COUNT=8
+ TestTripleDESTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.None,
+ key: "5bbc3423bf67e05262d65740708019f15bbc3423bf67e052".HexToByteArray(),
+ iv: "14544ea4813c49d9".HexToByteArray(),
+ plainBytes: "a21f26496f74fd8a93aa5423e2a4fc76facbff015db2f4ef14f08b8c13a29d0561e4e57d04b0b00211f8fba46d025a9c0727c8aebb7d25f27f1606321909ba50e660fa25358c63f9".HexToByteArray(),
+ cipherBytes: "c3acc89b9b6037effc65eacdc23b36c38d0e609566d360eba594e4481108983b4a67a5d9647c776ad5fcc4639116ca95734bd8a3df800fb9a6526a7b29a9fc3cc29079715f44f865".HexToByteArray(),
+ feedbackSize: 64
+ );
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ public static void VerifyKnownTransform_CFB64_NoPadding_9()
+ {
+ // NIST CAVS TDESMMT.ZIP TCFB64MMT2.rsp, [DECRYPT] COUNT=9
+ TestTripleDESTransformDirectKey(
+ CipherMode.CFB,
+ PaddingMode.None,
+ key: "197c738cfb6e0bc2fee57ffb1ca72675197c738cfb6e0bc2".HexToByteArray(),
+ iv: "f1a42447a333caa3".HexToByteArray(),
+ plainBytes: "6f914b6996ee8e7ea625b2fddd7677b4384320be0aba3af81d1210965ac37983f340d5698ddf35d45dfccbf783a50c6eed1a730b5c98675cb6b7645fc8374e10d8b340c44b0eae988c1ef635fab913da".HexToByteArray(),
+ cipherBytes: "8aabb83216e4bd5a3dd20586e598bb8e956dcbf7d09cde17a2cf8b7a788ecb853503ae5981004dfa644300b115f8d1ae0c7f30f25e70e86c4adc51620fd6c71301325c9bdc8dca16588eac08fe6aedfd".HexToByteArray(),
+ feedbackSize: 64
+ );
+ }
+
+ private static byte[] TripleDESEncryptDirectKey(TripleDES tdes, byte[] key, byte[] iv, byte[] plainBytes)
+ {
+ using (MemoryStream output = new MemoryStream())
+ using (CryptoStream cryptoStream = new CryptoStream(output, tdes.CreateEncryptor(key, iv), CryptoStreamMode.Write))
+ {
+ cryptoStream.Write(plainBytes, 0, plainBytes.Length);
+ cryptoStream.FlushFinalBlock();
+
+ return output.ToArray();
+ }
+ }
+
+ private static byte[] TripleDESDecryptDirectKey(TripleDES tdes, byte[] key, byte[] iv, byte[] cipherBytes)
+ {
+ using (MemoryStream output = new MemoryStream())
+ using (CryptoStream cryptoStream = new CryptoStream(output, tdes.CreateDecryptor(key, iv), CryptoStreamMode.Write))
+ {
+ cryptoStream.Write(cipherBytes, 0, cipherBytes.Length);
+ cryptoStream.FlushFinalBlock();
+
+ return output.ToArray();
+ }
+ }
+
+ private static void TestTripleDESTransformDirectKey(
+ CipherMode cipherMode,
+ PaddingMode paddingMode,
+ byte[] key,
+ byte[] iv,
+ byte[] plainBytes,
+ byte[] cipherBytes,
+ int? feedbackSize = default)
+ {
+ byte[] liveEncryptBytes;
+ byte[] liveDecryptBytes;
+
+ using (TripleDES tdes = TripleDESFactory.Create())
+ {
+ tdes.Mode = cipherMode;
+ tdes.Padding = paddingMode;
+
+ if (feedbackSize.HasValue)
+ {
+ tdes.FeedbackSize = feedbackSize.Value;
+ }
+
+ liveEncryptBytes = TripleDESEncryptDirectKey(tdes, key, iv, plainBytes);
+ liveDecryptBytes = TripleDESDecryptDirectKey(tdes, key, iv, cipherBytes);
+ }
+
+ Assert.Equal(cipherBytes, liveEncryptBytes);
+ Assert.Equal(plainBytes, liveDecryptBytes);
+ }
+
[Theory]
[InlineData(192, "e56f72478c7479d169d54c0548b744af5b53efb1cdd26037", "c5629363d957054eba793093b83739bb78711db221a82379")]
[InlineData(128, "1387b981dbb40f34b915c4ed89fd681a740d3b4869c0b575", "c5629363d957054eba793093b83739bb")]
--- /dev/null
+// 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 System.Text;
+using Test.Cryptography;
+using Xunit;
+
+namespace System.Security.Cryptography.Encryption.TripleDes.Tests
+{
+ public static class TripleDESContractTests
+ {
+
+ [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsWindows7))]
+ [InlineData(0, true)]
+ [InlineData(1, true)]
+ [InlineData(7, true)]
+ [InlineData(9, true)]
+ [InlineData(-1, true)]
+ [InlineData(int.MaxValue, true)]
+ [InlineData(int.MinValue, true)]
+ [InlineData(8, false)]
+ [InlineData(64, false)]
+ [InlineData(256, true)]
+ [InlineData(128, true)]
+ [InlineData(127, true)]
+ public static void Windows7DoesNotSupportCFB(int feedbackSize, bool discoverableInSetter)
+ {
+ using (TripleDES tdes = TripleDESFactory.Create())
+ {
+ tdes.GenerateKey();
+ tdes.Mode = CipherMode.CFB;
+
+ if (discoverableInSetter)
+ {
+ // there are some key sizes that are invalid for any of the modes,
+ // so the exception is thrown in the setter
+ Assert.ThrowsAny<CryptographicException>(() =>
+ {
+ tdes.FeedbackSize = feedbackSize;
+ });
+ }
+ else
+ {
+ tdes.FeedbackSize = feedbackSize;
+
+ // however, for CFB only few sizes are valid. Those should throw in the
+ // actual AES instantiation.
+
+ Assert.ThrowsAny<CryptographicException>(() =>
+ {
+ return tdes.CreateDecryptor();
+ });
+ Assert.ThrowsAny<CryptographicException>(() =>
+ {
+ return tdes.CreateEncryptor();
+ });
+ }
+ }
+ }
+
+ [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ [InlineData(0, true)]
+ [InlineData(1, true)]
+ [InlineData(7, true)]
+ [InlineData(9, true)]
+ [InlineData(-1, true)]
+ [InlineData(int.MaxValue, true)]
+ [InlineData(int.MinValue, true)]
+ [InlineData(256, true)]
+ [InlineData(128, true)]
+ [InlineData(127, true)]
+ public static void InvalidCFBFeedbackSizes(int feedbackSize, bool discoverableInSetter)
+ {
+ using (TripleDES tdes = TripleDESFactory.Create())
+ {
+ tdes.GenerateKey();
+ tdes.Mode = CipherMode.CFB;
+
+ if (discoverableInSetter)
+ {
+ // there are some key sizes that are invalid for any of the modes,
+ // so the exception is thrown in the setter
+ Assert.Throws<CryptographicException>(() =>
+ {
+ tdes.FeedbackSize = feedbackSize;
+ });
+ }
+ else
+ {
+ tdes.FeedbackSize = feedbackSize;
+
+ // however, for CFB only few sizes are valid. Those should throw in the
+ // actual AES instantiation.
+
+ Assert.Throws<CryptographicException>(() => tdes.CreateDecryptor());
+ Assert.Throws<CryptographicException>(() => tdes.CreateEncryptor());
+ }
+ }
+ }
+
+ [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ [InlineData(8)]
+ [InlineData(64)]
+ public static void ValidCFBFeedbackSizes(int feedbackSize)
+ {
+ using (TripleDES tdes = TripleDESFactory.Create())
+ {
+ tdes.GenerateKey();
+ tdes.Mode = CipherMode.CFB;
+
+ tdes.FeedbackSize = feedbackSize;
+
+ using var decryptor = tdes.CreateDecryptor();
+ using var encryptor = tdes.CreateEncryptor();
+ Assert.NotNull(decryptor);
+ Assert.NotNull(encryptor);
+ }
+ }
+ }
+}
c_static_assert(PAL_ChainingModeECB == kCCModeECB);
c_static_assert(PAL_ChainingModeCBC == kCCModeCBC);
+c_static_assert(PAL_ChainingModeCFB == kCCModeCFB);
+c_static_assert(PAL_ChainingModeCFB8 == kCCModeCFB8);
c_static_assert(PAL_PaddingModeNone == ccNoPadding);
c_static_assert(PAL_PaddingModePkcs7 == ccPKCS7Padding);
assert(operation == PAL_OperationEncrypt || operation == PAL_OperationDecrypt);
assert(algorithm == PAL_AlgorithmAES || algorithm == PAL_AlgorithmDES || algorithm == PAL_Algorithm3DES ||
algorithm == PAL_AlgorithmRC2);
- assert(chainingMode == PAL_ChainingModeECB || chainingMode == PAL_ChainingModeCBC);
+ assert(chainingMode == PAL_ChainingModeECB || chainingMode == PAL_ChainingModeCBC || chainingMode == PAL_ChainingModeCFB || chainingMode == PAL_ChainingModeCFB8);
assert(paddingMode == PAL_PaddingModeNone || paddingMode == PAL_PaddingModePkcs7);
assert(options == 0);
{
PAL_ChainingModeECB = 1,
PAL_ChainingModeCBC = 2,
+ PAL_ChainingModeCFB = 3,
+ PAL_ChainingModeCFB8 = 10,
};
typedef uint32_t PAL_ChainingMode;
REQUIRED_FUNCTION(ERR_reason_error_string) \
REQUIRED_FUNCTION(EVP_aes_128_cbc) \
REQUIRED_FUNCTION(EVP_aes_128_ccm) \
+ REQUIRED_FUNCTION(EVP_aes_128_cfb128) \
+ REQUIRED_FUNCTION(EVP_aes_128_cfb8) \
REQUIRED_FUNCTION(EVP_aes_128_ecb) \
REQUIRED_FUNCTION(EVP_aes_128_gcm) \
REQUIRED_FUNCTION(EVP_aes_192_cbc) \
REQUIRED_FUNCTION(EVP_aes_192_ccm) \
+ REQUIRED_FUNCTION(EVP_aes_192_cfb128) \
+ REQUIRED_FUNCTION(EVP_aes_192_cfb8) \
REQUIRED_FUNCTION(EVP_aes_192_ecb) \
REQUIRED_FUNCTION(EVP_aes_192_gcm) \
REQUIRED_FUNCTION(EVP_aes_256_cbc) \
REQUIRED_FUNCTION(EVP_aes_256_ccm) \
+ REQUIRED_FUNCTION(EVP_aes_256_cfb128) \
+ REQUIRED_FUNCTION(EVP_aes_256_cfb8) \
REQUIRED_FUNCTION(EVP_aes_256_ecb) \
REQUIRED_FUNCTION(EVP_aes_256_gcm) \
LEGACY_FUNCTION(EVP_CIPHER_CTX_cleanup) \
REQUIRED_FUNCTION(EVP_CipherInit_ex) \
REQUIRED_FUNCTION(EVP_CipherUpdate) \
REQUIRED_FUNCTION(EVP_des_cbc) \
+ REQUIRED_FUNCTION(EVP_des_cfb8) \
REQUIRED_FUNCTION(EVP_des_ecb) \
REQUIRED_FUNCTION(EVP_des_ede3) \
REQUIRED_FUNCTION(EVP_des_ede3_cbc) \
+ REQUIRED_FUNCTION(EVP_des_ede3_cfb8) \
+ REQUIRED_FUNCTION(EVP_des_ede3_cfb64) \
REQUIRED_FUNCTION(EVP_DigestFinal_ex) \
REQUIRED_FUNCTION(EVP_DigestInit_ex) \
REQUIRED_FUNCTION(EVP_DigestUpdate) \
#define ERR_put_error ERR_put_error_ptr
#define ERR_reason_error_string ERR_reason_error_string_ptr
#define EVP_aes_128_cbc EVP_aes_128_cbc_ptr
+#define EVP_aes_128_cfb8 EVP_aes_128_cfb8_ptr
+#define EVP_aes_128_cfb128 EVP_aes_128_cfb128_ptr
#define EVP_aes_128_ecb EVP_aes_128_ecb_ptr
#define EVP_aes_128_gcm EVP_aes_128_gcm_ptr
#define EVP_aes_128_ccm EVP_aes_128_ccm_ptr
#define EVP_aes_192_cbc EVP_aes_192_cbc_ptr
+#define EVP_aes_192_cfb8 EVP_aes_192_cfb8_ptr
+#define EVP_aes_192_cfb128 EVP_aes_192_cfb128_ptr
#define EVP_aes_192_ecb EVP_aes_192_ecb_ptr
#define EVP_aes_192_gcm EVP_aes_192_gcm_ptr
#define EVP_aes_192_ccm EVP_aes_192_ccm_ptr
#define EVP_aes_256_cbc EVP_aes_256_cbc_ptr
+#define EVP_aes_256_cfb8 EVP_aes_256_cfb8_ptr
+#define EVP_aes_256_cfb128 EVP_aes_256_cfb128_ptr
#define EVP_aes_256_ecb EVP_aes_256_ecb_ptr
#define EVP_aes_256_gcm EVP_aes_256_gcm_ptr
#define EVP_aes_256_ccm EVP_aes_256_ccm_ptr
#define EVP_CipherInit_ex EVP_CipherInit_ex_ptr
#define EVP_CipherUpdate EVP_CipherUpdate_ptr
#define EVP_des_cbc EVP_des_cbc_ptr
+#define EVP_des_cfb8 EVP_des_cfb8_ptr
#define EVP_des_ecb EVP_des_ecb_ptr
#define EVP_des_ede3 EVP_des_ede3_ptr
+#define EVP_des_ede3_cfb8 EVP_des_ede3_cfb8_ptr
+#define EVP_des_ede3_cfb64 EVP_des_ede3_cfb64_ptr
#define EVP_des_ede3_cbc EVP_des_ede3_cbc_ptr
#define EVP_DigestFinal_ex EVP_DigestFinal_ex_ptr
#define EVP_DigestInit_ex EVP_DigestInit_ex_ptr
return EVP_aes_128_gcm();
}
+const EVP_CIPHER* CryptoNative_EvpAes128Cfb128()
+{
+ return EVP_aes_128_cfb128();
+}
+
+const EVP_CIPHER* CryptoNative_EvpAes128Cfb8()
+{
+ return EVP_aes_128_cfb8();
+}
+
const EVP_CIPHER* CryptoNative_EvpAes128Ccm()
{
return EVP_aes_128_ccm();
return EVP_aes_192_ecb();
}
+const EVP_CIPHER* CryptoNative_EvpAes192Cfb128()
+{
+ return EVP_aes_192_cfb128();
+}
+
+const EVP_CIPHER* CryptoNative_EvpAes192Cfb8()
+{
+ return EVP_aes_192_cfb8();
+}
+
const EVP_CIPHER* CryptoNative_EvpAes192Cbc()
{
return EVP_aes_192_cbc();
return EVP_aes_256_ecb();
}
+const EVP_CIPHER* CryptoNative_EvpAes256Cfb128()
+{
+ return EVP_aes_256_cfb128();
+}
+
+const EVP_CIPHER* CryptoNative_EvpAes256Cfb8()
+{
+ return EVP_aes_256_cfb8();
+}
+
const EVP_CIPHER* CryptoNative_EvpAes256Cbc()
{
return EVP_aes_256_cbc();
return EVP_des_ecb();
}
+const EVP_CIPHER* CryptoNative_EvpDesCfb8()
+{
+ return EVP_des_cfb8();
+}
+
const EVP_CIPHER* CryptoNative_EvpDesCbc()
{
return EVP_des_cbc();
return EVP_des_ede3();
}
+const EVP_CIPHER* CryptoNative_EvpDes3Cfb8()
+{
+ return EVP_des_ede3_cfb8();
+}
+
+const EVP_CIPHER* CryptoNative_EvpDes3Cfb64()
+{
+ return EVP_des_ede3_cfb64();
+}
+
const EVP_CIPHER* CryptoNative_EvpDes3Cbc()
{
return EVP_des_ede3_cbc();
/*
Function:
+EvpAes128Cfb8
+
+Direct shim to EVP_aes_128_cfb8.
+*/
+PALEXPORT const EVP_CIPHER* CryptoNative_EvpAes128Cfb8(void);
+
+/*
+Function:
+EvpAes128Cfb128
+
+Direct shim to EVP_aes_128_cfb128.
+*/
+PALEXPORT const EVP_CIPHER* CryptoNative_EvpAes128Cfb128(void);
+
+/*
+Function:
EvpAes128Gcm
Direct shim to EVP_aes_128_gcm.
/*
Function:
+EvpAes192Cfb8
+
+Direct shim to EVP_aes_192_cfb8.
+*/
+PALEXPORT const EVP_CIPHER* CryptoNative_EvpAes192Cfb8(void);
+
+/*
+Function:
+EvpAes192Cfb128
+
+Direct shim to EVP_aes_192_cfb128.
+*/
+PALEXPORT const EVP_CIPHER* CryptoNative_EvpAes192Cfb128(void);
+
+/*
+Function:
EvpAes192Gcm
Direct shim to EVP_aes_192_gcm.
/*
Function:
+EvpAes256Cfb8
+
+Direct shim to EVP_aes_256_cfb8.
+*/
+PALEXPORT const EVP_CIPHER* CryptoNative_EvpAes256Cfb8(void);
+
+/*
+Function:
+EvpAes256Cfb128
+
+Direct shim to EVP_aes_256_cfb128.
+*/
+PALEXPORT const EVP_CIPHER* CryptoNative_EvpAes256Cfb128(void);
+
+/*
+Function:
EvpAes256Gcm
Direct shim to EVP_aes_256_gcm.
/*
Function:
+EvpDes3Cfb8
+
+Direct shim to EVP_des_ede3_cfb8.
+*/
+PALEXPORT const EVP_CIPHER* CryptoNative_EvpDes3Cfb8(void);
+
+/*
+Function:
+EvpDes3Cfb64
+
+Direct shim to EVP_des_ede3_cfb64.
+*/
+PALEXPORT const EVP_CIPHER* CryptoNative_EvpDes3Cfb64(void);
+
+/*
+Function:
EvpDesEcb
Direct shim to EVP_des_ecb.
/*
Function:
+EvpDesCfb8
+
+Direct shim to EVP_des_cfb8.
+*/
+PALEXPORT const EVP_CIPHER* CryptoNative_EvpDesCfb8(void);
+
+/*
+Function:
EvpDesCbc
Direct shim to EVP_des_ede_cbc.
byte[] key,
byte[]? iv,
int blockSize,
+ int paddingSize,
+ int feedbackSizeInBytes,
bool encrypting)
{
BasicSymmetricCipher cipher = new AppleCCCryptor(
blockSize,
key,
iv,
- encrypting);
+ encrypting,
+ feedbackSizeInBytes,
+ paddingSize);
return UniversalCryptoTransform.Create(paddingMode, cipher, encrypting);
}
byte[] key,
byte[]? iv,
int blockSize,
+ int paddingSize,
+ int feedback,
bool encrypting)
{
// The algorithm pointer is a static pointer, so not having any cleanup code is correct.
- IntPtr algorithm = GetAlgorithm(key.Length * 8, cipherMode);
+ IntPtr algorithm = GetAlgorithm(key.Length * 8, feedback * 8, cipherMode);
- BasicSymmetricCipher cipher = new OpenSslCipher(algorithm, cipherMode, blockSize, key, 0, iv, encrypting);
+ BasicSymmetricCipher cipher = new OpenSslCipher(algorithm, cipherMode, blockSize, paddingSize, key, 0, iv, encrypting);
return UniversalCryptoTransform.Create(paddingMode, cipher, encrypting);
}
- private static readonly Tuple<int, CipherMode, Func<IntPtr>>[] s_algorithmInitializers =
+ private static readonly Tuple<int, int, CipherMode, Func<IntPtr>>[] s_algorithmInitializers =
{
// Neither OpenSSL nor Cng Aes support CTS mode.
- // Cng Aes doesn't seem to support CFB mode, and that would
- // require passing in the feedback size. Since Windows doesn't support it,
- // we can skip it here, too.
- Tuple.Create(128, CipherMode.CBC, (Func<IntPtr>)Interop.Crypto.EvpAes128Cbc),
- Tuple.Create(128, CipherMode.ECB, (Func<IntPtr>)Interop.Crypto.EvpAes128Ecb),
+ // second parameter is feedback size (required only for CFB).
- Tuple.Create(192, CipherMode.CBC, (Func<IntPtr>)Interop.Crypto.EvpAes192Cbc),
- Tuple.Create(192, CipherMode.ECB, (Func<IntPtr>)Interop.Crypto.EvpAes192Ecb),
+ Tuple.Create(128, 0, CipherMode.CBC, (Func<IntPtr>)Interop.Crypto.EvpAes128Cbc),
+ Tuple.Create(128, 0, CipherMode.ECB, (Func<IntPtr>)Interop.Crypto.EvpAes128Ecb),
+ Tuple.Create(128, 8, CipherMode.CFB, (Func<IntPtr>)Interop.Crypto.EvpAes128Cfb8),
+ Tuple.Create(128, 128, CipherMode.CFB, (Func<IntPtr>)Interop.Crypto.EvpAes128Cfb128),
- Tuple.Create(256, CipherMode.CBC, (Func<IntPtr>)Interop.Crypto.EvpAes256Cbc),
- Tuple.Create(256, CipherMode.ECB, (Func<IntPtr>)Interop.Crypto.EvpAes256Ecb),
+ Tuple.Create(192, 0, CipherMode.CBC, (Func<IntPtr>)Interop.Crypto.EvpAes192Cbc),
+ Tuple.Create(192, 0, CipherMode.ECB, (Func<IntPtr>)Interop.Crypto.EvpAes192Ecb),
+ Tuple.Create(192, 8, CipherMode.CFB, (Func<IntPtr>)Interop.Crypto.EvpAes192Cfb8),
+ Tuple.Create(192, 128, CipherMode.CFB, (Func<IntPtr>)Interop.Crypto.EvpAes192Cfb128),
+
+ Tuple.Create(256, 0, CipherMode.CBC, (Func<IntPtr>)Interop.Crypto.EvpAes256Cbc),
+ Tuple.Create(256, 0, CipherMode.ECB, (Func<IntPtr>)Interop.Crypto.EvpAes256Ecb),
+ Tuple.Create(256, 8, CipherMode.CFB, (Func<IntPtr>)Interop.Crypto.EvpAes256Cfb8),
+ Tuple.Create(256, 128, CipherMode.CFB, (Func<IntPtr>)Interop.Crypto.EvpAes256Cfb128),
};
- private static IntPtr GetAlgorithm(int keySize, CipherMode cipherMode)
+ private static IntPtr GetAlgorithm(int keySize, int feedback, CipherMode cipherMode)
{
bool foundKeysize = false;
- foreach (var triplet in s_algorithmInitializers)
+ foreach (var tuple in s_algorithmInitializers)
{
- if (triplet.Item1 == keySize && triplet.Item2 == cipherMode)
+ if (tuple.Item1 == keySize && (tuple.Item2 == 0 || tuple.Item2 == feedback) && tuple.Item3 == cipherMode)
{
- return triplet.Item3();
+ return tuple.Item4();
}
- if (triplet.Item1 == keySize)
+ if (tuple.Item1 == keySize)
{
foundKeysize = true;
}
byte[] key,
byte[]? iv,
int blockSize,
+ int paddingSize,
+ int feedbackSize,
bool encrypting)
{
- SafeAlgorithmHandle algorithm = AesBCryptModes.GetSharedHandle(cipherMode);
+ SafeAlgorithmHandle algorithm = AesBCryptModes.GetSharedHandle(cipherMode, feedbackSize);
- BasicSymmetricCipher cipher = new BasicSymmetricCipherBCrypt(algorithm, cipherMode, blockSize, key, false, iv, encrypting);
+ BasicSymmetricCipher cipher = new BasicSymmetricCipherBCrypt(algorithm, cipherMode, blockSize, paddingSize, key, false, iv, encrypting);
return UniversalCryptoTransform.Create(paddingMode, cipher, encrypting);
}
}
throw new ArgumentException(SR.Cryptography_InvalidIVSize, nameof(rgbIV));
}
- return CreateTransformCore(Mode, Padding, rgbKey, rgbIV, BlockSize / BitsPerByte, encrypting);
+ if (Mode == CipherMode.CFB)
+ {
+ ValidateCFBFeedbackSize(FeedbackSize);
+ }
+
+ return CreateTransformCore(Mode, Padding, rgbKey, rgbIV, BlockSize / BitsPerByte, this.GetPaddingSize(), FeedbackSize / BitsPerByte, encrypting);
+ }
+
+ private static void ValidateCFBFeedbackSize(int feedback)
+ {
+ // only 8bits/128bits feedback would be valid.
+ if (feedback != 8 && feedback != 128)
+ {
+ throw new CryptographicException(string.Format(SR.Cryptography_CipherModeFeedbackNotSupported, feedback, CipherMode.CFB));
+ }
}
private const int BitsPerByte = 8;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Security.Cryptography;
+using Internal.Cryptography;
namespace Internal.Cryptography
{
private readonly bool _encrypting;
private SafeAppleCryptorHandle _cryptor;
+ // Reset operation is not supported on stream cipher
+ private readonly bool _supportsReset;
+
+ private Interop.AppleCrypto.PAL_SymmetricAlgorithm _algorithm;
+ private CipherMode _cipherMode;
+ private byte[] _key;
+ private int _feedbackSizeInBytes;
+
public AppleCCCryptor(
Interop.AppleCrypto.PAL_SymmetricAlgorithm algorithm,
CipherMode cipherMode,
int blockSizeInBytes,
byte[] key,
byte[]? iv,
- bool encrypting)
- : base(cipherMode.GetCipherIv(iv), blockSizeInBytes)
+ bool encrypting,
+ int feedbackSizeInBytes,
+ int paddingSizeInBytes)
+ : base(cipherMode.GetCipherIv(iv), blockSizeInBytes, paddingSizeInBytes)
{
_encrypting = encrypting;
- OpenCryptor(algorithm, cipherMode, key);
+ // CFB is streaming cipher, calling CCCryptorReset is not implemented (and is effectively noop)
+ _supportsReset = cipherMode != CipherMode.CFB;
+
+ _algorithm = algorithm;
+ _cipherMode = cipherMode;
+ _key = key;
+ _feedbackSizeInBytes = feedbackSizeInBytes;
+
+ OpenCryptor();
}
protected override void Dispose(bool disposing)
public override int Transform(ReadOnlySpan<byte> input, Span<byte> output)
{
Debug.Assert(input.Length > 0);
- Debug.Assert((input.Length % BlockSizeInBytes) == 0);
+ Debug.Assert((input.Length % PaddingSizeInBytes) == 0);
return CipherUpdate(input, output);
}
public override int TransformFinal(ReadOnlySpan<byte> input, Span<byte> output)
{
- Debug.Assert((input.Length % BlockSizeInBytes) == 0);
+ Debug.Assert((input.Length % PaddingSizeInBytes) == 0);
Debug.Assert(input.Length <= output.Length);
int written = ProcessFinalBlock(input, output);
}
[MemberNotNull(nameof(_cryptor))]
- private unsafe void OpenCryptor(
- Interop.AppleCrypto.PAL_SymmetricAlgorithm algorithm,
- CipherMode cipherMode,
- byte[] key)
+ private unsafe void OpenCryptor()
{
int ret;
int ccStatus;
byte[]? iv = IV;
- fixed (byte* pbKey = key)
+ fixed (byte* pbKey = _key)
fixed (byte* pbIv = iv)
{
ret = Interop.AppleCrypto.CryptorCreate(
_encrypting
? Interop.AppleCrypto.PAL_SymmetricOperation.Encrypt
: Interop.AppleCrypto.PAL_SymmetricOperation.Decrypt,
- algorithm,
- GetPalChainMode(cipherMode),
+ _algorithm,
+ GetPalChainMode(_algorithm, _cipherMode, _feedbackSizeInBytes),
Interop.AppleCrypto.PAL_PaddingMode.None,
pbKey,
- key.Length,
+ _key.Length,
pbIv,
Interop.AppleCrypto.PAL_SymmetricOptions.None,
out _cryptor,
ProcessInteropError(ret, ccStatus);
}
- private Interop.AppleCrypto.PAL_ChainingMode GetPalChainMode(CipherMode cipherMode)
+ private Interop.AppleCrypto.PAL_ChainingMode GetPalChainMode(Interop.AppleCrypto.PAL_SymmetricAlgorithm algorithm, CipherMode cipherMode, int feedbackSizeInBytes)
{
switch (cipherMode)
{
return Interop.AppleCrypto.PAL_ChainingMode.CBC;
case CipherMode.ECB:
return Interop.AppleCrypto.PAL_ChainingMode.ECB;
+ case CipherMode.CFB:
+ if (feedbackSizeInBytes == 1)
+ {
+ return Interop.AppleCrypto.PAL_ChainingMode.CFB8;
+ }
+
+ Debug.Assert(
+ (algorithm == Interop.AppleCrypto.PAL_SymmetricAlgorithm.AES && feedbackSizeInBytes == 16) ||
+ (algorithm == Interop.AppleCrypto.PAL_SymmetricAlgorithm.TripleDES && feedbackSizeInBytes == 8));
+
+ return Interop.AppleCrypto.PAL_ChainingMode.CFB;
default:
throw new PlatformNotSupportedException(SR.Format(SR.Cryptography_CipherModeNotSupported, cipherMode));
}
private unsafe void Reset()
{
- int ret;
- int ccStatus;
-
- byte[]? iv = IV;
-
- fixed (byte* pbIv = iv)
+ if (!_supportsReset)
{
- ret = Interop.AppleCrypto.CryptorReset(_cryptor, pbIv, out ccStatus);
+ // when CryptorReset is not supported,
+ // dispose & reopen
+ _cryptor?.Dispose();
+ OpenCryptor();
}
+ else
+ {
+ int ret;
+ int ccStatus;
- ProcessInteropError(ret, ccStatus);
+ byte[]? iv = IV;
+
+ fixed (byte* pbIv = iv)
+ {
+ ret = Interop.AppleCrypto.CryptorReset(_cryptor, pbIv, out ccStatus);
+ }
+
+ ProcessInteropError(ret, ccStatus);
+ }
}
private static void ProcessInteropError(int functionReturnCode, int ccStatus)
byte[] key,
byte[]? iv,
int blockSize,
+ int feedbackSizeInBytes,
+ int paddingSize,
bool encrypting)
{
BasicSymmetricCipher cipher = new AppleCCCryptor(
blockSize,
key,
iv,
- encrypting);
+ encrypting,
+ feedbackSizeInBytes,
+ paddingSize);
return UniversalCryptoTransform.Create(paddingMode, cipher, encrypting);
}
// The .NET Foundation licenses this file to you under the MIT license.
using System;
+using System.Diagnostics;
using System.Security.Cryptography;
namespace Internal.Cryptography
byte[] key,
byte[]? iv,
int blockSize,
+ int feedbackSize,
+ int paddingSize,
bool encrypting)
{
// The algorithm pointer is a static pointer, so not having any cleanup code is correct.
- IntPtr algorithm;
+ IntPtr algorithm = IntPtr.Zero;
+
switch (cipherMode)
{
case CipherMode.CBC:
case CipherMode.ECB:
algorithm = Interop.Crypto.EvpDesEcb();
break;
+ case CipherMode.CFB:
+
+ Debug.Assert(feedbackSize == 1, "TripleDES with CFB should have FeedbackSize set to 1");
+ algorithm = Interop.Crypto.EvpDesCfb8();
+
+ break;
default:
throw new NotSupportedException();
}
- BasicSymmetricCipher cipher = new OpenSslCipher(algorithm, cipherMode, blockSize, key, 0, iv, encrypting);
+ BasicSymmetricCipher cipher = new OpenSslCipher(algorithm, cipherMode, blockSize, paddingSize, key, 0, iv, encrypting);
return UniversalCryptoTransform.Create(paddingMode, cipher, encrypting);
}
}
byte[] key,
byte[]? iv,
int blockSize,
+ int feedbackSize,
+ int paddingSize,
bool encrypting)
{
- SafeAlgorithmHandle algorithm = DesBCryptModes.GetSharedHandle(cipherMode);
+ SafeAlgorithmHandle algorithm = DesBCryptModes.GetSharedHandle(cipherMode, feedbackSize);
- BasicSymmetricCipher cipher = new BasicSymmetricCipherBCrypt(algorithm, cipherMode, blockSize, key, false, iv, encrypting);
+ BasicSymmetricCipher cipher = new BasicSymmetricCipherBCrypt(algorithm, cipherMode, blockSize, paddingSize, key, false, iv, encrypting);
return UniversalCryptoTransform.Create(paddingMode, cipher, encrypting);
}
}
throw new ArgumentException(SR.Cryptography_InvalidIVSize, nameof(rgbIV));
}
- return CreateTransformCore(Mode, Padding, rgbKey, rgbIV, BlockSize / BitsPerByte, encrypting);
+ if (Mode == CipherMode.CFB)
+ {
+ ValidateCFBFeedbackSize(FeedbackSize);
+ }
+
+ return CreateTransformCore(Mode, Padding, rgbKey, rgbIV, BlockSize / BitsPerByte, FeedbackSize / BitsPerByte, this.GetPaddingSize(), encrypting);
+ }
+
+ private static void ValidateCFBFeedbackSize(int feedback)
+ {
+ // only 8bits feedback is available on all platforms
+ if (feedback != 8)
+ {
+ throw new CryptographicException(string.Format(SR.Cryptography_CipherModeFeedbackNotSupported, feedback, CipherMode.CFB));
+ }
}
}
}
private readonly bool _encrypting;
private SafeEvpCipherCtxHandle _ctx;
- public OpenSslCipher(IntPtr algorithm, CipherMode cipherMode, int blockSizeInBytes, byte[] key, int effectiveKeyLength, byte[]? iv, bool encrypting)
- : base(cipherMode.GetCipherIv(iv), blockSizeInBytes)
+ public OpenSslCipher(IntPtr algorithm, CipherMode cipherMode, int blockSizeInBytes, int paddingSizeInBytes, byte[] key, int effectiveKeyLength, byte[]? iv, bool encrypting)
+ : base(cipherMode.GetCipherIv(iv), blockSizeInBytes, paddingSizeInBytes)
{
Debug.Assert(algorithm != IntPtr.Zero);
public override unsafe int Transform(ReadOnlySpan<byte> input, Span<byte> output)
{
Debug.Assert(input.Length > 0);
- Debug.Assert((input.Length % BlockSizeInBytes) == 0);
+ Debug.Assert((input.Length % PaddingSizeInBytes) == 0);
// OpenSSL 1.1 does not allow partial overlap.
if (input.Overlaps(output, out int overlapOffset) && overlapOffset != 0)
public override int TransformFinal(ReadOnlySpan<byte> input, Span<byte> output)
{
- Debug.Assert((input.Length % BlockSizeInBytes) == 0);
+ Debug.Assert((input.Length % PaddingSizeInBytes) == 0);
Debug.Assert(input.Length <= output.Length);
int written = ProcessFinalBlock(input, output);
int effectiveKeyLength,
byte[]? iv,
int blockSize,
+ int feedbackSizeInBytes,
+ int paddingSize,
bool encrypting)
{
BasicSymmetricCipher cipher = new AppleCCCryptor(
blockSize,
key,
iv,
- encrypting);
+ encrypting,
+ feedbackSizeInBytes,
+ paddingSize);
return UniversalCryptoTransform.Create(paddingMode, cipher, encrypting);
}
int effectiveKeyLength,
byte[]? iv,
int blockSize,
+ int feedbackSize,
+ int paddingSize,
bool encrypting)
{
// The algorithm pointer is a static pointer, so not having any cleanup code is correct.
throw new NotSupportedException();
}
- BasicSymmetricCipher cipher = new OpenSslCipher(algorithm, cipherMode, blockSize, key, effectiveKeyLength, iv, encrypting);
+ BasicSymmetricCipher cipher = new OpenSslCipher(algorithm, cipherMode, blockSize, paddingSize, key, effectiveKeyLength, iv, encrypting);
return UniversalCryptoTransform.Create(paddingMode, cipher, encrypting);
}
}
int effectiveKeyLength,
byte[]? iv,
int blockSize,
+ int feedbackSize,
+ int paddingSize,
bool encrypting)
{
using (SafeAlgorithmHandle algorithm = RC2BCryptModes.GetHandle(cipherMode, effectiveKeyLength))
{
// The BasicSymmetricCipherBCrypt ctor will increase algorithm reference count and take ownership.
- BasicSymmetricCipher cipher = new BasicSymmetricCipherBCrypt(algorithm, cipherMode, blockSize, key, true, iv, encrypting);
+ BasicSymmetricCipher cipher = new BasicSymmetricCipherBCrypt(algorithm, cipherMode, blockSize, paddingSize, key, true, iv, encrypting);
return UniversalCryptoTransform.Create(paddingMode, cipher, encrypting);
}
}
throw new ArgumentException(SR.Cryptography_InvalidIVSize, nameof(rgbIV));
}
+ if (Mode == CipherMode.CFB)
+ {
+ ValidateCFBFeedbackSize(FeedbackSize);
+ }
+
int effectiveKeySize = EffectiveKeySizeValue == 0 ? (int)keySize : EffectiveKeySize;
- return CreateTransformCore(Mode, Padding, rgbKey, effectiveKeySize, rgbIV, BlockSize / BitsPerByte, encrypting);
+ return CreateTransformCore(Mode, Padding, rgbKey, effectiveKeySize, rgbIV, BlockSize / BitsPerByte, FeedbackSize / BitsPerByte, GetPaddingSize(), encrypting);
+ }
+
+ private static void ValidateCFBFeedbackSize(int feedback)
+ {
+ // CFB not supported at all
+ throw new CryptographicException(string.Format(SR.Cryptography_CipherModeFeedbackNotSupported, feedback, CipherMode.CFB));
+ }
+
+ private int GetPaddingSize()
+ {
+ return BlockSize / BitsPerByte;
}
}
}
byte[] key,
byte[]? iv,
int blockSize,
+ int paddingSize,
+ int feedbackSizeInBytes,
bool encrypting)
{
BasicSymmetricCipher cipher = new AppleCCCryptor(
blockSize,
key,
iv,
- encrypting);
+ encrypting,
+ feedbackSizeInBytes,
+ paddingSize);
return UniversalCryptoTransform.Create(paddingMode, cipher, encrypting);
}
byte[] key,
byte[]? iv,
int blockSize,
+ int paddingSize,
+ int feedbackSize,
bool encrypting)
{
// The algorithm pointer is a static pointer, so not having any cleanup code is correct.
IntPtr algorithm;
- switch (cipherMode)
+ switch ((cipherMode, feedbackSize))
{
- case CipherMode.CBC:
+ case (CipherMode.CBC, _):
algorithm = Interop.Crypto.EvpDes3Cbc();
break;
- case CipherMode.ECB:
+ case (CipherMode.ECB, _):
algorithm = Interop.Crypto.EvpDes3Ecb();
break;
+ case (CipherMode.CFB, 1):
+ algorithm = Interop.Crypto.EvpDes3Cfb8();
+ break;
+ case (CipherMode.CFB, 8):
+ algorithm = Interop.Crypto.EvpDes3Cfb64();
+ break;
default:
throw new NotSupportedException();
}
- BasicSymmetricCipher cipher = new OpenSslCipher(algorithm, cipherMode, blockSize, key, 0, iv, encrypting);
+ BasicSymmetricCipher cipher = new OpenSslCipher(algorithm, cipherMode, blockSize, paddingSize, key, 0, iv, encrypting);
return UniversalCryptoTransform.Create(paddingMode, cipher, encrypting);
}
}
byte[] key,
byte[]? iv,
int blockSize,
+ int paddingSize,
+ int feedbackSize,
bool encrypting)
{
- SafeAlgorithmHandle algorithm = TripleDesBCryptModes.GetSharedHandle(cipherMode);
+ SafeAlgorithmHandle algorithm = TripleDesBCryptModes.GetSharedHandle(cipherMode, feedbackSize);
- BasicSymmetricCipher cipher = new BasicSymmetricCipherBCrypt(algorithm, cipherMode, blockSize, key, false, iv, encrypting);
+ BasicSymmetricCipher cipher = new BasicSymmetricCipherBCrypt(algorithm, cipherMode, blockSize, paddingSize, key, false, iv, encrypting);
return UniversalCryptoTransform.Create(paddingMode, cipher, encrypting);
}
}
rgbKey = newkey;
}
- return CreateTransformCore(Mode, Padding, rgbKey, rgbIV, BlockSize / BitsPerByte, encrypting);
+ if (Mode == CipherMode.CFB)
+ {
+ ValidateCFBFeedbackSize(FeedbackSize);
+ }
+
+ return CreateTransformCore(Mode, Padding, rgbKey, rgbIV, BlockSize / BitsPerByte, this.GetPaddingSize(), FeedbackSize / BitsPerByte, encrypting);
+ }
+
+ private static void ValidateCFBFeedbackSize(int feedback)
+ {
+ // only 8bits/64bits feedback would be valid.
+ if (feedback != 8 && feedback != 64)
+ {
+ throw new CryptographicException(string.Format(SR.Cryptography_CipherModeFeedbackNotSupported, feedback, CipherMode.CFB));
+ }
}
}
}
<data name="Cryptography_TransformBeyondEndOfBuffer" xml:space="preserve">
<value>Attempt to transform beyond end of buffer.</value>
</data>
+ <data name="Cryptography_CipherModeFeedbackNotSupported" xml:space="preserve">
+ <value>The specified feedback size '{0}' for CipherMode '{1}' is not supported.</value>
+ </data>
<data name="Cryptography_CipherModeNotSupported" xml:space="preserve">
<value>The specified CipherMode '{0}' is not supported.</value>
</data>
{
public sealed partial class AesCcm
{
- private static readonly SafeAlgorithmHandle s_aesCcm = AesBCryptModes.OpenAesAlgorithm(Cng.BCRYPT_CHAIN_MODE_CCM);
+ private static readonly SafeAlgorithmHandle s_aesCcm = AesBCryptModes.OpenAesAlgorithm(Cng.BCRYPT_CHAIN_MODE_CCM).Value;
private SafeKeyHandle _keyHandle;
[MemberNotNull(nameof(_keyHandle))]
{
public partial class AesGcm
{
- private static readonly SafeAlgorithmHandle s_aesGcm = AesBCryptModes.OpenAesAlgorithm(Cng.BCRYPT_CHAIN_MODE_GCM);
+ private static readonly SafeAlgorithmHandle s_aesGcm = AesBCryptModes.OpenAesAlgorithm(Cng.BCRYPT_CHAIN_MODE_GCM).Value;
private SafeKeyHandle _keyHandle;
[MemberNotNull(nameof(_keyHandle))]
Link="CommonTest\System\Security\Cryptography\AlgorithmImplementations\RSA\TestData.cs" />
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\TripleDES\TripleDESCipherTests.cs"
Link="CommonTest\System\Security\Cryptography\AlgorithmImplementations\TripleDES\TripleDESCipherTests.cs" />
+ <Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\TripleDES\TripleDESContractTests.cs"
+ Link="CommonTest\System\Security\Cryptography\AlgorithmImplementations\TripleDES\TripleDESContractTests.cs" />
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\TripleDES\TripleDESFactory.cs"
Link="CommonTest\System\Security\Cryptography\AlgorithmImplementations\TripleDES\TripleDESFactory.cs" />
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\TripleDES\TripleDESReusabilityTests.cs"
Link="CommonTest\System\Security\Cryptography\AsymmetricSignatureFormatter.cs" />
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\DES\DESCipherTests.cs"
Link="CommonTest\System\Security\Cryptography\AlgorithmImplementations\DES\DESCipherTests.cs" />
+ <Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\DES\DESContractTests.cs"
+ Link="CommonTest\System\Security\Cryptography\AlgorithmImplementations\DES\DESContractTests.cs" />
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\DES\DESFactory.cs"
Link="CommonTest\System\Security\Cryptography\AlgorithmImplementations\DES\DESFactory.cs" />
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\DES\DesTests.cs"
Link="CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaXml.cs" />
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\RC2\RC2CipherTests.cs"
Link="CommonTest\System\Security\Cryptography\AlgorithmImplementations\RC2\RC2CipherTests.cs" />
+ <Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\RC2\RC2ContractTests.cs"
+ Link="CommonTest\System\Security\Cryptography\AlgorithmImplementations\RC2\RC2ContractTests.cs" />
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\RC2\RC2Factory.cs"
Link="CommonTest\System\Security\Cryptography\AlgorithmImplementations\RC2\RC2Factory.cs" />
<Compile Include="$(CommonTestPath)System\Security\Cryptography\AlgorithmImplementations\RC2\RC2Tests.cs"
//
// The delegate must instantiate a new CngKey, based on a new underlying NCryptKeyHandle, each time is called.
//
- public BasicSymmetricCipherNCrypt(Func<CngKey> cngKeyFactory, CipherMode cipherMode, int blockSizeInBytes, byte[] iv, bool encrypting)
- : base(iv, blockSizeInBytes)
+ public BasicSymmetricCipherNCrypt(Func<CngKey> cngKeyFactory, CipherMode cipherMode, int blockSizeInBytes, byte[] iv, bool encrypting, int feedbackSizeInBytes, int paddingSize)
+ : base(iv, blockSizeInBytes, paddingSize)
{
_encrypting = encrypting;
_cngKey = cngKeyFactory();
{
CipherMode.ECB => s_ECBMode,
CipherMode.CBC => s_CBCMode,
+ CipherMode.CFB => s_CFBMode,
_ => throw new CryptographicException(SR.Cryptography_InvalidCipherMode),
};
_cngKey.SetProperty(chainingModeProperty);
public sealed override int Transform(ReadOnlySpan<byte> input, Span<byte> output)
{
Debug.Assert(input.Length > 0);
- Debug.Assert((input.Length % BlockSizeInBytes) == 0);
+ Debug.Assert((input.Length % PaddingSizeInBytes) == 0);
int numBytesWritten;
ErrorCode errorCode;
public sealed override int TransformFinal(ReadOnlySpan<byte> input, Span<byte> output)
{
- Debug.Assert((input.Length % BlockSizeInBytes) == 0);
+ Debug.Assert((input.Length % PaddingSizeInBytes) == 0);
int numBytesWritten = 0;
new CngProperty(Interop.NCrypt.NCRYPT_CHAINING_MODE_PROPERTY, Encoding.Unicode.GetBytes(Interop.BCrypt.BCRYPT_CHAIN_MODE_ECB + "\0"), CngPropertyOptions.None);
private static readonly CngProperty s_CBCMode =
new CngProperty(Interop.NCrypt.NCRYPT_CHAINING_MODE_PROPERTY, Encoding.Unicode.GetBytes(Interop.BCrypt.BCRYPT_CHAIN_MODE_CBC + "\0"), CngPropertyOptions.None);
+ private static readonly CngProperty s_CFBMode =
+ new CngProperty(Interop.NCrypt.NCRYPT_CHAINING_MODE_PROPERTY, Encoding.Unicode.GetBytes(Interop.BCrypt.BCRYPT_CHAIN_MODE_CFB + "\0"), CngPropertyOptions.None);
}
}
algorithmModeHandle,
_outer.Mode,
blockSizeInBytes,
+ _outer.GetPaddingSize(),
key,
false,
iv,
// note: iv is guaranteed to be cloned before this method, so no need to clone it again
int blockSizeInBytes = _outer.BlockSize.BitSizeToByteSize();
- BasicSymmetricCipher cipher = new BasicSymmetricCipherNCrypt(cngKeyFactory, _outer.Mode, blockSizeInBytes, iv, encrypting);
+ int feedbackSizeInBytes = _outer.FeedbackSize;
+ BasicSymmetricCipher cipher = new BasicSymmetricCipherNCrypt(cngKeyFactory, _outer.Mode, blockSizeInBytes, iv, encrypting, feedbackSizeInBytes, _outer.GetPaddingSize());
return UniversalCryptoTransform.Create(_outer.Padding, cipher, encrypting);
}
{
// SymmetricAlgorithm members used by the core.
int BlockSize { get; }
+ int FeedbackSize { get; }
CipherMode Mode { get; }
PaddingMode Padding { get; }
byte[] IV { get; set; }
SafeAlgorithmHandle GetEphemeralModeHandle();
string GetNCryptAlgorithmIdentifier();
byte[] PreprocessKey(byte[] key);
+ int GetPaddingSize();
}
}
return false;
}
+ int ICngSymmetricAlgorithm.GetPaddingSize()
+ {
+ return this.GetPaddingSize();
+ }
+
SafeAlgorithmHandle ICngSymmetricAlgorithm.GetEphemeralModeHandle()
{
- return AesBCryptModes.GetSharedHandle(Mode);
+ try
+ {
+ return AesBCryptModes.GetSharedHandle(Mode, FeedbackSize / 8);
+ }
+ catch (NotSupportedException)
+ {
+ throw new CryptographicException(SR.Cryptography_InvalidCipherMode);
+ }
}
string ICngSymmetricAlgorithm.GetNCryptAlgorithmIdentifier()
return TripleDES.IsWeakKey(key);
}
+ int ICngSymmetricAlgorithm.GetPaddingSize()
+ {
+ return this.GetPaddingSize();
+ }
+
SafeAlgorithmHandle ICngSymmetricAlgorithm.GetEphemeralModeHandle()
{
- return TripleDesBCryptModes.GetSharedHandle(Mode);
+ return TripleDesBCryptModes.GetSharedHandle(Mode, FeedbackSize / 8);
}
string ICngSymmetricAlgorithm.GetNCryptAlgorithmIdentifier()
private SafeProvHandle _hProvider;
private SafeKeyHandle _hKey;
- public BasicSymmetricCipherCsp(int algId, CipherMode cipherMode, int blockSizeInBytes, byte[] key, int effectiveKeyLength, bool addNoSaltFlag, byte[]? iv, bool encrypting)
- : base(cipherMode.GetCipherIv(iv), blockSizeInBytes)
+ public BasicSymmetricCipherCsp(int algId, CipherMode cipherMode, int blockSizeInBytes, byte[] key, int effectiveKeyLength, bool addNoSaltFlag, byte[]? iv, bool encrypting, int feedbackSize, int paddingSizeInBytes)
+ : base(cipherMode.GetCipherIv(iv), blockSizeInBytes, paddingSizeInBytes)
{
_encrypting = encrypting;
_hKey = ImportCspBlob(_hProvider, algId, key, addNoSaltFlag);
SetKeyParameter(_hKey, CryptGetKeyParamQueryType.KP_MODE, (int)cipherMode);
+ if (cipherMode == CipherMode.CFB)
+ {
+ SetKeyParameter(_hKey, CryptGetKeyParamQueryType.KP_MODE_BITS, feedbackSize);
+ }
byte[]? currentIv = cipherMode.GetCipherIv(iv);
if (currentIv != null)
public override int TransformFinal(ReadOnlySpan<byte> input, Span<byte> output)
{
- Debug.Assert((input.Length % BlockSizeInBytes) == 0);
+ Debug.Assert((input.Length % PaddingSizeInBytes) == 0);
int numBytesWritten = 0;
private int Transform(ReadOnlySpan<byte> input, Span<byte> output, bool isFinal)
{
Debug.Assert(input.Length > 0);
- Debug.Assert((input.Length % BlockSizeInBytes) == 0);
+ Debug.Assert((input.Length % PaddingSizeInBytes) == 0);
int numBytesWritten;
if (_encrypting)
bool isFinal)
{
VerifyValidHandle(hKey);
- Debug.Assert((input.Length % 8) == 0);
// Figure out how big the encrypted data will be
int cbEncryptedData = input.Length;
Span<byte> output)
{
VerifyValidHandle(hKey);
- Debug.Assert((input.Length % 8) == 0);
byte[] dataToBeDecrypted = new byte[input.Length];
input.CopyTo(dataToBeDecrypted);
throw new CryptographicException(SR.Cryptography_InvalidIVSize);
}
- BasicSymmetricCipher cipher = new BasicSymmetricCipherCsp(CapiHelper.CALG_DES, Mode, BlockSize / BitsPerByte, rgbKey, 0, false, rgbIV, encrypting);
+ BasicSymmetricCipher cipher = new BasicSymmetricCipherCsp(CapiHelper.CALG_DES, Mode, BlockSize / BitsPerByte, rgbKey, 0, false, rgbIV, encrypting, FeedbackSize, this.GetPaddingSize());
return UniversalCryptoTransform.Create(Padding, cipher, encrypting);
}
}
}
int effectiveKeySize = EffectiveKeySizeValue == 0 ? (int)keySize : EffectiveKeySize;
- BasicSymmetricCipher cipher = new BasicSymmetricCipherCsp(CapiHelper.CALG_RC2, Mode, BlockSize / BitsPerByte, rgbKey, effectiveKeySize, !UseSalt, rgbIV, encrypting);
+ BasicSymmetricCipher cipher = new BasicSymmetricCipherCsp(CapiHelper.CALG_RC2, Mode, BlockSize / BitsPerByte, rgbKey, effectiveKeySize, !UseSalt, rgbIV, encrypting, 0, 0);
return UniversalCryptoTransform.Create(Padding, cipher, encrypting);
}
}
// This enum represents supported cipher chaining modes:
// cipher block chaining (CBC),
// electronic code book (ECB),
+ // cipher feedback (CFB),
// ciphertext-stealing (CTS).
// Not all implementations will support all modes.
public enum CipherMode
CBC = 1,
ECB = 2,
[EditorBrowsable(EditorBrowsableState.Never)] OFB = 3,
- [EditorBrowsable(EditorBrowsableState.Never)] CFB = 4,
+ CFB = 4,
CTS = 5
}
}
set
{
- if (!(value == CipherMode.CBC || value == CipherMode.ECB))
+ if (!(value == CipherMode.CBC || value == CipherMode.ECB || value == CipherMode.CFB))
throw new CryptographicException(SR.Cryptography_InvalidCipherMode);
ModeValue = value;