2
0

AesCipher.BclImpl.cs 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. using System;
  2. using System.Security.Cryptography;
  3. using Renci.SshNet.Common;
  4. namespace Renci.SshNet.Security.Cryptography.Ciphers
  5. {
  6. public partial class AesCipher
  7. {
  8. private sealed class BclImpl : BlockCipher, IDisposable
  9. {
  10. private readonly Aes _aes;
  11. private readonly ICryptoTransform _encryptor;
  12. private readonly ICryptoTransform _decryptor;
  13. public BclImpl(
  14. byte[] key,
  15. byte[] iv,
  16. System.Security.Cryptography.CipherMode cipherMode,
  17. PaddingMode paddingMode)
  18. : base(key, 16, mode: null, padding: null)
  19. {
  20. var aes = Aes.Create();
  21. aes.Key = key;
  22. if (cipherMode != System.Security.Cryptography.CipherMode.ECB)
  23. {
  24. ThrowHelper.ThrowIfNull(iv);
  25. aes.IV = iv.Take(16);
  26. }
  27. aes.Mode = cipherMode;
  28. aes.Padding = paddingMode;
  29. aes.FeedbackSize = 128; // We use CFB128
  30. _aes = aes;
  31. _encryptor = aes.CreateEncryptor();
  32. _decryptor = aes.CreateDecryptor();
  33. }
  34. public override byte[] Encrypt(byte[] input, int offset, int length)
  35. {
  36. if (_aes.Padding != PaddingMode.None)
  37. {
  38. // If padding has been specified, call TransformFinalBlock to apply
  39. // the padding and reset the state.
  40. return _encryptor.TransformFinalBlock(input, offset, length);
  41. }
  42. // Otherwise, (the most important case) assume this instance is
  43. // used for one direction of an SSH connection, whereby the
  44. // encrypted data in all packets are considered a single data
  45. // stream i.e. we do not want to reset the state between calls to Encrypt.
  46. var output = new byte[length];
  47. _ = _encryptor.TransformBlock(input, offset, length, output, 0);
  48. return output;
  49. }
  50. public override byte[] Decrypt(byte[] input, int offset, int length)
  51. {
  52. if (_aes.Padding != PaddingMode.None)
  53. {
  54. // If padding has been specified, call TransformFinalBlock to apply
  55. // the padding and reset the state.
  56. return _decryptor.TransformFinalBlock(input, offset, length);
  57. }
  58. // Otherwise, (the most important case) assume this instance is
  59. // used for one direction of an SSH connection, whereby the
  60. // encrypted data in all packets are considered a single data
  61. // stream i.e. we do not want to reset the state between calls to Decrypt.
  62. var output = new byte[length];
  63. _ = _decryptor.TransformBlock(input, offset, length, output, 0);
  64. return output;
  65. }
  66. public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
  67. {
  68. throw new NotImplementedException($"Invalid usage of {nameof(EncryptBlock)}.");
  69. }
  70. public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
  71. {
  72. throw new NotImplementedException($"Invalid usage of {nameof(DecryptBlock)}.");
  73. }
  74. private void Dispose(bool disposing)
  75. {
  76. if (disposing)
  77. {
  78. _aes.Dispose();
  79. _encryptor.Dispose();
  80. _decryptor.Dispose();
  81. }
  82. }
  83. public void Dispose()
  84. {
  85. // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
  86. Dispose(disposing: true);
  87. GC.SuppressFinalize(this);
  88. }
  89. }
  90. }
  91. }