| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130 |
- 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)
- {
- // Manually pad the input for cfb and ofb cipher mode as BCL doesn't support partial block.
- // See https://github.com/dotnet/runtime/blob/e7d837da5b1aacd9325a8b8f2214cfaf4d3f0ff6/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/SymmetricPadding.cs#L20-L21
- paddingLength = BlockSize - (length % BlockSize);
- input = input.Take(offset, length);
- length += paddingLength;
- Array.Resize(ref input, length);
- offset = 0;
- }
- }
- // Otherwise, (the most important case) assume this instance is
- // used for one direction of an SSH connection, whereby the
- // encrypted data in all packets are considered a single data
- // stream i.e. we do not want to reset the state between calls to Encrypt.
- var output = new byte[length];
- _ = _encryptor.TransformBlock(input, offset, length, output, 0);
- if (paddingLength > 0)
- {
- // Manually unpad the output.
- Array.Resize(ref output, output.Length - paddingLength);
- }
- return output;
- }
- public override byte[] Decrypt(byte[] input, int offset, int length)
- {
- if (_des.Padding != PaddingMode.None)
- {
- // If padding has been specified, call TransformFinalBlock to apply
- // the padding and reset the state.
- 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)
- {
- // Manually pad the input for cfb and ofb cipher mode as BCL doesn't support partial block.
- // See https://github.com/dotnet/runtime/blob/e7d837da5b1aacd9325a8b8f2214cfaf4d3f0ff6/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/SymmetricPadding.cs#L20-L21
- paddingLength = BlockSize - (length % BlockSize);
- input = input.Take(offset, length);
- length += paddingLength;
- Array.Resize(ref input, length);
- offset = 0;
- }
- }
- // Otherwise, (the most important case) assume this instance is
- // used for one direction of an SSH connection, whereby the
- // encrypted data in all packets are considered a single data
- // stream i.e. we do not want to reset the state between calls to Encrypt.
- var output = new byte[length];
- _ = _decryptor.TransformBlock(input, offset, length, output, 0);
- if (paddingLength > 0)
- {
- // Manually unpad the output.
- 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();
- }
- }
- }
- }
|