forked from sshnet/SSH.NET
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathAesCipher.BclImpl.cs
More file actions
144 lines (124 loc) · 5.51 KB
/
AesCipher.BclImpl.cs
File metadata and controls
144 lines (124 loc) · 5.51 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
using System;
using System.Security.Cryptography;
using Renci.SshNet.Common;
namespace Renci.SshNet.Security.Cryptography.Ciphers
{
public partial class AesCipher
{
private sealed class BclImpl : BlockCipher, IDisposable
{
private readonly Aes _aes;
private readonly ICryptoTransform _encryptor;
private readonly ICryptoTransform _decryptor;
public BclImpl(
byte[] key,
byte[] iv,
System.Security.Cryptography.CipherMode cipherMode,
PaddingMode paddingMode)
: base(key, 16, mode: null, padding: null)
{
var aes = Aes.Create();
aes.Key = key;
if (cipherMode != System.Security.Cryptography.CipherMode.ECB)
{
ThrowHelper.ThrowIfNull(iv);
aes.IV = iv.Take(16);
}
aes.Mode = cipherMode;
aes.Padding = paddingMode;
aes.FeedbackSize = 128; // We use CFB128
_aes = aes;
_encryptor = aes.CreateEncryptor();
_decryptor = aes.CreateDecryptor();
}
public override byte[] Encrypt(byte[] input, int offset, int length)
{
if (_aes.Padding != PaddingMode.None)
{
// If padding has been specified, call TransformFinalBlock to apply
// the padding and reset the state.
return _encryptor.TransformFinalBlock(input, offset, length);
}
var paddingLength = 0;
if (length % BlockSize > 0)
{
if (_aes.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;
}
}
// 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)
{
Array.Resize(ref output, output.Length - paddingLength);
}
return output;
}
public override byte[] Decrypt(byte[] input, int offset, int length)
{
if (_aes.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 (_aes.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;
}
}
// 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 Decrypt.
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)}.");
}
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);
}
}
}
}