0

These two function should be equivalent but VerifyBouncyCastle() returns false (failed verification) for the same input that VerifyDotNet() returns true on. The message was signed with .Net's DSACryptoServiceProvider.SignHash(). What's wrong with VerifyBouncyCastle() that makes it behave differently from the .Net version?

.Net built in crypto library:

Private Function VerifyDotNet(hash() As Byte, p() As Byte, q() As Byte, g() As Byte, y() As Byte, r() As Byte, s() As Byte) As Boolean

    'Public key
    Dim dotNetDSA As New DSACryptoServiceProvider()
    Dim dotNetParameters As New DSAParameters
    dotNetParameters.P = p
    dotNetParameters.Q = q
    dotNetParameters.G = g
    dotNetParameters.Y = y
    dotNetDSA.ImportParameters(dotNetParameters)

    'Signature
    Dim signature(39) As Byte
    Array.ConstrainedCopy(r, 0, signature, 0, 20)
    Array.ConstrainedCopy(s, 0, signature, 20, 20)

    'Verify
    Return dotNetDSA.VerifyHash(hash, "SHA1", signature)

End Function

BouncyCastle:

Private Function VerifyBouncyCastle(hash() As Byte, p() As Byte, q() As Byte, g() As Byte, y() As Byte, r() As Byte, s() As Byte) As Boolean

    'Public key
    Dim pBigInt As New Org.BouncyCastle.Math.BigInteger(p)
    Dim qBigInt As New Org.BouncyCastle.Math.BigInteger(q)
    Dim gBigInt As New Org.BouncyCastle.Math.BigInteger(g)
    Dim yBigInt As New Org.BouncyCastle.Math.BigInteger(y)
    Dim bouncyParameters As New Org.BouncyCastle.Crypto.Parameters.DsaParameters(pBigInt, qBigInt, gBigInt)
    Dim bouncyPublicKey As New Org.BouncyCastle.Crypto.Parameters.DsaPublicKeyParameters(yBigInt, bouncyParameters)
    Dim bouncyDSA As New Org.BouncyCastle.Crypto.Signers.DsaSigner
    bouncyDSA.Init(False, bouncyPublicKey)

    'Signature
    Dim signatureR As New Org.BouncyCastle.Math.BigInteger(r)
    Dim signatureS As New Org.BouncyCastle.Math.BigInteger(s)

    'Verify
    Return bouncyDSA.VerifySignature(hash, signatureR, signatureS)

End Function

I've tried reversing the byte arrays, and also verified that BouncyCastle's Sha1Digest.DoFinal() generates the same hash for the same message as .Net's SHA1Managed.ComputeHash() which was used to generate the hash for signing.

user1318499
  • 1,327
  • 11
  • 33

1 Answers1

0

BouncyCastle's byte arrays for the public key parameters p,q,g,y have a leading 0 while .Net's don't. So pad with a leading zero to make BouncyCastle work on .Net key parameters.

Private Function VerifyBouncyCastle(hash() As Byte, p() As Byte, q() As Byte, g() As Byte, y() As Byte, r() As Byte, s() As Byte) As Boolean

    'Public key
    Dim bouncyCastleP(p.Length) As Byte
    Dim bouncyCastleQ(q.Length) As Byte
    Dim bouncyCastleG(g.Length) As Byte
    Dim bouncyCastleY(y.Length) As Byte
    Array.ConstrainedCopy(p, 0, bouncyCastleP, 1, p.Length)
    Array.ConstrainedCopy(q, 0, bouncyCastleQ, 1, q.Length)
    Array.ConstrainedCopy(g, 0, bouncyCastleG, 1, g.Length)
    Array.ConstrainedCopy(y, 0, bouncyCastleY, 1, y.Length)
    Dim pBigInt As New Org.BouncyCastle.Math.BigInteger(bouncyCastleP)
    Dim qBigInt As New Org.BouncyCastle.Math.BigInteger(bouncyCastleQ)
    Dim gBigInt As New Org.BouncyCastle.Math.BigInteger(bouncyCastleG)
    Dim yBigInt As New Org.BouncyCastle.Math.BigInteger(bouncyCastleY)
    Dim bouncyParameters As New Org.BouncyCastle.Crypto.Parameters.DsaParameters(pBigInt, qBigInt, gBigInt)
    Dim bouncyPublicKey As New Org.BouncyCastle.Crypto.Parameters.DsaPublicKeyParameters(yBigInt, bouncyParameters)

    'Signature
    Dim bouncyDSA As New Org.BouncyCastle.Crypto.Signers.DsaSigner
    bouncyDSA.Init(False, bouncyPublicKey)
    Dim signatureR As New Org.BouncyCastle.Math.BigInteger(r)
    Dim signatureS As New Org.BouncyCastle.Math.BigInteger(s)

    'Verify
    Return bouncyDSA.VerifySignature(hash, signatureR, signatureS)

End Function

Alternatively, you can use Org.BouncyCastle.Security.DotNetUtilities.GetDsaPublicKey() to convert the .Net public key parameters to BouncyCastle's.

user1318499
  • 1,327
  • 11
  • 33