diff --git a/PgpCore.Tests/PgpCore.Tests.csproj b/PgpCore.Tests/PgpCore.Tests.csproj index 802c034..b8c77b2 100644 --- a/PgpCore.Tests/PgpCore.Tests.csproj +++ b/PgpCore.Tests/PgpCore.Tests.csproj @@ -1,7 +1,7 @@  - net472;netcoreapp6.0 + net472;net8.0 false diff --git a/PgpCore.Tests/UnitTests/Sign/SignAsync.File.cs b/PgpCore.Tests/UnitTests/Sign/SignAsync.File.cs index dd76286..a73c8f1 100644 --- a/PgpCore.Tests/UnitTests/Sign/SignAsync.File.cs +++ b/PgpCore.Tests/UnitTests/Sign/SignAsync.File.cs @@ -275,5 +275,42 @@ public async Task ClearSignAsync_SignMessageWithHeaders_ShouldSignMessage(KeyTyp // Teardown testFactory.Teardown(); } + + [Theory] + [InlineData(KeyType.Generated)] + [InlineData(KeyType.Known)] + [InlineData(KeyType.KnownGpg)] + public async Task ClearSignAsync_SignMessageWithUtf8Characters_ShouldPreserveUtf8(KeyType keyType) + { + // Arrange + TestFactory testFactory = new TestFactory(); + await testFactory.ArrangeAsync(keyType); + string utf8Content = "Test with UTF-8: š ž č ć đ ñ ü ö ä € ₹ 中文 日本語 한글"; + File.WriteAllText(testFactory.ContentFileInfo.FullName, utf8Content, Encoding.UTF8); + + EncryptionKeys signingKeys = new EncryptionKeys(testFactory.PrivateKeyFileInfo, testFactory.Password); + EncryptionKeys verificationKeys = new EncryptionKeys(testFactory.PublicKeyFileInfo); + PGP pgpSign = new PGP(signingKeys); + PGP pgpVerify = new PGP(verificationKeys); + + // Act + await pgpSign.ClearSignAsync(testFactory.ContentFileInfo, testFactory.EncryptedContentFileInfo); + bool verified = await pgpVerify.VerifyClearAsync(testFactory.EncryptedContentFileInfo); + string signedContent = File.ReadAllText(testFactory.EncryptedContentFileInfo.FullName, Encoding.UTF8); + + // Assert + using (new AssertionScope()) + { + verified.Should().BeTrue(); + signedContent.Should().Contain(utf8Content); + // Verify that specific UTF-8 characters are preserved + signedContent.Should().Contain("š"); + signedContent.Should().Contain("€"); + signedContent.Should().Contain("中文"); + } + + // Teardown + testFactory.Teardown(); + } } } diff --git a/PgpCore.Tests/UnitTests/Sign/SignAsync.Stream.cs b/PgpCore.Tests/UnitTests/Sign/SignAsync.Stream.cs index b09ea5b..265ee48 100644 --- a/PgpCore.Tests/UnitTests/Sign/SignAsync.Stream.cs +++ b/PgpCore.Tests/UnitTests/Sign/SignAsync.Stream.cs @@ -289,5 +289,44 @@ public async Task ClearSignAsync_SignMessageWithHeaders_ShouldSignMessage(KeyTyp // Teardown testFactory.Teardown(); } + + [Theory] + [InlineData(KeyType.Generated)] + [InlineData(KeyType.Known)] + [InlineData(KeyType.KnownGpg)] + public async Task ClearSignAsync_SignMessageWithUtf8Characters_ShouldPreserveUtf8(KeyType keyType) + { + // Arrange + TestFactory testFactory = new TestFactory(); + await testFactory.ArrangeAsync(keyType); + string utf8Content = "Test with UTF-8: š ž č ć đ ñ ü ö ä € ₹ 中文 日本語 한글"; + File.WriteAllText(testFactory.ContentFileInfo.FullName, utf8Content, Encoding.UTF8); + + EncryptionKeys signingKeys = new EncryptionKeys(testFactory.PrivateKeyStream, testFactory.Password); + EncryptionKeys verificationKeys = new EncryptionKeys(testFactory.PublicKeyStream); + PGP pgpSign = new PGP(signingKeys); + PGP pgpVerify = new PGP(verificationKeys); + + // Act + using (Stream outputFileStream = testFactory.EncryptedContentFileInfo.Create()) + await pgpSign.ClearSignAsync(testFactory.ContentStream, outputFileStream); + + bool verified = await pgpVerify.VerifyClearAsync(testFactory.EncryptedContentStream); + string signedContent = File.ReadAllText(testFactory.EncryptedContentFileInfo.FullName, Encoding.UTF8); + + // Assert + using (new AssertionScope()) + { + verified.Should().BeTrue(); + signedContent.Should().Contain(utf8Content); + // Verify that specific UTF-8 characters are preserved + signedContent.Should().Contain("š"); + signedContent.Should().Contain("€"); + signedContent.Should().Contain("中文"); + } + + // Teardown + testFactory.Teardown(); + } } } diff --git a/PgpCore.Tests/UnitTests/Sign/SignAsync.String.cs b/PgpCore.Tests/UnitTests/Sign/SignAsync.String.cs index 00daa16..37ca11d 100644 --- a/PgpCore.Tests/UnitTests/Sign/SignAsync.String.cs +++ b/PgpCore.Tests/UnitTests/Sign/SignAsync.String.cs @@ -236,5 +236,39 @@ public async Task ClearSignAsync_SignMessageWithHeaders_ShouldSignMessage(KeyTyp // Teardown testFactory.Teardown(); } + + [Theory] + [InlineData(KeyType.Generated)] + [InlineData(KeyType.Known)] + [InlineData(KeyType.KnownGpg)] + public async Task ClearSignAsync_SignMessageWithUtf8Characters_ShouldPreserveUtf8(KeyType keyType) + { + // Arrange + TestFactory testFactory = new TestFactory(); + await testFactory.ArrangeAsync(keyType, FileType.Known); + EncryptionKeys signingKeys = new EncryptionKeys(testFactory.PrivateKey, testFactory.Password); + EncryptionKeys verificationKeys = new EncryptionKeys(testFactory.PublicKey); + PGP pgpSign = new PGP(signingKeys); + PGP pgpVerify = new PGP(verificationKeys); + string utf8Content = "Test with UTF-8: š ž č ć đ ñ ü ö ä € ₹ 中文 日本語 한글"; + + // Act + string signedContent = await pgpSign.ClearSignAsync(utf8Content); + bool verified = await pgpVerify.VerifyClearAsync(signedContent); + + // Assert + using (new AssertionScope()) + { + verified.Should().BeTrue(); + signedContent.Should().Contain(utf8Content); + // Verify that specific UTF-8 characters are preserved + signedContent.Should().Contain("š"); + signedContent.Should().Contain("€"); + signedContent.Should().Contain("中文"); + } + + // Teardown + testFactory.Teardown(); + } } } diff --git a/PgpCore.Tests/UnitTests/Sign/SignSync.File.cs b/PgpCore.Tests/UnitTests/Sign/SignSync.File.cs index 419e237..384aebb 100644 --- a/PgpCore.Tests/UnitTests/Sign/SignSync.File.cs +++ b/PgpCore.Tests/UnitTests/Sign/SignSync.File.cs @@ -275,5 +275,42 @@ public void ClearSign_SignMessageWithHeaders_ShouldSignMessage(KeyType keyType) // Teardown testFactory.Teardown(); } + + [Theory] + [InlineData(KeyType.Generated)] + [InlineData(KeyType.Known)] + [InlineData(KeyType.KnownGpg)] + public void ClearSign_SignMessageWithUtf8Characters_ShouldPreserveUtf8(KeyType keyType) + { + // Arrange + TestFactory testFactory = new TestFactory(); + testFactory.Arrange(keyType); + string utf8Content = "Test with UTF-8: š ž č ć đ ñ ü ö ä € ₹ 中文 日本語 한글"; + File.WriteAllText(testFactory.ContentFileInfo.FullName, utf8Content, Encoding.UTF8); + + EncryptionKeys signingKeys = new EncryptionKeys(testFactory.PrivateKeyFileInfo, testFactory.Password); + EncryptionKeys verificationKeys = new EncryptionKeys(testFactory.PublicKeyFileInfo); + PGP pgpSign = new PGP(signingKeys); + PGP pgpVerify = new PGP(verificationKeys); + + // Act + pgpSign.ClearSign(testFactory.ContentFileInfo, testFactory.EncryptedContentFileInfo); + bool verified = pgpVerify.VerifyClear(testFactory.EncryptedContentFileInfo); + string signedContent = File.ReadAllText(testFactory.EncryptedContentFileInfo.FullName, Encoding.UTF8); + + // Assert + using (new AssertionScope()) + { + verified.Should().BeTrue(); + signedContent.Should().Contain(utf8Content); + // Verify that specific UTF-8 characters are preserved + signedContent.Should().Contain("š"); + signedContent.Should().Contain("€"); + signedContent.Should().Contain("中文"); + } + + // Teardown + testFactory.Teardown(); + } } } diff --git a/PgpCore.Tests/UnitTests/Sign/SignSync.Stream.cs b/PgpCore.Tests/UnitTests/Sign/SignSync.Stream.cs index fb3be23..b859502 100644 --- a/PgpCore.Tests/UnitTests/Sign/SignSync.Stream.cs +++ b/PgpCore.Tests/UnitTests/Sign/SignSync.Stream.cs @@ -289,5 +289,44 @@ public void ClearSign_SignMessageWithHeaders_ShouldSignMessage(KeyType keyType) // Teardown testFactory.Teardown(); } + + [Theory] + [InlineData(KeyType.Generated)] + [InlineData(KeyType.Known)] + [InlineData(KeyType.KnownGpg)] + public void ClearSign_SignMessageWithUtf8Characters_ShouldPreserveUtf8(KeyType keyType) + { + // Arrange + TestFactory testFactory = new TestFactory(); + testFactory.Arrange(keyType); + string utf8Content = "Test with UTF-8: š ž č ć đ ñ ü ö ä € ₹ 中文 日本語 한글"; + File.WriteAllText(testFactory.ContentFileInfo.FullName, utf8Content, Encoding.UTF8); + + EncryptionKeys signingKeys = new EncryptionKeys(testFactory.PrivateKeyStream, testFactory.Password); + EncryptionKeys verificationKeys = new EncryptionKeys(testFactory.PublicKeyStream); + PGP pgpSign = new PGP(signingKeys); + PGP pgpVerify = new PGP(verificationKeys); + + // Act + using (Stream outputFileStream = testFactory.EncryptedContentFileInfo.Create()) + pgpSign.ClearSign(testFactory.ContentStream, outputFileStream); + + bool verified = pgpVerify.VerifyClear(testFactory.EncryptedContentStream); + string signedContent = File.ReadAllText(testFactory.EncryptedContentFileInfo.FullName, Encoding.UTF8); + + // Assert + using (new AssertionScope()) + { + verified.Should().BeTrue(); + signedContent.Should().Contain(utf8Content); + // Verify that specific UTF-8 characters are preserved + signedContent.Should().Contain("š"); + signedContent.Should().Contain("€"); + signedContent.Should().Contain("中文"); + } + + // Teardown + testFactory.Teardown(); + } } } diff --git a/PgpCore.Tests/UnitTests/Sign/SignSync.String.cs b/PgpCore.Tests/UnitTests/Sign/SignSync.String.cs index 88824ad..48d1f81 100644 --- a/PgpCore.Tests/UnitTests/Sign/SignSync.String.cs +++ b/PgpCore.Tests/UnitTests/Sign/SignSync.String.cs @@ -236,5 +236,39 @@ public void ClearSign_SignMessageWithHeaders_ShouldSignMessage(KeyType keyType) // Teardown testFactory.Teardown(); } + + [Theory] + [InlineData(KeyType.Generated)] + [InlineData(KeyType.Known)] + [InlineData(KeyType.KnownGpg)] + public void ClearSign_SignMessageWithUtf8Characters_ShouldPreserveUtf8(KeyType keyType) + { + // Arrange + TestFactory testFactory = new TestFactory(); + testFactory.Arrange(keyType, FileType.Known); + EncryptionKeys signingKeys = new EncryptionKeys(testFactory.PrivateKey, testFactory.Password); + EncryptionKeys verificationKeys = new EncryptionKeys(testFactory.PublicKey); + PGP pgpSign = new PGP(signingKeys); + PGP pgpVerify = new PGP(verificationKeys); + string utf8Content = "Test with UTF-8: š ž č ć đ ñ ü ö ä € ₹ 中文 日本語 한글"; + + // Act + string signedContent = pgpSign.ClearSign(utf8Content); + bool verified = pgpVerify.VerifyClear(signedContent); + + // Assert + using (new AssertionScope()) + { + verified.Should().BeTrue(); + signedContent.Should().Contain(utf8Content); + // Verify that specific UTF-8 characters are preserved + signedContent.Should().Contain("š"); + signedContent.Should().Contain("€"); + signedContent.Should().Contain("中文"); + } + + // Teardown + testFactory.Teardown(); + } } } diff --git a/PgpCore/PGP.cs b/PgpCore/PGP.cs index 1b3cf1a..a0f58a7 100644 --- a/PgpCore/PGP.cs +++ b/PgpCore/PGP.cs @@ -222,11 +222,11 @@ private async Task OutputClearSignedAsync(Stream inputStream, Stream outputStrea while (streamReader.Peek() >= 0) { string line = await streamReader.ReadLineAsync(); - byte[] lineByteArray = Encoding.ASCII.GetBytes(line); + byte[] lineByteArray = Encoding.UTF8.GetBytes(line); // Does the line end with whitespace? // Trailing white space needs to be removed from the end of the document for a valid signature RFC 4880 Section 7.1 string cleanLine = line.TrimEnd(); - byte[] cleanLineByteArray = Encoding.ASCII.GetBytes(cleanLine); + byte[] cleanLineByteArray = Encoding.UTF8.GetBytes(cleanLine); pgpSignatureGenerator.Update(cleanLineByteArray, 0, cleanLineByteArray.Length); await armoredOutputStream.WriteAsync(lineByteArray, 0, lineByteArray.Length); @@ -273,11 +273,11 @@ private void OutputClearSigned(Stream inputStream, Stream outputStream, IDiction { string line = streamReader.ReadLine(); if (line == null) continue; - byte[] lineByteArray = Encoding.ASCII.GetBytes(line); + byte[] lineByteArray = Encoding.UTF8.GetBytes(line); // Does the line end with whitespace? // Trailing white space needs to be removed from the end of the document for a valid signature RFC 4880 Section 7.1 string cleanLine = line.TrimEnd(); - byte[] cleanLineByteArray = Encoding.ASCII.GetBytes(cleanLine); + byte[] cleanLineByteArray = Encoding.UTF8.GetBytes(cleanLine); pgpSignatureGenerator.Update(cleanLineByteArray, 0, cleanLineByteArray.Length); armoredOutputStream.Write(lineByteArray, 0, lineByteArray.Length); diff --git a/PgpCore/PgpCore.csproj b/PgpCore/PgpCore.csproj index f86f58d..ac054b6 100644 --- a/PgpCore/PgpCore.csproj +++ b/PgpCore/PgpCore.csproj @@ -10,10 +10,10 @@ https://github.com/mattosaurus/PgpCore https://github.com/mattosaurus/PgpCore PGP .NET Core - 6.5.3.0 + 6.5.4.0 6.0.0.0 - 6.5.3 - v6.5.3 - Fix missing bytes + 6.5.4 + v6.5.4 - Fix clearsign encoding MIT true true