1- #if NET6_0_OR_GREATER
2- using System ;
1+ using System ;
32using System . Buffers . Binary ;
43using System . Diagnostics ;
5- using System . Security . Cryptography ;
64
75using Renci . SshNet . Common ;
86
@@ -12,10 +10,16 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
1210 /// AES GCM cipher implementation.
1311 /// <see href="https://datatracker.ietf.org/doc/html/rfc5647"/>.
1412 /// </summary>
15- internal sealed class AesGcmCipher : SymmetricCipher , IDisposable
13+ internal sealed partial class AesGcmCipher : SymmetricCipher , IDisposable
1614 {
15+ private const int PacketLengthFieldLength = 4 ;
16+ private const int TagSizeInBytes = 16 ;
1717 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
1923
2024 /// <summary>
2125 /// Gets the minimun block size.
@@ -42,7 +46,7 @@ public override int TagSize
4246 {
4347 get
4448 {
45- return 16 ;
49+ return TagSizeInBytes ;
4650 }
4751 }
4852
@@ -56,11 +60,16 @@ public AesGcmCipher(byte[] key, byte[] iv)
5660 {
5761 // SSH AES-GCM requires a 12-octet Initial IV
5862 _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
6369#endif
70+ {
71+ _impl = new BouncyCastleImpl ( key , _iv ) ;
72+ }
6473 }
6574
6675 /// <summary>
@@ -84,15 +93,17 @@ public AesGcmCipher(byte[] key, byte[] iv)
8493 /// </returns>
8594 public override byte [ ] Encrypt ( byte [ ] input , int offset , int length )
8695 {
87- var packetLengthField = new ReadOnlySpan < byte > ( input , offset , 4 ) ;
88- var plainText = new ReadOnlySpan < byte > ( input , offset + 4 , length - 4 ) ;
89-
9096 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 ) ;
9498
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 ) ;
96107
97108 IncrementCounter ( ) ;
98109
@@ -122,14 +133,16 @@ public override byte[] Decrypt(byte[] input, int offset, int length)
122133 {
123134 Debug . Assert ( offset == 8 , "The offset must be 8" ) ;
124135
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-
129136 var output = new byte [ length ] ;
130- var plainText = new Span < byte > ( output ) ;
131137
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 ) ;
133146
134147 IncrementCounter ( ) ;
135148
@@ -158,7 +171,7 @@ public void Dispose(bool disposing)
158171 {
159172 if ( disposing )
160173 {
161- _aesGcm . Dispose ( ) ;
174+ _impl . Dispose ( ) ;
162175 }
163176 }
164177
@@ -169,6 +182,23 @@ public void Dispose()
169182 Dispose ( disposing : true ) ;
170183 GC . SuppressFinalize ( this ) ;
171184 }
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+ }
172203 }
173204}
174- #endif
0 commit comments