diff --git a/PgpCore.Tests/UnitTests/LegacyUnitTestsAsync.cs b/PgpCore.Tests/UnitTests/LegacyUnitTestsAsync.cs index 9a90232..58e0758 100644 --- a/PgpCore.Tests/UnitTests/LegacyUnitTestsAsync.cs +++ b/PgpCore.Tests/UnitTests/LegacyUnitTestsAsync.cs @@ -127,7 +127,7 @@ public async Task ClearSignFileAsync_CreateClearSignedFile(KeyType keyType) [InlineData(KeyType.Generated)] [InlineData(KeyType.Known)] [InlineData(KeyType.KnownGpg)] - public async Task ClearSignAndVerifyFileAsync_CreateClearSignedFileAndVerify(KeyType keyType) + public async Task ClearSignFileAsync_CreateClearSignedFileAndVerify(KeyType keyType) { // Arrange TestFactory testFactory = new TestFactory(); @@ -148,7 +148,7 @@ public async Task ClearSignAndVerifyFileAsync_CreateClearSignedFileAndVerify(Key [InlineData(KeyType.Generated)] [InlineData(KeyType.Known)] [InlineData(KeyType.KnownGpg)] - public async Task ClearSignAndDoNotVerifyFileAsync_CreateClearSignedFileAndDoNotVerify(KeyType keyType) + public async Task ClearSignFileAsync_CreateClearSignedFileAndDoNotVerify(KeyType keyType) { // Arrange TestFactory testFactory = new TestFactory(); @@ -168,6 +168,31 @@ public async Task ClearSignAndDoNotVerifyFileAsync_CreateClearSignedFileAndDoNot testFactory2.Teardown(); } + [Theory] + [InlineData(KeyType.Generated)] + [InlineData(KeyType.Known)] + [InlineData(KeyType.KnownGpg)] + public async Task ClearSignFileAsync_CreateClearSignedFileWithBadContentAndDoNotVerify(KeyType keyType) + { + // Arrange + TestFactory testFactory = new TestFactory(); + await testFactory.ArrangeAsync(keyType, FileType.Known); + EncryptionKeys encryptionKeys = new EncryptionKeys(testFactory.PrivateKeyFileInfo, testFactory.Password); + PGP pgp = new PGP(encryptionKeys); + + // Act + await pgp.ClearSignFileAsync(testFactory.ContentFilePath, testFactory.SignedContentFilePath); + string fileContent = await File.ReadAllTextAsync(testFactory.SignedContentFilePath); + fileContent = fileContent.Replace("fox", "rabbit"); + System.IO.File.WriteAllText(testFactory.SignedContentFilePath, fileContent); + + // Assert + Assert.False(await pgp.VerifyClearFileAsync(testFactory.SignedContentFilePath, testFactory.PublicKeyFilePath)); + + // Teardown + testFactory.Teardown(); + } + [Theory] [InlineData(KeyType.Generated)] [InlineData(KeyType.Known)] diff --git a/PgpCore.Tests/UnitTests/LegacyUnitTestsSync.cs b/PgpCore.Tests/UnitTests/LegacyUnitTestsSync.cs index 35eab6d..612c71c 100644 --- a/PgpCore.Tests/UnitTests/LegacyUnitTestsSync.cs +++ b/PgpCore.Tests/UnitTests/LegacyUnitTestsSync.cs @@ -158,7 +158,7 @@ public void ClearSignFile_CreateClearSignedFile(KeyType keyType) [InlineData(KeyType.Generated)] [InlineData(KeyType.Known)] [InlineData(KeyType.KnownGpg)] - public void ClearSignAndVerifyFile_CreateClearSignedFileAndVerify(KeyType keyType) + public void ClearSignFile_CreateClearSignedFileAndVerify(KeyType keyType) { // Arrange TestFactory testFactory = new TestFactory(); @@ -179,7 +179,7 @@ public void ClearSignAndVerifyFile_CreateClearSignedFileAndVerify(KeyType keyTyp [InlineData(KeyType.Generated)] [InlineData(KeyType.Known)] [InlineData(KeyType.KnownGpg)] - public void ClearSignAndDoNotVerifyFile_CreateClearSignedFileAndDoNotVerify(KeyType keyType) + public void ClearSignFile_CreateClearSignedFileAndDoNotVerify(KeyType keyType) { // Arrange TestFactory testFactory = new TestFactory(); @@ -199,6 +199,31 @@ public void ClearSignAndDoNotVerifyFile_CreateClearSignedFileAndDoNotVerify(KeyT testFactory2.Teardown(); } + [Theory] + [InlineData(KeyType.Generated)] + [InlineData(KeyType.Known)] + [InlineData(KeyType.KnownGpg)] + public void ClearSignFile_CreateClearSignedFileWithBadContentAndDoNotVerify(KeyType keyType) + { + // Arrange + TestFactory testFactory = new TestFactory(); + testFactory.Arrange(keyType, FileType.Known); + EncryptionKeys encryptionKeys = new EncryptionKeys(testFactory.PrivateKeyFileInfo, testFactory.Password); + PGP pgp = new PGP(encryptionKeys); + + // Act + pgp.ClearSignFile(testFactory.ContentFilePath, testFactory.SignedContentFilePath); + string fileContent = File.ReadAllText(testFactory.SignedContentFilePath); + fileContent = fileContent.Replace("fox", "rabbit"); + File.WriteAllText(testFactory.SignedContentFilePath, fileContent); + + // Assert + Assert.False(pgp.VerifyClearFile(testFactory.SignedContentFilePath, testFactory.PublicKeyFilePath)); + + // Teardown + testFactory.Teardown(); + } + [Theory] [InlineData(KeyType.Generated)] [InlineData(KeyType.Known)] diff --git a/PgpCore.Tests/UnitTests/UnitTestsAsync.cs b/PgpCore.Tests/UnitTests/UnitTestsAsync.cs index 7b9d2ae..655ffe1 100644 --- a/PgpCore.Tests/UnitTests/UnitTestsAsync.cs +++ b/PgpCore.Tests/UnitTests/UnitTestsAsync.cs @@ -131,7 +131,7 @@ public async Task ClearSignFileAsync_CreateClearSignedFile(KeyType keyType) [InlineData(KeyType.Generated)] [InlineData(KeyType.Known)] [InlineData(KeyType.KnownGpg)] - public async Task ClearSignAndVerifyFileAsync_CreateClearSignedFileAndVerify(KeyType keyType) + public async Task ClearSignFileAsync_CreateClearSignedFileAndVerify(KeyType keyType) { // Arrange TestFactory testFactory = new TestFactory(); @@ -153,7 +153,7 @@ public async Task ClearSignAndVerifyFileAsync_CreateClearSignedFileAndVerify(Key [InlineData(KeyType.Generated)] [InlineData(KeyType.Known)] [InlineData(KeyType.KnownGpg)] - public async Task ClearSignAndDoNotVerifyFileAsync_CreateClearSignedFileAndDoNotVerify(KeyType keyType) + public async Task ClearSignFileAsync_CreateClearSignedFileAndDoNotVerify(KeyType keyType) { // Arrange TestFactory testFactory = new TestFactory(); @@ -176,6 +176,31 @@ public async Task ClearSignAndDoNotVerifyFileAsync_CreateClearSignedFileAndDoNot testFactory2.Teardown(); } + [Theory] + [InlineData(KeyType.Generated)] + [InlineData(KeyType.Known)] + [InlineData(KeyType.KnownGpg)] + public async Task ClearSignFileAsync_CreateClearSignedFileWithBadContentAndDoNotVerify(KeyType keyType) + { + // Arrange + TestFactory testFactory = new TestFactory(); + await testFactory.ArrangeAsync(keyType, FileType.Known); + EncryptionKeys encryptionKeys = new EncryptionKeys(testFactory.PrivateKeyFileInfo, testFactory.Password); + PGP pgp = new PGP(encryptionKeys); + + // Act + await pgp.ClearSignFileAsync(testFactory.ContentFilePath, testFactory.SignedContentFilePath); + string fileContent = await File.ReadAllTextAsync(testFactory.SignedContentFilePath); + fileContent = fileContent.Replace("fox", "rabbit"); + System.IO.File.WriteAllText(testFactory.SignedContentFilePath, fileContent); + + // Assert + Assert.False(await pgp.VerifyClearFileAsync(testFactory.SignedContentFilePath, testFactory.PublicKeyFilePath)); + + // Teardown + testFactory.Teardown(); + } + [Theory] [InlineData(KeyType.Generated)] [InlineData(KeyType.Known)] diff --git a/PgpCore.Tests/UnitTests/UnitTestsSync.cs b/PgpCore.Tests/UnitTests/UnitTestsSync.cs index ed30c1f..27cb7ed 100644 --- a/PgpCore.Tests/UnitTests/UnitTestsSync.cs +++ b/PgpCore.Tests/UnitTests/UnitTestsSync.cs @@ -121,7 +121,7 @@ public void ClearSignFile_CreateClearSignedFile(KeyType keyType) [InlineData(KeyType.Generated)] [InlineData(KeyType.Known)] [InlineData(KeyType.KnownGpg)] - public void ClearSignAndVerifyFile_CreateClearSignedFileAndVerify(KeyType keyType) + public void ClearSignFile_CreateClearSignedFileAndVerify(KeyType keyType) { // Arrange TestFactory testFactory = new TestFactory(); @@ -143,7 +143,7 @@ public void ClearSignAndVerifyFile_CreateClearSignedFileAndVerify(KeyType keyTyp [InlineData(KeyType.Generated)] [InlineData(KeyType.Known)] [InlineData(KeyType.KnownGpg)] - public void ClearSignAndDoNotVerifyFile_CreateClearSignedFileAndDoNotVerify(KeyType keyType) + public void ClearSignFile_CreateClearSignedFileAndDoNotVerify(KeyType keyType) { // Arrange TestFactory testFactory = new TestFactory(); @@ -166,6 +166,31 @@ public void ClearSignAndDoNotVerifyFile_CreateClearSignedFileAndDoNotVerify(KeyT testFactory2.Teardown(); } + [Theory] + [InlineData(KeyType.Generated)] + [InlineData(KeyType.Known)] + [InlineData(KeyType.KnownGpg)] + public void ClearSignFile_CreateClearSignedFileWithBadContentAndDoNotVerify(KeyType keyType) + { + // Arrange + TestFactory testFactory = new TestFactory(); + testFactory.Arrange(keyType, FileType.Known); + EncryptionKeys encryptionKeys = new EncryptionKeys(testFactory.PrivateKeyFileInfo, testFactory.Password); + PGP pgp = new PGP(encryptionKeys); + + // Act + pgp.ClearSignFile(testFactory.ContentFilePath, testFactory.SignedContentFilePath); + string fileContent = File.ReadAllText(testFactory.SignedContentFilePath); + fileContent = fileContent.Replace("fox", "rabbit"); + File.WriteAllText(testFactory.SignedContentFilePath, fileContent); + + // Assert + Assert.False(pgp.VerifyClearFile(testFactory.SignedContentFilePath, testFactory.PublicKeyFilePath)); + + // Teardown + testFactory.Teardown(); + } + [Theory] [InlineData(KeyType.Generated)] [InlineData(KeyType.Known)] @@ -670,6 +695,32 @@ public void Verify_DoNotVerifyEncryptedAndSignedFile(KeyType keyType) testFactory.Teardown(); } + [Theory] + [InlineData(KeyType.Generated)] + [InlineData(KeyType.Known)] + [InlineData(KeyType.KnownGpg)] + public void Verify_DoNotVerifySignedFileWithBadContent(KeyType keyType) + { + // Arrange + TestFactory testFactory = new TestFactory(); + testFactory.Arrange(keyType, FileType.Known); + EncryptionKeys encryptionKeys = new EncryptionKeys(testFactory.PublicKeyFileInfo, testFactory.PrivateKeyFileInfo, testFactory.Password); + PGP pgp = new PGP(encryptionKeys); + + // Act + pgp.SignFile(testFactory.ContentFilePath, testFactory.EncryptedContentFilePath); + string[] fileLines = File.ReadAllLines(testFactory.EncryptedContentFilePath); + fileLines[3] = fileLines[3].Substring(0, fileLines[3].Length - 1 - 1) + "x"; + File.WriteAllLines(testFactory.EncryptedContentFilePath, fileLines); + bool verified = pgp.VerifyFile(testFactory.EncryptedContentFilePath); + + // Assert + Assert.False(verified); + + // Teardown + testFactory.Teardown(); + } + [Theory] [InlineData(KeyType.Generated)] [InlineData(KeyType.Known)] diff --git a/PgpCore.sln b/PgpCore.sln index 0463bab..370c470 100644 --- a/PgpCore.sln +++ b/PgpCore.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.28803.352 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PgpCore", "PgpCore\PgpCore.csproj", "{109C82AE-0229-494D-845F-828B61C712E6}" EndProject @@ -21,6 +21,10 @@ Global {9F70E456-1511-4466-B805-6D0AABC48AD9}.Debug|Any CPU.Build.0 = Debug|Any CPU {9F70E456-1511-4466-B805-6D0AABC48AD9}.Release|Any CPU.ActiveCfg = Release|Any CPU {9F70E456-1511-4466-B805-6D0AABC48AD9}.Release|Any CPU.Build.0 = Release|Any CPU + {DB356D7C-0C5C-4E8C-8DE3-A4372AA61850}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DB356D7C-0C5C-4E8C-8DE3-A4372AA61850}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DB356D7C-0C5C-4E8C-8DE3-A4372AA61850}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DB356D7C-0C5C-4E8C-8DE3-A4372AA61850}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/PgpCore/PGP.cs b/PgpCore/PGP.cs index 4b80afb..be2f691 100644 --- a/PgpCore/PGP.cs +++ b/PgpCore/PGP.cs @@ -4761,16 +4761,55 @@ private async Task VerifyAsync(Stream inputStream) { verified = false; } + //PgpEncryptedDataList encryptedDataList = (PgpEncryptedDataList)pgpObject; + + //foreach (PgpPublicKeyEncryptedData encryptedData in encryptedDataList.GetEncryptedDataObjects()) + //{ + // encryptedData.GetDataStream(EncryptionKeys.PrivateKey); + // if (encryptedData.Verify()) + // { + // verified = true; + // break; + // } + //} } else if (pgpObject is PgpOnePassSignatureList) { PgpOnePassSignatureList pgpOnePassSignatureList = (PgpOnePassSignatureList)pgpObject; PgpOnePassSignature pgpOnePassSignature = pgpOnePassSignatureList[0]; + PgpLiteralData pgpLiteralData = (PgpLiteralData)factory.NextPgpObject(); + Stream pgpLiteralStream = pgpLiteralData.GetInputStream(); // Verify against public key ID and that of any sub keys if (publicKey.KeyId == pgpOnePassSignature.KeyId || publicKey.GetKeySignatures().Cast().Select(x => x.KeyId).Contains(pgpOnePassSignature.KeyId)) { - verified = true; + pgpOnePassSignature.InitVerify(publicKey); + + int ch; + while ((ch = pgpLiteralStream.ReadByte()) >= 0) + { + pgpOnePassSignature.Update((byte)ch); + } + + try + { + PgpSignatureList pgpSignatureList = (PgpSignatureList)factory.NextPgpObject(); + + for (int i = 0; i < pgpSignatureList.Count; i++) + { + PgpSignature pgpSignature = pgpSignatureList[i]; + + if (pgpOnePassSignature.Verify(pgpSignature)) + { + verified = true; + break; + } + } + } + catch + { + verified = false; + } } else { @@ -4781,11 +4820,31 @@ private async Task VerifyAsync(Stream inputStream) { PgpSignatureList pgpSignatureList = (PgpSignatureList)pgpObject; PgpSignature pgpSignature = pgpSignatureList[0]; + PgpLiteralData pgpLiteralData = (PgpLiteralData)factory.NextPgpObject(); + Stream pgpLiteralStream = pgpLiteralData.GetInputStream(); // Verify against public key ID and that of any sub keys if (publicKey.KeyId == pgpSignature.KeyId || publicKey.GetKeySignatures().Cast().Select(x => x.KeyId).Contains(pgpSignature.KeyId)) { - verified = true; + foreach (PgpSignature signature in publicKey.GetSignatures()) + { + if (!verified) + { + pgpSignature.InitVerify(publicKey); + + int ch; + while ((ch = pgpLiteralStream.ReadByte()) >= 0) + { + pgpSignature.Update((byte)ch); + } + + verified = pgpSignature.Verify(); + } + else + { + break; + } + } } else { @@ -4812,12 +4871,55 @@ private bool Verify(Stream inputStream) if (pgpObject is PgpCompressedData) { - PgpPublicKeyEncryptedData publicKeyED = Utilities.ExtractPublicKeyEncryptedData(encodedFile); + PgpCompressedData pgpCompressedData = (PgpCompressedData)pgpObject; + PgpObjectFactory pgpCompressedFactory = new PgpObjectFactory(pgpCompressedData.GetDataStream()); + + PgpOnePassSignatureList pgpOnePassSignatureList = (PgpOnePassSignatureList)pgpCompressedFactory.NextPgpObject(); + PgpOnePassSignature pgpOnePassSignature = pgpOnePassSignatureList[0]; + PgpLiteralData pgpLiteralData = (PgpLiteralData)factory.NextPgpObject(); + Stream pgpLiteralStream = pgpLiteralData.GetInputStream(); // Verify against public key ID and that of any sub keys - if (publicKey.KeyId == publicKeyED.KeyId || publicKey.GetKeySignatures().Cast().Select(x => x.KeyId).Contains(publicKeyED.KeyId)) + if (publicKey.KeyId == pgpOnePassSignature.KeyId || publicKey.GetKeySignatures().Cast().Select(x => x.KeyId).Contains(pgpOnePassSignature.KeyId)) { - verified = true; + foreach (PgpSignature signature in publicKey.GetSignatures()) + { + if (!verified) + { + pgpOnePassSignature.InitVerify(publicKey); + + int ch; + while ((ch = pgpLiteralStream.ReadByte()) >= 0) + { + pgpOnePassSignature.Update((byte)ch); + } + + try + { + PgpSignatureList pgpSignatureList = (PgpSignatureList)factory.NextPgpObject(); + + for (int i = 0; i < pgpSignatureList.Count; i++) + { + PgpSignature pgpSignature = pgpSignatureList[i]; + + if (pgpOnePassSignature.Verify(pgpSignature)) + { + verified = true; + break; + } + } + } + catch + { + verified = false; + break; + } + } + else + { + break; + } + } } else { @@ -4838,16 +4940,57 @@ private bool Verify(Stream inputStream) { verified = false; } + //PgpEncryptedDataList encryptedDataList = (PgpEncryptedDataList)pgpObject; + + //foreach (PgpPublicKeyEncryptedData encryptedData in encryptedDataList.GetEncryptedDataObjects()) + //{ + // using (encryptedData.GetDataStream(EncryptionKeys.PrivateKey)) + // { + // if (encryptedData.Verify()) + // { + // verified = true; + // break; + // } + // } + //} } else if (pgpObject is PgpOnePassSignatureList) { PgpOnePassSignatureList pgpOnePassSignatureList = (PgpOnePassSignatureList)pgpObject; PgpOnePassSignature pgpOnePassSignature = pgpOnePassSignatureList[0]; + PgpLiteralData pgpLiteralData = (PgpLiteralData)factory.NextPgpObject(); + Stream pgpLiteralStream = pgpLiteralData.GetInputStream(); // Verify against public key ID and that of any sub keys if (publicKey.KeyId == pgpOnePassSignature.KeyId || publicKey.GetKeySignatures().Cast().Select(x => x.KeyId).Contains(pgpOnePassSignature.KeyId)) { - verified = true; + pgpOnePassSignature.InitVerify(publicKey); + + int ch; + while ((ch = pgpLiteralStream.ReadByte()) >= 0) + { + pgpOnePassSignature.Update((byte)ch); + } + + try + { + PgpSignatureList pgpSignatureList = (PgpSignatureList)factory.NextPgpObject(); + + for (int i = 0; i < pgpSignatureList.Count; i++) + { + PgpSignature pgpSignature = pgpSignatureList[i]; + + if (pgpOnePassSignature.Verify(pgpSignature)) + { + verified = true; + break; + } + } + } + catch + { + verified = false; + } } else { @@ -4856,18 +4999,38 @@ private bool Verify(Stream inputStream) } else if (pgpObject is PgpSignatureList) { - PgpSignatureList pgpSignatureList = (PgpSignatureList)pgpObject; - PgpSignature pgpSignature = pgpSignatureList[0]; - - // Verify against public key ID and that of any sub keys - if (publicKey.KeyId == pgpSignature.KeyId || publicKey.GetKeySignatures().Cast().Select(x => x.KeyId).Contains(pgpSignature.KeyId)) - { - verified = true; - } - else - { - verified = false; - } + PgpSignatureList pgpSignatureList = (PgpSignatureList)pgpObject; + PgpSignature pgpSignature = pgpSignatureList[0]; + PgpLiteralData pgpLiteralData = (PgpLiteralData)factory.NextPgpObject(); + Stream pgpLiteralStream = pgpLiteralData.GetInputStream(); + + // Verify against public key ID and that of any sub keys + if (publicKey.KeyId == pgpSignature.KeyId || publicKey.GetKeySignatures().Cast().Select(x => x.KeyId).Contains(pgpSignature.KeyId)) + { + foreach (PgpSignature signature in publicKey.GetSignatures()) + { + if (!verified) + { + pgpSignature.InitVerify(publicKey); + + int ch; + while ((ch = pgpLiteralStream.ReadByte()) >= 0) + { + pgpSignature.Update((byte)ch); + } + + verified = pgpSignature.Verify(); + } + else + { + break; + } + } + } + else + { + verified = false; + } } else throw new PgpException("Message is not a encrypted and signed file or simple signed file.");