Finally got it working. It turns out the root cause for the
verification failure was the message that was being verified was
different from the message that was signed. This was because in Java
the string that gets signed first is converted to a byte array that
encodes the string using big endian UTF-16 that includes the BOM. So
in C++ I had to insert the BOM into the beginning of the string and
then I had to byte swap each word since they were in little endian
format. Below is the complete working code:
#include <dsa.h>
#include <gfpcrypt.h>
#include <hmac.h>
#include <sha.h>
#include <base64.h>
#include <files.h>
const byte KEY[] = {
48, -126, 1, -72, 48, -126, 1, 44, 6, 7, 42, -122, 72, -50,
56,
4, 1, 48, -126, 1, 31, 2, -127, -127, 0, -3, 127, 83, -127,
29,
117, 18, 41, 82, -33, 74, -100, 46, -20, -28, -25, -10, 17,
-73,
82, 60, -17, 68, 0, -61, 30, 63, -128, -74, 81, 38, 105, 69,
93,
64, 34, 81, -5, 89, 61, -115, 88, -6, -65, -59, -11, -70, 48,
-10, -53, -101, 85, 108, -41, -127, 59, -128, 29, 52, 111,
-14,
102, 96, -73, 107, -103, 80, -91, -92, -97, -97, -24, 4, 123,
16, 34, -62, 79, -69, -87, -41, -2, -73, -58, 27, -8, 59, 87,
-25, -58, -88, -90, 21, 15, 4, -5, -125, -10, -45, -59, 30,
-61, 2,
53, 84, 19, 90, 22, -111, 50, -10, 117, -13, -82, 43, 97, -41,
42,
-17, -14, 34, 3, 25, -99, -47, 72, 1, -57, 2, 21, 0, -105, 96,
80,
-113, 21, 35, 11, -52, -78, -110, -71, -126, -94, -21, -124,
11,
-16, 88, 28, -11, 2, -127, -127, 0, -9, -31, -96, -123, -42,
-101,
61, -34, -53, -68, -85, 92, 54, -72, 87, -71, 121, -108, -81,
-69,
-6, 58, -22, -126, -7, 87, 76, 11, 61, 7, -126, 103, 81, 89,
87,
-114, -70, -44, 89, 79, -26, 113, 7, 16, -127, -128, -76, 73,
22,
113, 35, -24, 76, 40, 22, 19, -73, -49, 9, 50, -116, -56, -90,
-31, 60, 22, 122, -117, 84, 124, -115, 40, -32, -93, -82, 30,
43, -77, -90, 117, -111, 110, -93, 127, 11, -6, 33, 53, 98,
-15, -5, 98, 122, 1, 36, 59, -52, -92, -15, -66, -88, 81,
-112, -119, -88, -125, -33, -31, 90, -27, -97, 6, -110, -117,
102, 94, -128, 123, 85, 37, 100, 1, 76, 59, -2, -49, 73, 42,
3, -127, -123, 0, 2, -127, -127, 0, -39, -79, 23, 79, -70, 46,
-20, 66, 123, 4, -81, -32, 32, 98, -41, -84, -12, 35, -85, 44,
-7,
-42, 94, -43, -107, 16, 109, -56, 14, -84, -56, 74, 117, 49,
-38, 78,
-9, -10, 75, -78, 7, -2, -1, 65, 98, -21, 117, 22, -101, 40,
8, -43,
35, -36, -109, 25, 96, -117, 106, -18, -70, -58, 45, -76, -76,
110,
126, 33, -105, -54, -56, 33, -3, 124, 12, -84, -72, 73, 4, -9,
78,
-31, 85, -107, -87, 23, 116, -55, 117, -53, -46, -76, -28,
-60, -98,
-104, -49, -126, -78, 77, -102, 96, 112, -102, -121, -113,
-112, -12,
5, 7, 2, -66, 75, -60, -83, -9, -27, -64, 7, -52, 43, -25,
-49, 88,
-49, 122, 94, 118 };
void test()
{
wstring strMsg(L"00:0d:56:89:cd:c012060369693041203444969304");
string strB64Sig =
"MC0CFQCGETPy4vOhTUwtTXVWPC8416WOoAIUQAOAEpluqH7aHuyzRNuty0qndMg=";
StringStore ssPubKey((byte*)KEY, sizeof(KEY));
StringSource ssSignature(strB64Sig, true, new Base64Decoder);
int iMsgLen = strMsg.length() * 2; // In bytes.
SecByteBlock abMessage(iMsgLen + 2); // Additional 2 bytes for
BOM.
bool bResult;
int iSigSize = 0;
GDSA<SHA1>::Verifier verifier;
// Add the BOM to the beginning of the message to mirror the
// message from which the signature is generated.
abMessage[0] = 0xFF;
abMessage[1] = 0xFE;
memcpy(&abMessage[2], (byte*)strMsg.c_str(), iMsgLen);
// Byte swap the message because the signature is generated from a
// big-endian formatted string. Must include the BOM in the
length.
for( int i = 0; i < iMsgLen + 1; i += 2 )
{
byte one = abMessage[i];
abMessage[i] = abMessage[i+1];
abMessage[i+1] = one;
}
try
{
verifier.AccessMaterial().Load(ssPubKey);
SecByteBlock abSigDER(
ssSignature.MaxRetrievable()); // DER formatted signature.
SecByteBlock abSigP1363(
verifier.SignatureLength()); // P1363 formatted signature.
ssSignature.Get(abSigDER, abSigDER.size());
// Convert signature from DER to P1363 format.
iSigSize = DSAConvertSignatureFormat(abSigP1363,
verifier.SignatureLength(), DSA_P1363,
abSigDER, abSigDER.size(), DSA_DER);
bResult = verifier.VerifyMessage(abMessage, iMsgLen + 2,
abSigP1363, iSigSize);
}
catch( ... )
{
printf("Exception occurred.\n");
}
}
On Mar 15, 9:25 am, ronald <[EMAIL PROTECTED]> wrote:
> Thanks for all the great suggestions guys.
>
> I'll double-check the key -- I just assumed it would be correct
> because my colleague is able to verify the message in Java with the
> same key. My colleague got the key directly from the Java PublicKey
> interface -- maybe he can give me the hex encoding of the public key.
>
> My colleague did mention on Friday that in Java he is converting the
> string message to a UTF-16 encoded byte array (he does the same thing
> before he signs the message). In my code I am not doing any
> conversion of the string. Maybe I need to convert the message to a
> wide character array? This should definitely be causing the
> verification to fail -- but I wonder if this is the only problem.
>
> I don't go back to work until Tuesday so I'll try then and post back
> here what I find.
>
> On Mar 14, 11:39 pm, "Jeffrey Walton" <[EMAIL PROTECTED]> wrote:
>
> > Hi Unfleshed One,
>
> > > Signed char -126 is 130 when converted to unsigned char (256 - x).
> > > So assuming original byte was 0x82 that's perfectly fine.
>
> > Introp can be frustrating for at times. Crypto++ is usually our first
> > language. We see tricks like this, and we are suspect. It's something
> > else we have to question because we are not as familiar with languages
> > such as Java, Bouncy Castle, mcrypt, C#, etc.
>
> > Can you pick another language/libray such as C# (another area I am
> > familiar) or OpenSSL (another area Geoff is familiar)? Just
> > kidding....
>
> > > > Ronald, I never used DSA, so I can't tell if you use it correctly,
>
> > DSA uses a random parameter (k). So you will probably have a difficult
> > time producing the exact output in each library. Below, your signature
> > on m is the pair (r,s)
>
> > 1) select random k
> > 2) compute r = (a^k mod p) mod q
> > 3) compute k^-1 mod q
> > 4) compute s = k^-1{ h(m) +ar } mod q
>
> > I recall seeing some source code posted for Java/Crpyto++ Interop on
> > the mailing list by Donald Bergstrom. It is a 3DES sample, but het
> > works out all the wrinkles (String versus Byte[], etc).
> > Seehttp://groups.google.com/group/cryptopp-users/browse_thread/thread/91...
>
> > Here's other topics of ineterst:
> > 1) Test the Java encoders -
> > seehttp://groups.google.com/group/cryptopp-users/browse_thread/thread/c7...
> > 2) Java String versus Byte[] -
> > seehttp://groups.google.com/group/cryptopp-users/browse_thread/thread/8b...
> > 3) Verify your use of Java's Str::getBytes() -
> > seehttp://groups.google.com/group/cryptopp-users/browse_thread/thread/12...
>
> > Jeff
>
> > On 3/14/08, UnFleshed One <[EMAIL PROTECTED]> wrote:> Geoff Beier wrote:
> > > const byte KEY[] = {
>
> > 48, -126, 1, -72, 48, -126, 1, 44, 6, 7, 42, -122,
>
> > > 72, -50,
> > > This jumps out at me immediately; I suspect you've not exported your
> > key
> > > properly.
>
> > A byte is an unsigned type. -126, -72, etc. don't make sense.
>
> > > Signed char -126 is 130 when converted to unsigned char (256 - x). So
> > > assuming original byte was 0x82 that's perfectly fine.
>
> > > Ronald, I never used DSA, so I can't tell if you use it correctly, but one
> > > thing you can try is create a signature using Crypto++, encode it into b64
> > > same way you get it from java, and then verify it using your code. That
> > > way
> > > you can eliminate at least one of possible errors (it is obvious thing,
> > > but
> > > just in case you didn't think about it yet :)).
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the "Crypto++ Users"
Google Group.
To unsubscribe, send an email to [EMAIL PROTECTED]
More information about Crypto++ and this group is available at
http://www.cryptopp.com.
-~----------~----~----~----~------~----~------~--~---