Skip to content

Commit e8d21d2

Browse files
committed
Lots of optimizations
Signed-off-by: Alireza Poodineh <itsaeliux@gmail.com>
1 parent b988d41 commit e8d21d2

14 files changed

Lines changed: 254 additions & 71 deletions

Directory.Build.props

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
<NoWarn>SYSLIB0002;SYSLIB0005;SYSLIB0012;SYSLIB0020;CS8002</NoWarn>
2424
<Nullable>disable</Nullable>
2525
<ImplicitUsings>enable</ImplicitUsings>
26+
<Features>strict</Features>
27+
<EnforceCodeStyleInBuild>false</EnforceCodeStyleInBuild>
2628

2729
<SignAssembly>true</SignAssembly>
2830
<AssemblyOriginatorKeyFile>$(MSBuildThisFileDirectory)Kryptor.snk</AssemblyOriginatorKeyFile>

build/Library.props

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
<ProduceReferenceAssembly>True</ProduceReferenceAssembly>
66
<GenerateAssemblyInfo>True</GenerateAssemblyInfo>
77
<IsTrimmable>true</IsTrimmable>
8+
<EnableTrimAnalyzer>true</EnableTrimAnalyzer>
9+
<EnableSingleFileAnalyzer>true</EnableSingleFileAnalyzer>
810
<Deterministic>True</Deterministic>
911

1012
<IncludeSymbols>true</IncludeSymbols>

src/Kryptor.Cli/Kryptor.Cli.csproj

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@
2929
<_PubMode>Aot</_PubMode>
3030
<PublishTrimmed>True</PublishTrimmed>
3131
<PublishAot>True</PublishAot>
32+
<IlcOptimizationPreference>Speed</IlcOptimizationPreference>
33+
<IlcGenerateStackTraceData>false</IlcGenerateStackTraceData>
34+
<EventSourceSupport>false</EventSourceSupport>
35+
<UseSystemResourceKeys>true</UseSystemResourceKeys>
36+
<IlcTrimMetadata>true</IlcTrimMetadata>
3237
</PropertyGroup>
3338

3439
<PropertyGroup Condition="'$(CompileBundled)' == 'True'">

src/Kryptor.Cli/Program.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -127,13 +127,13 @@ public static RootCommand GetRootCommand()
127127
{
128128
BlockSize = parseResult.GetValue(blockSize),
129129
Provider = parseResult.GetValue(provider),
130-
Parameters = parseResult.GetValue(parameters)?.SelectMany(p => p.Split(',')).ToArray() ?? Array.Empty<string>(),
130+
Parameters = parseResult.GetValue(parameters)?.SelectMany(p => p.Split(',')).ToArray() ?? [],
131131
Continuous = parseResult.GetValue(continuous),
132132
RemoveHash = parseResult.GetValue(removeHash),
133133
DynamicBlockProcessing = parseResult.GetValue(dbp),
134134
OutputPath = parseResult.GetValue(outputPath),
135135
KeyStore = parseResult.GetValue(keystore),
136-
Files = parseResult.GetValue(files) ?? Array.Empty<string>()
136+
Files = parseResult.GetValue(files) ?? []
137137
};
138138

139139
EncryptionSessionHost sessionHost = new EncryptionSessionHost(globalOptions, dpo, parseResult.GetValue(hVerbose), parseResult.GetValue(keyChain), parseResult.GetValue(obfuscate));
@@ -166,13 +166,13 @@ public static RootCommand GetRootCommand()
166166
{
167167
BlockSize = parseResult.GetValue(blockSize),
168168
Provider = parseResult.GetValue(provider),
169-
Parameters = parseResult.GetValue(parameters)?.SelectMany(p => p.Split(',')).ToArray() ?? Array.Empty<string>(),
169+
Parameters = parseResult.GetValue(parameters)?.SelectMany(p => p.Split(',')).ToArray() ?? [],
170170
Continuous = parseResult.GetValue(continuous),
171171
RemoveHash = parseResult.GetValue(removeHash),
172172
DynamicBlockProcessing = parseResult.GetValue(dbp),
173173
OutputPath = parseResult.GetValue(outputPath),
174174
KeyStore = parseResult.GetValue(keystore),
175-
Files = parseResult.GetValue(files) ?? Array.Empty<string>()
175+
Files = parseResult.GetValue(files) ?? []
176176
};
177177

178178
DecryptionSessionHost sessionHost = new DecryptionSessionHost(globalOptions, dpo);

src/Kryptor/CryptoProcess.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,12 @@ public void InitializeData()
4545
if (!_initialized)
4646
{
4747
BlockIndex = 0;
48-
BlockHash = Array.Empty<byte>();
48+
BlockHash = [];
4949

5050
ChunkIndex = 0;
5151

52-
BlockData = new Dictionary<string, object>();
53-
ProcessData = new Dictionary<string, object>();
52+
BlockData = [];
53+
ProcessData = [];
5454

5555
_initialized = true;
5656
}
@@ -61,7 +61,7 @@ internal void NextBlock(bool resetChunk)
6161
BlockIndex++;
6262

6363
BlockData.Clear();
64-
BlockHash = Array.Empty<byte>();
64+
BlockHash = [];
6565

6666
if (resetChunk)
6767
{

src/Kryptor/CryptoProvider.cs

Lines changed: 46 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
using SAPTeam.Kryptor.CryptoProviders;
1+
using System.Runtime.CompilerServices;
2+
3+
using SAPTeam.Kryptor.CryptoProviders;
24
using SAPTeam.Kryptor.Extensions;
35
using SAPTeam.Kryptor.Helpers;
46

@@ -143,14 +145,26 @@ public virtual async Task<byte[]> EncryptBlockAsync(byte[] data, CryptoProcess p
143145
process.ChunkIndex = 0;
144146
}
145147

146-
process.BlockHash = Configuration.RemoveHash ? Array.Empty<byte>() : data.Sha256();
148+
process.BlockHash = Configuration.RemoveHash ? [] : data.Sha256();
147149
byte[] hash = Configuration.DynamicBlockProcessing ? Transformers.Rotate(process.BlockHash, DynamicEncryption.GetDynamicBlockEntropy(KeyStore, process)) : process.BlockHash;
148-
List<byte> result = new List<byte>(hash);
150+
151+
// Pre-calculate capacity: hash + (chunks * chunk size)
152+
int estimatedChunks = (data.Length + EncryptionChunkSize - 1) / EncryptionChunkSize;
153+
List<byte> result = new List<byte>(hash.Length + (estimatedChunks * DecryptionChunkSize));
154+
result.AddRange(hash);
149155

150156
foreach (byte[] chunk in data.Chunk(EncryptionChunkSize))
151157
{
152158
IEnumerable<byte> c = await EncryptChunkAsync(chunk, process, cancellationToken);
153-
result.AddRange(Configuration.DynamicBlockProcessing ? Transformers.Rotate(c.ToArray(), DynamicEncryption.GetDynamicChunkEntropy(KeyStore, process)) : c);
159+
if (Configuration.DynamicBlockProcessing)
160+
{
161+
byte[] cArray = c as byte[] ?? c.ToArray();
162+
result.AddRange(Transformers.Rotate(cArray, DynamicEncryption.GetDynamicChunkEntropy(KeyStore, process)));
163+
}
164+
else
165+
{
166+
result.AddRange(c);
167+
}
154168
process.ChunkIndex++;
155169
}
156170

@@ -177,24 +191,39 @@ public virtual async Task<byte[]> DecryptBlockAsync(byte[] data, CryptoProcess p
177191
process.ChunkIndex = 0;
178192
}
179193

180-
IEnumerable<byte[]> chunks;
181-
182-
if (Configuration.RemoveHash)
194+
int dataOffset = 0;
195+
196+
if (!Configuration.RemoveHash)
183197
{
184-
chunks = data.Chunk(DecryptionChunkSize);
185-
}
186-
else
187-
{
188-
byte[] _hash = data.Take(32).ToArray();
189-
process.BlockHash = Configuration.DynamicBlockProcessing ? Transformers.Rotate(_hash, DynamicEncryption.GetDynamicBlockEntropy(KeyStore, process) * -1) : _hash;
190-
chunks = data.Skip(32).Chunk(DecryptionChunkSize);
198+
// Extract hash without allocating via Take
199+
process.BlockHash = new byte[32];
200+
Array.Copy(data, 0, process.BlockHash, 0, 32);
201+
202+
if (Configuration.DynamicBlockProcessing)
203+
{
204+
process.BlockHash = Transformers.Rotate(process.BlockHash, DynamicEncryption.GetDynamicBlockEntropy(KeyStore, process) * -1);
205+
}
206+
dataOffset = 32;
191207
}
192208

193-
List<byte> result = new List<byte>();
209+
// Pre-calculate capacity for result list
210+
int estimatedChunks = (data.Length - dataOffset + DecryptionChunkSize - 1) / DecryptionChunkSize;
211+
List<byte> result = new List<byte>(estimatedChunks * EncryptionChunkSize);
194212

195-
foreach (byte[] chunk in chunks)
213+
// Process chunks without Skip/Chunk allocation overhead
214+
int dataLength = data.Length - dataOffset;
215+
for (int i = 0; i < dataLength; i += DecryptionChunkSize)
196216
{
197-
result.AddRange(await DecryptChunkAsync(Configuration.DynamicBlockProcessing ? Transformers.Rotate(chunk, DynamicEncryption.GetDynamicChunkEntropy(KeyStore, process) * -1) : chunk, process, cancellationToken));
217+
int chunkLength = Math.Min(DecryptionChunkSize, dataLength - i);
218+
byte[] chunk = new byte[chunkLength];
219+
Array.Copy(data, dataOffset + i, chunk, 0, chunkLength);
220+
221+
if (Configuration.DynamicBlockProcessing)
222+
{
223+
chunk = Transformers.Rotate(chunk, DynamicEncryption.GetDynamicChunkEntropy(KeyStore, process) * -1);
224+
}
225+
226+
result.AddRange(await DecryptChunkAsync(chunk, process, cancellationToken));
198227
process.ChunkIndex++;
199228
}
200229

src/Kryptor/CryptoProviders/DynamicEncryption.cs

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
using SAPTeam.Kryptor.Extensions;
1+
using System.Runtime.CompilerServices;
2+
3+
using SAPTeam.Kryptor.Extensions;
24
using SAPTeam.Kryptor.Helpers;
35

46
namespace SAPTeam.Kryptor.CryptoProviders
@@ -47,9 +49,38 @@ private byte[] CreateDynamicKey(CryptoProcess process)
4749
byte[] key2 = KeyStore[process.ChunkIndex - (Configuration.RemoveHash ? key1[4] : process.BlockHash[key1[27] % 32])];
4850
byte[] key3 = KeyStore[process.ChunkIndex + process.BlockSize];
4951

50-
byte[] mKey = process.BlockIndex > 0
51-
? ((byte[])process.ProcessData[$"b{process.BlockIndex - 1}.sha512"]).Concat(key1).Concat(key2).Concat(key3).Concat(process.BlockHash).ToArray()
52-
: key1.Concat(key2).Concat(key3).Concat(process.BlockHash).ToArray();
52+
byte[] mKey;
53+
if (process.BlockIndex > 0)
54+
{
55+
byte[] previousSha512 = (byte[])process.ProcessData[$"b{process.BlockIndex - 1}.sha512"];
56+
int totalLength = previousSha512.Length + key1.Length + key2.Length + key3.Length + process.BlockHash.Length;
57+
mKey = new byte[totalLength];
58+
59+
int offset = 0;
60+
previousSha512.CopyTo(mKey, offset);
61+
offset += previousSha512.Length;
62+
key1.CopyTo(mKey, offset);
63+
offset += key1.Length;
64+
key2.CopyTo(mKey, offset);
65+
offset += key2.Length;
66+
key3.CopyTo(mKey, offset);
67+
offset += key3.Length;
68+
process.BlockHash.CopyTo(mKey, offset);
69+
}
70+
else
71+
{
72+
int totalLength = key1.Length + key2.Length + key3.Length + process.BlockHash.Length;
73+
mKey = new byte[totalLength];
74+
75+
int offset = 0;
76+
key1.CopyTo(mKey, offset);
77+
offset += key1.Length;
78+
key2.CopyTo(mKey, offset);
79+
offset += key2.Length;
80+
key3.CopyTo(mKey, offset);
81+
offset += key3.Length;
82+
process.BlockHash.CopyTo(mKey, offset);
83+
}
5384

5485
return mKey.Sha256();
5586
}
@@ -79,6 +110,7 @@ internal static byte[] CreateMixedIV(KeyStore keyStore, CryptoProcess process)
79110
};
80111
}
81112

113+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
82114
internal static int GetDynamicBlockSize(KeyStore keyStore, CryptoProcess process)
83115
{
84116
int index = process.BlockIndex;
@@ -87,6 +119,7 @@ internal static int GetDynamicBlockSize(KeyStore keyStore, CryptoProcess process
87119
return Math.Abs(BitConverter.ToInt32(lastBytes, 0) % 0xC000);
88120
}
89121

122+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
90123
internal static int GetDynamicBlockEntropy(KeyStore keyStore, CryptoProcess process)
91124
{
92125
int index = process.BlockIndex * 4;
@@ -95,6 +128,7 @@ internal static int GetDynamicBlockEntropy(KeyStore keyStore, CryptoProcess proc
95128
return BitConverter.ToInt32(lastBytes, 0) % 0xC000;
96129
}
97130

131+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
98132
internal static int GetDynamicChunkEntropy(KeyStore keyStore, CryptoProcess process)
99133
{
100134
int index = process.BlockIndex + process.ChunkIndex;

src/Kryptor/Extensions/CryptoExtensions.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,14 @@ public static class CryptoExtensions
1414
/// <returns>The computed hash array.</returns>
1515
public static byte[] Sha256(this byte[] buffer)
1616
{
17+
#if NET8_0_OR_GREATER
18+
return SHA256.HashData(buffer);
19+
#else
1720
using (SHA256 sha256 = SHA256.Create())
1821
{
1922
return sha256.ComputeHash(buffer);
2023
}
24+
#endif
2125
}
2226

2327
/// <summary>
@@ -57,10 +61,14 @@ public static byte[] Sha256(this Stream stream, bool startFromOrigin = true)
5761
/// <returns>The computed hash array.</returns>
5862
public static byte[] Sha384(this byte[] buffer)
5963
{
64+
#if NET8_0_OR_GREATER
65+
return SHA384.HashData(buffer);
66+
#else
6067
using (SHA384 sha384 = SHA384.Create())
6168
{
6269
return sha384.ComputeHash(buffer);
6370
}
71+
#endif
6472
}
6573

6674
/// <summary>
@@ -70,10 +78,14 @@ public static byte[] Sha384(this byte[] buffer)
7078
/// <returns>The computed hash array.</returns>
7179
public static byte[] Sha512(this byte[] buffer)
7280
{
81+
#if NET8_0_OR_GREATER
82+
return SHA512.HashData(buffer);
83+
#else
7384
using (SHA512 sha512 = SHA512.Create())
7485
{
7586
return sha512.ComputeHash(buffer);
7687
}
88+
#endif
7789
}
7890

7991
/// <summary>
@@ -84,10 +96,14 @@ public static byte[] Sha512(this byte[] buffer)
8496
/// <returns>The computed hash array.</returns>
8597
public static byte[] HmacSha256(this byte[] buffer, byte[] key)
8698
{
99+
#if NET8_0_OR_GREATER
100+
return HMACSHA256.HashData(key, buffer);
101+
#else
87102
using (HMACSHA256 hmacSha256 = new HMACSHA256(key))
88103
{
89104
return hmacSha256.ComputeHash(buffer);
90105
}
106+
#endif
91107
}
92108

93109
/// <summary>
@@ -98,10 +114,14 @@ public static byte[] HmacSha256(this byte[] buffer, byte[] key)
98114
/// <returns>The computed hash array.</returns>
99115
public static byte[] HmacSha384(this byte[] buffer, byte[] key)
100116
{
117+
#if NET8_0_OR_GREATER
118+
return HMACSHA384.HashData(key, buffer);
119+
#else
101120
using (HMACSHA384 hmacSha384 = new HMACSHA384(key))
102121
{
103122
return hmacSha384.ComputeHash(buffer);
104123
}
124+
#endif
105125
}
106126

107127
/// <summary>
@@ -112,10 +132,14 @@ public static byte[] HmacSha384(this byte[] buffer, byte[] key)
112132
/// <returns>The computed hash array.</returns>
113133
public static byte[] HmacSha512(this byte[] buffer, byte[] key)
114134
{
135+
#if NET8_0_OR_GREATER
136+
return HMACSHA512.HashData(key, buffer);
137+
#else
115138
using (HMACSHA512 hmacSha512 = new HMACSHA512(key))
116139
{
117140
return hmacSha512.ComputeHash(buffer);
118141
}
142+
#endif
119143
}
120144
}
121145
}

src/Kryptor/Extensions/EnumerableExtensions.cs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,23 @@ public static IEnumerable<TSource[]> Chunk<TSource>(this IEnumerable<TSource> so
5151
/// <returns>Start index of first occurrence.</returns>
5252
public static int LocatePattern<T>(this IEnumerable<T> src, IEnumerable<T> pattern)
5353
{
54-
for (int i = 0; i < src.Count(); i++)
54+
T[] srcArray = src as T[] ?? src.ToArray();
55+
T[] patternArray = pattern as T[] ?? pattern.ToArray();
56+
int patternLength = patternArray.Length;
57+
int srcLength = srcArray.Length;
58+
59+
for (int i = 0; i <= srcLength - patternLength; i++)
5560
{
56-
if (src.Skip(i).Take(pattern.Count()).SequenceEqual(pattern))
61+
bool found = true;
62+
for (int j = 0; j < patternLength; j++)
5763
{
58-
return i;
64+
if (!EqualityComparer<T>.Default.Equals(srcArray[i + j], patternArray[j]))
65+
{
66+
found = false;
67+
break;
68+
}
5969
}
70+
if (found) return i;
6071
}
6172

6273
return -1;

0 commit comments

Comments
 (0)