Skip to content

Commit 04afdf5

Browse files
committed
Refactor crypto, tests, and workflows for security & perf
Updated GitVersion workflow to streamline releases and added conditional checks for version changes. Bumped `next-version` to 3.0.0. Refactored `KeyDerivation` to use HKDF (RFC 5869) with optional salt, improving cryptographic practices and memory safety. Updated `KeyDerivationTests` to align with the new implementation. Enhanced `AesGcmStreamCipher` with `IDisposable`, memory limits, and stronger integrity checks using associated data (AAD). Improved encryption/decryption pipelines. Refactored reliability tests for better scoping, exception handling, and maintainability. Updated performance benchmarks to reflect encryption optimizations. Added XML documentation to `IMediator` for clarity. Updated binary performance analysis files to reflect new results.
2 parents 2bc660b + 2b77f8a commit 04afdf5

15 files changed

Lines changed: 383 additions & 269 deletions

File tree

.github/workflows/publish-release.yml

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ jobs:
2424
uses: gittools/actions/gitversion/setup@v3.1.11
2525
with:
2626
versionSpec: 5.x
27+
2728
- name: Determine Version
2829
uses: gittools/actions/gitversion/execute@v3.1.11
2930
id: gitversion # step id used as reference for output values
@@ -67,15 +68,6 @@ jobs:
6768
dotnet nuget push *.nupkg --skip-duplicate --api-key ${{ secrets.DEPLOY_GITHUB_TOKEN }} --source "github"
6869
dotnet nuget push *.nupkg --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --source https://api.nuget.org/v3/index.json
6970
70-
#Create release
71-
- name: Create Release
72-
if: 1 == 0 #needs.build.outputs.CommitsSinceVersionSource > 0 #Only release if there has been a commit/version change
73-
uses: actions/create-release@v1
74-
env:
75-
GITHUB_TOKEN: ${{ secrets.DEPLOY_GITHUB_TOKEN }}
76-
with:
77-
tag_name: ${{ needs.build.outputs.Version }}
78-
release_name: Release ${{ needs.build.outputs.Version }}
7971
- name: Create Release
8072
if: needs.build.outputs.CommitsSinceVersionSource > 0 #Only release if there has been a commit/version change
8173
uses: ncipollo/release-action@v1

GitVersion.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
next-version: 2.0.0
1+
next-version: 3.0.0
-82.5 KB
Loading
Lines changed: 80 additions & 130 deletions
Original file line numberDiff line numberDiff line change
@@ -1,144 +1,94 @@
1-
Decrypt_ThreadSweep_ChunkSweep
2-
 Source: PerformanceTests.cs line 88
3-
 Duration: 15.1 sec
1+
Encrypt_ThreadSweep_ChunkSweep
2+
 Source: PerformanceTests.cs line 55
3+
 Duration: 6.2 sec
44

55
Standard Output: 
6-
=== DECRYPTION THREAD/CHUNK SWEEP ===
6+
=== ENCRYPTION THREAD/CHUNK SWEEP ===
77
Data size: 1000 MB
88
Threads: 1, 2, 4, 8, 16
9-
Chunk sizes: 0.0MB, 0.0MB, 0.0MB, 0.0MB, 0.0MB, 0.0MB, 0.1MB, 0.1MB, 0.5MB, 1.0MB, 4.0MB, 8.0MB, 16.0MB
9+
Chunk sizes: 0.1MB, 0.1MB, 0.5MB, 1.0MB, 4.0MB, 8.0MB, 16.0MB
1010
Threads | ChunkMB | Avg MB/s
11-
1 | 0.001 | 7474.8
12-
1 | 0.002 | 7408.4
13-
1 | 0.004 | 7564.8
14-
1 | 0.008 | 7402.4
15-
1 | 0.016 | 7592.4
16-
1 | 0.031 | 7881.8
17-
1 | 0.062 | 7760.4
18-
1 | 0.125 | 7844.9
19-
1 | 0.500 | 7933.8
20-
1 | 1.000 | 7691.4
21-
1 | 4.000 | 7997.9
22-
1 | 8.000 | 7800.5
23-
1 | 16.000 | 7570.1
24-
2 | 0.001 | 9380.8
25-
2 | 0.002 | 9190.2
26-
2 | 0.004 | 9427.7
27-
2 | 0.008 | 9688.8
28-
2 | 0.016 | 9945.4
29-
2 | 0.031 | 9692.3
30-
2 | 0.062 | 9666.8
31-
2 | 0.125 | 9637.3
32-
2 | 0.500 | 9609.4
33-
2 | 1.000 | 9518.5
34-
2 | 4.000 | 9563.1
35-
2 | 8.000 | 9574.3
36-
2 | 16.000 | 9734.5
37-
4 | 0.001 | 9353.5
38-
4 | 0.002 | 9249.1
39-
4 | 0.004 | 9235.2
40-
4 | 0.008 | 9382.8
41-
4 | 0.016 | 9374.9
42-
4 | 0.031 | 9455.9
43-
4 | 0.062 | 9293.3
44-
4 | 0.125 | 9536.8
45-
4 | 0.500 | 8914.2
46-
4 | 1.000 | 9412.5
47-
4 | 4.000 | 9607.3
48-
4 | 8.000 | 9530.0
49-
4 | 16.000 | 9204.4
50-
8 | 0.001 | 9539.0
51-
8 | 0.002 | 9602.0
52-
8 | 0.004 | 9087.6
53-
8 | 0.008 | 9350.7
54-
8 | 0.016 | 9154.3
55-
8 | 0.031 | 9248.2
56-
8 | 0.062 | 9436.3
57-
8 | 0.125 | 9255.7
58-
8 | 0.500 | 8906.6
59-
8 | 1.000 | 9391.8
60-
8 | 4.000 | 9402.3
61-
8 | 8.000 | 9552.3
62-
8 | 16.000 | 9451.9
63-
16 | 0.001 | 9413.0
64-
16 | 0.002 | 9679.7
65-
16 | 0.004 | 9658.1
66-
16 | 0.008 | 9413.8
67-
16 | 0.016 | 9385.4
68-
16 | 0.031 | 9477.2
69-
16 | 0.062 | 9623.6
70-
16 | 0.125 | 8805.0
71-
16 | 0.500 | 8691.3
72-
16 | 1.000 | 8571.9
73-
16 | 4.000 | 9108.3
74-
16 | 8.000 | 9360.3
75-
16 | 16.000 | 9416.8
11+
1 | 0.062 | 9518.9
12+
1 | 0.125 | 11383.9
13+
1 | 0.500 | 12712.2
14+
1 | 1.000 | 12431.7
15+
1 | 4.000 | 9790.9
16+
1 | 8.000 | 8820.4
17+
1 | 16.000 | 7354.2
18+
2 | 0.062 | 14578.4
19+
2 | 0.125 | 15069.9
20+
2 | 0.500 | 15962.9
21+
2 | 1.000 | 14960.1
22+
2 | 4.000 | 11781.2
23+
2 | 8.000 | 10775.6
24+
2 | 16.000 | 9166.5
25+
4 | 0.062 | 13555.8
26+
4 | 0.125 | 14117.3
27+
4 | 0.500 | 14702.3
28+
4 | 1.000 | 14299.6
29+
4 | 4.000 | 11945.5
30+
4 | 8.000 | 10768.6
31+
4 | 16.000 | 8431.8
32+
8 | 0.062 | 10921.1
33+
8 | 0.125 | 13173.2
34+
8 | 0.500 | 13962.2
35+
8 | 1.000 | 13168.2
36+
8 | 4.000 | 11042.9
37+
8 | 8.000 | 9701.7
38+
8 | 16.000 | 9387.7
39+
16 | 0.062 | 8194.4
40+
16 | 0.125 | 10708.4
41+
16 | 0.500 | 14302.7
42+
16 | 1.000 | 13576.2
43+
16 | 4.000 | 11187.2
44+
16 | 8.000 | 9916.9
45+
16 | 16.000 | 9275.1
7646

7747

7848

79-
Encrypt_ThreadSweep_ChunkSweep
80-
 Source: PerformanceTests.cs line 43
81-
 Duration: 16 sec
49+
Decrypt_ThreadSweep_ChunkSweep
50+
 Source: PerformanceTests.cs line 100
51+
 Duration: 6.5 sec
8252

8353
Standard Output: 
84-
=== ENCRYPTION THREAD/CHUNK SWEEP ===
54+
=== DECRYPTION THREAD/CHUNK SWEEP ===
8555
Data size: 1000 MB
8656
Threads: 1, 2, 4, 8, 16
87-
Chunk sizes: 0.0MB, 0.0MB, 0.0MB, 0.0MB, 0.1MB, 0.1MB, 0.5MB, 1.0MB, 4.0MB, 8.0MB, 16.0MB
57+
Chunk sizes: 0.1MB, 0.1MB, 0.5MB, 1.0MB, 4.0MB, 8.0MB, 16.0MB
8858
Threads | ChunkMB | Avg MB/s
89-
1 | 0.004 | 2887.2
90-
1 | 0.008 | 4974.3
91-
1 | 0.016 | 7226.3
92-
1 | 0.031 | 9415.9
93-
1 | 0.062 | 11265.3
94-
1 | 0.125 | 12084.1
95-
1 | 0.500 | 12569.8
96-
1 | 1.000 | 12163.6
97-
1 | 4.000 | 10085.4
98-
1 | 8.000 | 9354.9
99-
1 | 16.000 | 7881.5
100-
2 | 0.004 | 4272.8
101-
2 | 0.008 | 7117.3
102-
2 | 0.016 | 10355.5
103-
2 | 0.031 | 12858.0
104-
2 | 0.062 | 13823.1
105-
2 | 0.125 | 15474.5
106-
2 | 0.500 | 15252.4
107-
2 | 1.000 | 13803.9
108-
2 | 4.000 | 12313.6
109-
2 | 8.000 | 10621.5
110-
2 | 16.000 | 9413.4
111-
4 | 0.004 | 3022.9
112-
4 | 0.008 | 5417.8
113-
4 | 0.016 | 7913.9
114-
4 | 0.031 | 12175.1
115-
4 | 0.062 | 14190.0
116-
4 | 0.125 | 15301.6
117-
4 | 0.500 | 14930.2
118-
4 | 1.000 | 13461.7
119-
4 | 4.000 | 12259.3
120-
4 | 8.000 | 11456.5
121-
4 | 16.000 | 9260.8
122-
8 | 0.004 | 1961.7
123-
8 | 0.008 | 3626.4
124-
8 | 0.016 | 6746.5
125-
8 | 0.031 | 10925.9
126-
8 | 0.062 | 13287.6
127-
8 | 0.125 | 14806.6
128-
8 | 0.500 | 15225.5
129-
8 | 1.000 | 15100.1
130-
8 | 4.000 | 10884.0
131-
8 | 8.000 | 10909.6
132-
8 | 16.000 | 9042.3
133-
16 | 0.004 | 1112.1
134-
16 | 0.008 | 1897.4
135-
16 | 0.016 | 3112.1
136-
16 | 0.031 | 4809.1
137-
16 | 0.062 | 7532.8
138-
16 | 0.125 | 13798.6
139-
16 | 0.500 | 15279.9
140-
16 | 1.000 | 15090.4
141-
16 | 4.000 | 12667.9
142-
16 | 8.000 | 11849.1
143-
16 | 16.000 | 9927.1
59+
1 | 0.062 | 10084.2
60+
1 | 0.125 | 10595.1
61+
1 | 0.500 | 10137.6
62+
1 | 1.000 | 10591.1
63+
1 | 4.000 | 11068.6
64+
1 | 8.000 | 10761.2
65+
1 | 16.000 | 11065.3
66+
2 | 0.062 | 15031.0
67+
2 | 0.125 | 14879.9
68+
2 | 0.500 | 14992.7
69+
2 | 1.000 | 15025.4
70+
2 | 4.000 | 14977.7
71+
2 | 8.000 | 13735.5
72+
2 | 16.000 | 14784.0
73+
4 | 0.062 | 14776.7
74+
4 | 0.125 | 14420.2
75+
4 | 0.500 | 14424.2
76+
4 | 1.000 | 14175.5
77+
4 | 4.000 | 14824.2
78+
4 | 8.000 | 14960.0
79+
4 | 16.000 | 14551.7
80+
8 | 0.062 | 14780.2
81+
8 | 0.125 | 14725.3
82+
8 | 0.500 | 14713.9
83+
8 | 1.000 | 14693.7
84+
8 | 4.000 | 14694.7
85+
8 | 8.000 | 14763.9
86+
8 | 16.000 | 14890.1
87+
16 | 0.062 | 13035.8
88+
16 | 0.125 | 13864.2
89+
16 | 0.500 | 13645.4
90+
16 | 1.000 | 13345.7
91+
16 | 4.000 | 14402.7
92+
16 | 8.000 | 14745.1
93+
16 | 16.000 | 14301.3
14494

-68.8 KB
Loading
-129 KB
Loading
-14.1 KB
Loading

Sources/EasyExtensions.Crypto.Tests/KeyDerivationTests.cs

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ public class KeyDerivationTests
1515
[Test]
1616
public void DeriveSubkey_Returns_Requested_Length([Values(0, 1, 16, 32, 48, 64, 100)] int len)
1717
{
18-
var bytes = EasyExtensions.Crypto.KeyDerivation.DeriveSubkey(Master1, PurposeA, len);
18+
var bytes = KeyDerivation.DeriveSubkey(Master1, PurposeA, len);
1919
Assert.That(bytes, Is.Not.Null);
20-
Assert.That(bytes.Length, Is.EqualTo(len));
20+
Assert.That(bytes, Has.Length.EqualTo(len));
2121
if (len > 0)
2222
{
2323
// Not all zeros
@@ -28,53 +28,53 @@ public void DeriveSubkey_Returns_Requested_Length([Values(0, 1, 16, 32, 48, 64,
2828
[Test]
2929
public void Deterministic_For_Same_Inputs()
3030
{
31-
var a1 = EasyExtensions.Crypto.KeyDerivation.DeriveSubkey(Master1, PurposeA, 48);
32-
var a2 = EasyExtensions.Crypto.KeyDerivation.DeriveSubkey(Master1, PurposeA, 48);
31+
var a1 = KeyDerivation.DeriveSubkey(Master1, PurposeA, 48);
32+
var a2 = KeyDerivation.DeriveSubkey(Master1, PurposeA, 48);
3333
Assert.That(a1, Is.EqualTo(a2));
3434
}
3535

3636
[Test]
3737
public void Different_Master_Produces_Different_Key()
3838
{
39-
var a = EasyExtensions.Crypto.KeyDerivation.DeriveSubkey(Master1, PurposeA, 48);
40-
var b = EasyExtensions.Crypto.KeyDerivation.DeriveSubkey(Master2, PurposeA, 48);
39+
var a = KeyDerivation.DeriveSubkey(Master1, PurposeA, 48);
40+
var b = KeyDerivation.DeriveSubkey(Master2, PurposeA, 48);
4141
Assert.That(a, Is.Not.EqualTo(b));
4242
}
4343

4444
[Test]
4545
public void Different_Purpose_Produces_Different_Key()
4646
{
47-
var a = EasyExtensions.Crypto.KeyDerivation.DeriveSubkey(Master1, PurposeA, 48);
48-
var b = EasyExtensions.Crypto.KeyDerivation.DeriveSubkey(Master1, PurposeB, 48);
47+
var a = KeyDerivation.DeriveSubkey(Master1, PurposeA, 48);
48+
var b = KeyDerivation.DeriveSubkey(Master1, PurposeB, 48);
4949
Assert.That(a, Is.Not.EqualTo(b));
5050
}
5151

5252
[Test]
5353
public void Base64_Matches_Raw_Encoding()
5454
{
55-
var bytes = EasyExtensions.Crypto.KeyDerivation.DeriveSubkey(Master1, PurposeA, 32);
55+
var bytes = KeyDerivation.DeriveSubkey(Master1, PurposeA, 32);
5656
var b64A = EasyExtensions.Crypto.KeyDerivation.DeriveSubkeyBase64(Master1, PurposeA, 32);
5757
var b64B = Convert.ToBase64String(bytes);
5858
Assert.That(b64A, Is.EqualTo(b64B));
5959
}
6060

6161
[Test]
62-
public void Length32_Vs_Length64_Prefixes_Differ_By_Design()
62+
public void Length32_Vs_Length64_Prefixes_NotDiffer_By_Design()
6363
{
6464
// length 32 uses HMAC(purpose) directly
65-
var l32 = EasyExtensions.Crypto.KeyDerivation.DeriveSubkey(Master1, PurposeA, 32);
65+
var l32 = KeyDerivation.DeriveSubkey(Master1, PurposeA, 32);
6666
// length 64 uses HMAC(purpose||1) + HMAC(purpose||2)
67-
var l64 = EasyExtensions.Crypto.KeyDerivation.DeriveSubkey(Master1, PurposeA, 64);
68-
Assert.That(l32, Is.Not.EqualTo(l64.Take(32).ToArray()));
67+
var l64 = KeyDerivation.DeriveSubkey(Master1, PurposeA, 64);
68+
Assert.That(l32, Is.EqualTo(l64.Take(32).ToArray()));
6969
}
7070

7171
[Test]
7272
public void Longer_Length_Extends_With_Deterministic_Blocks()
7373
{
7474
// For lengths > 32, result is concatenation of counter-based blocks starting at 1,
7575
// so prefix of 64 should match prefix of 96.
76-
var l64 = EasyExtensions.Crypto.KeyDerivation.DeriveSubkey(Master1, PurposeA, 64);
77-
var l96 = EasyExtensions.Crypto.KeyDerivation.DeriveSubkey(Master1, PurposeA, 96);
76+
var l64 = KeyDerivation.DeriveSubkey(Master1, PurposeA, 64);
77+
var l96 = KeyDerivation.DeriveSubkey(Master1, PurposeA, 96);
7878
Assert.That(l96.Take(64).ToArray(), Is.EqualTo(l64));
7979
}
8080
}

0 commit comments

Comments
 (0)