AesCipher.BclImpl.cs 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  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. if (iv is null)
  25. {
  26. throw new ArgumentNullException(nameof(iv));
  27. }
  28. aes.IV = iv.Take(16);
  29. }
  30. aes.Mode = cipherMode;
  31. aes.Padding = paddingMode;
  32. aes.FeedbackSize = 128; // We use CFB128
  33. _aes = aes;
  34. _encryptor = aes.CreateEncryptor();
  35. _decryptor = aes.CreateDecryptor();
  36. }
  37. public override byte[] Encrypt(byte[] input, int offset, int length)
  38. {
  39. if (_aes.Padding != PaddingMode.None)
  40. {
  41. // If padding has been specified, call TransformFinalBlock to apply
  42. // the padding and reset the state.
  43. return _encryptor.TransformFinalBlock(input, offset, length);
  44. }
  45. // Otherwise, (the most important case) assume this instance is
  46. // used for one direction of an SSH connection, whereby the
  47. // encrypted data in all packets are considered a single data
  48. // stream i.e. we do not want to reset the state between calls to Encrypt.
  49. var output = new byte[length];
  50. _ = _encryptor.TransformBlock(input, offset, length, output, 0);
  51. return output;
  52. }
  53. public override byte[] Decrypt(byte[] input, int offset, int length)
  54. {
  55. if (_aes.Padding != PaddingMode.None)
  56. {
  57. // If padding has been specified, call TransformFinalBlock to apply
  58. // the padding and reset the state.
  59. return _decryptor.TransformFinalBlock(input, offset, length);
  60. }
  61. // Otherwise, (the most important case) assume this instance is
  62. // used for one direction of an SSH connection, whereby the
  63. // encrypted data in all packets are considered a single data
  64. // stream i.e. we do not want to reset the state between calls to Decrypt.
  65. var output = new byte[length];
  66. _ = _decryptor.TransformBlock(input, offset, length, output, 0);
  67. return output;
  68. }
  69. public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
  70. {
  71. throw new NotImplementedException($"Invalid usage of {nameof(EncryptBlock)}.");
  72. }
  73. public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
  74. {
  75. throw new NotImplementedException($"Invalid usage of {nameof(DecryptBlock)}.");
  76. }
  77. private void Dispose(bool disposing)
  78. {
  79. if (disposing)
  80. {
  81. _aes.Dispose();
  82. _encryptor.Dispose();
  83. _decryptor.Dispose();
  84. }
  85. }
  86. public void Dispose()
  87. {
  88. // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
  89. Dispose(disposing: true);
  90. GC.SuppressFinalize(this);
  91. }
  92. }
  93. }
  94. }