public void SnPublicKeyIsReturnedAsIs() { var key = ImmutableArray.Create(TestResources.General.snPublicKey); ImmutableArray <byte> pubKey; Assert.True(CryptoBlobParser.TryParseKey(key, out pubKey, out _)); Assert.True(CryptoBlobParser.IsValidPublicKey(pubKey)); AssertEx.Equal(key, pubKey); }
public void GetPublicKeyFromKeyPair2() { var key = ImmutableArray.Create(TestResources.General.snKey2); ImmutableArray <byte> pubKey; Assert.True(CryptoBlobParser.TryParseKey(key, out pubKey, out _)); Assert.True(CryptoBlobParser.IsValidPublicKey(pubKey)); AssertEx.Equal(TestResources.General.snPublicKey2, pubKey); }
public void GetPrivateKeyFromKeyPair2() { var key = ImmutableArray.Create(TestResources.General.snKey2); RSAParameters?privateKeyOpt; Assert.True(CryptoBlobParser.TryParseKey(key, out _, out privateKeyOpt)); Assert.True(privateKeyOpt.HasValue); var privKey = privateKeyOpt.Value; AssertEx.Equal(privKey.Exponent, new byte[] { 0x01, 0x00, 0x01 }); var expectedModulus = key.Skip(HEADER_LEN).Take(MOD_LEN).ToArray(); Array.Reverse(expectedModulus); AssertEx.Equal(expectedModulus, privKey.Modulus); var expectedP = key.Skip(HEADER_LEN + MOD_LEN).Take(HALF_LEN).ToArray(); Array.Reverse(expectedP); AssertEx.Equal(expectedP, privKey.P); var expectedQ = key.Skip(HEADER_LEN + MOD_LEN + HALF_LEN).Take(HALF_LEN).ToArray(); Array.Reverse(expectedQ); AssertEx.Equal(expectedQ, privKey.Q); var expectedDP = key.Skip(HEADER_LEN + MOD_LEN + HALF_LEN * 2).Take(HALF_LEN).ToArray(); Array.Reverse(expectedDP); AssertEx.Equal(expectedDP, privKey.DP); var expectedDQ = key.Skip(HEADER_LEN + MOD_LEN + HALF_LEN * 3).Take(HALF_LEN).ToArray(); Array.Reverse(expectedDQ); AssertEx.Equal(expectedDQ, privKey.DQ); var expectedInverseQ = key.Skip(HEADER_LEN + MOD_LEN + HALF_LEN * 4) .Take(HALF_LEN) .ToArray(); Array.Reverse(expectedInverseQ); AssertEx.Equal(expectedInverseQ, privKey.InverseQ); var expectedD = key.Skip(HEADER_LEN + MOD_LEN + HALF_LEN * 5).Take(MOD_LEN).ToArray(); Array.Reverse(expectedD); AssertEx.Equal(expectedD, privKey.D); Assert.True(key.Skip(HEADER_LEN + MOD_LEN * 2 + HALF_LEN * 5).ToArray().Length == 0); }
public void TryGetPublicKeyFailsForInvalidKeyBlobs() { var invalidKeyBlobs = new[] { string.Empty, new string('0', 160 * 2), // 160 * 2 - the length of a public key, 2 - 2 chars per byte new string('0', 596 * 2), // 596 * 2 - the length of a key pair, 2 - 2 chars per byte "0702000000240000DEADBEEF" + new string('0', 584 * 2), // private key blob without magic private key "0602000000240000DEADBEEF" + new string('0', 136 * 2), // public key blob without magic public key }; Assert.False(CryptoBlobParser.TryParseKey(HexToBin(invalidKeyBlobs[0]), out _, out _)); Assert.False(CryptoBlobParser.TryParseKey(HexToBin(invalidKeyBlobs[1]), out _, out _)); Assert.False(CryptoBlobParser.TryParseKey(HexToBin(invalidKeyBlobs[2]), out _, out _)); Assert.False(CryptoBlobParser.TryParseKey(HexToBin(invalidKeyBlobs[3]), out _, out _)); }
public void GetSnPublicKeyFromPublicKeyBlob() { // An Strongname public key blob includes an additional header on top // of the wincrypt.h public key blob var snBlob = TestResources.General.snPublicKey; var buf = new byte[snBlob.Length - CryptoBlobParser.s_publicKeyHeaderSize]; Array.Copy(snBlob, CryptoBlobParser.s_publicKeyHeaderSize, buf, 0, buf.Length); var publicKeyBlob = ImmutableArray.Create(buf); ImmutableArray <byte> pubKey; Assert.True(CryptoBlobParser.TryParseKey(publicKeyBlob, out pubKey, out _)); Assert.True(CryptoBlobParser.IsValidPublicKey(pubKey)); AssertEx.Equal(snBlob, pubKey); }
public void TryGetPublicKeyFailsForInvalidKeyBlobs() { var invalidKeyBlobs = new[] { string.Empty, new string('0', 160 * 2), // 160 * 2 - the length of a public key, 2 - 2 chars per byte new string('0', 596 * 2), // 596 * 2 - the length of a key pair, 2 - 2 chars per byte "0702000000240000DEADBEEF" + new string('0', 584 * 2), // private key blob without magic private key "0602000000240000DEADBEEF" + new string('0', 136 * 2), // public key blob without magic public key }; ImmutableArray <byte> pubKey; foreach (var key in invalidKeyBlobs) { Assert.False(CryptoBlobParser.TryGetPublicKey(HexToBin(key), out pubKey)); } }
/// <summary> /// Validates that the given stream is marked as signed, the signature matches /// the public key, and the header checksum is correct. /// </summary> public static bool IsStreamFullSigned(Stream moduleContents) { var savedPosition = moduleContents.Position; try { moduleContents.Position = 0; var peHeaders = new PEHeaders(moduleContents); moduleContents.Position = 0; using (var metadata = ModuleMetadata.CreateFromStream(moduleContents, leaveOpen: true)) { var metadataReader = metadata.MetadataReader; var peReader = metadata.Module.PEReaderOpt; var flags = peHeaders.CorHeader.Flags; if (CorFlags.StrongNameSigned != (flags & CorFlags.StrongNameSigned)) { return(false); } var snDirectory = peReader.PEHeaders.CorHeader.StrongNameSignatureDirectory; if (!peHeaders.TryGetDirectoryOffset(snDirectory, out int snOffset)) { return(false); } moduleContents.Position = 0; int peSize; try { peSize = checked ((int)moduleContents.Length); } catch { return(false); } var peImage = new BlobBuilder(peSize); if (peSize != peImage.TryWriteBytes(moduleContents, peSize)) { return(false); } byte[] buffer = GetBlobBuffer(peImage.GetBlobs().Single()); uint expectedChecksum = peHeaders.PEHeader.CheckSum; Blob checksumBlob = MakeBlob(buffer, peHeaders.PEHeaderStartOffset + ChecksumOffset, sizeof(uint)); if (expectedChecksum != PeWriter.CalculateChecksum(peImage, checksumBlob)) { return(false); } int snSize = snDirectory.Size; byte[] hash = ComputeSigningHash(peImage, peHeaders, checksumBlob, snOffset, snSize); ImmutableArray <byte> publicKeyBlob = metadataReader.GetBlobContent(metadataReader.GetAssemblyDefinition().PublicKey); // RSA parameters start after the public key offset byte[] publicKeyParams = new byte[publicKeyBlob.Length - CryptoBlobParser.s_publicKeyHeaderSize]; publicKeyBlob.CopyTo(CryptoBlobParser.s_publicKeyHeaderSize, publicKeyParams, 0, publicKeyParams.Length); var snKey = CryptoBlobParser.ToRSAParameters(publicKeyParams.AsSpan(), includePrivateParameters: false); using (var rsa = RSA.Create()) { rsa.ImportParameters(snKey); var reversedSignature = peReader.GetSectionData(snDirectory.RelativeVirtualAddress).GetContent(0, snSize).ToArray(); // Unknown why the signature is reversed, but this matches the behavior of the CLR // signing implementation. Array.Reverse(reversedSignature); if (!rsa.VerifyHash(hash, reversedSignature, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1)) { return(false); } } return(true); } } finally { moduleContents.Position = savedPosition; } }