From eadc5ab9edb4f1d447706d305f36276d987389e1 Mon Sep 17 00:00:00 2001 From: Scott Xu Date: Sun, 1 Dec 2024 00:43:58 +0800 Subject: [PATCH] Use System.Security.Cryptography in DesCipher and TripleDesCipher Falls back to use BouncyCastle if BCL doesn't support --- src/Renci.SshNet/ConnectionInfo.cs | 15 +- src/Renci.SshNet/PrivateKeyFile.OpenSSH.cs | 15 +- src/Renci.SshNet/PrivateKeyFile.PKCS1.cs | 14 +- src/Renci.SshNet/PrivateKeyFile.SSHCOM.cs | 3 +- .../Cryptography/Ciphers/AesCipher.BclImpl.cs | 16 +- .../Ciphers/AesCipher.BlockImpl.cs | 16 +- .../Cryptography/Ciphers/AesCipher.CtrImpl.cs | 14 +- .../Cryptography/Ciphers/AesCipher.cs | 27 +- .../{AesCipherMode.cs => BlockCipherMode.cs} | 4 +- .../Cryptography/Ciphers/DesCipher.BclImpl.cs | 77 +++ .../Ciphers/DesCipher.BouncyCastleImpl.cs | 44 ++ .../Cryptography/Ciphers/DesCipher.cs | 474 ++---------------- .../Ciphers/Modes/CbcCipherMode.cs | 100 ---- .../Ciphers/TripleDesCipher.BclImpl.cs | 115 +++++ .../TripleDesCipher.BouncyCastleImpl.cs | 44 ++ .../Cryptography/Ciphers/TripleDesCipher.cs | 168 ++----- .../Ciphers/AesCipherBenchmarks.cs | 16 +- .../Ciphers/TripleDesCipherBenchmarks.cs | 51 ++ .../Ciphers/AesCipherTest.Gen.cs.txt | 10 +- .../Cryptography/Ciphers/AesCipherTest.cs | 220 ++++---- .../Ciphers/DesCipherTest.Gen.cs.txt | 151 ++++++ .../Cryptography/Ciphers/DesCipherTest.cs | 278 ++++++++-- .../Ciphers/TripleDesCipherTest.Gen.cs.txt | 151 ++++++ .../Ciphers/TripleDesCipherTest.cs | 277 +++++++++- 24 files changed, 1387 insertions(+), 913 deletions(-) rename src/Renci.SshNet/Security/Cryptography/Ciphers/{AesCipherMode.cs => BlockCipherMode.cs} (82%) create mode 100644 src/Renci.SshNet/Security/Cryptography/Ciphers/DesCipher.BclImpl.cs create mode 100644 src/Renci.SshNet/Security/Cryptography/Ciphers/DesCipher.BouncyCastleImpl.cs delete mode 100644 src/Renci.SshNet/Security/Cryptography/Ciphers/Modes/CbcCipherMode.cs create mode 100644 src/Renci.SshNet/Security/Cryptography/Ciphers/TripleDesCipher.BclImpl.cs create mode 100644 src/Renci.SshNet/Security/Cryptography/Ciphers/TripleDesCipher.BouncyCastleImpl.cs create mode 100644 test/Renci.SshNet.Benchmarks/Security/Cryptography/Ciphers/TripleDesCipherBenchmarks.cs create mode 100644 test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/DesCipherTest.Gen.cs.txt create mode 100644 test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/TripleDesCipherTest.Gen.cs.txt diff --git a/src/Renci.SshNet/ConnectionInfo.cs b/src/Renci.SshNet/ConnectionInfo.cs index 52f614554..67b4b6c73 100644 --- a/src/Renci.SshNet/ConnectionInfo.cs +++ b/src/Renci.SshNet/ConnectionInfo.cs @@ -12,7 +12,6 @@ using Renci.SshNet.Security; using Renci.SshNet.Security.Cryptography; using Renci.SshNet.Security.Cryptography.Ciphers; -using Renci.SshNet.Security.Cryptography.Ciphers.Modes; namespace Renci.SshNet { @@ -363,16 +362,16 @@ public ConnectionInfo(string host, int port, string username, ProxyTypes proxyTy Encryptions = new Dictionary { - { "aes128-ctr", new CipherInfo(128, (key, iv) => new AesCipher(key, iv, AesCipherMode.CTR, pkcs7Padding: false)) }, - { "aes192-ctr", new CipherInfo(192, (key, iv) => new AesCipher(key, iv, AesCipherMode.CTR, pkcs7Padding: false)) }, - { "aes256-ctr", new CipherInfo(256, (key, iv) => new AesCipher(key, iv, AesCipherMode.CTR, pkcs7Padding: false)) }, + { "aes128-ctr", new CipherInfo(128, (key, iv) => new AesCipher(key, iv, BlockCipherMode.CTR, pkcs7Padding: false)) }, + { "aes192-ctr", new CipherInfo(192, (key, iv) => new AesCipher(key, iv, BlockCipherMode.CTR, pkcs7Padding: false)) }, + { "aes256-ctr", new CipherInfo(256, (key, iv) => new AesCipher(key, iv, BlockCipherMode.CTR, pkcs7Padding: false)) }, { "aes128-gcm@openssh.com", new CipherInfo(128, (key, iv) => new AesGcmCipher(key, iv, aadLength: 4), isAead: true) }, { "aes256-gcm@openssh.com", new CipherInfo(256, (key, iv) => new AesGcmCipher(key, iv, aadLength: 4), isAead: true) }, { "chacha20-poly1305@openssh.com", new CipherInfo(512, (key, iv) => new ChaCha20Poly1305Cipher(key, aadLength: 4), isAead: true) }, - { "aes128-cbc", new CipherInfo(128, (key, iv) => new AesCipher(key, iv, AesCipherMode.CBC, pkcs7Padding: false)) }, - { "aes192-cbc", new CipherInfo(192, (key, iv) => new AesCipher(key, iv, AesCipherMode.CBC, pkcs7Padding: false)) }, - { "aes256-cbc", new CipherInfo(256, (key, iv) => new AesCipher(key, iv, AesCipherMode.CBC, pkcs7Padding: false)) }, - { "3des-cbc", new CipherInfo(192, (key, iv) => new TripleDesCipher(key, new CbcCipherMode(iv), padding: null)) }, + { "aes128-cbc", new CipherInfo(128, (key, iv) => new AesCipher(key, iv, BlockCipherMode.CBC, pkcs7Padding: false)) }, + { "aes192-cbc", new CipherInfo(192, (key, iv) => new AesCipher(key, iv, BlockCipherMode.CBC, pkcs7Padding: false)) }, + { "aes256-cbc", new CipherInfo(256, (key, iv) => new AesCipher(key, iv, BlockCipherMode.CBC, pkcs7Padding: false)) }, + { "3des-cbc", new CipherInfo(192, (key, iv) => new TripleDesCipher(key, iv, BlockCipherMode.CBC, pkcs7Padding: false)) }, }; HmacAlgorithms = new Dictionary diff --git a/src/Renci.SshNet/PrivateKeyFile.OpenSSH.cs b/src/Renci.SshNet/PrivateKeyFile.OpenSSH.cs index ead73bb50..3248acddf 100644 --- a/src/Renci.SshNet/PrivateKeyFile.OpenSSH.cs +++ b/src/Renci.SshNet/PrivateKeyFile.OpenSSH.cs @@ -8,7 +8,6 @@ using Renci.SshNet.Security; using Renci.SshNet.Security.Cryptography; using Renci.SshNet.Security.Cryptography.Ciphers; -using Renci.SshNet.Security.Cryptography.Ciphers.Modes; namespace Renci.SshNet { @@ -91,25 +90,25 @@ public Key Parse() { case "3des-cbc": ivLength = 8; - cipherInfo = new CipherInfo(192, (key, iv) => new TripleDesCipher(key, new CbcCipherMode(iv), padding: null)); + cipherInfo = new CipherInfo(192, (key, iv) => new TripleDesCipher(key, iv, BlockCipherMode.CBC, pkcs7Padding: false)); break; case "aes128-cbc": - cipherInfo = new CipherInfo(128, (key, iv) => new AesCipher(key, iv, AesCipherMode.CBC, pkcs7Padding: false)); + cipherInfo = new CipherInfo(128, (key, iv) => new AesCipher(key, iv, BlockCipherMode.CBC, pkcs7Padding: false)); break; case "aes192-cbc": - cipherInfo = new CipherInfo(192, (key, iv) => new AesCipher(key, iv, AesCipherMode.CBC, pkcs7Padding: false)); + cipherInfo = new CipherInfo(192, (key, iv) => new AesCipher(key, iv, BlockCipherMode.CBC, pkcs7Padding: false)); break; case "aes256-cbc": - cipherInfo = new CipherInfo(256, (key, iv) => new AesCipher(key, iv, AesCipherMode.CBC, pkcs7Padding: false)); + cipherInfo = new CipherInfo(256, (key, iv) => new AesCipher(key, iv, BlockCipherMode.CBC, pkcs7Padding: false)); break; case "aes128-ctr": - cipherInfo = new CipherInfo(128, (key, iv) => new AesCipher(key, iv, AesCipherMode.CTR, pkcs7Padding: false)); + cipherInfo = new CipherInfo(128, (key, iv) => new AesCipher(key, iv, BlockCipherMode.CTR, pkcs7Padding: false)); break; case "aes192-ctr": - cipherInfo = new CipherInfo(192, (key, iv) => new AesCipher(key, iv, AesCipherMode.CTR, pkcs7Padding: false)); + cipherInfo = new CipherInfo(192, (key, iv) => new AesCipher(key, iv, BlockCipherMode.CTR, pkcs7Padding: false)); break; case "aes256-ctr": - cipherInfo = new CipherInfo(256, (key, iv) => new AesCipher(key, iv, AesCipherMode.CTR, pkcs7Padding: false)); + cipherInfo = new CipherInfo(256, (key, iv) => new AesCipher(key, iv, BlockCipherMode.CTR, pkcs7Padding: false)); break; case "aes128-gcm@openssh.com": cipherInfo = new CipherInfo(128, (key, iv) => new AesGcmCipher(key, iv, aadLength: 0), isAead: true); diff --git a/src/Renci.SshNet/PrivateKeyFile.PKCS1.cs b/src/Renci.SshNet/PrivateKeyFile.PKCS1.cs index 801b46563..8af608c1d 100644 --- a/src/Renci.SshNet/PrivateKeyFile.PKCS1.cs +++ b/src/Renci.SshNet/PrivateKeyFile.PKCS1.cs @@ -9,8 +9,6 @@ using Renci.SshNet.Common; using Renci.SshNet.Security; using Renci.SshNet.Security.Cryptography.Ciphers; -using Renci.SshNet.Security.Cryptography.Ciphers.Modes; -using Renci.SshNet.Security.Cryptography.Ciphers.Paddings; namespace Renci.SshNet { @@ -53,22 +51,22 @@ public Key Parse() switch (_cipherName) { case "DES-EDE3-CBC": - cipher = new CipherInfo(192, (key, iv) => new TripleDesCipher(key, new CbcCipherMode(iv), new PKCS7Padding())); + cipher = new CipherInfo(192, (key, iv) => new TripleDesCipher(key, iv, BlockCipherMode.CBC, pkcs7Padding: true)); break; case "DES-EDE3-CFB": - cipher = new CipherInfo(192, (key, iv) => new TripleDesCipher(key, new CfbCipherMode(iv), padding: null)); + cipher = new CipherInfo(192, (key, iv) => new TripleDesCipher(key, iv, BlockCipherMode.CFB, pkcs7Padding: false)); break; case "DES-CBC": - cipher = new CipherInfo(64, (key, iv) => new DesCipher(key, new CbcCipherMode(iv), new PKCS7Padding())); + cipher = new CipherInfo(64, (key, iv) => new DesCipher(key, iv, BlockCipherMode.CBC, pkcs7Padding: true)); break; case "AES-128-CBC": - cipher = new CipherInfo(128, (key, iv) => new AesCipher(key, iv, AesCipherMode.CBC, pkcs7Padding: true)); + cipher = new CipherInfo(128, (key, iv) => new AesCipher(key, iv, BlockCipherMode.CBC, pkcs7Padding: true)); break; case "AES-192-CBC": - cipher = new CipherInfo(192, (key, iv) => new AesCipher(key, iv, AesCipherMode.CBC, pkcs7Padding: true)); + cipher = new CipherInfo(192, (key, iv) => new AesCipher(key, iv, BlockCipherMode.CBC, pkcs7Padding: true)); break; case "AES-256-CBC": - cipher = new CipherInfo(256, (key, iv) => new AesCipher(key, iv, AesCipherMode.CBC, pkcs7Padding: true)); + cipher = new CipherInfo(256, (key, iv) => new AesCipher(key, iv, BlockCipherMode.CBC, pkcs7Padding: true)); break; default: throw new SshException(string.Format(CultureInfo.InvariantCulture, "Private key cipher \"{0}\" is not supported.", _cipherName)); diff --git a/src/Renci.SshNet/PrivateKeyFile.SSHCOM.cs b/src/Renci.SshNet/PrivateKeyFile.SSHCOM.cs index 290494c4b..767b6ee2f 100644 --- a/src/Renci.SshNet/PrivateKeyFile.SSHCOM.cs +++ b/src/Renci.SshNet/PrivateKeyFile.SSHCOM.cs @@ -7,7 +7,6 @@ using Renci.SshNet.Common; using Renci.SshNet.Security; using Renci.SshNet.Security.Cryptography.Ciphers; -using Renci.SshNet.Security.Cryptography.Ciphers.Modes; namespace Renci.SshNet { @@ -51,7 +50,7 @@ public Key Parse() } var key = GetCipherKey(_passPhrase, 192 / 8); - var ssh2Сipher = new TripleDesCipher(key, new CbcCipherMode(new byte[8]), padding: null); + var ssh2Сipher = new TripleDesCipher(key, new byte[8], BlockCipherMode.CBC, pkcs7Padding: false); keyData = ssh2Сipher.Decrypt(reader.ReadBytes(blobSize)); } else diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.BclImpl.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.BclImpl.cs index 2e1850896..8d0fec0e2 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.BclImpl.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.BclImpl.cs @@ -123,21 +123,11 @@ public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputC throw new NotImplementedException($"Invalid usage of {nameof(DecryptBlock)}."); } - private void Dispose(bool disposing) - { - if (disposing) - { - _aes.Dispose(); - _encryptor.Dispose(); - _decryptor.Dispose(); - } - } - public void Dispose() { - // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method - Dispose(disposing: true); - GC.SuppressFinalize(this); + _aes.Dispose(); + _encryptor.Dispose(); + _decryptor.Dispose(); } } } diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.BlockImpl.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.BlockImpl.cs index ff261d767..ea2ec3be5 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.BlockImpl.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.BlockImpl.cs @@ -33,21 +33,11 @@ public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputC return _decryptor.TransformBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset); } - private void Dispose(bool disposing) - { - if (disposing) - { - _aes.Dispose(); - _encryptor.Dispose(); - _decryptor.Dispose(); - } - } - public void Dispose() { - // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method - Dispose(disposing: true); - GC.SuppressFinalize(this); + _aes.Dispose(); + _encryptor.Dispose(); + _decryptor.Dispose(); } } } diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.CtrImpl.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.CtrImpl.cs index fb60acdf2..0d4dde5cd 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.CtrImpl.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.CtrImpl.cs @@ -105,20 +105,10 @@ private static void ArrayXOR(byte[] buffer, byte[] data, int offset, int length) } } - private void Dispose(bool disposing) - { - if (disposing) - { - _aes.Dispose(); - _encryptor.Dispose(); - } - } - public void Dispose() { - // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method - Dispose(disposing: true); - GC.SuppressFinalize(this); + _aes.Dispose(); + _encryptor.Dispose(); } } } diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.cs index a7c16f72c..5a8a2eed6 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.cs @@ -17,27 +17,27 @@ public sealed partial class AesCipher : BlockCipher, IDisposable /// Initializes a new instance of the class. /// /// The key. - /// The mode. /// The IV. + /// The mode. /// Enable PKCS7 padding. /// is . /// Keysize is not valid for this algorithm. - public AesCipher(byte[] key, byte[] iv, AesCipherMode mode, bool pkcs7Padding = false) + public AesCipher(byte[] key, byte[] iv, BlockCipherMode mode, bool pkcs7Padding = false) : base(key, 16, mode: null, padding: null) { - if (mode == AesCipherMode.OFB) + if (mode == BlockCipherMode.OFB) { // OFB is not supported on modern .NET _impl = new BlockImpl(key, new OfbCipherMode(iv), pkcs7Padding ? new PKCS7Padding() : null); } #if !NET6_0_OR_GREATER - else if (mode == AesCipherMode.CFB) + else if (mode == BlockCipherMode.CFB) { // CFB not supported on NetStandard 2.1 _impl = new BlockImpl(key, new CfbCipherMode(iv), pkcs7Padding ? new PKCS7Padding() : null); } #endif - else if (mode == AesCipherMode.CTR) + else if (mode == BlockCipherMode.CTR) { // CTR not supported by the BCL, use an optimized implementation _impl = new CtrImpl(key, iv); @@ -76,24 +76,13 @@ public override byte[] Decrypt(byte[] input, int offset, int length) return _impl.Decrypt(input, offset, length); } - /// - /// Dispose the instance. - /// - /// Set to True to dispose of resouces. - public void Dispose(bool disposing) + /// + public void Dispose() { - if (disposing && _impl is IDisposable disposableImpl) + if (_impl is IDisposable disposableImpl) { disposableImpl.Dispose(); } } - - /// - public void Dispose() - { - // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method - Dispose(disposing: true); - GC.SuppressFinalize(this); - } } } diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipherMode.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/BlockCipherMode.cs similarity index 82% rename from src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipherMode.cs rename to src/Renci.SshNet/Security/Cryptography/Ciphers/BlockCipherMode.cs index 9f948b3cf..0ffa6db29 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipherMode.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/BlockCipherMode.cs @@ -1,9 +1,9 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers { /// - /// Custom AES Cipher Mode, follows System.Security.Cryptography.CipherMode. + /// Custom Cipher Mode, follows System.Security.Cryptography.CipherMode. /// - public enum AesCipherMode + public enum BlockCipherMode { /// Cipher Block Chain Mode. CBC = 1, diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/DesCipher.BclImpl.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/DesCipher.BclImpl.cs new file mode 100644 index 000000000..0b1a30176 --- /dev/null +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/DesCipher.BclImpl.cs @@ -0,0 +1,77 @@ +using System; +using System.Security.Cryptography; + +using Renci.SshNet.Common; + +namespace Renci.SshNet.Security.Cryptography.Ciphers +{ + public partial class DesCipher + { + private sealed class BclImpl : BlockCipher, IDisposable + { + private readonly DES _des; + private readonly ICryptoTransform _encryptor; + private readonly ICryptoTransform _decryptor; + + public BclImpl( + byte[] key, + byte[] iv, + System.Security.Cryptography.CipherMode mode, + PaddingMode padding) + : base(key, 8, mode: null, padding: null) + { + var des = DES.Create(); + des.Key = Key; + des.IV = iv.Take(8); + des.Mode = mode; + des.Padding = padding; + _des = des; + _encryptor = _des.CreateEncryptor(); + _decryptor = _des.CreateDecryptor(); + } + + public override byte[] Encrypt(byte[] input, int offset, int length) + { + if (_des.Padding != PaddingMode.None) + { + return _encryptor.TransformFinalBlock(input, offset, length); + } + + var output = new byte[length]; + _ = _encryptor.TransformBlock(input, offset, length, output, 0); + + return output; + } + + public override byte[] Decrypt(byte[] input, int offset, int length) + { + if (_des.Padding != PaddingMode.None) + { + return _decryptor.TransformFinalBlock(input, offset, length); + } + + var output = new byte[length]; + _ = _decryptor.TransformBlock(input, offset, length, output, 0); + + return output; + } + + public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) + { + throw new NotImplementedException($"Invalid usage of {nameof(EncryptBlock)}."); + } + + public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) + { + throw new NotImplementedException($"Invalid usage of {nameof(DecryptBlock)}."); + } + + public void Dispose() + { + _des.Dispose(); + _encryptor.Dispose(); + _decryptor.Dispose(); + } + } + } +} diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/DesCipher.BouncyCastleImpl.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/DesCipher.BouncyCastleImpl.cs new file mode 100644 index 000000000..01bb837f0 --- /dev/null +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/DesCipher.BouncyCastleImpl.cs @@ -0,0 +1,44 @@ +using Org.BouncyCastle.Crypto.Engines; +using Org.BouncyCastle.Crypto.Parameters; + +namespace Renci.SshNet.Security.Cryptography.Ciphers +{ + public partial class DesCipher + { + private sealed class BouncyCastleImpl : BlockCipher + { + private KeyParameter _parameter; + private DesEngine _encryptor; + private DesEngine _decryptor; + + public BouncyCastleImpl(byte[] key, CipherMode mode, CipherPadding padding) + : base(key, 8, mode, padding) + { + } + + public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) + { + if (_encryptor == null) + { + _parameter ??= new KeyParameter(Key); + _encryptor = new DesEngine(); + _encryptor.Init(forEncryption: true, _parameter); + } + + return _encryptor.ProcessBlock(inputBuffer, inputOffset, outputBuffer, outputOffset); + } + + public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) + { + if (_decryptor == null) + { + _parameter ??= new KeyParameter(Key); + _decryptor = new DesEngine(); + _decryptor.Init(forEncryption: false, _parameter); + } + + return _decryptor.ProcessBlock(inputBuffer, inputOffset, outputBuffer, outputOffset); + } + } + } +} diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/DesCipher.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/DesCipher.cs index 9d38df923..35e6c7272 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/DesCipher.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/DesCipher.cs @@ -1,479 +1,71 @@ using System; -using System.Buffers.Binary; +using System.Security.Cryptography; + +using Renci.SshNet.Security.Cryptography.Ciphers.Modes; +using Renci.SshNet.Security.Cryptography.Ciphers.Paddings; namespace Renci.SshNet.Security.Cryptography.Ciphers { /// /// Implements DES cipher algorithm. /// - public class DesCipher : BlockCipher + public sealed partial class DesCipher : BlockCipher, IDisposable { - private int[] _encryptionKey; - - private int[] _decryptionKey; - - private static readonly short[] Bytebit = { 128, 64, 32, 16, 8, 4, 2, 1 }; - - private static readonly int[] Bigbyte = - { - 0x800000, 0x400000, 0x200000, 0x100000, - 0x080000, 0x040000, 0x020000, 0x010000, - 0x008000, 0x004000, 0x002000, 0x001000, - 0x000800, 0x000400, 0x000200, 0x000100, - 0x000080, 0x000040, 0x000020, 0x000010, - 0x000008, 0x000004, 0x000002, 0x000001 - }; - - /* - * Use the key schedule specified in the Standard (ANSI X3.92-1981). - */ - - private static readonly byte[] Pc1 = - { - 56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17, - 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35, - 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21, - 13, 5, 60, 52, 44, 36, 28, 20, 12, 4, 27, 19, 11, 3 - }; - - private static readonly byte[] Totrot = - { - 1, 2, 4, 6, 8, 10, 12, 14, - 15, 17, 19, 21, 23, 25, 27, 28 - }; - - private static readonly byte[] Pc2 = - { - 13, 16, 10, 23, 0, 4, 2, 27, 14, 5, 20, 9, - 22, 18, 11, 3, 25, 7, 15, 6, 26, 19, 12, 1, - 40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47, - 43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31 - }; - - private static readonly uint[] Sp1 = - { - 0x01010400, 0x00000000, 0x00010000, 0x01010404, - 0x01010004, 0x00010404, 0x00000004, 0x00010000, - 0x00000400, 0x01010400, 0x01010404, 0x00000400, - 0x01000404, 0x01010004, 0x01000000, 0x00000004, - 0x00000404, 0x01000400, 0x01000400, 0x00010400, - 0x00010400, 0x01010000, 0x01010000, 0x01000404, - 0x00010004, 0x01000004, 0x01000004, 0x00010004, - 0x00000000, 0x00000404, 0x00010404, 0x01000000, - 0x00010000, 0x01010404, 0x00000004, 0x01010000, - 0x01010400, 0x01000000, 0x01000000, 0x00000400, - 0x01010004, 0x00010000, 0x00010400, 0x01000004, - 0x00000400, 0x00000004, 0x01000404, 0x00010404, - 0x01010404, 0x00010004, 0x01010000, 0x01000404, - 0x01000004, 0x00000404, 0x00010404, 0x01010400, - 0x00000404, 0x01000400, 0x01000400, 0x00000000, - 0x00010004, 0x00010400, 0x00000000, 0x01010004 - }; - - private static readonly uint[] Sp2 = - { - 0x80108020, 0x80008000, 0x00008000, 0x00108020, - 0x00100000, 0x00000020, 0x80100020, 0x80008020, - 0x80000020, 0x80108020, 0x80108000, 0x80000000, - 0x80008000, 0x00100000, 0x00000020, 0x80100020, - 0x00108000, 0x00100020, 0x80008020, 0x00000000, - 0x80000000, 0x00008000, 0x00108020, 0x80100000, - 0x00100020, 0x80000020, 0x00000000, 0x00108000, - 0x00008020, 0x80108000, 0x80100000, 0x00008020, - 0x00000000, 0x00108020, 0x80100020, 0x00100000, - 0x80008020, 0x80100000, 0x80108000, 0x00008000, - 0x80100000, 0x80008000, 0x00000020, 0x80108020, - 0x00108020, 0x00000020, 0x00008000, 0x80000000, - 0x00008020, 0x80108000, 0x00100000, 0x80000020, - 0x00100020, 0x80008020, 0x80000020, 0x00100020, - 0x00108000, 0x00000000, 0x80008000, 0x00008020, - 0x80000000, 0x80100020, 0x80108020, 0x00108000 - }; - - private static readonly uint[] Sp3 = - { - 0x00000208, 0x08020200, 0x00000000, 0x08020008, - 0x08000200, 0x00000000, 0x00020208, 0x08000200, - 0x00020008, 0x08000008, 0x08000008, 0x00020000, - 0x08020208, 0x00020008, 0x08020000, 0x00000208, - 0x08000000, 0x00000008, 0x08020200, 0x00000200, - 0x00020200, 0x08020000, 0x08020008, 0x00020208, - 0x08000208, 0x00020200, 0x00020000, 0x08000208, - 0x00000008, 0x08020208, 0x00000200, 0x08000000, - 0x08020200, 0x08000000, 0x00020008, 0x00000208, - 0x00020000, 0x08020200, 0x08000200, 0x00000000, - 0x00000200, 0x00020008, 0x08020208, 0x08000200, - 0x08000008, 0x00000200, 0x00000000, 0x08020008, - 0x08000208, 0x00020000, 0x08000000, 0x08020208, - 0x00000008, 0x00020208, 0x00020200, 0x08000008, - 0x08020000, 0x08000208, 0x00000208, 0x08020000, - 0x00020208, 0x00000008, 0x08020008, 0x00020200 - }; - - private static readonly uint[] Sp4 = - { - 0x00802001, 0x00002081, 0x00002081, 0x00000080, - 0x00802080, 0x00800081, 0x00800001, 0x00002001, - 0x00000000, 0x00802000, 0x00802000, 0x00802081, - 0x00000081, 0x00000000, 0x00800080, 0x00800001, - 0x00000001, 0x00002000, 0x00800000, 0x00802001, - 0x00000080, 0x00800000, 0x00002001, 0x00002080, - 0x00800081, 0x00000001, 0x00002080, 0x00800080, - 0x00002000, 0x00802080, 0x00802081, 0x00000081, - 0x00800080, 0x00800001, 0x00802000, 0x00802081, - 0x00000081, 0x00000000, 0x00000000, 0x00802000, - 0x00002080, 0x00800080, 0x00800081, 0x00000001, - 0x00802001, 0x00002081, 0x00002081, 0x00000080, - 0x00802081, 0x00000081, 0x00000001, 0x00002000, - 0x00800001, 0x00002001, 0x00802080, 0x00800081, - 0x00002001, 0x00002080, 0x00800000, 0x00802001, - 0x00000080, 0x00800000, 0x00002000, 0x00802080 - }; - - private static readonly uint[] Sp5 = - { - 0x00000100, 0x02080100, 0x02080000, 0x42000100, - 0x00080000, 0x00000100, 0x40000000, 0x02080000, - 0x40080100, 0x00080000, 0x02000100, 0x40080100, - 0x42000100, 0x42080000, 0x00080100, 0x40000000, - 0x02000000, 0x40080000, 0x40080000, 0x00000000, - 0x40000100, 0x42080100, 0x42080100, 0x02000100, - 0x42080000, 0x40000100, 0x00000000, 0x42000000, - 0x02080100, 0x02000000, 0x42000000, 0x00080100, - 0x00080000, 0x42000100, 0x00000100, 0x02000000, - 0x40000000, 0x02080000, 0x42000100, 0x40080100, - 0x02000100, 0x40000000, 0x42080000, 0x02080100, - 0x40080100, 0x00000100, 0x02000000, 0x42080000, - 0x42080100, 0x00080100, 0x42000000, 0x42080100, - 0x02080000, 0x00000000, 0x40080000, 0x42000000, - 0x00080100, 0x02000100, 0x40000100, 0x00080000, - 0x00000000, 0x40080000, 0x02080100, 0x40000100 - }; - - private static readonly uint[] Sp6 = - { - 0x20000010, 0x20400000, 0x00004000, 0x20404010, - 0x20400000, 0x00000010, 0x20404010, 0x00400000, - 0x20004000, 0x00404010, 0x00400000, 0x20000010, - 0x00400010, 0x20004000, 0x20000000, 0x00004010, - 0x00000000, 0x00400010, 0x20004010, 0x00004000, - 0x00404000, 0x20004010, 0x00000010, 0x20400010, - 0x20400010, 0x00000000, 0x00404010, 0x20404000, - 0x00004010, 0x00404000, 0x20404000, 0x20000000, - 0x20004000, 0x00000010, 0x20400010, 0x00404000, - 0x20404010, 0x00400000, 0x00004010, 0x20000010, - 0x00400000, 0x20004000, 0x20000000, 0x00004010, - 0x20000010, 0x20404010, 0x00404000, 0x20400000, - 0x00404010, 0x20404000, 0x00000000, 0x20400010, - 0x00000010, 0x00004000, 0x20400000, 0x00404010, - 0x00004000, 0x00400010, 0x20004010, 0x00000000, - 0x20404000, 0x20000000, 0x00400010, 0x20004010 - }; - - private static readonly uint[] Sp7 = - { - 0x00200000, 0x04200002, 0x04000802, 0x00000000, - 0x00000800, 0x04000802, 0x00200802, 0x04200800, - 0x04200802, 0x00200000, 0x00000000, 0x04000002, - 0x00000002, 0x04000000, 0x04200002, 0x00000802, - 0x04000800, 0x00200802, 0x00200002, 0x04000800, - 0x04000002, 0x04200000, 0x04200800, 0x00200002, - 0x04200000, 0x00000800, 0x00000802, 0x04200802, - 0x00200800, 0x00000002, 0x04000000, 0x00200800, - 0x04000000, 0x00200800, 0x00200000, 0x04000802, - 0x04000802, 0x04200002, 0x04200002, 0x00000002, - 0x00200002, 0x04000000, 0x04000800, 0x00200000, - 0x04200800, 0x00000802, 0x00200802, 0x04200800, - 0x00000802, 0x04000002, 0x04200802, 0x04200000, - 0x00200800, 0x00000000, 0x00000002, 0x04200802, - 0x00000000, 0x00200802, 0x04200000, 0x00000800, - 0x04000002, 0x04000800, 0x00000800, 0x00200002 - }; - - private static readonly uint[] Sp8 = - { - 0x10001040, 0x00001000, 0x00040000, 0x10041040, - 0x10000000, 0x10001040, 0x00000040, 0x10000000, - 0x00040040, 0x10040000, 0x10041040, 0x00041000, - 0x10041000, 0x00041040, 0x00001000, 0x00000040, - 0x10040000, 0x10000040, 0x10001000, 0x00001040, - 0x00041000, 0x00040040, 0x10040040, 0x10041000, - 0x00001040, 0x00000000, 0x00000000, 0x10040040, - 0x10000040, 0x10001000, 0x00041040, 0x00040000, - 0x00041040, 0x00040000, 0x10041000, 0x00001000, - 0x00000040, 0x10040040, 0x00001000, 0x00041040, - 0x10001000, 0x00000040, 0x10000040, 0x10040000, - 0x10040040, 0x10000000, 0x00040000, 0x10001040, - 0x00000000, 0x10041040, 0x00040040, 0x10000040, - 0x10040000, 0x10001000, 0x10001040, 0x00000000, - 0x10041040, 0x00041000, 0x00041000, 0x00001040, - 0x00001040, 0x00040040, 0x10000000, 0x10041000 - }; + private readonly BlockCipher _impl; /// /// Initializes a new instance of the class. /// /// The key. + /// The IV. /// The mode. - /// The padding. + /// Enable PKCS7 padding. /// is . - public DesCipher(byte[] key, CipherMode mode, CipherPadding padding) - : base(key, 8, mode, padding) - { - } - - /// - /// Encrypts the specified region of the input byte array and copies the encrypted data to the specified region of the output byte array. - /// - /// The input data to encrypt. - /// The offset into the input byte array from which to begin using data. - /// The number of bytes in the input byte array to use as data. - /// The output to which to write encrypted data. - /// The offset into the output byte array from which to begin writing data. - /// - /// The number of bytes encrypted. - /// - public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) + public DesCipher(byte[] key, byte[] iv, BlockCipherMode mode, bool pkcs7Padding) + : base(key, 8, mode: null, padding: null) { - if ((inputOffset + BlockSize) > inputBuffer.Length) + if (mode == BlockCipherMode.CFB) { - throw new ArgumentException("input buffer too short"); + // BCL's DES CFB implementation is different with OpenSSL + _impl = new BouncyCastleImpl(key, new CfbCipherMode(iv), pkcs7Padding ? new PKCS7Padding() : null); } - - if ((outputOffset + BlockSize) > outputBuffer.Length) + else { - throw new ArgumentException("output buffer too short"); + _impl = new BclImpl(key, iv, (System.Security.Cryptography.CipherMode)mode, pkcs7Padding ? PaddingMode.PKCS7 : PaddingMode.None); } - - _encryptionKey ??= GenerateWorkingKey(encrypting: true, Key); - - DesFunc(_encryptionKey, inputBuffer, inputOffset, outputBuffer, outputOffset); - - return BlockSize; } - /// - /// Decrypts the specified region of the input byte array and copies the decrypted data to the specified region of the output byte array. - /// - /// The input data to decrypt. - /// The offset into the input byte array from which to begin using data. - /// The number of bytes in the input byte array to use as data. - /// The output to which to write decrypted data. - /// The offset into the output byte array from which to begin writing data. - /// - /// The number of bytes decrypted. - /// - public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) + /// + public override byte[] Encrypt(byte[] input, int offset, int length) { - if ((inputOffset + BlockSize) > inputBuffer.Length) - { - throw new ArgumentException("input buffer too short"); - } - - if ((outputOffset + BlockSize) > outputBuffer.Length) - { - throw new ArgumentException("output buffer too short"); - } - - _decryptionKey ??= GenerateWorkingKey(encrypting: false, Key); - - DesFunc(_decryptionKey, inputBuffer, inputOffset, outputBuffer, outputOffset); - - return BlockSize; + return _impl.Encrypt(input, offset, length); } - /// - /// Generates the working key. - /// - /// if set to [encrypting]. - /// The key. - /// Generated working key. - protected int[] GenerateWorkingKey(bool encrypting, byte[] key) + /// + public override byte[] Decrypt(byte[] input, int offset, int length) { - ValidateKey(); - - var newKey = new int[32]; - var pc1m = new bool[56]; - var pcr = new bool[56]; - - for (var j = 0; j < 56; j++) - { - int l = Pc1[j]; - - pc1m[j] = (key[(uint)l >> 3] & Bytebit[l & 07]) != 0; - } - - for (var i = 0; i < 16; i++) - { - int l, m; - - if (encrypting) - { - m = i << 1; - } - else - { - m = (15 - i) << 1; - } - - var n = m + 1; - newKey[m] = newKey[n] = 0; - - for (var j = 0; j < 28; j++) - { - l = j + Totrot[i]; - if (l < 28) - { - pcr[j] = pc1m[l]; - } - else - { - pcr[j] = pc1m[l - 28]; - } - } - - for (var j = 28; j < 56; j++) - { - l = j + Totrot[i]; - if (l < 56) - { - pcr[j] = pc1m[l]; - } - else - { - pcr[j] = pc1m[l - 28]; - } - } - - for (var j = 0; j < 24; j++) - { - if (pcr[Pc2[j]]) - { - newKey[m] |= Bigbyte[j]; - } - - if (pcr[Pc2[j + 24]]) - { - newKey[n] |= Bigbyte[j]; - } - } - } - - /* - * store the processed key - */ - - for (var i = 0; i != 32; i += 2) - { - var i1 = newKey[i]; - var i2 = newKey[i + 1]; - - newKey[i] = (int)((uint)((i1 & 0x00fc0000) << 6) | - (uint)((i1 & 0x00000fc0) << 10) | - ((uint)(i2 & 0x00fc0000) >> 10) | - ((uint)(i2 & 0x00000fc0) >> 6)); - - newKey[i + 1] = (int)((uint)((i1 & 0x0003f000) << 12) | - (uint)((i1 & 0x0000003f) << 16) | - ((uint)(i2 & 0x0003f000) >> 4) | - (uint)(i2 & 0x0000003f)); - } - - return newKey; + return _impl.Decrypt(input, offset, length); } - /// - /// Validates the key. - /// - protected virtual void ValidateKey() + /// + public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) { - var keySize = Key.Length * 8; - - if (keySize != 64) - { - throw new ArgumentException(string.Format("KeySize '{0}' is not valid for this algorithm.", keySize)); - } + return _impl.EncryptBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset); } - /// - /// Performs DES function. - /// - /// The w key. - /// The input. - /// The in off. - /// The out bytes. - /// The out off. - protected static void DesFunc(int[] wKey, byte[] input, int inOff, byte[] outBytes, int outOff) + /// + public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) { - var left = BinaryPrimitives.ReadUInt32BigEndian(input.AsSpan(inOff)); - var right = BinaryPrimitives.ReadUInt32BigEndian(input.AsSpan(inOff + 4)); - - var work = ((left >> 4) ^ right) & 0x0f0f0f0f; - right ^= work; - left ^= work << 4; - work = ((left >> 16) ^ right) & 0x0000ffff; - right ^= work; - left ^= work << 16; - work = ((right >> 2) ^ left) & 0x33333333; - left ^= work; - right ^= work << 2; - work = ((right >> 8) ^ left) & 0x00ff00ff; - left ^= work; - right ^= work << 8; - right = (right << 1) | (right >> 31); - work = (left ^ right) & 0xaaaaaaaa; - left ^= work; - right ^= work; - left = (left << 1) | (left >> 31); + return _impl.DecryptBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset); + } - for (var round = 0; round < 8; round++) + /// + public void Dispose() + { + if (_impl is IDisposable disposableImpl) { - work = (right << 28) | (right >> 4); - work ^= (uint)wKey[(round * 4) + 0]; - var fval = Sp7[work & 0x3f]; - fval |= Sp5[(work >> 8) & 0x3f]; - fval |= Sp3[(work >> 16) & 0x3f]; - fval |= Sp1[(work >> 24) & 0x3f]; - work = right ^ (uint)wKey[(round * 4) + 1]; - fval |= Sp8[work & 0x3f]; - fval |= Sp6[(work >> 8) & 0x3f]; - fval |= Sp4[(work >> 16) & 0x3f]; - fval |= Sp2[(work >> 24) & 0x3f]; - left ^= fval; - work = (left << 28) | (left >> 4); - work ^= (uint)wKey[(round * 4) + 2]; - fval = Sp7[work & 0x3f]; - fval |= Sp5[(work >> 8) & 0x3f]; - fval |= Sp3[(work >> 16) & 0x3f]; - fval |= Sp1[(work >> 24) & 0x3f]; - work = left ^ (uint)wKey[(round * 4) + 3]; - fval |= Sp8[work & 0x3f]; - fval |= Sp6[(work >> 8) & 0x3f]; - fval |= Sp4[(work >> 16) & 0x3f]; - fval |= Sp2[(work >> 24) & 0x3f]; - right ^= fval; + disposableImpl.Dispose(); } - - right = (right << 31) | (right >> 1); - work = (left ^ right) & 0xaaaaaaaa; - left ^= work; - right ^= work; - left = (left << 31) | (left >> 1); - work = ((left >> 8) ^ right) & 0x00ff00ff; - right ^= work; - left ^= work << 8; - work = ((left >> 2) ^ right) & 0x33333333; - right ^= work; - left ^= work << 2; - work = ((right >> 16) ^ left) & 0x0000ffff; - left ^= work; - right ^= work << 16; - work = ((right >> 4) ^ left) & 0x0f0f0f0f; - left ^= work; - right ^= work << 4; - - BinaryPrimitives.WriteUInt32BigEndian(outBytes.AsSpan(outOff), right); - BinaryPrimitives.WriteUInt32BigEndian(outBytes.AsSpan(outOff + 4), left); } } } diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/Modes/CbcCipherMode.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/Modes/CbcCipherMode.cs deleted file mode 100644 index a2b9243d4..000000000 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/Modes/CbcCipherMode.cs +++ /dev/null @@ -1,100 +0,0 @@ -using System; -using System.Globalization; - -namespace Renci.SshNet.Security.Cryptography.Ciphers.Modes -{ - /// - /// Implements CBC cipher mode. - /// - public class CbcCipherMode : CipherMode - { - /// - /// Initializes a new instance of the class. - /// - /// The iv. - public CbcCipherMode(byte[] iv) - : base(iv) - { - } - - /// - /// Encrypts the specified region of the input byte array and copies the encrypted data to the specified region of the output byte array. - /// - /// The input data to encrypt. - /// The offset into the input byte array from which to begin using data. - /// The number of bytes in the input byte array to use as data. - /// The output to which to write encrypted data. - /// The offset into the output byte array from which to begin writing data. - /// - /// The number of bytes encrypted. - /// - public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) - { - if (inputBuffer.Length - inputOffset < _blockSize) - { - throw new ArgumentException("Invalid input buffer"); - } - - if (outputBuffer.Length - outputOffset < _blockSize) - { - throw new ArgumentException("Invalid output buffer"); - } - - if (inputCount != _blockSize) - { - throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "inputCount must be {0}.", _blockSize)); - } - - for (var i = 0; i < _blockSize; i++) - { - IV[i] ^= inputBuffer[inputOffset + i]; - } - - _ = Cipher.EncryptBlock(IV, 0, inputCount, outputBuffer, outputOffset); - - Buffer.BlockCopy(outputBuffer, outputOffset, IV, 0, IV.Length); - - return _blockSize; - } - - /// - /// Decrypts the specified region of the input byte array and copies the decrypted data to the specified region of the output byte array. - /// - /// The input data to decrypt. - /// The offset into the input byte array from which to begin using data. - /// The number of bytes in the input byte array to use as data. - /// The output to which to write decrypted data. - /// The offset into the output byte array from which to begin writing data. - /// - /// The number of bytes decrypted. - /// - public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) - { - if (inputBuffer.Length - inputOffset < _blockSize) - { - throw new ArgumentException("Invalid input buffer"); - } - - if (outputBuffer.Length - outputOffset < _blockSize) - { - throw new ArgumentException("Invalid output buffer"); - } - - if (inputCount != _blockSize) - { - throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "inputCount must be {0}.", _blockSize)); - } - - _ = Cipher.DecryptBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset); - - for (var i = 0; i < _blockSize; i++) - { - outputBuffer[outputOffset + i] ^= IV[i]; - } - - Buffer.BlockCopy(inputBuffer, inputOffset, IV, 0, IV.Length); - - return _blockSize; - } - } -} diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/TripleDesCipher.BclImpl.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/TripleDesCipher.BclImpl.cs new file mode 100644 index 000000000..d5d4ca0f2 --- /dev/null +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/TripleDesCipher.BclImpl.cs @@ -0,0 +1,115 @@ +using System; +using System.Security.Cryptography; + +using Renci.SshNet.Common; + +namespace Renci.SshNet.Security.Cryptography.Ciphers +{ + public partial class TripleDesCipher + { + private sealed class BclImpl : BlockCipher, IDisposable + { + private readonly TripleDES _des; + private readonly ICryptoTransform _encryptor; + private readonly ICryptoTransform _decryptor; + + public BclImpl( + byte[] key, + byte[] iv, + System.Security.Cryptography.CipherMode mode, + PaddingMode padding) + : base(key, 8, mode: null, padding: null) + { + var des = TripleDES.Create(); + des.FeedbackSize = 64; // We use CFB8 + des.Key = Key; + des.IV = iv.Take(8); + des.Mode = mode; + des.Padding = padding; + _des = des; + _encryptor = _des.CreateEncryptor(); + _decryptor = _des.CreateDecryptor(); + } + + public override byte[] Encrypt(byte[] input, int offset, int length) + { + if (_des.Padding != PaddingMode.None) + { + return _encryptor.TransformFinalBlock(input, offset, length); + } + + var paddingLength = 0; + if (length % BlockSize > 0) + { + if (_des.Mode is System.Security.Cryptography.CipherMode.CFB or System.Security.Cryptography.CipherMode.OFB) + { + paddingLength = BlockSize - (length % BlockSize); + input = input.Take(offset, length); + length += paddingLength; + Array.Resize(ref input, length); + offset = 0; + } + } + + var output = new byte[length]; + _ = _encryptor.TransformBlock(input, offset, length, output, 0); + + if (paddingLength > 0) + { + Array.Resize(ref output, output.Length - paddingLength); + } + + return output; + } + + public override byte[] Decrypt(byte[] input, int offset, int length) + { + if (_des.Padding != PaddingMode.None) + { + return _decryptor.TransformFinalBlock(input, offset, length); + } + + var paddingLength = 0; + if (length % BlockSize > 0) + { + if (_des.Mode is System.Security.Cryptography.CipherMode.CFB or System.Security.Cryptography.CipherMode.OFB) + { + paddingLength = BlockSize - (length % BlockSize); + var newInput = new byte[input.Length + paddingLength]; + Buffer.BlockCopy(input, offset, newInput, 0, length); + input = newInput; + length = input.Length; + offset = 0; + } + } + + var output = new byte[length]; + _ = _decryptor.TransformBlock(input, offset, length, output, 0); + + if (paddingLength > 0) + { + Array.Resize(ref output, output.Length - paddingLength); + } + + return output; + } + + public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) + { + throw new NotImplementedException($"Invalid usage of {nameof(EncryptBlock)}."); + } + + public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) + { + throw new NotImplementedException($"Invalid usage of {nameof(DecryptBlock)}."); + } + + public void Dispose() + { + _des.Dispose(); + _encryptor.Dispose(); + _decryptor.Dispose(); + } + } + } +} diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/TripleDesCipher.BouncyCastleImpl.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/TripleDesCipher.BouncyCastleImpl.cs new file mode 100644 index 000000000..467adcf4f --- /dev/null +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/TripleDesCipher.BouncyCastleImpl.cs @@ -0,0 +1,44 @@ +using Org.BouncyCastle.Crypto.Engines; +using Org.BouncyCastle.Crypto.Parameters; + +namespace Renci.SshNet.Security.Cryptography.Ciphers +{ + public partial class TripleDesCipher + { + private sealed class BouncyCastleImpl : BlockCipher + { + private KeyParameter _parameter; + private DesEdeEngine _encryptor; + private DesEdeEngine _decryptor; + + public BouncyCastleImpl(byte[] key, CipherMode mode, CipherPadding padding) + : base(key, 8, mode, padding) + { + } + + public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) + { + if (_encryptor == null) + { + _parameter ??= new KeyParameter(Key); + _encryptor = new DesEdeEngine(); + _encryptor.Init(forEncryption: true, _parameter); + } + + return _encryptor.ProcessBlock(inputBuffer, inputOffset, outputBuffer, outputOffset); + } + + public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) + { + if (_decryptor == null) + { + _parameter ??= new KeyParameter(Key); + _decryptor = new DesEdeEngine(); + _decryptor.Init(forEncryption: false, _parameter); + } + + return _decryptor.ProcessBlock(inputBuffer, inputOffset, outputBuffer, outputOffset); + } + } + } +} diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/TripleDesCipher.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/TripleDesCipher.cs index eb1c0839d..2db23dc32 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/TripleDesCipher.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/TripleDesCipher.cs @@ -1,154 +1,84 @@ using System; +using System.Security.Cryptography; + +#if !NET +using Renci.SshNet.Security.Cryptography.Ciphers.Modes; +using Renci.SshNet.Security.Cryptography.Ciphers.Paddings; +#endif namespace Renci.SshNet.Security.Cryptography.Ciphers { /// /// Implements 3DES cipher algorithm. /// - public sealed class TripleDesCipher : DesCipher + public sealed partial class TripleDesCipher : BlockCipher, IDisposable { - private int[] _encryptionKey1; - private int[] _encryptionKey2; - private int[] _encryptionKey3; - private int[] _decryptionKey1; - private int[] _decryptionKey2; - private int[] _decryptionKey3; +#if NET + private readonly BclImpl _impl; +#else + private readonly BlockCipher _impl; +#endif /// /// Initializes a new instance of the class. /// /// The key. + /// The IV. /// The mode. - /// The padding. + /// Enable PKCS7 padding. /// is . - public TripleDesCipher(byte[] key, CipherMode mode, CipherPadding padding) - : base(key, mode, padding) + public TripleDesCipher(byte[] key, byte[] iv, BlockCipherMode mode, bool pkcs7Padding) + : base(key, 8, mode: null, padding: null) { - } - - /// - /// Encrypts the specified region of the input byte array and copies the encrypted data to the specified region of the output byte array. - /// - /// The input data to encrypt. - /// The offset into the input byte array from which to begin using data. - /// The number of bytes in the input byte array to use as data. - /// The output to which to write encrypted data. - /// The offset into the output byte array from which to begin writing data. - /// - /// The number of bytes encrypted. - /// - public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) - { - if ((inputOffset + BlockSize) > inputBuffer.Length) +#if !NET6_0_OR_GREATER + if (mode == BlockCipherMode.CFB) { - throw new ArgumentException("input buffer too short"); + // CFB8 not supported on .NET Framework + // see https://github.com/microsoft/referencesource/blob/51cf7850defa8a17d815b4700b67116e3fa283c2/mscorlib/system/security/cryptography/tripledescryptoserviceprovider.cs#L76-L78 + _impl = new BouncyCastleImpl(key, new CfbCipherMode(iv), pkcs7Padding ? new PKCS7Padding() : null); } - - if ((outputOffset + BlockSize) > outputBuffer.Length) + else +#endif { - throw new ArgumentException("output buffer too short"); - } - - if (_encryptionKey1 is null || _encryptionKey2 is null || _encryptionKey3 is null) - { - var part1 = new byte[8]; - var part2 = new byte[8]; - - Buffer.BlockCopy(Key, 0, part1, 0, 8); - Buffer.BlockCopy(Key, 8, part2, 0, 8); - - _encryptionKey1 = GenerateWorkingKey(encrypting: true, part1); - _encryptionKey2 = GenerateWorkingKey(encrypting: false, part2); - - if (Key.Length == 24) - { - var part3 = new byte[8]; - Buffer.BlockCopy(Key, 16, part3, 0, 8); - - _encryptionKey3 = GenerateWorkingKey(encrypting: true, part3); - } - else - { - _encryptionKey3 = _encryptionKey1; - } + _impl = new BclImpl(key, iv, (System.Security.Cryptography.CipherMode)mode, pkcs7Padding ? PaddingMode.PKCS7 : PaddingMode.None); } + } - var temp = new byte[BlockSize]; + /// + public override byte[] Encrypt(byte[] input, int offset, int length) + { + return _impl.Encrypt(input, offset, length); + } - DesFunc(_encryptionKey1, inputBuffer, inputOffset, temp, 0); - DesFunc(_encryptionKey2, temp, 0, temp, 0); - DesFunc(_encryptionKey3, temp, 0, outputBuffer, outputOffset); + /// + public override byte[] Decrypt(byte[] input, int offset, int length) + { + return _impl.Decrypt(input, offset, length); + } - return BlockSize; + /// + public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) + { + return _impl.EncryptBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset); } - /// - /// Decrypts the specified region of the input byte array and copies the decrypted data to the specified region of the output byte array. - /// - /// The input data to decrypt. - /// The offset into the input byte array from which to begin using data. - /// The number of bytes in the input byte array to use as data. - /// The output to which to write decrypted data. - /// The offset into the output byte array from which to begin writing data. - /// - /// The number of bytes decrypted. - /// + /// public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) { - if ((inputOffset + BlockSize) > inputBuffer.Length) - { - throw new ArgumentException("input buffer too short"); - } - - if ((outputOffset + BlockSize) > outputBuffer.Length) - { - throw new ArgumentException("output buffer too short"); - } - - if (_decryptionKey1 is null || _decryptionKey2 is null || _decryptionKey3 is null) - { - var part1 = new byte[8]; - var part2 = new byte[8]; - - Buffer.BlockCopy(Key, 0, part1, 0, 8); - Buffer.BlockCopy(Key, 8, part2, 0, 8); - - _decryptionKey1 = GenerateWorkingKey(encrypting: false, part1); - _decryptionKey2 = GenerateWorkingKey(encrypting: true, part2); - - if (Key.Length == 24) - { - var part3 = new byte[8]; - Buffer.BlockCopy(Key, 16, part3, 0, 8); - - _decryptionKey3 = GenerateWorkingKey(encrypting: false, part3); - } - else - { - _decryptionKey3 = _decryptionKey1; - } - } - - var temp = new byte[BlockSize]; - - DesFunc(_decryptionKey3, inputBuffer, inputOffset, temp, 0); - DesFunc(_decryptionKey2, temp, 0, temp, 0); - DesFunc(_decryptionKey1, temp, 0, outputBuffer, outputOffset); - - return BlockSize; + return _impl.DecryptBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset); } - /// - /// Validates the key. - /// - protected override void ValidateKey() + /// + public void Dispose() { - var keySize = Key.Length * 8; - - if (keySize is not (128 or 128 + 64)) +#if NET + _impl.Dispose(); +#else + if (_impl is IDisposable disposableImpl) { - throw new ArgumentException(string.Format("KeySize '{0}' is not valid for this algorithm.", keySize)); + disposableImpl.Dispose(); } +#endif } } } diff --git a/test/Renci.SshNet.Benchmarks/Security/Cryptography/Ciphers/AesCipherBenchmarks.cs b/test/Renci.SshNet.Benchmarks/Security/Cryptography/Ciphers/AesCipherBenchmarks.cs index 9cecc0855..9a96b3496 100644 --- a/test/Renci.SshNet.Benchmarks/Security/Cryptography/Ciphers/AesCipherBenchmarks.cs +++ b/test/Renci.SshNet.Benchmarks/Security/Cryptography/Ciphers/AesCipherBenchmarks.cs @@ -26,49 +26,49 @@ public AesCipherBenchmarks() [Benchmark] public byte[] Encrypt_CBC() { - return new AesCipher(_key, _iv, AesCipherMode.CBC, false).Encrypt(_data); + return new AesCipher(_key, _iv, BlockCipherMode.CBC, false).Encrypt(_data); } [Benchmark] public byte[] Decrypt_CBC() { - return new AesCipher(_key, _iv, AesCipherMode.CBC, false).Decrypt(_data); + return new AesCipher(_key, _iv, BlockCipherMode.CBC, false).Decrypt(_data); } [Benchmark] public byte[] Encrypt_CFB() { - return new AesCipher(_key, _iv, AesCipherMode.CFB, false).Encrypt(_data); + return new AesCipher(_key, _iv, BlockCipherMode.CFB, false).Encrypt(_data); } [Benchmark] public byte[] Decrypt_CFB() { - return new AesCipher(_key, _iv, AesCipherMode.CFB, false).Decrypt(_data); + return new AesCipher(_key, _iv, BlockCipherMode.CFB, false).Decrypt(_data); } [Benchmark] public byte[] Encrypt_CTR() { - return new AesCipher(_key, _iv, AesCipherMode.CTR, false).Encrypt(_data); + return new AesCipher(_key, _iv, BlockCipherMode.CTR, false).Encrypt(_data); } [Benchmark] public byte[] Decrypt_CTR() { - return new AesCipher(_key, _iv, AesCipherMode.CTR, false).Decrypt(_data); + return new AesCipher(_key, _iv, BlockCipherMode.CTR, false).Decrypt(_data); } [Benchmark] public byte[] Encrypt_ECB() { - return new AesCipher(_key, null, AesCipherMode.ECB, false).Encrypt(_data); + return new AesCipher(_key, null, BlockCipherMode.ECB, false).Encrypt(_data); } [Benchmark] public byte[] Decrypt_ECB() { - return new AesCipher(_key, null, AesCipherMode.ECB, false).Decrypt(_data); + return new AesCipher(_key, null, BlockCipherMode.ECB, false).Decrypt(_data); } } } diff --git a/test/Renci.SshNet.Benchmarks/Security/Cryptography/Ciphers/TripleDesCipherBenchmarks.cs b/test/Renci.SshNet.Benchmarks/Security/Cryptography/Ciphers/TripleDesCipherBenchmarks.cs new file mode 100644 index 000000000..da0c207b8 --- /dev/null +++ b/test/Renci.SshNet.Benchmarks/Security/Cryptography/Ciphers/TripleDesCipherBenchmarks.cs @@ -0,0 +1,51 @@ +using BenchmarkDotNet.Attributes; + +using Renci.SshNet.Security.Cryptography.Ciphers; +using Renci.SshNet.Security.Cryptography.Ciphers.Modes; + +namespace Renci.SshNet.Benchmarks.Security.Cryptography.Ciphers +{ + [MemoryDiagnoser] + public class TripleDesCipherBenchmarks + { + private readonly byte[] _key; + private readonly byte[] _iv; + private readonly byte[] _data; + + public TripleDesCipherBenchmarks() + { + _key = new byte[24]; + _iv = new byte[8]; + _data = new byte[32 * 1024]; + + Random random = new(Seed: 12345); + random.NextBytes(_key); + random.NextBytes(_iv); + random.NextBytes(_data); + } + + [Benchmark] + public byte[] Encrypt_CBC() + { + return new TripleDesCipher(_key, _iv, BlockCipherMode.CBC, false).Encrypt(_data); + } + + [Benchmark] + public byte[] Decrypt_CBC() + { + return new TripleDesCipher(_key, _iv, BlockCipherMode.CBC, false).Decrypt(_data); + } + + [Benchmark] + public byte[] Encrypt_CFB() + { + return new TripleDesCipher(_key, _iv, BlockCipherMode.CFB, false).Encrypt(_data); + } + + [Benchmark] + public byte[] Decrypt_CFB() + { + return new TripleDesCipher(_key, _iv, BlockCipherMode.CFB, false).Decrypt(_data); + } + } +} diff --git a/test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/AesCipherTest.Gen.cs.txt b/test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/AesCipherTest.Gen.cs.txt index f1d4d6bb7..04f969e46 100644 --- a/test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/AesCipherTest.Gen.cs.txt +++ b/test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/AesCipherTest.Gen.cs.txt @@ -6,11 +6,11 @@ Dictionary modes = new() { - ["ecb"] = ("iv: null, AesCipherMode.ECB", CipherMode.ECB), - ["cbc"] = ("(byte[])iv.Clone(), AesCipherMode.CBC", CipherMode.CBC), - ["cfb"] = ("(byte[])iv.Clone(), AesCipherMode.CFB", CipherMode.CFB), - ["ctr"] = ("(byte[])iv.Clone(), AesCipherMode.CTR", null), - ["ofb"] = ("(byte[])iv.Clone(), AesCipherMode.OFB", CipherMode.OFB), + ["ecb"] = ("iv: null, BlockCipherMode.ECB", CipherMode.ECB), + ["cbc"] = ("(byte[])iv.Clone(), BlockCipherMode.CBC", CipherMode.CBC), + ["cfb"] = ("(byte[])iv.Clone(), BlockCipherMode.CFB", CipherMode.CFB), + ["ctr"] = ("(byte[])iv.Clone(), BlockCipherMode.CTR", null), + ["ofb"] = ("(byte[])iv.Clone(), BlockCipherMode.OFB", CipherMode.OFB), }; Random random = new(123); diff --git a/test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/AesCipherTest.cs b/test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/AesCipherTest.cs index bb9e346ca..9d1d24187 100644 --- a/test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/AesCipherTest.cs +++ b/test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/AesCipherTest.cs @@ -42,7 +42,7 @@ public void AES_CTR_Encrypt_Should_Preserve_Cipher_Stream_State() 0xec, 0x47, 0x81, 0x82, 0x89, 0x24, 0x76, 0xe2, 0x20, 0x6a, 0x99, 0xe2, 0xa7, 0x5a, 0xb0, 0x40, }; - var cipher = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CTR, pkcs7Padding: false); + var cipher = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CTR, pkcs7Padding: false); var actual1 = cipher.Encrypt(input.Take(32)); var actual2 = cipher.Encrypt(input.Take(32, 32)); @@ -78,7 +78,7 @@ public void AES_CTR_Decrypt_Should_Preserve_Cipher_Stream_State() 0xbc, 0x89, 0x7a, 0x22, 0x42, 0x2c, 0xba, 0x8e, 0xd7, 0x15, 0x22, 0x41, 0xe4, 0xb5, 0x0b, 0xad, }; - var cipher = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CTR, pkcs7Padding: false); + var cipher = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CTR, pkcs7Padding: false); var actual1 = cipher.Decrypt(input.Take(32)); var actual2 = cipher.Decrypt(input.Take(32, 32)); @@ -115,11 +115,11 @@ public void AES_CTR_IV_Overflow() 0xfd, 0x34, 0xc5, 0x81, 0xfa, 0xb9, 0xe3, 0xc4, 0x10, 0xed, 0x06, 0x6e, 0x91, 0x5e, 0xfc, 0x47, }; - var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CTR, pkcs7Padding: false).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CTR, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CTR, pkcs7Padding: false).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CTR, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -133,7 +133,7 @@ public void Encrypt_InputAndOffsetAndLength_128_CBC() var key = new byte[] { 0xe4, 0x94, 0xf9, 0xb1, 0x00, 0x4f, 0x16, 0x2a, 0x80, 0x11, 0xea, 0x73, 0x0d, 0xb9, 0xbf, 0x64 }; var iv = new byte[] { 0x74, 0x8b, 0x4f, 0xe6, 0xc1, 0x29, 0xb3, 0x54, 0xec, 0x77, 0x92, 0xf3, 0x15, 0xa0, 0x41, 0xa8 }; var expected = new byte[] { 0x19, 0x7f, 0x80, 0xd8, 0xc9, 0x89, 0xc4, 0xa7, 0xc6, 0xc6, 0x3f, 0x9f, 0x1e, 0x00, 0x1f, 0x72, 0xa7, 0x5e, 0xde, 0x40, 0x88, 0xa2, 0x72, 0xf2, 0xed, 0x3f, 0x81, 0x45, 0xb6, 0xbd, 0x45, 0x87, 0x15, 0xa5, 0x10, 0x92, 0x4a, 0x37, 0x9e, 0xa9, 0x80, 0x1c, 0x14, 0x83, 0xa3, 0x39, 0x45, 0x28 }; - var testCipher = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CBC, pkcs7Padding: false); + var testCipher = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CBC, pkcs7Padding: false); var actual = testCipher.Encrypt(input, 2, input.Length - 5); @@ -147,7 +147,7 @@ public void Encrypt_Input_128_CTR() var key = new byte[] { 0x17, 0x78, 0x56, 0xe1, 0x3e, 0xbd, 0x3e, 0x50, 0x1d, 0x79, 0x3f, 0x0f, 0x55, 0x37, 0x45, 0x54 }; var iv = new byte[] { 0xe6, 0x65, 0x36, 0x0d, 0xdd, 0xd7, 0x50, 0xc3, 0x48, 0xdb, 0x48, 0x07, 0xa1, 0x30, 0xd2, 0x38 }; var expected = new byte[] { 0xca, 0xfb, 0x1c, 0x49, 0xbf, 0x82, 0x2a, 0xbb, 0x1c, 0x52, 0xc7, 0x86, 0x22, 0x8a, 0xe5, 0xa4, 0xf3, 0xda, 0x4e, 0x1c, 0x3a, 0x87, 0x41, 0x1c, 0xd2, 0x6e, 0x76, 0xdc, 0xc2, 0xe9, 0xc2, 0x0e, 0xf5, 0xc7, 0xbd, 0x12, 0x85, 0xfa, 0x0e, 0xda, 0xee, 0x50, 0xd7, 0xfd, 0x81, 0x34, 0x25, 0x6d }; - var testCipher = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CTR, pkcs7Padding: false); + var testCipher = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CTR, pkcs7Padding: false); var actual = testCipher.Encrypt(input); @@ -161,7 +161,7 @@ public void Decrypt_Input_128_CTR() var iv = new byte[] { 0xe6, 0x65, 0x36, 0x0d, 0xdd, 0xd7, 0x50, 0xc3, 0x48, 0xdb, 0x48, 0x07, 0xa1, 0x30, 0xd2, 0x38 }; var input = new byte[] { 0xca, 0xfb, 0x1c, 0x49, 0xbf, 0x82, 0x2a, 0xbb, 0x1c, 0x52, 0xc7, 0x86, 0x22, 0x8a, 0xe5, 0xa4, 0xf3, 0xda, 0x4e, 0x1c, 0x3a, 0x87, 0x41, 0x1c, 0xd2, 0x6e, 0x76, 0xdc, 0xc2, 0xe9, 0xc2, 0x0e, 0xf5, 0xc7, 0xbd, 0x12, 0x85, 0xfa, 0x0e, 0xda, 0xee, 0x50, 0xd7, 0xfd, 0x81, 0x34, 0x25, 0x6d }; var expected = new byte[] { 0x00, 0x00, 0x00, 0x2c, 0x1a, 0x05, 0x00, 0x00, 0x00, 0x0c, 0x73, 0x73, 0x68, 0x2d, 0x75, 0x73, 0x65, 0x72, 0x61, 0x75, 0x74, 0x68, 0xb0, 0x74, 0x21, 0x87, 0x16, 0xb9, 0x69, 0x48, 0x33, 0xce, 0xb3, 0xe7, 0xdc, 0x3f, 0x50, 0xdc, 0xcc, 0xd5, 0x27, 0xb7, 0xfe, 0x7a, 0x78, 0x22, 0xae, 0xc8 }; - var testCipher = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CTR, pkcs7Padding: false); + var testCipher = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CTR, pkcs7Padding: false); var actual = testCipher.Decrypt(input); @@ -175,7 +175,7 @@ public void Decrypt_InputAndOffsetAndLength_128_CTR() var iv = new byte[] { 0xe6, 0x65, 0x36, 0x0d, 0xdd, 0xd7, 0x50, 0xc3, 0x48, 0xdb, 0x48, 0x07, 0xa1, 0x30, 0xd2, 0x38 }; var input = new byte[] { 0x0a, 0xca, 0xfb, 0x1c, 0x49, 0xbf, 0x82, 0x2a, 0xbb, 0x1c, 0x52, 0xc7, 0x86, 0x22, 0x8a, 0xe5, 0xa4, 0xf3, 0xda, 0x4e, 0x1c, 0x3a, 0x87, 0x41, 0x1c, 0xd2, 0x6e, 0x76, 0xdc, 0xc2, 0xe9, 0xc2, 0x0e, 0xf5, 0xc7, 0xbd, 0x12, 0x85, 0xfa, 0x0e, 0xda, 0xee, 0x50, 0xd7, 0xfd, 0x81, 0x34, 0x25, 0x6d, 0x0a, 0x05 }; var expected = new byte[] { 0x00, 0x00, 0x00, 0x2c, 0x1a, 0x05, 0x00, 0x00, 0x00, 0x0c, 0x73, 0x73, 0x68, 0x2d, 0x75, 0x73, 0x65, 0x72, 0x61, 0x75, 0x74, 0x68, 0xb0, 0x74, 0x21, 0x87, 0x16, 0xb9, 0x69, 0x48, 0x33, 0xce, 0xb3, 0xe7, 0xdc, 0x3f, 0x50, 0xdc, 0xcc, 0xd5, 0x27, 0xb7, 0xfe, 0x7a, 0x78, 0x22, 0xae, 0xc8 }; - var testCipher = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CTR, pkcs7Padding: false); + var testCipher = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CTR, pkcs7Padding: false); var actual = testCipher.Decrypt(input, 1, input.Length - 3); @@ -201,11 +201,11 @@ public void AES_ECB_128_Length16_NoPad() 0x9d, 0x55, 0x05, 0x4e, 0xe9, 0x50, 0xb5, 0x93, 0x50, 0x93, 0x69, 0x96, 0xa6, 0xdd, 0x1e, 0x15, }; - var actual = new AesCipher(key, iv: null, AesCipherMode.ECB, pkcs7Padding: false).Encrypt(input); + var actual = new AesCipher(key, iv: null, BlockCipherMode.ECB, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, iv: null, AesCipherMode.ECB, pkcs7Padding: false).Decrypt(actual); + var decrypted = new AesCipher(key, iv: null, BlockCipherMode.ECB, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -229,11 +229,11 @@ public void AES_ECB_128_Length16_Pad() 0x5b, 0x27, 0x39, 0x52, 0x46, 0x1d, 0x16, 0x28, 0xc7, 0xec, 0x1f, 0x65, 0x7f, 0x67, 0x76, 0x70, }; - var actual = new AesCipher(key, iv: null, AesCipherMode.ECB, pkcs7Padding: true).Encrypt(input); + var actual = new AesCipher(key, iv: null, BlockCipherMode.ECB, pkcs7Padding: true).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, iv: null, AesCipherMode.ECB, pkcs7Padding: true).Decrypt(actual); + var decrypted = new AesCipher(key, iv: null, BlockCipherMode.ECB, pkcs7Padding: true).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -260,11 +260,11 @@ public void AES_ECB_128_Length35_Pad() 0xb1, 0xe2, 0x80, 0xcc, 0x21, 0x98, 0xa1, 0x26, 0x28, 0xac, 0x0b, 0x61, 0x19, 0x9d, 0xda, 0xaa, }; - var actual = new AesCipher(key, iv: null, AesCipherMode.ECB, pkcs7Padding: true).Encrypt(input); + var actual = new AesCipher(key, iv: null, BlockCipherMode.ECB, pkcs7Padding: true).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, iv: null, AesCipherMode.ECB, pkcs7Padding: true).Decrypt(actual); + var decrypted = new AesCipher(key, iv: null, BlockCipherMode.ECB, pkcs7Padding: true).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -293,11 +293,11 @@ public void AES_ECB_128_Length64_NoPad() 0x5a, 0xf4, 0xf8, 0x16, 0xc6, 0xf2, 0xdd, 0x6d, 0x51, 0x4d, 0x42, 0xa9, 0x59, 0xdc, 0xb2, 0x01, }; - var actual = new AesCipher(key, iv: null, AesCipherMode.ECB, pkcs7Padding: false).Encrypt(input); + var actual = new AesCipher(key, iv: null, BlockCipherMode.ECB, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, iv: null, AesCipherMode.ECB, pkcs7Padding: false).Decrypt(actual); + var decrypted = new AesCipher(key, iv: null, BlockCipherMode.ECB, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -327,11 +327,11 @@ public void AES_ECB_128_Length64_Pad() 0x3d, 0xc3, 0x0b, 0x2e, 0x7b, 0xd4, 0x20, 0x23, 0xb4, 0xb9, 0x2e, 0x07, 0x73, 0x37, 0x92, 0x80, }; - var actual = new AesCipher(key, iv: null, AesCipherMode.ECB, pkcs7Padding: true).Encrypt(input); + var actual = new AesCipher(key, iv: null, BlockCipherMode.ECB, pkcs7Padding: true).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, iv: null, AesCipherMode.ECB, pkcs7Padding: true).Decrypt(actual); + var decrypted = new AesCipher(key, iv: null, BlockCipherMode.ECB, pkcs7Padding: true).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -355,11 +355,11 @@ public void AES_ECB_192_Length16_NoPad() 0x6b, 0x19, 0xbc, 0x1a, 0xe8, 0xf5, 0x3c, 0x9a, 0xbb, 0xaf, 0xb2, 0x28, 0xe1, 0x99, 0xd4, 0x81, }; - var actual = new AesCipher(key, iv: null, AesCipherMode.ECB, pkcs7Padding: false).Encrypt(input); + var actual = new AesCipher(key, iv: null, BlockCipherMode.ECB, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, iv: null, AesCipherMode.ECB, pkcs7Padding: false).Decrypt(actual); + var decrypted = new AesCipher(key, iv: null, BlockCipherMode.ECB, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -384,11 +384,11 @@ public void AES_ECB_192_Length16_Pad() 0x95, 0x9a, 0x5d, 0x23, 0x23, 0x58, 0x25, 0x2d, 0x5f, 0x33, 0xc1, 0x9e, 0x6b, 0x68, 0xa2, 0x1e, }; - var actual = new AesCipher(key, iv: null, AesCipherMode.ECB, pkcs7Padding: true).Encrypt(input); + var actual = new AesCipher(key, iv: null, BlockCipherMode.ECB, pkcs7Padding: true).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, iv: null, AesCipherMode.ECB, pkcs7Padding: true).Decrypt(actual); + var decrypted = new AesCipher(key, iv: null, BlockCipherMode.ECB, pkcs7Padding: true).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -416,11 +416,11 @@ public void AES_ECB_192_Length35_Pad() 0x40, 0xae, 0x13, 0xd6, 0xc1, 0xfc, 0x2b, 0xc0, 0xa0, 0x90, 0x9a, 0xfb, 0x96, 0xc7, 0xa0, 0x16, }; - var actual = new AesCipher(key, iv: null, AesCipherMode.ECB, pkcs7Padding: true).Encrypt(input); + var actual = new AesCipher(key, iv: null, BlockCipherMode.ECB, pkcs7Padding: true).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, iv: null, AesCipherMode.ECB, pkcs7Padding: true).Decrypt(actual); + var decrypted = new AesCipher(key, iv: null, BlockCipherMode.ECB, pkcs7Padding: true).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -450,11 +450,11 @@ public void AES_ECB_192_Length64_NoPad() 0xa5, 0xd7, 0x6e, 0x76, 0x4f, 0x45, 0xef, 0xfe, 0xb2, 0x9f, 0xbc, 0x96, 0xd5, 0x49, 0x55, 0x31, }; - var actual = new AesCipher(key, iv: null, AesCipherMode.ECB, pkcs7Padding: false).Encrypt(input); + var actual = new AesCipher(key, iv: null, BlockCipherMode.ECB, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, iv: null, AesCipherMode.ECB, pkcs7Padding: false).Decrypt(actual); + var decrypted = new AesCipher(key, iv: null, BlockCipherMode.ECB, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -485,11 +485,11 @@ public void AES_ECB_192_Length64_Pad() 0xa0, 0xec, 0xa8, 0x7e, 0x68, 0xb7, 0x63, 0x7b, 0xc2, 0x5e, 0xc4, 0x33, 0xfa, 0xf2, 0x76, 0x83, }; - var actual = new AesCipher(key, iv: null, AesCipherMode.ECB, pkcs7Padding: true).Encrypt(input); + var actual = new AesCipher(key, iv: null, BlockCipherMode.ECB, pkcs7Padding: true).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, iv: null, AesCipherMode.ECB, pkcs7Padding: true).Decrypt(actual); + var decrypted = new AesCipher(key, iv: null, BlockCipherMode.ECB, pkcs7Padding: true).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -513,11 +513,11 @@ public void AES_ECB_256_Length16_NoPad() 0xf5, 0x94, 0x26, 0x13, 0x73, 0x7c, 0x20, 0xc4, 0xc4, 0xd3, 0x46, 0xb6, 0x0c, 0xd4, 0x29, 0xf2, }; - var actual = new AesCipher(key, iv: null, AesCipherMode.ECB, pkcs7Padding: false).Encrypt(input); + var actual = new AesCipher(key, iv: null, BlockCipherMode.ECB, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, iv: null, AesCipherMode.ECB, pkcs7Padding: false).Decrypt(actual); + var decrypted = new AesCipher(key, iv: null, BlockCipherMode.ECB, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -542,11 +542,11 @@ public void AES_ECB_256_Length16_Pad() 0xbb, 0x89, 0x9c, 0xcb, 0x62, 0x32, 0x82, 0xb2, 0x58, 0xe2, 0x69, 0xd5, 0xce, 0x1d, 0xd0, 0xa9, }; - var actual = new AesCipher(key, iv: null, AesCipherMode.ECB, pkcs7Padding: true).Encrypt(input); + var actual = new AesCipher(key, iv: null, BlockCipherMode.ECB, pkcs7Padding: true).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, iv: null, AesCipherMode.ECB, pkcs7Padding: true).Decrypt(actual); + var decrypted = new AesCipher(key, iv: null, BlockCipherMode.ECB, pkcs7Padding: true).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -574,11 +574,11 @@ public void AES_ECB_256_Length35_Pad() 0xe4, 0xd5, 0x5d, 0x03, 0x40, 0x5a, 0xd8, 0x91, 0x30, 0x89, 0xdf, 0xcf, 0x74, 0x54, 0x43, 0x31, }; - var actual = new AesCipher(key, iv: null, AesCipherMode.ECB, pkcs7Padding: true).Encrypt(input); + var actual = new AesCipher(key, iv: null, BlockCipherMode.ECB, pkcs7Padding: true).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, iv: null, AesCipherMode.ECB, pkcs7Padding: true).Decrypt(actual); + var decrypted = new AesCipher(key, iv: null, BlockCipherMode.ECB, pkcs7Padding: true).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -608,11 +608,11 @@ public void AES_ECB_256_Length64_NoPad() 0x4e, 0xd4, 0xc2, 0x5d, 0x32, 0x33, 0x1a, 0xb0, 0x12, 0xa7, 0x60, 0x31, 0x6a, 0xed, 0xa2, 0x2b, }; - var actual = new AesCipher(key, iv: null, AesCipherMode.ECB, pkcs7Padding: false).Encrypt(input); + var actual = new AesCipher(key, iv: null, BlockCipherMode.ECB, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, iv: null, AesCipherMode.ECB, pkcs7Padding: false).Decrypt(actual); + var decrypted = new AesCipher(key, iv: null, BlockCipherMode.ECB, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -643,11 +643,11 @@ public void AES_ECB_256_Length64_Pad() 0x62, 0xa7, 0x55, 0xf1, 0xc7, 0x6a, 0x0d, 0xb6, 0x67, 0xee, 0x09, 0xcc, 0xae, 0xe8, 0x13, 0x0f, }; - var actual = new AesCipher(key, iv: null, AesCipherMode.ECB, pkcs7Padding: true).Encrypt(input); + var actual = new AesCipher(key, iv: null, BlockCipherMode.ECB, pkcs7Padding: true).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, iv: null, AesCipherMode.ECB, pkcs7Padding: true).Decrypt(actual); + var decrypted = new AesCipher(key, iv: null, BlockCipherMode.ECB, pkcs7Padding: true).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -674,11 +674,11 @@ public void AES_CBC_128_Length16_NoPad() 0xbd, 0x17, 0x7d, 0x43, 0xf9, 0x66, 0x21, 0xf3, 0x3f, 0xc1, 0x89, 0xd7, 0x8d, 0x11, 0xf0, 0x52, }; - var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CBC, pkcs7Padding: false).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CBC, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CBC, pkcs7Padding: false).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CBC, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -706,11 +706,11 @@ public void AES_CBC_128_Length16_Pad() 0x97, 0xb2, 0xf2, 0xbf, 0xde, 0x3e, 0x6b, 0xee, 0x78, 0xf5, 0x77, 0xc9, 0x1a, 0x56, 0x01, 0x56, }; - var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CBC, pkcs7Padding: true).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CBC, pkcs7Padding: true).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CBC, pkcs7Padding: true).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CBC, pkcs7Padding: true).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -741,11 +741,11 @@ public void AES_CBC_128_Length35_Pad() 0xc8, 0x60, 0x05, 0xde, 0x81, 0xe4, 0xc6, 0xcd, 0x31, 0x7f, 0x9e, 0x5d, 0x4b, 0x03, 0x5f, 0x71, }; - var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CBC, pkcs7Padding: true).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CBC, pkcs7Padding: true).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CBC, pkcs7Padding: true).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CBC, pkcs7Padding: true).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -778,11 +778,11 @@ public void AES_CBC_128_Length64_NoPad() 0xe9, 0x40, 0x33, 0xc1, 0x3f, 0xb8, 0xf6, 0x69, 0x6b, 0x78, 0xaf, 0x4f, 0x58, 0x4c, 0xe6, 0x74, }; - var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CBC, pkcs7Padding: false).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CBC, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CBC, pkcs7Padding: false).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CBC, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -816,11 +816,11 @@ public void AES_CBC_128_Length64_Pad() 0xb4, 0x20, 0xcb, 0xb8, 0xb1, 0x7f, 0x0c, 0xf6, 0x17, 0x00, 0x0d, 0xde, 0x41, 0x46, 0x14, 0xae, }; - var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CBC, pkcs7Padding: true).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CBC, pkcs7Padding: true).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CBC, pkcs7Padding: true).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CBC, pkcs7Padding: true).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -848,11 +848,11 @@ public void AES_CBC_192_Length16_NoPad() 0x1f, 0x5a, 0xe4, 0x2d, 0x8b, 0x65, 0x70, 0x71, 0x26, 0x25, 0x3e, 0x46, 0x54, 0x3a, 0x99, 0x93, }; - var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CBC, pkcs7Padding: false).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CBC, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CBC, pkcs7Padding: false).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CBC, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -881,11 +881,11 @@ public void AES_CBC_192_Length16_Pad() 0x26, 0xac, 0x95, 0x24, 0xb5, 0x20, 0x37, 0x0b, 0x38, 0x72, 0x02, 0x19, 0x46, 0xfc, 0x63, 0xc7, }; - var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CBC, pkcs7Padding: true).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CBC, pkcs7Padding: true).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CBC, pkcs7Padding: true).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CBC, pkcs7Padding: true).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -917,11 +917,11 @@ public void AES_CBC_192_Length35_Pad() 0x10, 0x33, 0xf9, 0xe5, 0x3c, 0x5e, 0x35, 0x63, 0x5f, 0xbd, 0x35, 0x30, 0xbf, 0x9d, 0x1f, 0x9f, }; - var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CBC, pkcs7Padding: true).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CBC, pkcs7Padding: true).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CBC, pkcs7Padding: true).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CBC, pkcs7Padding: true).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -955,11 +955,11 @@ public void AES_CBC_192_Length64_NoPad() 0x8a, 0x64, 0x2a, 0x96, 0x82, 0xaa, 0xac, 0x8e, 0x88, 0x63, 0x28, 0x52, 0x5a, 0xfa, 0x8a, 0x5d, }; - var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CBC, pkcs7Padding: false).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CBC, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CBC, pkcs7Padding: false).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CBC, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -994,11 +994,11 @@ public void AES_CBC_192_Length64_Pad() 0xe5, 0xa1, 0x39, 0x09, 0x9c, 0xdd, 0xea, 0x04, 0xb9, 0x60, 0x34, 0xbe, 0x65, 0x9c, 0x15, 0x98, }; - var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CBC, pkcs7Padding: true).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CBC, pkcs7Padding: true).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CBC, pkcs7Padding: true).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CBC, pkcs7Padding: true).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -1026,11 +1026,11 @@ public void AES_CBC_256_Length16_NoPad() 0x3e, 0x7c, 0xdd, 0x13, 0x85, 0x57, 0x34, 0x61, 0xe6, 0x6e, 0xcd, 0x87, 0xd9, 0xaa, 0xf8, 0xe3, }; - var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CBC, pkcs7Padding: false).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CBC, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CBC, pkcs7Padding: false).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CBC, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -1059,11 +1059,11 @@ public void AES_CBC_256_Length16_Pad() 0x3e, 0x08, 0x87, 0x8c, 0xae, 0x30, 0xbc, 0x4f, 0x89, 0x16, 0x30, 0x42, 0x2a, 0xd9, 0xe6, 0xac, }; - var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CBC, pkcs7Padding: true).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CBC, pkcs7Padding: true).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CBC, pkcs7Padding: true).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CBC, pkcs7Padding: true).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -1095,11 +1095,11 @@ public void AES_CBC_256_Length35_Pad() 0x88, 0x46, 0x53, 0x42, 0x98, 0x69, 0x4b, 0x91, 0x9e, 0x5f, 0x69, 0x22, 0x58, 0xff, 0x48, 0xca, }; - var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CBC, pkcs7Padding: true).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CBC, pkcs7Padding: true).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CBC, pkcs7Padding: true).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CBC, pkcs7Padding: true).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -1133,11 +1133,11 @@ public void AES_CBC_256_Length64_NoPad() 0xfe, 0xa4, 0x71, 0xef, 0x33, 0x6b, 0x4f, 0x86, 0xe1, 0xa9, 0xf8, 0xc3, 0x40, 0xa4, 0x56, 0xc4, }; - var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CBC, pkcs7Padding: false).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CBC, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CBC, pkcs7Padding: false).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CBC, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -1172,11 +1172,11 @@ public void AES_CBC_256_Length64_Pad() 0xbc, 0xcc, 0x5a, 0x91, 0x8a, 0xbb, 0xe9, 0x70, 0x39, 0x42, 0x8d, 0xb1, 0x02, 0x53, 0xa7, 0x88, }; - var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CBC, pkcs7Padding: true).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CBC, pkcs7Padding: true).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CBC, pkcs7Padding: true).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CBC, pkcs7Padding: true).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -1203,11 +1203,11 @@ public void AES_CFB_128_Length16_NoPad() 0x8c, 0x75, 0xf1, 0xba, 0xf9, 0xe6, 0x66, 0x7d, 0x14, 0x4a, 0x9f, 0xfc, 0x31, 0xf7, 0x98, 0xcb, }; - var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CFB, pkcs7Padding: false).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CFB, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CFB, pkcs7Padding: false).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CFB, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -1238,11 +1238,11 @@ public void AES_CFB_128_Length35_NoPad() 0xfc, 0x42, 0x49, }; - var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CFB, pkcs7Padding: false).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CFB, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CFB, pkcs7Padding: false).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CFB, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -1275,11 +1275,11 @@ public void AES_CFB_128_Length64_NoPad() 0xd7, 0x15, 0xa4, 0x00, 0x33, 0xe6, 0x07, 0x1a, 0x6c, 0xc7, 0x95, 0x95, 0xb2, 0x52, 0x51, 0xc8, }; - var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CFB, pkcs7Padding: false).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CFB, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CFB, pkcs7Padding: false).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CFB, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -1307,11 +1307,11 @@ public void AES_CFB_192_Length16_NoPad() 0x57, 0x7a, 0x4f, 0x03, 0x6e, 0x76, 0x43, 0x2d, 0xc0, 0x23, 0x26, 0x19, 0x58, 0x2e, 0x77, 0x83, }; - var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CFB, pkcs7Padding: false).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CFB, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CFB, pkcs7Padding: false).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CFB, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -1343,11 +1343,11 @@ public void AES_CFB_192_Length35_NoPad() 0x05, 0xcb, 0xad, }; - var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CFB, pkcs7Padding: false).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CFB, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CFB, pkcs7Padding: false).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CFB, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -1381,11 +1381,11 @@ public void AES_CFB_192_Length64_NoPad() 0x08, 0x4e, 0x2b, 0xbd, 0xbb, 0x0a, 0xdc, 0x25, 0xe5, 0x10, 0x6c, 0x3c, 0x89, 0x03, 0xa7, 0x63, }; - var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CFB, pkcs7Padding: false).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CFB, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CFB, pkcs7Padding: false).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CFB, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -1413,11 +1413,11 @@ public void AES_CFB_256_Length16_NoPad() 0xd4, 0x21, 0xc2, 0xf2, 0x06, 0xcf, 0xa6, 0x65, 0x5d, 0xb0, 0x13, 0x3c, 0x87, 0x04, 0x5c, 0x59, }; - var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CFB, pkcs7Padding: false).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CFB, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CFB, pkcs7Padding: false).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CFB, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -1449,11 +1449,11 @@ public void AES_CFB_256_Length35_NoPad() 0xb5, 0xcb, 0x97, }; - var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CFB, pkcs7Padding: false).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CFB, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CFB, pkcs7Padding: false).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CFB, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -1487,11 +1487,11 @@ public void AES_CFB_256_Length64_NoPad() 0xbe, 0x24, 0x47, 0xeb, 0xe5, 0x0a, 0x24, 0x6d, 0xc2, 0x1e, 0xca, 0x52, 0x8d, 0x9a, 0xe7, 0x49, }; - var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CFB, pkcs7Padding: false).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CFB, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CFB, pkcs7Padding: false).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CFB, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -1518,11 +1518,11 @@ public void AES_CTR_128_Length16_NoPad() 0xee, 0x28, 0x3f, 0x2e, 0xd9, 0xac, 0x08, 0x36, 0x8a, 0xc0, 0x44, 0x90, 0x4d, 0x1f, 0x35, 0x06, }; - var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CTR, pkcs7Padding: false).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CTR, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CTR, pkcs7Padding: false).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CTR, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -1555,11 +1555,11 @@ public void AES_CTR_128_Length64_NoPad() 0xaf, 0x36, 0x92, 0xb0, 0x21, 0x49, 0x35, 0xff, 0xbf, 0xcf, 0x06, 0xdd, 0x22, 0xba, 0xea, 0xe5, }; - var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CTR, pkcs7Padding: false).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CTR, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CTR, pkcs7Padding: false).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CTR, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -1587,11 +1587,11 @@ public void AES_CTR_192_Length16_NoPad() 0x45, 0x5f, 0x3f, 0x9b, 0x2e, 0xe0, 0x2a, 0x60, 0x91, 0xd5, 0xe7, 0x8d, 0xf0, 0x24, 0x2d, 0x3a, }; - var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CTR, pkcs7Padding: false).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CTR, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CTR, pkcs7Padding: false).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CTR, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -1625,11 +1625,11 @@ public void AES_CTR_192_Length64_NoPad() 0xc9, 0xd9, 0x5c, 0xc5, 0x6c, 0x37, 0x68, 0x9f, 0xc7, 0x41, 0x3d, 0xe9, 0xee, 0xa7, 0xff, 0x0c, }; - var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CTR, pkcs7Padding: false).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CTR, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CTR, pkcs7Padding: false).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CTR, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -1657,11 +1657,11 @@ public void AES_CTR_256_Length16_NoPad() 0xe9, 0x0e, 0x8e, 0xe0, 0xff, 0xe1, 0xb3, 0x3d, 0x35, 0xa4, 0xd6, 0xeb, 0x05, 0x02, 0x32, 0x39, }; - var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CTR, pkcs7Padding: false).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CTR, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CTR, pkcs7Padding: false).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CTR, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -1695,11 +1695,11 @@ public void AES_CTR_256_Length64_NoPad() 0x2e, 0xdd, 0xea, 0x50, 0x36, 0x94, 0xb4, 0x40, 0x28, 0x04, 0xbd, 0xc0, 0x4d, 0x48, 0xa1, 0x34, }; - var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CTR, pkcs7Padding: false).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CTR, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CTR, pkcs7Padding: false).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CTR, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -1726,11 +1726,11 @@ public void AES_OFB_128_Length16_NoPad() 0x6d, 0xce, 0x96, 0xe5, 0x3c, 0x5a, 0xf3, 0xa5, 0x5b, 0x84, 0x89, 0x68, 0x00, 0xe7, 0xbf, 0x38, }; - var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.OFB, pkcs7Padding: false).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.OFB, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.OFB, pkcs7Padding: false).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.OFB, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -1763,11 +1763,11 @@ public void AES_OFB_128_Length64_NoPad() 0x53, 0x19, 0xe7, 0x96, 0xc5, 0x4c, 0x6f, 0x76, 0xe4, 0x6e, 0x96, 0xdc, 0x4c, 0x8e, 0x8e, 0x74, }; - var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.OFB, pkcs7Padding: false).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.OFB, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.OFB, pkcs7Padding: false).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.OFB, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -1795,11 +1795,11 @@ public void AES_OFB_192_Length16_NoPad() 0xa5, 0xfc, 0xcb, 0x1d, 0xca, 0xa0, 0x7d, 0x15, 0x4f, 0xe8, 0x17, 0x11, 0x8d, 0x95, 0x62, 0x81, }; - var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.OFB, pkcs7Padding: false).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.OFB, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.OFB, pkcs7Padding: false).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.OFB, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -1833,11 +1833,11 @@ public void AES_OFB_192_Length64_NoPad() 0xa7, 0xdc, 0x91, 0x3d, 0x95, 0x51, 0xc3, 0xe2, 0xcf, 0xf3, 0x64, 0x93, 0x43, 0x17, 0x27, 0x49, }; - var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.OFB, pkcs7Padding: false).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.OFB, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.OFB, pkcs7Padding: false).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.OFB, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -1865,11 +1865,11 @@ public void AES_OFB_256_Length16_NoPad() 0xaa, 0xa2, 0x2a, 0x8e, 0xd2, 0x03, 0x23, 0x13, 0x7f, 0xd5, 0x8b, 0x95, 0x80, 0xc2, 0x8d, 0xf3, }; - var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.OFB, pkcs7Padding: false).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.OFB, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.OFB, pkcs7Padding: false).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.OFB, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -1903,11 +1903,11 @@ public void AES_OFB_256_Length64_NoPad() 0x5e, 0x2e, 0x84, 0x3a, 0x3c, 0x0a, 0x45, 0xa2, 0x59, 0xe2, 0xa2, 0x53, 0x2b, 0xb9, 0x65, 0xe2, }; - var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.OFB, pkcs7Padding: false).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.OFB, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.OFB, pkcs7Padding: false).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), BlockCipherMode.OFB, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } diff --git a/test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/DesCipherTest.Gen.cs.txt b/test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/DesCipherTest.Gen.cs.txt new file mode 100644 index 000000000..04ee2bcbc --- /dev/null +++ b/test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/DesCipherTest.Gen.cs.txt @@ -0,0 +1,151 @@ +// Used to generate tests in DesCipherTest.cs + +// The script works by running "openssl enc [...]" (via WSL) to generate the +// expected encrypted values, and also verifies those values against the .NET +// BCL implementation as an extra validation before generating the tests. + +Dictionary modes = new() +{ + ["cbc"] = ("(byte[])iv.Clone(), BlockCipherMode.CBC", CipherMode.CBC), + ["cfb"] = ("(byte[])iv.Clone(), BlockCipherMode.CFB", CipherMode.CFB), +}; + +Random random = new(123); + +using IndentedTextWriter tw = new(Console.Out); + +foreach ((string mode, (string modeCode, CipherMode? bclMode)) in modes) +{ + foreach (int inputLength in new int[] { 8, 17, 32 }) + { + foreach (bool pad in new bool[] { false, true }) + { + // It is not allowed to use no padding on non-block lengths + // It makes sense in cfb, ctr and ofb modes + if (!pad && inputLength % 8 != 0 && mode is not "cfb") + { + continue; + } + + // It does not make sense to test padding for stream cipher modes + // (and the OpenSSL, BCL implementations differ) + if (pad && mode is "cfb") + { + continue; + } + + byte[] input = new byte[inputLength]; + random.NextBytes(input); + + byte[] key = new byte[64 / 8]; + random.NextBytes(key); + + byte[] iv = new byte[8]; + random.NextBytes(iv); + + StringBuilder openSslCmd = new(); + + openSslCmd.Append($"echo -n -e '{string.Join("", input.Select(b => $"\\x{b:x2}"))}' |"); + openSslCmd.Append($" openssl enc -e -des-{mode}"); + openSslCmd.Append($" -K {Convert.ToHexString(key)}"); + openSslCmd.Append($" -iv {Convert.ToHexString(iv)}"); + openSslCmd.Append($" -provider legacy"); + + if (!pad) + { + openSslCmd.Append(" -nopad"); + } + + ProcessStartInfo pi = new("wsl", openSslCmd.ToString()) + { + RedirectStandardOutput = true, + RedirectStandardError = true, + }; + + byte[] expected; + string error; + + using (MemoryStream ms = new()) + { + var p = Process.Start(pi); + p.StandardOutput.BaseStream.CopyTo(ms); + error = p.StandardError.ReadToEnd(); + + p.WaitForExit(); + + expected = ms.ToArray(); + } + + tw.WriteLine("[TestMethod]"); + tw.WriteLine($"public void DES_{mode.ToUpper()}_Length{inputLength}_{(pad ? "Pad" : "NoPad")}()"); + tw.WriteLine("{"); + tw.Indent++; + + WriteBytes(input); + WriteBytes(key); + WriteBytes(iv); + tw.WriteLine(); + + if (!string.IsNullOrWhiteSpace(error)) + { + tw.WriteLine($"// {openSslCmd}"); + tw.WriteLine($"Assert.Fail(@\"{error}\");"); + + tw.Indent--; + tw.WriteLine("}"); + tw.WriteLine(); + continue; + } + + tw.WriteLine($"// {openSslCmd} | hd"); // pipe to hexdump + WriteBytes(expected); + tw.WriteLine(); + tw.WriteLine($"var actual = new DesCipher(key, {modeCode}, pkcs7Padding: {(pad ? "true" : "false")}).Encrypt(input);"); + tw.WriteLine(); + tw.WriteLine($"CollectionAssert.AreEqual(expected, actual);"); + + if (bclMode is not CipherMode.CFB) + { + // Verify the OpenSSL result is the same as the .NET BCL, just to be sure + DES bcl = DES.Create(); + bcl.Key = key; + bcl.IV = iv; + bcl.Mode = bclMode.Value; + bcl.Padding = pad ? PaddingMode.PKCS7 : PaddingMode.None; + byte[] bclBytes = bcl.CreateEncryptor().TransformFinalBlock(input, 0, input.Length); + + if (!bclBytes.AsSpan().SequenceEqual(expected)) + { + tw.WriteLine(); + tw.WriteLine(@"Assert.Inconclusive(@""OpenSSL does not match the .NET BCL"); + tw.Indent++; + tw.WriteLine($@"OpenSSL: {Convert.ToHexString(expected)}"); + tw.WriteLine($@"BCL: {Convert.ToHexString(bclBytes)}"");"); + tw.Indent--; + } + } + + tw.WriteLine(); + tw.WriteLine($"var decrypted = new DesCipher(key, {modeCode}, pkcs7Padding: {(pad ? "true" : "false")}).Decrypt(actual);"); + tw.WriteLine(); + tw.WriteLine($"CollectionAssert.AreEqual(input, decrypted);"); + + tw.Indent--; + tw.WriteLine("}"); + tw.WriteLine(); + } + } +} + +void WriteBytes(byte[] bytes, [CallerArgumentExpression(nameof(bytes))] string name = null) +{ + tw.WriteLine($"var {name} = new byte[]"); + tw.WriteLine("{"); + tw.Indent++; + foreach (byte[] chunk in bytes.Chunk(16)) + { + tw.WriteLine(string.Join(", ", chunk.Select(b => $"0x{b:x2}")) + ','); + } + tw.Indent--; + tw.WriteLine("};"); +} diff --git a/test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/DesCipherTest.cs b/test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/DesCipherTest.cs index 23448c12d..90d5511b0 100644 --- a/test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/DesCipherTest.cs +++ b/test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/DesCipherTest.cs @@ -1,10 +1,6 @@ -using System.Text; +using Microsoft.VisualStudio.TestTools.UnitTesting; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -using Renci.SshNet.Common; using Renci.SshNet.Security.Cryptography.Ciphers; -using Renci.SshNet.Security.Cryptography.Ciphers.Modes; using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Security.Cryptography.Ciphers @@ -15,44 +11,264 @@ namespace Renci.SshNet.Tests.Classes.Security.Cryptography.Ciphers [TestClass] public class DesCipherTest : TestBase { + // All tests below this line were generated by the script in DesCipherTest.Gen.cs.txt + [TestMethod] + public void DES_CBC_Length8_NoPad() + { + var input = new byte[] + { + 0x03, 0xe1, 0xe1, 0xaa, 0xa5, 0xbc, 0xa1, 0x9f, + }; + var key = new byte[] + { + 0xba, 0x8c, 0x42, 0x05, 0x8b, 0x4a, 0xbf, 0x28, + }; + var iv = new byte[] + { + 0x96, 0x39, 0xec, 0x0d, 0xfc, 0x2d, 0xb2, 0x7c, + }; + + // echo -n -e '\x03\xe1\xe1\xaa\xa5\xbc\xa1\x9f' | openssl enc -e -des-cbc -K BA8C42058B4ABF28 -iv 9639EC0DFC2DB27C -provider legacy -nopad | hd + var expected = new byte[] + { + 0x46, 0x02, 0xdd, 0x47, 0xe2, 0xe4, 0x1c, 0x7e, + }; + + var actual = new DesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CBC, pkcs7Padding: false).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new DesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CBC, pkcs7Padding: false).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] + public void DES_CBC_Length8_Pad() + { + var input = new byte[] + { + 0xe9, 0x74, 0x8e, 0x5f, 0xb9, 0xf3, 0x99, 0xce, + }; + var key = new byte[] + { + 0xe1, 0x1a, 0x5c, 0x51, 0xa3, 0x1d, 0xd7, 0x1b, + }; + var iv = new byte[] + { + 0x15, 0x8c, 0xad, 0xa6, 0xaf, 0x63, 0x0d, 0x8c, + }; + + // echo -n -e '\xe9\x74\x8e\x5f\xb9\xf3\x99\xce' | openssl enc -e -des-cbc -K E11A5C51A31DD71B -iv 158CADA6AF630D8C -provider legacy | hd + var expected = new byte[] + { + 0xdf, 0xb3, 0x0f, 0x80, 0x5c, 0x9b, 0x47, 0xa8, 0x0b, 0x68, 0x6b, 0x47, 0x00, 0xb7, 0x66, 0x20, + }; + + var actual = new DesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CBC, pkcs7Padding: true).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new DesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CBC, pkcs7Padding: true).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + [TestMethod] - public void Cbc_Encrypt() + public void DES_CBC_Length17_Pad() { - var expectedCypher = new byte[] - { - 0x15, 0x43, 0x3e, 0x97, 0x65, 0x66, 0xea, 0x81, 0x22, 0xab, 0xe3, - 0x11, 0x0f, 0x7d, 0xcb, 0x78, 0x56, 0x91, 0x22, 0x3d, 0xd6, 0xca, - 0xe3, 0xbd - }; + var input = new byte[] + { + 0x1a, 0xf1, 0x3a, 0x35, 0x8c, 0xca, 0x3f, 0xd6, 0x2f, 0x65, 0xc1, 0x31, 0x2d, 0x41, 0xe5, 0xc7, + 0xf3, + }; + var key = new byte[] + { + 0x74, 0x23, 0x71, 0xed, 0x6d, 0x84, 0x79, 0x61, + }; + var iv = new byte[] + { + 0xd0, 0xf8, 0x6f, 0x7f, 0x0c, 0xcc, 0x86, 0x67, + }; + + // echo -n -e '\x1a\xf1\x3a\x35\x8c\xca\x3f\xd6\x2f\x65\xc1\x31\x2d\x41\xe5\xc7\xf3' | openssl enc -e -des-cbc -K 742371ED6D847961 -iv D0F86F7F0CCC8667 -provider legacy | hd + var expected = new byte[] + { + 0x11, 0x53, 0x6b, 0x68, 0xe9, 0xb7, 0x08, 0xed, 0x51, 0x23, 0x94, 0xee, 0x3d, 0xac, 0xab, 0xa0, + 0x86, 0x5a, 0x46, 0x6e, 0xe5, 0x5d, 0x4a, 0xe9, + }; + + var actual = new DesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CBC, pkcs7Padding: true).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new DesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CBC, pkcs7Padding: true).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] + public void DES_CBC_Length32_NoPad() + { + var input = new byte[] + { + 0x02, 0x45, 0xc8, 0xb8, 0x64, 0x42, 0x17, 0xda, 0x85, 0x21, 0x3e, 0x5c, 0xa6, 0xee, 0xd4, 0xa7, + 0xe6, 0xb3, 0x3b, 0x3f, 0x9c, 0x9e, 0xac, 0x6c, 0xc1, 0xd3, 0xbb, 0xd2, 0xd0, 0x57, 0x22, 0x99, + }; + var key = new byte[] + { + 0x3a, 0xc9, 0x2b, 0xfb, 0x1d, 0x0e, 0x8e, 0x31, + }; + var iv = new byte[] + { + 0x0c, 0x96, 0x68, 0x4c, 0x46, 0x1d, 0xbb, 0xe1, + }; + + // echo -n -e '\x02\x45\xc8\xb8\x64\x42\x17\xda\x85\x21\x3e\x5c\xa6\xee\xd4\xa7\xe6\xb3\x3b\x3f\x9c\x9e\xac\x6c\xc1\xd3\xbb\xd2\xd0\x57\x22\x99' | openssl enc -e -des-cbc -K 3AC92BFB1D0E8E31 -iv 0C96684C461DBBE1 -provider legacy -nopad | hd + var expected = new byte[] + { + 0xfc, 0x48, 0xcb, 0x04, 0x71, 0x03, 0x5a, 0x04, 0xfa, 0x66, 0x1e, 0x12, 0x26, 0x27, 0xf1, 0x98, + 0x19, 0x68, 0xce, 0xea, 0x8e, 0x60, 0x3b, 0xa9, 0xa2, 0x06, 0xbf, 0x18, 0x59, 0xab, 0xd8, 0xd9, + }; + + var actual = new DesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CBC, pkcs7Padding: false).Encrypt(input); - var input = Encoding.ASCII.GetBytes("www.javaCODEgeeks.com!!!"); - var key = new byte[] { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }; - var iv = new byte[] { 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 }; + CollectionAssert.AreEqual(expected, actual); - var des = new DesCipher(key, new CbcCipherMode(iv), padding: null); - var actualCypher = des.Encrypt(input); + var decrypted = new DesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CBC, pkcs7Padding: false).Decrypt(actual); - Assert.IsTrue((expectedCypher.IsEqualTo(actualCypher))); + CollectionAssert.AreEqual(input, decrypted); } [TestMethod] - public void Cbc_Decrypt() + public void DES_CBC_Length32_Pad() { - var expectedPlain = Encoding.ASCII.GetBytes("www.javaCODEgeeks.com!!!"); + var input = new byte[] + { + 0x23, 0xc8, 0x99, 0x59, 0x90, 0x47, 0xcb, 0x63, 0x99, 0x5b, 0xf7, 0x91, 0x87, 0x44, 0x09, 0x2e, + 0xff, 0xa4, 0x21, 0xdc, 0xc3, 0xd9, 0x89, 0xd7, 0x24, 0x0a, 0x32, 0x05, 0x36, 0x60, 0x25, 0xa4, + }; + var key = new byte[] + { + 0x17, 0xda, 0xaf, 0x08, 0xbe, 0xc9, 0x08, 0xf3, + }; + var iv = new byte[] + { + 0xfe, 0xc7, 0x61, 0xc2, 0x17, 0xfd, 0xaa, 0xc7, + }; + + // echo -n -e '\x23\xc8\x99\x59\x90\x47\xcb\x63\x99\x5b\xf7\x91\x87\x44\x09\x2e\xff\xa4\x21\xdc\xc3\xd9\x89\xd7\x24\x0a\x32\x05\x36\x60\x25\xa4' | openssl enc -e -des-cbc -K 17DAAF08BEC908F3 -iv FEC761C217FDAAC7 -provider legacy | hd + var expected = new byte[] + { + 0x93, 0xcb, 0xb1, 0x86, 0x4f, 0xd1, 0x6b, 0x15, 0xc5, 0x00, 0xaf, 0x50, 0xfc, 0xd2, 0x34, 0xdb, + 0x73, 0xa1, 0x6f, 0x4c, 0x9c, 0xcd, 0xd8, 0xf9, 0x95, 0xee, 0xa2, 0xb2, 0x46, 0x1a, 0x5a, 0x9a, + 0xea, 0xb5, 0xb5, 0xb8, 0x97, 0x65, 0xd0, 0x0b, + }; + + var actual = new DesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CBC, pkcs7Padding: true).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new DesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CBC, pkcs7Padding: true).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] + public void DES_CFB_Length8_NoPad() + { + var input = new byte[] + { + 0x8d, 0x3a, 0x4c, 0xa2, 0xfb, 0xde, 0x1e, 0x49, + }; + var key = new byte[] + { + 0x3e, 0xc1, 0x34, 0x86, 0x14, 0xc6, 0x2d, 0x39, + }; + var iv = new byte[] + { + 0x35, 0x52, 0x79, 0xad, 0x95, 0x01, 0x6f, 0x36, + }; + + // echo -n -e '\x8d\x3a\x4c\xa2\xfb\xde\x1e\x49' | openssl enc -e -des-cfb -K 3EC1348614C62D39 -iv 355279AD95016F36 -provider legacy -nopad | hd + var expected = new byte[] + { + 0x9b, 0x67, 0x40, 0x20, 0x40, 0x5e, 0x9e, 0x00, + }; + + var actual = new DesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CFB, pkcs7Padding: false).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new DesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CFB, pkcs7Padding: false).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] + public void DES_CFB_Length17_NoPad() + { + var input = new byte[] + { + 0x9b, 0x2e, 0xde, 0xfc, 0x77, 0xc7, 0xc0, 0x27, 0x60, 0x6b, 0x78, 0xfc, 0x13, 0x83, 0xa8, 0x38, + 0xbb, + }; + var key = new byte[] + { + 0x65, 0xca, 0xfd, 0x94, 0x82, 0xde, 0x38, 0x99, + }; + var iv = new byte[] + { + 0x28, 0x8c, 0xc4, 0x84, 0xfd, 0x32, 0x8c, 0xca, + }; + + // echo -n -e '\x9b\x2e\xde\xfc\x77\xc7\xc0\x27\x60\x6b\x78\xfc\x13\x83\xa8\x38\xbb' | openssl enc -e -des-cfb -K 65CAFD9482DE3899 -iv 288CC484FD328CCA -provider legacy -nopad | hd + var expected = new byte[] + { + 0x03, 0x86, 0xd9, 0x49, 0x1b, 0x60, 0x76, 0xec, 0x06, 0x47, 0xd3, 0xe0, 0xfd, 0x33, 0x08, 0xc4, + 0x3f, + }; + + var actual = new DesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CFB, pkcs7Padding: false).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new DesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CFB, pkcs7Padding: false).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] + public void DES_CFB_Length32_NoPad() + { + var input = new byte[] + { + 0x16, 0x06, 0xcc, 0x00, 0x22, 0xd2, 0x76, 0x00, 0x0d, 0x25, 0xa9, 0x4e, 0x31, 0x25, 0xb1, 0xaa, + 0x40, 0xf1, 0x2f, 0x36, 0x72, 0xa2, 0x18, 0x4f, 0xa6, 0x62, 0x4f, 0x3b, 0xfb, 0xa3, 0x63, 0x38, + }; + var key = new byte[] + { + 0xec, 0x32, 0xfd, 0x7d, 0xdb, 0x38, 0x99, 0x93, + }; + var iv = new byte[] + { + 0x53, 0xfc, 0x86, 0x5d, 0x35, 0xe9, 0x68, 0x02, + }; + + // echo -n -e '\x16\x06\xcc\x00\x22\xd2\x76\x00\x0d\x25\xa9\x4e\x31\x25\xb1\xaa\x40\xf1\x2f\x36\x72\xa2\x18\x4f\xa6\x62\x4f\x3b\xfb\xa3\x63\x38' | openssl enc -e -des-cfb -K EC32FD7DDB389993 -iv 53FC865D35E96802 -provider legacy -nopad | hd + var expected = new byte[] + { + 0x73, 0x97, 0xc2, 0xcb, 0x6b, 0xec, 0xa5, 0x00, 0x5d, 0xaf, 0x5c, 0xf3, 0x10, 0x55, 0x5e, 0xe6, + 0x6e, 0x97, 0x4e, 0xd3, 0xad, 0x27, 0x33, 0xe4, 0xa0, 0x8e, 0x35, 0xc9, 0x1a, 0x17, 0x07, 0x64, + }; + + var actual = new DesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CFB, pkcs7Padding: false).Encrypt(input); - var key = new byte[] { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }; - var iv = new byte[] { 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 }; - var cypher = new byte[] - { - 0x15, 0x43, 0x3e, 0x97, 0x65, 0x66, 0xea, 0x81, 0x22, 0xab, 0xe3, - 0x11, 0x0f, 0x7d, 0xcb, 0x78, 0x56, 0x91, 0x22, 0x3d, 0xd6, 0xca, - 0xe3, 0xbd - }; + CollectionAssert.AreEqual(expected, actual); - var des = new DesCipher(key, new CbcCipherMode(iv), padding: null); - var plain = des.Decrypt(cypher); + var decrypted = new DesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CFB, pkcs7Padding: false).Decrypt(actual); - Assert.IsTrue(expectedPlain.IsEqualTo(plain)); + CollectionAssert.AreEqual(input, decrypted); } } } diff --git a/test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/TripleDesCipherTest.Gen.cs.txt b/test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/TripleDesCipherTest.Gen.cs.txt new file mode 100644 index 000000000..563d1d5d1 --- /dev/null +++ b/test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/TripleDesCipherTest.Gen.cs.txt @@ -0,0 +1,151 @@ +// Used to generate tests in TripleDesCipherTest.cs + +// The script works by running "openssl enc [...]" (via WSL) to generate the +// expected encrypted values, and also verifies those values against the .NET +// BCL implementation as an extra validation before generating the tests. + +Dictionary modes = new() +{ + ["cbc"] = ("(byte[])iv.Clone(), BlockCipherMode.CBC", CipherMode.CBC), + ["cfb"] = ("(byte[])iv.Clone(), BlockCipherMode.CFB", CipherMode.CFB), +}; + +Random random = new(123); + +using IndentedTextWriter tw = new(Console.Out); + +foreach ((string mode, (string modeCode, CipherMode? bclMode)) in modes) +{ + foreach (int inputLength in new int[] { 8, 17, 32 }) + { + foreach (bool pad in new bool[] { false, true }) + { + // It is not allowed to use no padding on non-block lengths + // It makes sense in cfb, ctr and ofb modes + if (!pad && inputLength % 8 != 0 && mode is not "cfb") + { + continue; + } + + // It does not make sense to test padding for stream cipher modes + // (and the OpenSSL, BCL implementations differ) + if (pad && mode is "cfb") + { + continue; + } + + byte[] input = new byte[inputLength]; + random.NextBytes(input); + + byte[] key = new byte[64 * 3 / 8]; + random.NextBytes(key); + + byte[] iv = new byte[8]; + random.NextBytes(iv); + + StringBuilder openSslCmd = new(); + + openSslCmd.Append($"echo -n -e '{string.Join("", input.Select(b => $"\\x{b:x2}"))}' |"); + openSslCmd.Append($" openssl enc -e -des-ede3-{mode}"); + openSslCmd.Append($" -K {Convert.ToHexString(key)}"); + openSslCmd.Append($" -iv {Convert.ToHexString(iv)}"); + + if (!pad) + { + openSslCmd.Append(" -nopad"); + } + + ProcessStartInfo pi = new("wsl", openSslCmd.ToString()) + { + RedirectStandardOutput = true, + RedirectStandardError = true, + }; + + byte[] expected; + string error; + + using (MemoryStream ms = new()) + { + var p = Process.Start(pi); + p.StandardOutput.BaseStream.CopyTo(ms); + error = p.StandardError.ReadToEnd(); + + p.WaitForExit(); + + expected = ms.ToArray(); + } + + tw.WriteLine("[TestMethod]"); + tw.WriteLine($"public void TripleDes_{mode.ToUpper()}_Length{inputLength}_{(pad ? "Pad" : "NoPad")}()"); + tw.WriteLine("{"); + tw.Indent++; + + WriteBytes(input); + WriteBytes(key); + WriteBytes(iv); + tw.WriteLine(); + + if (!string.IsNullOrWhiteSpace(error)) + { + tw.WriteLine($"// {openSslCmd}"); + tw.WriteLine($"Assert.Fail(@\"{error}\");"); + + tw.Indent--; + tw.WriteLine("}"); + tw.WriteLine(); + continue; + } + + tw.WriteLine($"// {openSslCmd} | hd"); // pipe to hexdump + WriteBytes(expected); + tw.WriteLine(); + tw.WriteLine($"var actual = new TripleDesCipher(key, {modeCode}, pkcs7Padding: {(pad ? "true" : "false")}).Encrypt(input);"); + tw.WriteLine(); + tw.WriteLine($"CollectionAssert.AreEqual(expected, actual);"); + + if (bclMode is not CipherMode.CFB) + { + // Verify the OpenSSL result is the same as the .NET BCL, just to be sure + TripleDES bcl = TripleDES.Create(); + bcl.Key = key; + bcl.IV = iv; + bcl.FeedbackSize = 8 * 8; // .NET is CFB1 by default, OpenSSL is CFB8 + bcl.Mode = bclMode.Value; + bcl.Padding = pad ? PaddingMode.PKCS7 : PaddingMode.None; + byte[] bclBytes = bcl.CreateEncryptor().TransformFinalBlock(input, 0, input.Length); + + if (!bclBytes.AsSpan().SequenceEqual(expected)) + { + tw.WriteLine(); + tw.WriteLine(@"Assert.Inconclusive(@""OpenSSL does not match the .NET BCL"); + tw.Indent++; + tw.WriteLine($@"OpenSSL: {Convert.ToHexString(expected)}"); + tw.WriteLine($@"BCL: {Convert.ToHexString(bclBytes)}"");"); + tw.Indent--; + } + } + + tw.WriteLine(); + tw.WriteLine($"var decrypted = new TripleDesCipher(key, {modeCode}, pkcs7Padding: {(pad ? "true" : "false")}).Decrypt(actual);"); + tw.WriteLine(); + tw.WriteLine($"CollectionAssert.AreEqual(input, decrypted);"); + + tw.Indent--; + tw.WriteLine("}"); + tw.WriteLine(); + } + } +} + +void WriteBytes(byte[] bytes, [CallerArgumentExpression(nameof(bytes))] string name = null) +{ + tw.WriteLine($"var {name} = new byte[]"); + tw.WriteLine("{"); + tw.Indent++; + foreach (byte[] chunk in bytes.Chunk(16)) + { + tw.WriteLine(string.Join(", ", chunk.Select(b => $"0x{b:x2}")) + ','); + } + tw.Indent--; + tw.WriteLine("};"); +} diff --git a/test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/TripleDesCipherTest.cs b/test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/TripleDesCipherTest.cs index da340cd9d..64e3dee0a 100644 --- a/test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/TripleDesCipherTest.cs +++ b/test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/TripleDesCipherTest.cs @@ -1,9 +1,6 @@ -using System.Linq; - -using Microsoft.VisualStudio.TestTools.UnitTesting; +using Microsoft.VisualStudio.TestTools.UnitTesting; using Renci.SshNet.Security.Cryptography.Ciphers; -using Renci.SshNet.Security.Cryptography.Ciphers.Modes; using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Security.Cryptography.Ciphers @@ -14,20 +11,272 @@ namespace Renci.SshNet.Tests.Classes.Security.Cryptography.Ciphers [TestClass] public class TripleDesCipherTest : TestBase { + // All tests below this line were generated by the script in TripleDesCipherTest.Gen.cs.txt + [TestMethod] + public void TripleDes_CBC_Length8_NoPad() + { + var input = new byte[] + { + 0x03, 0xe1, 0xe1, 0xaa, 0xa5, 0xbc, 0xa1, 0x9f, + }; + var key = new byte[] + { + 0xba, 0x8c, 0x42, 0x05, 0x8b, 0x4a, 0xbf, 0x28, 0x96, 0x39, 0xec, 0x0d, 0xfc, 0x2d, 0xb2, 0x7c, + 0xe9, 0x74, 0x8e, 0x5f, 0xb9, 0xf3, 0x99, 0xce, + }; + var iv = new byte[] + { + 0xe1, 0x1a, 0x5c, 0x51, 0xa3, 0x1d, 0xd7, 0x1b, + }; + + // echo -n -e '\x03\xe1\xe1\xaa\xa5\xbc\xa1\x9f' | openssl enc -e -des-ede3-cbc -K BA8C42058B4ABF289639EC0DFC2DB27CE9748E5FB9F399CE -iv E11A5C51A31DD71B -nopad | hd + var expected = new byte[] + { + 0x0c, 0xd8, 0x26, 0xd1, 0xed, 0x41, 0x73, 0x25, + }; + + var actual = new TripleDesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CBC, pkcs7Padding: false).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new TripleDesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CBC, pkcs7Padding: false).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] + public void TripleDes_CBC_Length8_Pad() + { + var input = new byte[] + { + 0x15, 0x8c, 0xad, 0xa6, 0xaf, 0x63, 0x0d, 0x8c, + }; + var key = new byte[] + { + 0x1a, 0xf1, 0x3a, 0x35, 0x8c, 0xca, 0x3f, 0xd6, 0x2f, 0x65, 0xc1, 0x31, 0x2d, 0x41, 0xe5, 0xc7, + 0xf3, 0x74, 0x23, 0x71, 0xed, 0x6d, 0x84, 0x79, + }; + var iv = new byte[] + { + 0x61, 0xd0, 0xf8, 0x6f, 0x7f, 0x0c, 0xcc, 0x86, + }; + + // echo -n -e '\x15\x8c\xad\xa6\xaf\x63\x0d\x8c' | openssl enc -e -des-ede3-cbc -K 1AF13A358CCA3FD62F65C1312D41E5C7F3742371ED6D8479 -iv 61D0F86F7F0CCC86 | hd + var expected = new byte[] + { + 0x91, 0xcb, 0x5c, 0xdf, 0x6d, 0xf2, 0x85, 0xbf, 0x5c, 0xf8, 0xf9, 0xbd, 0xe1, 0xc4, 0xb9, 0xab, + }; + + var actual = new TripleDesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CBC, pkcs7Padding: true).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new TripleDesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CBC, pkcs7Padding: true).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + [TestMethod] - public void Test_Cipher_3DES_CBC() + public void TripleDes_CBC_Length17_Pad() { - var input = new byte[] { 0x00, 0x00, 0x00, 0x1c, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x0c, 0x73, 0x73, 0x68, 0x2d, 0x75, 0x73, 0x65, 0x72, 0x61, 0x75, 0x74, 0x68, 0x72, 0x4e, 0x06, 0x08, 0x28, 0x2d, 0xaa, 0xe2, 0xb3, 0xd9 }; - var key = new byte[] { 0x78, 0xf6, 0xc6, 0xbb, 0x57, 0x03, 0x69, 0xca, 0xba, 0x31, 0x18, 0x2f, 0x2f, 0x4c, 0x35, 0x34, 0x64, 0x06, 0x85, 0x30, 0xbe, 0x78, 0x60, 0xb3 }; - var iv = new byte[] { 0xc0, 0x75, 0xf2, 0x26, 0x0a, 0x2a, 0x42, 0x96 }; - var output = new byte[] { 0x28, 0x77, 0x2f, 0x07, 0x3e, 0xc2, 0x27, 0xa6, 0xdb, 0x36, 0x4d, 0xc6, 0x7a, 0x26, 0x7a, 0x38, 0xe6, 0x54, 0x0b, 0xab, 0x07, 0x87, 0xf0, 0xa4, 0x73, 0x1f, 0xde, 0xe6, 0x81, 0x1d, 0x4b, 0x4b }; - var testCipher = new TripleDesCipher(key, new CbcCipherMode(iv), null); - var r = testCipher.Encrypt(input); + var input = new byte[] + { + 0x67, 0x02, 0x45, 0xc8, 0xb8, 0x64, 0x42, 0x17, 0xda, 0x85, 0x21, 0x3e, 0x5c, 0xa6, 0xee, 0xd4, + 0xa7, + }; + var key = new byte[] + { + 0xe6, 0xb3, 0x3b, 0x3f, 0x9c, 0x9e, 0xac, 0x6c, 0xc1, 0xd3, 0xbb, 0xd2, 0xd0, 0x57, 0x22, 0x99, + 0x3a, 0xc9, 0x2b, 0xfb, 0x1d, 0x0e, 0x8e, 0x31, + }; + var iv = new byte[] + { + 0x0c, 0x96, 0x68, 0x4c, 0x46, 0x1d, 0xbb, 0xe1, + }; - if (!r.SequenceEqual(output)) + // echo -n -e '\x67\x02\x45\xc8\xb8\x64\x42\x17\xda\x85\x21\x3e\x5c\xa6\xee\xd4\xa7' | openssl enc -e -des-ede3-cbc -K E6B33B3F9C9EAC6CC1D3BBD2D05722993AC92BFB1D0E8E31 -iv 0C96684C461DBBE1 | hd + var expected = new byte[] { - Assert.Fail("Invalid encryption"); - } + 0xd1, 0x8b, 0xe6, 0x2d, 0x26, 0x99, 0xff, 0x02, 0xd8, 0x45, 0x2b, 0x21, 0x90, 0xc6, 0x85, 0xa3, + 0x58, 0xa7, 0x5a, 0xfc, 0xc7, 0x20, 0x40, 0x1f, + }; + + var actual = new TripleDesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CBC, pkcs7Padding: true).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new TripleDesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CBC, pkcs7Padding: true).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] + public void TripleDes_CBC_Length32_NoPad() + { + var input = new byte[] + { + 0x23, 0xc8, 0x99, 0x59, 0x90, 0x47, 0xcb, 0x63, 0x99, 0x5b, 0xf7, 0x91, 0x87, 0x44, 0x09, 0x2e, + 0xff, 0xa4, 0x21, 0xdc, 0xc3, 0xd9, 0x89, 0xd7, 0x24, 0x0a, 0x32, 0x05, 0x36, 0x60, 0x25, 0xa4, + }; + var key = new byte[] + { + 0x17, 0xda, 0xaf, 0x08, 0xbe, 0xc9, 0x08, 0xf3, 0xfe, 0xc7, 0x61, 0xc2, 0x17, 0xfd, 0xaa, 0xc7, + 0x8d, 0x3a, 0x4c, 0xa2, 0xfb, 0xde, 0x1e, 0x49, + }; + var iv = new byte[] + { + 0x3e, 0xc1, 0x34, 0x86, 0x14, 0xc6, 0x2d, 0x39, + }; + + // echo -n -e '\x23\xc8\x99\x59\x90\x47\xcb\x63\x99\x5b\xf7\x91\x87\x44\x09\x2e\xff\xa4\x21\xdc\xc3\xd9\x89\xd7\x24\x0a\x32\x05\x36\x60\x25\xa4' | openssl enc -e -des-ede3-cbc -K 17DAAF08BEC908F3FEC761C217FDAAC78D3A4CA2FBDE1E49 -iv 3EC1348614C62D39 -nopad | hd + var expected = new byte[] + { + 0x75, 0x50, 0xa3, 0x30, 0xc8, 0xaf, 0x2d, 0xa8, 0x8b, 0x78, 0x07, 0x89, 0xb0, 0x82, 0xa1, 0x74, + 0xd1, 0x1c, 0x44, 0xd2, 0x1f, 0x74, 0x1b, 0xc7, 0x93, 0x17, 0x5e, 0x31, 0x31, 0x0b, 0x95, 0x50, + }; + + var actual = new TripleDesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CBC, pkcs7Padding: false).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new TripleDesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CBC, pkcs7Padding: false).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] + public void TripleDes_CBC_Length32_Pad() + { + var input = new byte[] + { + 0x35, 0x52, 0x79, 0xad, 0x95, 0x01, 0x6f, 0x36, 0x9b, 0x2e, 0xde, 0xfc, 0x77, 0xc7, 0xc0, 0x27, + 0x60, 0x6b, 0x78, 0xfc, 0x13, 0x83, 0xa8, 0x38, 0xbb, 0x65, 0xca, 0xfd, 0x94, 0x82, 0xde, 0x38, + }; + var key = new byte[] + { + 0x99, 0x28, 0x8c, 0xc4, 0x84, 0xfd, 0x32, 0x8c, 0xca, 0x16, 0x06, 0xcc, 0x00, 0x22, 0xd2, 0x76, + 0x00, 0x0d, 0x25, 0xa9, 0x4e, 0x31, 0x25, 0xb1, + }; + var iv = new byte[] + { + 0xaa, 0x40, 0xf1, 0x2f, 0x36, 0x72, 0xa2, 0x18, + }; + + // echo -n -e '\x35\x52\x79\xad\x95\x01\x6f\x36\x9b\x2e\xde\xfc\x77\xc7\xc0\x27\x60\x6b\x78\xfc\x13\x83\xa8\x38\xbb\x65\xca\xfd\x94\x82\xde\x38' | openssl enc -e -des-ede3-cbc -K 99288CC484FD328CCA1606CC0022D276000D25A94E3125B1 -iv AA40F12F3672A218 | hd + var expected = new byte[] + { + 0x0f, 0x9a, 0xb5, 0xc9, 0x30, 0xac, 0xd0, 0x64, 0xaf, 0xdd, 0x5e, 0x0a, 0x89, 0xda, 0xe3, 0xcb, + 0x08, 0xa1, 0x82, 0x1f, 0x76, 0xd5, 0x3b, 0x59, 0x3a, 0x61, 0xff, 0x87, 0x11, 0xa9, 0x40, 0x5a, + 0x74, 0x04, 0x8c, 0x1f, 0xa4, 0xca, 0x1b, 0xf7, + }; + + var actual = new TripleDesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CBC, pkcs7Padding: true).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new TripleDesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CBC, pkcs7Padding: true).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] + public void TripleDes_CFB_Length8_NoPad() + { + var input = new byte[] + { + 0x4f, 0xa6, 0x62, 0x4f, 0x3b, 0xfb, 0xa3, 0x63, + }; + var key = new byte[] + { + 0x38, 0xec, 0x32, 0xfd, 0x7d, 0xdb, 0x38, 0x99, 0x93, 0x53, 0xfc, 0x86, 0x5d, 0x35, 0xe9, 0x68, + 0x02, 0xda, 0x1a, 0x43, 0x0b, 0x02, 0x55, 0x57, + }; + var iv = new byte[] + { + 0x74, 0xed, 0x7d, 0x5a, 0xbf, 0x82, 0x3b, 0x05, + }; + + // echo -n -e '\x4f\xa6\x62\x4f\x3b\xfb\xa3\x63' | openssl enc -e -des-ede3-cfb -K 38EC32FD7DDB38999353FC865D35E96802DA1A430B025557 -iv 74ED7D5ABF823B05 -nopad | hd + var expected = new byte[] + { + 0x28, 0x48, 0x3f, 0xb4, 0x48, 0xce, 0x96, 0xaf, + }; + + var actual = new TripleDesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CFB, pkcs7Padding: false).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new TripleDesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CFB, pkcs7Padding: false).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] + public void TripleDes_CFB_Length17_NoPad() + { + var input = new byte[] + { + 0x6a, 0xc2, 0x70, 0x62, 0xff, 0x28, 0x34, 0xce, 0x08, 0x58, 0x9c, 0xe3, 0x76, 0x1b, 0xbb, 0x1a, + 0xbc, + }; + var key = new byte[] + { + 0xf9, 0x4c, 0x60, 0xe1, 0x5f, 0x57, 0x35, 0x96, 0xda, 0x89, 0x8f, 0x5e, 0xde, 0xd9, 0x10, 0x17, + 0xf6, 0x1b, 0x9a, 0xc4, 0x87, 0x69, 0xda, 0xa5, + }; + var iv = new byte[] + { + 0x4b, 0x3b, 0xb3, 0x66, 0x71, 0xe0, 0x58, 0x31, + }; + + // echo -n -e '\x6a\xc2\x70\x62\xff\x28\x34\xce\x08\x58\x9c\xe3\x76\x1b\xbb\x1a\xbc' | openssl enc -e -des-ede3-cfb -K F94C60E15F573596DA898F5EDED91017F61B9AC48769DAA5 -iv 4B3BB36671E05831 -nopad | hd + var expected = new byte[] + { + 0x5a, 0x7e, 0x55, 0x4d, 0x63, 0xc1, 0x80, 0x32, 0x84, 0xdc, 0xd0, 0xa7, 0x6c, 0xea, 0x65, 0x42, + 0xc3, + }; + + var actual = new TripleDesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CFB, pkcs7Padding: false).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new TripleDesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CFB, pkcs7Padding: false).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] + public void TripleDes_CFB_Length32_NoPad() + { + var input = new byte[] + { + 0x62, 0x9d, 0xc6, 0x36, 0xda, 0x23, 0x0b, 0x6b, 0x3b, 0xcb, 0x24, 0x9f, 0xa4, 0x6f, 0x29, 0x7e, + 0x8b, 0xcb, 0x7f, 0xff, 0x21, 0x56, 0x34, 0x90, 0x72, 0xba, 0x95, 0x23, 0xa3, 0xcf, 0x25, 0xfa, + }; + var key = new byte[] + { + 0x30, 0x5e, 0xfc, 0x40, 0x13, 0xda, 0x3d, 0xd3, 0x10, 0x2f, 0x89, 0xbc, 0x44, 0x3a, 0x01, 0xdb, + 0x11, 0x34, 0xda, 0xa5, 0x60, 0x58, 0x10, 0x0c, + }; + var iv = new byte[] + { + 0x69, 0x35, 0xc3, 0x1f, 0x8d, 0xe7, 0xc7, 0x6b, + }; + + // echo -n -e '\x62\x9d\xc6\x36\xda\x23\x0b\x6b\x3b\xcb\x24\x9f\xa4\x6f\x29\x7e\x8b\xcb\x7f\xff\x21\x56\x34\x90\x72\xba\x95\x23\xa3\xcf\x25\xfa' | openssl enc -e -des-ede3-cfb -K 305EFC4013DA3DD3102F89BC443A01DB1134DAA56058100C -iv 6935C31F8DE7C76B -nopad | hd + var expected = new byte[] + { + 0xb8, 0xcf, 0xf4, 0xf9, 0x88, 0xfd, 0x02, 0xf1, 0xb9, 0xe9, 0xf0, 0xb3, 0x1d, 0x0a, 0x9b, 0x91, + 0x30, 0x3e, 0xf7, 0xa2, 0xf6, 0xb4, 0xa5, 0xc4, 0x4d, 0x89, 0x06, 0xed, 0x55, 0xd3, 0x28, 0xd0, + }; + + var actual = new TripleDesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CFB, pkcs7Padding: false).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new TripleDesCipher(key, (byte[])iv.Clone(), BlockCipherMode.CFB, pkcs7Padding: false).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); } } }