Hi,
I have faced some problem related to generation of digital signature
on Microsoft .NET platform and it's verification on Java platform.
I create a digital signature in my C# (Microsoft ASP.NET) application.
The public/private keys are generated by another C# application and it
saves the key parameters to the XML files.
The public key XML files looks like following:
================================================================================
<DSAKeyValue>
<P>vMYiMuNfgygyNr9aMQQO5QWcoGobLmrcjcvee7RGVzUgAMD7XQMbkXNKw3DpYNrGpQxAgf9/g1fHRFvfIQmueGVcXCdhGuEgR85KeMwsbfOms75M2YDiZd+Txn2uq80RUvae2EgV9mEfJd4sILJqpbxdYNaam5IlK4erPIsDyhU=</P>
<Q>pm88Q93QPyKctcsbk2AEY9DQL2s=</Q>
<G>NY2afKKr7vWBON/JYuITdkAaRqfOq8j2CP4k/E5KFFEJsoXX0OTuA97SkGkFH4rI7duFBts8AgPMFT+4sol8hyBxlXZAk/mYNsOXbi+tGx+UjhVXr1q1Py1Oeh2nm9LFUvatf25mvnCXXaS7D5m6oDhisceFmj037+Tb0x4Rn2I=</G>
<Y>H08XX/n2aVwdHLygLUmOWyKu5tx20NX6fs2ZrgP2I6E1VKmYHQm3hhPRlQK6+48Vz+AmXDiqbO3Ptcbl01k847Zz+Fe8r9R9gGzjqFUcRSor5g7jZxIHaYVZ9NXsis6xt77AbhJ9mbKRFvqaddYvRuu6wOoBTL8wXTQFVV/1hMk=</Y>
<J>AAAAASJcevs9ahEe2/FWRzkVX3tKOumVUJY+0G+j1RK7X+klzqGUpO7Ih+KV4uw7DAakbP63489PReT8umGXzbcHhoXMuPFK/ziJCdnEvKbhgUQUCBmddpb0nGhNlGB3UoEPRfaYdoTztAMRNbZHPA==</J>
<Seed>EtzxtCwjIVklWmY8dtR0jtonX0Y=</Seed>
<PgenCounter>RA==</PgenCounter>
</DSAKeyValue>
================================================================================
In my Java application I create the PublicKey object using the
parameters P, G, Q, Y of the public key, that I get from the public
key XML, generated by my C# application.
//------------------------------------------------------------------------------
private PublicKey getPublicKey() throws Exception
{
PublicKey publicKey = null;
try
{
String sKeyFile = GetKeyFilePath(false);
File keyFile = new File(sKeyFile);
DocumentBuilderFactory factory =
DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document pubKeyXml = builder.parse(keyFile);
BigInteger P = GetKeyParam(pubKeyXml, "P");
BigInteger G = GetKeyParam(pubKeyXml, "G");
BigInteger Q = GetKeyParam(pubKeyXml, "Q");
BigInteger Y = GetKeyParam(pubKeyXml, "Y");
DSAPublicKeySpec dsaPubKeySpec = new DSAPublicKeySpec(Y, P, Q,
G);
KeyFactory keyFactory = KeyFactory.getInstance("DSA");
publicKey = keyFactory.generatePublic(dsaPubKeySpec);
}
catch(Exception ex)
{
String msg = ex.getMessage();
throw new Exception("getPublicKey(): " + msg);
}
return publicKey;
}
//------------------------------------------------------------------------------
private BigInteger GetKeyParam(Document keyXml, String paramName)
throws
Exception
{
BigInteger biParam = null;
try
{
String sParam = GetNodeValue(keyXml, paramName);
// byte [] param = sParam.getBytes("UTF-8");
// biParam = new BigInteger(param);
biParam = new BigInteger(sParam);
}
catch (Exception ex)
{
String msg = ex.getMessage();
throw new Exception("GetKeyParam(): " + msg);
}
return biParam;
}
//------------------------------------------------------------------------------
I try to verify the digital signature in my Java program.
But I get the "BigInteger not invertible." exception when I call the
verify() method of the Signature object.
I have tried to create & verify the signature in the same Java program
using the keys parameters, generated by C# application,
but I get same exception.
If I generate the key pair in my Java application and use them to
create & verify the digital signature, all works fine.
I have also succeed to generate and verify the digital signature in my
C# applications, using the private/public keys parameters saved in XML
file.
I use the "DSA with SHA1" algorithm.
I suppose that the different byte-ordering in .NET and in Java causes
the problem.
.NET uses the little-endian format and Java uses the big-endian
format.
I have tried to save the XML with public key parameters to file using
the Encoding.BigEndianUnicode.
The "BigInteger not invertible." exception disappeared, but the the
verify() method of the Signature class returns false.
What encoding should I use in my GetKeyParam() method to convert the
string with key parameter to correct byte array and then to
BigInteger?
// byte [] param = sParam.getBytes("UTF-8");
// biParam = new BigInteger(param);
Regards,
Arkady
Michel Gallant - 04 Apr 2004 16:47 GMT
The following .NET/Java interop might be useful. It deals with RSA (not DSA), but
some of the issues will be similar:
http://www.jensign.com/JavaScience/dotnet/JKeyNet
There are some other short "tech-notes" at my site which discuss asymmetric and
symmetric encryption, and .NET/Java interop with a bit of OpenSSL mixed in (more
of the coming).
- Mitch Gallant
www.jensign.com
> Hi,
>
[quoted text clipped - 7 lines]
> ================================================================================
> <DSAKeyValue>
<P>vMYiMuNfgygyNr9aMQQO5QWcoGobLmrcjcvee7RGVzUgAMD7XQMbkXNKw3DpYNrGpQxAgf9/g1fHRFvfIQmueGVcXCdhGuEgR
85KeMwsbfOms75M2YDiZd+Txn2uq80RUvae2EgV9mEfJd4sILJqpbxdYNaam5IlK4erPIsDyhU=</P>
> <Q>pm88Q93QPyKctcsbk2AEY9DQL2s=</Q>
<G>NY2afKKr7vWBON/JYuITdkAaRqfOq8j2CP4k/E5KFFEJsoXX0OTuA97SkGkFH4rI7duFBts8AgPMFT+4sol8hyBxlXZAk/mYN
sOXbi+tGx+UjhVXr1q1Py1Oeh2nm9LFUvatf25mvnCXXaS7D5m6oDhisceFmj037+Tb0x4Rn2I=</G>
<Y>H08XX/n2aVwdHLygLUmOWyKu5tx20NX6fs2ZrgP2I6E1VKmYHQm3hhPRlQK6+48Vz+AmXDiqbO3Ptcbl01k847Zz+Fe8r9R9g
GzjqFUcRSor5g7jZxIHaYVZ9NXsis6xt77AbhJ9mbKRFvqaddYvRuu6wOoBTL8wXTQFVV/1hMk=</Y>
<J>AAAAASJcevs9ahEe2/FWRzkVX3tKOumVUJY+0G+j1RK7X+klzqGUpO7Ih+KV4uw7DAakbP63489PReT8umGXzbcHhoXMuPFK/
ziJCdnEvKbhgUQUCBmddpb0nGhNlGB3UoEPRfaYdoTztAMRNbZHPA==</J>
> <Seed>EtzxtCwjIVklWmY8dtR0jtonX0Y=</Seed>
> <PgenCounter>RA==</PgenCounter>
[quoted text clipped - 102 lines]
> Regards,
> Arkady
Michael Amling - 04 Apr 2004 21:09 GMT
> Hi,
>
[quoted text clipped - 14 lines]
> <Seed>EtzxtCwjIVklWmY8dtR0jtonX0Y=</Seed>
> <PgenCounter>RA==</PgenCounter>
These values look like they're all in base 64.
> </DSAKeyValue>
>[...]
[quoted text clipped - 12 lines]
>
> biParam = new BigInteger(sParam);
The documentation for java.math.BigInteger says that the
BigInteger(String) constructor expects the String to contain "an
optional minus sign followed by a sequence of one or more decimal
digits", not base 64.
> }
> catch (Exception ex)
[quoted text clipped - 5 lines]
>
> }
--Mike Amling
Roedy Green - 05 Apr 2004 01:55 GMT
> The documentation for java.math.BigInteger says that the
>BigInteger(String) constructor expects the String to contain "an
>optional minus sign followed by a sequence of one or more decimal
>digits", not base 64.
Some day we are going to have to come up with something like accurate
mime types so that every file has a header to tell you what format it
is, or where you can find the details.
We sort of dance around it, but never get truly serious. It should
available or ignorable by a program. It should automatically follow a
file around as it is copied.
The other thing I often want to know is who created the file in the
first place. I have so many files on my machine I don't know what
they are for.
--
Canadian Mind Products, Roedy Green.
Coaching, problem solving, economical contract programming.
See http://mindprod.com/jgloss/jgloss.html for The Java Glossary.
arkady55 - 07 Apr 2004 09:45 GMT
Michael,
you are right!
The XML with key's parameters was base64 encoded.
I have applied the base64 decoding to the public & private keys.
As a result I succeed to create & verify the signature in my Java
application using the keys pair generated in my C# (.NET) application.
There is another thing I changed in key parameters initializaton:
biParam = new BigInteger(1, param);
// instead of
// biParam = new BigInteger(sParam);
I still have a problem with the verification of a signature generated
on .NET platform. Now I get the "Invalid encoding for signature"
exception when the
Signature.verify() method is called.
I have tried to apply the base64 encoding(in C# app)/decoding(in Java
app) to the signature. I have also tried to convert the byte array
with signature in C# to big-endian. Unfortunately, these two things
did not solve the problem.
Do you have any idea about this???
Regards,
Arkady
> > Hi,
> >
[quoted text clipped - 50 lines]
>
> --Mike Amling