Skip to content

Commit 5cc5d4a

Browse files
author
Pedro Fonseca
committed
fix rebase issues
restructure AES CSP code into its own class
1 parent 75fa982 commit 5cc5d4a

File tree

4 files changed

+271
-194
lines changed

4 files changed

+271
-194
lines changed

src/Renci.SshNet/Renci.SshNet.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
</PropertyGroup>
77

88
<PropertyGroup Condition=" '$(TargetFramework)' == 'net462' ">
9-
<DefineConstants>FEATURE_BINARY_SERIALIZATION;FEATURE_SOCKET_EAP;FEATURE_SOCKET_APM;FEATURE_DNS_SYNC;FEATURE_HASH_RIPEMD160_CREATE;FEATURE_HMAC_RIPEMD160</DefineConstants>
9+
<DefineConstants>FEATURE_BINARY_SERIALIZATION;FEATURE_SOCKET_EAP;FEATURE_SOCKET_APM;FEATURE_DNS_SYNC;FEATURE_HASH_RIPEMD160_CREATE;FEATURE_HMAC_RIPEMD160;FEATURE_AES_CSP</DefineConstants>
1010
</PropertyGroup>
1111

1212
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' or '$(TargetFramework)' == 'netstandard2.1' or '$(TargetFramework)' == 'net6.0' or '$(TargetFramework)' == 'net7.0' ">

src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.cs

Lines changed: 28 additions & 192 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
using System;
22
using System.Globalization;
33
using Renci.SshNet.Common;
4-
using csp = System.Security.Cryptography;
54

65
namespace Renci.SshNet.Security.Cryptography.Ciphers
76
{
@@ -14,20 +13,15 @@ public sealed class AesCipher : BlockCipher
1413
private const uint M2 = 0x7f7f7f7f;
1514
private const uint M3 = 0x0000001b;
1615

16+
private readonly AesCipherCSP _aesCSP;
17+
1718
private int _rounds;
1819
private uint[] _encryptionKey;
1920
private uint[] _decryptionKey;
20-
private uint C0, C1, C2, C3;
21-
22-
#if FEATURE_AES_CSP
23-
private csp.ICryptoTransform aesDecryptor;
24-
private csp.ICryptoTransform aesEncryptor;
25-
private bool useCSP; // set to false when CSP is not available for a given mode; falls back to legacy code
26-
private bool isCTRMode;
27-
private uint[] _ctrIV;
28-
29-
CipherPadding _padding;
30-
#endif
21+
private uint _c0;
22+
private uint _c1;
23+
private uint _c2;
24+
private uint _c3;
3125

3226
#region Static Definition Tables
3327

@@ -580,10 +574,8 @@ public AesCipher(byte[] key, CipherMode mode, CipherPadding padding)
580574
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "KeySize '{0}' is not valid for this algorithm.", keySize));
581575
}
582576

583-
#if FEATURE_AES_CSP
584577
// initialize AesCryptoServiceProvider which uses AES-NI (faster, less CPU usage)
585-
useCSP = initCryptoServiceProvider(mode, padding);
586-
#endif
578+
_aesCSP = new AesCipherCSP(key, 16, mode, padding);
587579
}
588580

589581
/// <summary>
@@ -678,199 +670,43 @@ public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputC
678670
return BlockSize;
679671
}
680672

681-
#if FEATURE_AES_CSP
682-
683673
/// <summary>
684-
/// Encrypts the specified data using AesCryptoServiceProvider
674+
/// Encrypts the specified data using CSP acceleration if enabled.
685675
/// </summary>
686-
/// <param name="data">The data.</param>
687-
/// <param name="offset">The zero-based offset in <paramref name="data"/> at which to begin encrypting.</param>
688-
/// <param name="length">The number of bytes to encrypt from <paramref name="data"/>.</param>
689-
/// <returns>Encrypted data</returns>
690-
public override byte[] Encrypt(byte[] data, int offset, int length)
676+
/// <param name="input">The data.</param>
677+
/// <param name="offset">The zero-based offset in <paramref name="input"/> at which to begin encrypting.</param>
678+
/// <param name="length">The number of bytes to encrypt from <paramref name="input"/>.</param>
679+
/// <returns>
680+
/// The encrypted data.
681+
/// </returns>
682+
public override byte[] Encrypt(byte[] input, int offset, int length)
691683
{
692-
if (useCSP)
684+
if (_aesCSP.IsCSPEnabled)
693685
{
694-
if (length % BlockSize > 0)
695-
{
696-
if (_padding == null)
697-
{
698-
throw new ArgumentException("data");
699-
}
700-
data = _padding.Pad(BlockSize, data, offset, length);
701-
offset = 0;
702-
length = data.Length;
703-
}
704-
705-
if (isCTRMode)
706-
return CTREncryptDecrypt(data, offset, length);
707-
else
708-
{
709-
byte[] output = new byte[length];
710-
aesEncryptor.TransformBlock(data, offset, length, output, 0);
711-
return output;
712-
}
686+
return _aesCSP.Encrypt(input, offset, length);
713687
}
714-
else
715-
return base.Encrypt(data, offset, length);
688+
689+
return base.Encrypt(input, offset, length);
716690
}
717691

718692
/// <summary>
719-
/// Decrypts the specified input using AesCryptoServiceProvider
693+
/// Encrypts the specified data using CSP acceleration if enabled.
720694
/// </summary>
721-
/// <param name="data">The input.</param>
722-
/// <param name="offset">The zero-based offset in <paramref name="data"/> at which to begin decrypting.</param>
723-
/// <param name="length">The number of bytes to decrypt from <paramref name="data"/>.</param>
695+
/// <param name="input">The data.</param>
696+
/// <param name="offset">The zero-based offset in <paramref name="input"/> at which to begin encrypting.</param>
697+
/// <param name="length">The number of bytes to encrypt from <paramref name="input"/>.</param>
724698
/// <returns>
725-
/// The decrypted data.
699+
/// The encrypted data.
726700
/// </returns>
727-
public override byte[] Decrypt(byte[] data, int offset, int length)
701+
public override byte[] Decrypt(byte[] input, int offset, int length)
728702
{
729-
if (useCSP)
703+
if (_aesCSP.IsCSPEnabled)
730704
{
731-
if (length % BlockSize > 0)
732-
{
733-
if (_padding == null)
734-
{
735-
throw new ArgumentException("data");
736-
}
737-
data = _padding.Pad(BlockSize, data, offset, length);
738-
offset = 0;
739-
length = data.Length;
740-
}
741-
742-
if (isCTRMode)
743-
return CTREncryptDecrypt(data, offset, length);
744-
else
745-
{
746-
byte[] output = new byte[length];
747-
aesDecryptor.TransformBlock(data, offset, length, output, 0);
748-
return output;
749-
}
705+
return _aesCSP.Decrypt(input, offset, length);
750706
}
751-
else
752-
return base.Encrypt(data, offset, length);
753-
}
754-
755-
// initialize AesCryptoServiceProvider
756-
private bool initCryptoServiceProvider(CipherMode mode, CipherPadding padding)
757-
{
758-
try
759-
{
760-
// use the provided CipherPadding object
761-
_padding = padding;
762-
csp.PaddingMode cspPadding = csp.PaddingMode.None;
763-
764-
// set the Mode
765-
csp.CipherMode cspMode = 0;
766-
isCTRMode = mode is Modes.CtrCipherMode;
767-
768-
if (mode is Modes.CbcCipherMode)
769-
cspMode = csp.CipherMode.CBC;
770-
else if (isCTRMode)
771-
cspMode = csp.CipherMode.ECB; // CTR uses ECB
772-
else
773-
return false; // OFB and CFB not supported, fallback to managed code
774-
775-
// prepare IV array for CTR mode
776-
if (isCTRMode)
777-
_ctrIV = GetPackedIV(mode.IV);
778-
779-
// create ICryptoTransform instances
780-
var aesProvider = new csp.AesCryptoServiceProvider()
781-
{
782-
BlockSize = BlockSize * 8,
783-
KeySize = Key.Length * 8,
784-
Mode = cspMode,
785-
Padding = cspPadding,
786-
Key = Key,
787-
IV = mode.IV,
788-
};
789-
aesEncryptor = aesProvider.CreateEncryptor(Key, mode.IV);
790-
aesDecryptor = aesProvider.CreateDecryptor(Key, mode.IV);
791-
return true;
792-
}
793-
catch { } // fallback for unsupported key/iv/blocksize combinations
794-
return false;
795-
}
796-
797-
// convert the IV into an array of uint[4]
798-
private uint[] GetPackedIV(byte[] iv)
799-
{
800-
uint[] packedIV = new uint[4];
801-
packedIV[0] = (uint)((iv[0] << 24) | (iv[1] << 16) | (iv[2] << 8) | (iv[3]));
802-
packedIV[1] = (uint)((iv[4] << 24) | (iv[5] << 16) | (iv[6] << 8) | (iv[7]));
803-
packedIV[2] = (uint)((iv[8] << 24) | (iv[9] << 16) | (iv[10] << 8) | (iv[11]));
804-
packedIV[3] = (uint)((iv[12] << 24) | (iv[13] << 16) | (iv[14] << 8) | (iv[15]));
805-
return packedIV;
806-
}
807-
808-
// Perform AES-CTR encryption/decryption
809-
private byte[] CTREncryptDecrypt(byte[] data, int offset, int length)
810-
{
811-
int count = length / BlockSize;
812-
if (length % BlockSize != 0) count++;
813-
814-
byte[] counter = CTRCreateCounterArray(count);
815-
byte[] aesCounter = aesEncryptor.TransformFinalBlock(counter, 0, counter.Length);
816-
byte[] output = CTRArrayXOR(aesCounter, data, offset, length);
817-
818-
return output;
819-
}
820-
821-
// creates the Counter array filled with incrementing copies of IV
822-
private byte[] CTRCreateCounterArray(int blocks)
823-
{
824-
// fill an array with IV, increment by 1 for each copy
825-
uint[] counter = new uint[blocks * 4];
826-
for (int i = 0; i < counter.Length; i += 4)
827-
{
828-
// write IV to buffer (big endian)
829-
counter[i] = (_ctrIV[0] << 24) | ((_ctrIV[0] << 8) & 0x00FF0000) | ((_ctrIV[0] >> 8) & 0x0000FF00) | (_ctrIV[0] >> 24);
830-
counter[i + 1] = (_ctrIV[1] << 24) | ((_ctrIV[1] << 8) & 0x00FF0000) | ((_ctrIV[1] >> 8) & 0x0000FF00) | (_ctrIV[1] >> 24);
831-
counter[i + 2] = (_ctrIV[2] << 24) | ((_ctrIV[2] << 8) & 0x00FF0000) | ((_ctrIV[2] >> 8) & 0x0000FF00) | (_ctrIV[2] >> 24);
832-
counter[i + 3] = (_ctrIV[3] << 24) | ((_ctrIV[3] << 8) & 0x00FF0000) | ((_ctrIV[3] >> 8) & 0x0000FF00) | (_ctrIV[3] >> 24);
833-
834-
// increment IV (little endian)
835-
for (int j = 3; j >= 0 && ++_ctrIV[j] == 0; j--) ;
836-
}
837-
838-
// copy uint[] to byte[]
839-
byte[] counterBytes = new byte[blocks * 16];
840-
System.Buffer.BlockCopy(counter, 0, counterBytes, 0, counterBytes.Length);
841-
return counterBytes;
842-
}
843-
844-
// XORs the input data with the encrypted Counter array to produce the final output
845-
// uses uint arrays for speed
846-
private byte[] CTRArrayXOR(byte[] counter, byte[] data, int offset, int length)
847-
{
848-
int words = length / 4;
849-
if (length % 4 != 0) words++;
850-
851-
// convert original data to words
852-
uint[] datawords = new uint[words];
853-
System.Buffer.BlockCopy(data, offset, datawords, 0, length);
854-
855-
// convert encrypted IV counter to words
856-
uint[] counterwords = new uint[words];
857-
System.Buffer.BlockCopy(counter, 0, counterwords, 0, length);
858-
859-
// XOR encrypted Counter with input data
860-
for (int i = 0; i < words; i++)
861-
counterwords[i] = counterwords[i] ^ datawords[i];
862-
863-
// copy uint[] to byte[]
864-
byte[] output = counter;
865-
System.Buffer.BlockCopy(counterwords, 0, output, 0, length);
866-
867-
// adjust output for non-aligned lengths
868-
if (output.Length > length)
869-
Array.Resize(ref output, length);
870707

871-
return output;
708+
return base.Encrypt(input, offset, length);
872709
}
873-
#endif
874710

875711
private uint[] GenerateWorkingKey(bool isEncryption, byte[] key)
876712
{

0 commit comments

Comments
 (0)