Skip to content

Commit d53c12c

Browse files
authored
Merge pull request #1 from Rob-Hague/feature_AES_CSP
Factor out the implementations and re-add the existing constructor
2 parents 0d5ecd9 + 36cea67 commit d53c12c

File tree

7 files changed

+688
-644
lines changed

7 files changed

+688
-644
lines changed

.editorconfig

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,9 @@ dotnet_diagnostic.SA1520.severity = none
291291
# We do not use file headers.
292292
dotnet_diagnostic.SA1633.severity = none
293293

294+
# SA1601: Partial elements should be documented
295+
dotnet_diagnostic.SA1601.severity = none
296+
294297
# SA1648: <inheritdoc> must be used with inheriting class
295298
#
296299
# This rule is disabled by default, hence we need to explicitly enable it.
@@ -555,6 +558,18 @@ dotnet_code_quality.CA1859.api_surface = all
555558
# This is similar to, but less powerful than, MA0015.
556559
dotnet_diagnostic.CA2208.severity = none
557560

561+
# CA5358: Do Not Use Unsafe Cipher Modes / Review cipher mode usage with cryptography experts
562+
# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca5358
563+
#
564+
# We use ECB mode as the basis for other modes (e.g. CTR)
565+
dotnet_diagnostic.CA5358.severity = none
566+
567+
# CA5401: Do not use CreateEncryptor with non-default IV
568+
# https://learn.microsoft.com/en-gb/dotnet/fundamentals/code-analysis/quality-rules/ca5401
569+
#
570+
# We need to specify the IV.
571+
dotnet_diagnostic.CA5401.severity = none
572+
558573
#### Roslyn IDE analyser rules ####
559574

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

0 commit comments

Comments
 (0)