Skip to content

Commit 19411a7

Browse files
authored
Merge pull request #27 from jogibear9988/main
Add .NET Framework 4.8 compatibility
2 parents 788045d + 2c48c1d commit 19411a7

45 files changed

Lines changed: 530 additions & 130 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/dotnet.yml

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ jobs:
2525
- name: Build
2626
run: dotnet build -c Release --no-restore
2727
- name: Test
28-
run: dotnet test -c Release --no-build --verbosity normal /p:CollectCoverage=true /p:CoverletOutputFormat=opencover
28+
run: dotnet test -c Release --framework net8.0 --no-build --verbosity normal /p:CollectCoverage=true /p:CoverletOutputFormat=opencover
2929
- name: Upload coverage reports to Codecov
3030
uses: codecov/codecov-action@v7
3131
env:
@@ -54,11 +54,55 @@ jobs:
5454
name: HarpoS7.PoC_Windows_x64_SelfContained
5555
path: ./windows/*
5656

57+
net48-compatibility:
58+
runs-on: windows-latest
59+
needs: [build]
60+
steps:
61+
- uses: actions/checkout@v7
62+
- name: Setup .NET
63+
uses: actions/setup-dotnet@v5
64+
with:
65+
dotnet-version: 8.0.x
66+
- name: Run library tests on .NET Framework 4.8
67+
shell: pwsh
68+
run: |
69+
$testProjects = @(
70+
'HarpoS7.Tests/HarpoS7.Tests.csproj',
71+
'HarpoS7.Family0.Tests/HarpoS7.Family0.Tests.csproj',
72+
'HarpoS7.Utilities.Tests/HarpoS7.Utilities.Tests.csproj',
73+
'HarpoS7.PublicKeys.Tests/HarpoS7.PublicKeys.Tests.csproj'
74+
)
75+
76+
$resultsDirectory = Join-Path $env:RUNNER_TEMP 'harpos7-net48-results'
77+
foreach ($testProject in $testProjects) {
78+
$testName = [IO.Path]::GetFileNameWithoutExtension($testProject)
79+
$resultFile = "$testName.trx"
80+
dotnet test $testProject -c Release --framework net48 `
81+
--logger "trx;LogFileName=$resultFile" `
82+
--results-directory $resultsDirectory
83+
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
84+
85+
[xml]$testResult = Get-Content (Join-Path $resultsDirectory $resultFile)
86+
if ([int]$testResult.TestRun.ResultSummary.Counters.total -eq 0) {
87+
throw "No .NET Framework 4.8 tests were discovered for $testProject"
88+
}
89+
}
90+
- uses: actions/download-artifact@v7
91+
with:
92+
name: HarpoS7-NuGet-Packages
93+
path: ./artifacts
94+
- name: Validate .NET Framework 4.8 NuGet packages
95+
shell: pwsh
96+
run: |
97+
$packageSource = (Resolve-Path ./artifacts).Path
98+
dotnet restore HarpoS7.NetFramework48.SmokeTest/HarpoS7.NetFramework48.SmokeTest.csproj -p:RestoreAdditionalProjectSources="$packageSource"
99+
dotnet run --project HarpoS7.NetFramework48.SmokeTest/HarpoS7.NetFramework48.SmokeTest.csproj -c Release --no-restore
100+
57101
publish-nuget:
58102
runs-on: ubuntu-latest
59103
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
60104
environment: nuget-release
61-
needs: [build]
105+
needs: [build, net48-compatibility]
62106
permissions:
63107
id-token: write # enable GitHub OIDC token issuance for this job
64108
steps:

Directory.Build.props

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
<Project>
22
<PropertyGroup>
3-
<TargetFramework>net8.0</TargetFramework>
43
<ImplicitUsings>enable</ImplicitUsings>
54
<Nullable>enable</Nullable>
65
<LangVersion>latest</LangVersion>
@@ -11,16 +10,26 @@
1110
<RepositoryType>git</RepositoryType>
1211
<PackageTags>siemens;s7</PackageTags>
1312

14-
<PackageVersion>1.1.3</PackageVersion>
15-
<AssemblyVersion>1.1.3</AssemblyVersion>
16-
<FileVersion>1.1.3</FileVersion>
17-
<Version>1.1.3</Version>
18-
<PackageReleaseNotes>Fix legacy challenge fingerprint derivation for the final lookup-table block.</PackageReleaseNotes>
13+
<PackageVersion>1.1.4</PackageVersion>
14+
<AssemblyVersion>1.1.4</AssemblyVersion>
15+
<FileVersion>1.1.4</FileVersion>
16+
<Version>1.1.4</Version>
17+
<PackageReleaseNotes>Add .NET Standard 2.0 and .NET Framework 4.8 support while preserving .NET 8. Fix legacy challenge fingerprint derivation for the final lookup-table block.</PackageReleaseNotes>
1918

2019
<PackageIcon>nuget-icon.png</PackageIcon>
2120
</PropertyGroup>
2221

2322
<ItemGroup>
2423
<None Include="$(MSBuildThisFileDirectory)tools\nuget-icon.png" Pack="true" PackagePath="\" />
2524
</ItemGroup>
25+
26+
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
27+
<PackageReference Include="PolySharp" Version="1.15.0" PrivateAssets="all" />
28+
<PackageReference Include="System.Buffers" Version="4.5.1" />
29+
<PackageReference Include="System.Memory" Version="4.5.5" />
30+
</ItemGroup>
31+
32+
<ItemGroup Condition="'$(TargetFramework)' == 'net48'">
33+
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.3" PrivateAssets="all" />
34+
</ItemGroup>
2635
</Project>

HarpoS7.Family0.Tests/HarpoS7.Family0.Tests.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4+
<TargetFrameworks>net8.0;net48</TargetFrameworks>
45
<IsPackable>false</IsPackable>
56
<IsTestProject>true</IsTestProject>
67
</PropertyGroup>
78

89
<ItemGroup>
910
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0"/>
1011
<PackageReference Include="NUnit" Version="3.13.3"/>
11-
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1"/>
12+
<PackageReference Include="NUnit3TestAdapter" Version="6.2.0"/>
1213
<PackageReference Include="NUnit.Analyzers" Version="3.6.1"/>
1314
<PackageReference Include="coverlet.collector" Version="6.0.0"/>
1415
</ItemGroup>

HarpoS7.Family0.Tests/Monoliths/MonolithTests.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,13 @@ public void ExecuteNoReturn(int monolithIndex)
7272

7373
Span<byte> destinationBuffer = stackalloc byte[MonolithBufferSizes.GetDestinationBufferSize(monolithIndex)];
7474

75-
var executeDelegate = executeMethod.CreateDelegate<MonolithExecuteMethodNoReturn>();
75+
var executeDelegate = (MonolithExecuteMethodNoReturn)executeMethod.CreateDelegate(
76+
typeof(MonolithExecuteMethodNoReturn));
7677
executeDelegate(destinationBuffer, expectedSrcBytes.AsSpan());
7778

7879
// Arrays work better with Is.EqualTo than Span<T> (shows the error index)
7980
Assert.That(destinationBuffer.ToArray(), Is.EqualTo(expectedDstBytes));
8081
}
8182

8283
private delegate void MonolithExecuteMethodNoReturn(Span<byte> destination, ReadOnlySpan<byte> source);
83-
}
84+
}

HarpoS7.Family0.Tests/Transforms/TransformTests.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ public void Execute(string className, int blobIndex, int? subIndex = null)
3434

3535
Span<byte> destinationBuffer = stackalloc byte[TransformBufferSizes.DstSizes[blobIndex - 1]];
3636

37-
var executeDelegate = executeMethod.CreateDelegate<TransformExecuteMethodNoReturn>();
37+
var executeDelegate = (TransformExecuteMethodNoReturn)executeMethod.CreateDelegate(
38+
typeof(TransformExecuteMethodNoReturn));
3839
executeDelegate(destinationBuffer, expectedSrcBytes.AsSpan());
3940

4041
// Arrays work better with Is.EqualTo than Span<T> (shows the error index)
@@ -168,4 +169,4 @@ public void ExecuteTransform12(int blobIndex, int dwordIndex, int count)
168169
}
169170

170171
private delegate void TransformExecuteMethodNoReturn(Span<byte> destination, ReadOnlySpan<byte> source);
171-
}
172+
}

HarpoS7.Family0/Auth/RealPlcAuthenticator.cs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using HarpoS7.Family0.BitOperations;
66
using HarpoS7.Family0.Transforms;
77
using HarpoS7.Utilities.Auth;
8+
using HarpoS7.Utilities.Compatibility;
89
using HarpoS7.Utilities.Extensions;
910

1011
namespace HarpoS7.Family0.Auth;
@@ -73,7 +74,7 @@ public int WriteMetadata(Span<byte> destination, ReadOnlySpan<byte> publicKey, E
7374
if (keyFamily != EPublicKeyFamily.S71200 && keyFamily != EPublicKeyFamily.S71500)
7475
{
7576
throw new ArgumentException(
76-
$"{Enum.GetName(keyFamily)} is not supported by this authenticator",
77+
$"{Enum.GetName(typeof(EPublicKeyFamily), keyFamily)} is not supported by this authenticator",
7778
nameof(keyFamily)
7879
);
7980
}
@@ -117,7 +118,8 @@ public int EncryptFullBlocks(Span<byte> destination, ReadOnlySpan<byte> challeng
117118
// Encrypt 16 bytes of challenge
118119
Span<byte> ciphertextBlock = stackalloc byte[_aes.BlockSize / 8];
119120

120-
_aes.EncryptEcb(
121+
CryptoCompatibility.EncryptEcb(
122+
_aes,
121123
_iv.Span,
122124
ciphertextBlock,
123125
Padding
@@ -134,7 +136,8 @@ public int EncryptFullBlocks(Span<byte> destination, ReadOnlySpan<byte> challeng
134136
// Encrypt all full blocks (16 byte chunks) of _key2
135137
for (var i = 0; i < _key2.Length / 16; ++i)
136138
{
137-
_aes.EncryptEcb(
139+
CryptoCompatibility.EncryptEcb(
140+
_aes,
138141
_iv.Span,
139142
ciphertextBlock,
140143
Padding
@@ -160,7 +163,8 @@ public int EncryptFinalBlock(Span<byte> destination)
160163

161164
var leftOverStartIndex = _key2.Length - Key2LeftOverLength;
162165

163-
_aes.EncryptEcb(
166+
CryptoCompatibility.EncryptEcb(
167+
_aes,
164168
_iv.Span,
165169
ciphertextBlock,
166170
Padding
@@ -182,7 +186,8 @@ public int EncryptFinalBlock(Span<byte> destination)
182186
ChecksumTransform.Execute(_checksum.Span, _checksum.Span, _lookupTable.Span);
183187

184188
_aes.Key = _checksumEncryptionKey;
185-
_aes.EncryptEcb(
189+
CryptoCompatibility.EncryptEcb(
190+
_aes,
186191
_checksum.Span,
187192
ciphertextBlock,
188193
PaddingMode.Zeros
@@ -238,4 +243,4 @@ public void Dispose()
238243
_checksum.Dispose();
239244
_aes.Dispose();
240245
}
241-
}
246+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
using System.Numerics;
2+
3+
namespace HarpoS7.Family0.Compatibility;
4+
5+
internal static class BigIntegerCompatibility
6+
{
7+
public static BigInteger FromUnsignedLittleEndian(ReadOnlySpan<byte> source)
8+
{
9+
#if NETSTANDARD2_0
10+
var bytes = new byte[source.Length + 1];
11+
source.CopyTo(bytes);
12+
return new BigInteger(bytes);
13+
#else
14+
return new BigInteger(source, isUnsigned: true, isBigEndian: false);
15+
#endif
16+
}
17+
18+
public static int GetSignedByteCount(BigInteger value)
19+
{
20+
#if NETSTANDARD2_0
21+
return value.ToByteArray().Length;
22+
#else
23+
return value.GetByteCount();
24+
#endif
25+
}
26+
27+
public static int WriteLittleEndian(BigInteger value, Span<byte> destination, bool isUnsigned)
28+
{
29+
#if NETSTANDARD2_0
30+
var bytes = value.ToByteArray();
31+
var length = bytes.Length;
32+
if (isUnsigned && value.Sign >= 0 && length > 1 && bytes[length - 1] == 0)
33+
{
34+
--length;
35+
}
36+
37+
if (destination.Length < length)
38+
{
39+
throw new ArgumentException($"Destination must be at least {length} bytes long", nameof(destination));
40+
}
41+
42+
bytes.AsSpan(0, length).CopyTo(destination);
43+
return length;
44+
#else
45+
if (!value.TryWriteBytes(destination, out var length, isUnsigned, isBigEndian: false))
46+
{
47+
throw new ArgumentException("Destination is too short", nameof(destination));
48+
}
49+
50+
return length;
51+
#endif
52+
}
53+
}

HarpoS7.Family0/Data/BlobReader.cs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,19 @@ public static void ReadTransform12Metadata()
2828
throw new Exception("Transform12 metadata stream was null");
2929
}
3030

31-
_t12Metadata = new byte[stream.Length];
32-
_ = stream.Read(_t12Metadata.Span);
31+
var metadata = new byte[stream.Length];
32+
var offset = 0;
33+
while (offset < metadata.Length)
34+
{
35+
var bytesRead = stream.Read(metadata, offset, metadata.Length - offset);
36+
if (bytesRead == 0)
37+
{
38+
throw new EndOfStreamException("Transform12 metadata stream ended unexpectedly");
39+
}
40+
41+
offset += bytesRead;
42+
}
43+
44+
_t12Metadata = metadata;
3345
}
34-
}
46+
}

HarpoS7.Family0/HarpoS7.Family0.csproj

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4+
<TargetFrameworks>net8.0;netstandard2.0</TargetFrameworks>
45
<IsPackable>false</IsPackable>
56
</PropertyGroup>
67

@@ -13,12 +14,6 @@
1314
<EmbeddedResource Include="Data\Blobs\Transform12Metadata.bin" />
1415
</ItemGroup>
1516

16-
<ItemGroup>
17-
<Reference Include="CommunityToolkit.HighPerformance">
18-
<HintPath>..\..\..\.nuget\packages\communitytoolkit.highperformance\8.2.2\lib\net7.0\CommunityToolkit.HighPerformance.dll</HintPath>
19-
</Reference>
20-
</ItemGroup>
21-
2217
<ItemGroup>
2318
<PackageReference Include="CommunityToolkit.HighPerformance" Version="8.2.2" />
2419
</ItemGroup>

HarpoS7.Family0/Transforms/BigIntAddition.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System.Numerics;
22
using System.Runtime.InteropServices;
33
using HarpoS7.Family0.BitOperations;
4+
using HarpoS7.Family0.Compatibility;
45
using HarpoS7.Family0.Exceptions;
56

67
namespace HarpoS7.Family0.Transforms;
@@ -37,15 +38,15 @@ public static void Execute(Span<byte> destination, ReadOnlySpan<byte> source1, R
3738
BigIntOperations.Prepare(buffer1, source1);
3839
BigIntOperations.Prepare(buffer2, source2);
3940

40-
var bigInt1 = new BigInteger(buffer1, isUnsigned: true, isBigEndian: false);
41-
var bigInt2 = new BigInteger(buffer2, isUnsigned: true, isBigEndian: false);
41+
var bigInt1 = BigIntegerCompatibility.FromUnsignedLittleEndian(buffer1);
42+
var bigInt2 = BigIntegerCompatibility.FromUnsignedLittleEndian(buffer2);
4243
var sum = bigInt1 + bigInt2;
4344

4445
// TryWriteBytes(out int) and GetByteCount() can differ
45-
var length = sum.GetByteCount();
46+
var length = BigIntegerCompatibility.GetSignedByteCount(sum);
4647

4748
Span<byte> sumBuffer = stackalloc byte[length];
48-
_ = sum.TryWriteBytes(sumBuffer, out length, isUnsigned: true, isBigEndian: false);
49+
length = BigIntegerCompatibility.WriteLittleEndian(sum, sumBuffer, isUnsigned: true);
4950

5051
if (length > BigIntOperations.FinalizeSourceSize)
5152
{
@@ -70,4 +71,4 @@ public static void Execute(Span<byte> destination, ReadOnlySpan<byte> source1, R
7071

7172
BigIntOperations.Finalize(destination, sumBuffer);
7273
}
73-
}
74+
}

0 commit comments

Comments
 (0)