1
- #if NET6_0_OR_GREATER
2
- using System ;
1
+ using System ;
3
2
using System . Buffers . Binary ;
4
3
using System . Diagnostics ;
5
- using System . Security . Cryptography ;
6
4
7
5
using Renci . SshNet . Common ;
8
6
@@ -12,10 +10,16 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
12
10
/// AES GCM cipher implementation.
13
11
/// <see href="https://datatracker.ietf.org/doc/html/rfc5647"/>.
14
12
/// </summary>
15
- internal sealed class AesGcmCipher : SymmetricCipher , IDisposable
13
+ internal sealed partial class AesGcmCipher : SymmetricCipher , IDisposable
16
14
{
15
+ private const int PacketLengthFieldLength = 4 ;
16
+ private const int TagSizeInBytes = 16 ;
17
17
private readonly byte [ ] _iv ;
18
- private readonly AesGcm _aesGcm ;
18
+ #if NET6_0_OR_GREATER
19
+ private readonly Impl _impl ;
20
+ #else
21
+ private readonly BouncyCastleImpl _impl ;
22
+ #endif
19
23
20
24
/// <summary>
21
25
/// Gets the minimun block size.
@@ -42,7 +46,7 @@ public override int TagSize
42
46
{
43
47
get
44
48
{
45
- return 16 ;
49
+ return TagSizeInBytes ;
46
50
}
47
51
}
48
52
@@ -56,11 +60,16 @@ public AesGcmCipher(byte[] key, byte[] iv)
56
60
{
57
61
// SSH AES-GCM requires a 12-octet Initial IV
58
62
_iv = iv . Take ( 12 ) ;
59
- #if NET8_0_OR_GREATER
60
- _aesGcm = new AesGcm ( key , TagSize ) ;
61
- #else
62
- _aesGcm = new AesGcm ( key ) ;
63
+ #if NET6_0_OR_GREATER
64
+ if ( System . Security . Cryptography . AesGcm . IsSupported )
65
+ {
66
+ _impl = new BclImpl ( key , _iv ) ;
67
+ }
68
+ else
63
69
#endif
70
+ {
71
+ _impl = new BouncyCastleImpl ( key , _iv ) ;
72
+ }
64
73
}
65
74
66
75
/// <summary>
@@ -84,15 +93,17 @@ public AesGcmCipher(byte[] key, byte[] iv)
84
93
/// </returns>
85
94
public override byte [ ] Encrypt ( byte [ ] input , int offset , int length )
86
95
{
87
- var packetLengthField = new ReadOnlySpan < byte > ( input , offset , 4 ) ;
88
- var plainText = new ReadOnlySpan < byte > ( input , offset + 4 , length - 4 ) ;
89
-
90
96
var output = new byte [ length + TagSize ] ;
91
- packetLengthField . CopyTo ( output ) ;
92
- var cipherText = new Span < byte > ( output , 4 , length - 4 ) ;
93
- var tag = new Span < byte > ( output , length , TagSize ) ;
97
+ Buffer . BlockCopy ( input , offset , output , 0 , PacketLengthFieldLength ) ;
94
98
95
- _aesGcm . Encrypt ( nonce : _iv , plainText , cipherText , tag , associatedData : packetLengthField ) ;
99
+ _impl . Encrypt (
100
+ input ,
101
+ plainTextOffset : offset + PacketLengthFieldLength ,
102
+ plainTextLength : length - PacketLengthFieldLength ,
103
+ associatedDataOffset : offset ,
104
+ associatedDataLength : PacketLengthFieldLength ,
105
+ output ,
106
+ cipherTextOffset : PacketLengthFieldLength ) ;
96
107
97
108
IncrementCounter ( ) ;
98
109
@@ -122,14 +133,16 @@ public override byte[] Decrypt(byte[] input, int offset, int length)
122
133
{
123
134
Debug . Assert ( offset == 8 , "The offset must be 8" ) ;
124
135
125
- var packetLengthField = new ReadOnlySpan < byte > ( input , 4 , 4 ) ;
126
- var cipherText = new ReadOnlySpan < byte > ( input , offset , length ) ;
127
- var tag = new ReadOnlySpan < byte > ( input , offset + length , TagSize ) ;
128
-
129
136
var output = new byte [ length ] ;
130
- var plainText = new Span < byte > ( output ) ;
131
137
132
- _aesGcm . Decrypt ( nonce : _iv , cipherText , tag , plainText , associatedData : packetLengthField ) ;
138
+ _impl . Decrypt (
139
+ input ,
140
+ cipherTextOffset : offset ,
141
+ cipherTextLength : length ,
142
+ associatedDataOffset : offset - PacketLengthFieldLength ,
143
+ associatedDataLength : PacketLengthFieldLength ,
144
+ output ,
145
+ plainTextOffset : 0 ) ;
133
146
134
147
IncrementCounter ( ) ;
135
148
@@ -158,7 +171,7 @@ public void Dispose(bool disposing)
158
171
{
159
172
if ( disposing )
160
173
{
161
- _aesGcm . Dispose ( ) ;
174
+ _impl . Dispose ( ) ;
162
175
}
163
176
}
164
177
@@ -169,6 +182,23 @@ public void Dispose()
169
182
Dispose ( disposing : true ) ;
170
183
GC . SuppressFinalize ( this ) ;
171
184
}
185
+
186
+ private abstract class Impl : IDisposable
187
+ {
188
+ public abstract void Encrypt ( byte [ ] input , int plainTextOffset , int plainTextLength , int associatedDataOffset , int associatedDataLength , byte [ ] output , int cipherTextOffset ) ;
189
+
190
+ public abstract void Decrypt ( byte [ ] input , int cipherTextOffset , int cipherTextLength , int associatedDataOffset , int associatedDataLength , byte [ ] output , int plainTextOffset ) ;
191
+
192
+ protected virtual void Dispose ( bool disposing )
193
+ {
194
+ }
195
+
196
+ public void Dispose ( )
197
+ {
198
+ // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
199
+ Dispose ( disposing : true ) ;
200
+ GC . SuppressFinalize ( this ) ;
201
+ }
202
+ }
172
203
}
173
204
}
174
- #endif
0 commit comments