I've run into countless brick walls on this and would greatly
appreciate any guidance this group might offer...
I have a java class that holds a PrivateKey object and a PublicKey
object. I need to export each of these such that a C program can use
them.
I'm using J2SE 1.4.1, and BouncyCastle 1.13.
BouncyCastle has a class that helped me bridge the gap for PrivateKey
objects:
/*---------------------------------+
| snippet for PrivateKey approach |
+---------------------------------*/
ByteArrayInputStream bais =
new ByteArrayInputStream(priv.getEncoded());
DERInputStream derInputStream = new DERInputStream(bais);
PrivateKeyInfo privateInfo = new PrivateKeyInfo
( (DERConstructedSequence)derInputStream.readObject() );
RSAPrivateKeyStructure privateStructure = new RSAPrivateKeyStructure
( (DERConstructedSequence)privateInfo.getPrivateKey() );
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DEROutputStream derOutputStream = new DEROutputStream(baos);
byte[] bytesToWrite = baos.toByteArray();
// Write the bytes to a file
/*------------------------+
| End PrivateKey snippet |
+------------------------*/
But I don't see an equivalent to PrivateKeyInfo for PublicKeys. Here
are the approaches I've considered or tried thus far:
1) Write PublicKey bytes to a file using pub.getEncoded() Supposedly,
this is DER format. d2i_RSAPublicKey is suppose to understand that.
Result: ERROR trying to read key from C process
Error Code 218751106: error:0D09E082:lib(13):func(158):reason(130)
2) Write PublicKey to file using BouncyCastle's ASN1Dump()
/*--------------+
| ASN1 snippet |
+--------------*/
ByteArrayInputStream bais = new
ByteArrayInputStream(priv.getEncoded());
DERInputStream derInputStream = new DERInputStream(bais);
DERObject dObj = derInputStream.readObject();
String asn1Format = ASN1Dump.dumpAsString( dObj );
// Write the String to a file.
/*------------------+
| End ASN1 snippet |
+------------------*/
Result: ERROR trying to read key from C process
Error Code 218751106: error:0D09E082:lib(13):func(158):reason(130)
3) I considered writing/reading the key in PEM format. But all the
Java methods I found require an x509 cert (which is WAY overkill for
my project).
4) I could extract the PublicKey's components separately using
getPublicComponent() and getModulus(), store them separately, and
have the C process piece together into its own RSA struct.
(There's GOT to be a better way!)
Questions:
a) What are DER and PEM, and how are they related?
b) How do I export a PublicKey in either of these formats in a manner
that is understood by libcrypto (d2i_RSAPublicKey()).
c) Can I use the same approach for SecretKeys as was suggested for
PublicKeys in b)?
d) How do I translate those cryptic error mssages from libcrypto?
Thanks a bundle!
Rob - 22 Oct 2003 23:10 GMT
Just correcting a typo in the original post. In the ASN1 snippet,
priv.getEncoded() is actually pub.getEncoded(). This typo is not
in the actual code, so the problem is still present.
>
> /*--------------+
> | ASN1 snippet |
> +--------------*/
> ByteArrayInputStream bais = new
>>>> ByteArrayInputStream(pub.getEncoded());
> DERInputStream derInputStream = new DERInputStream(bais);
> DERObject dObj = derInputStream.readObject();
> String asn1Format = ASN1Dump.dumpAsString( dObj );
>
> // Write the String to a file.
> /*------------------+
> | End ASN1 snippet |
> +------------------*/
Rob - 27 Oct 2003 06:06 GMT
It looks like my key-loading problem is resolved. I don't have a
solid reason as to why the other approach did not work, so I'll make a
few guesses here and leave myself open to correction if someone sees
errors in the explanation.
It looks like the PublicKey and PrivateKey classes of J2SE cannot be
exported. They can be serialized and thus used in other JVMs, but
they do not hold enough information to get exported in DER or PEM
format.
BTW: I still don't know exactly what DER and PEM mean, but DER seems
to indicate raw bytes of a key in a format that 'everyone'
understands.
DER objects cannot be properly created from these interface classes.
I had to
get away from using KeyPairGenerator() in favor of BouncyCastle's
RSAKeyPairGenerator(). Then I could extract the information needed to
construct an org.bouncycastle.asn1.pkcs.RSAPrivateKeyStructure, and an
org.bouncycastle.asn1.x509.RSAPublicKeyStructure. These structures
can be DER
exported. Please reference the code provided below. RSA_print() in C
and
Hex() in Java were used to confirm that all components of the exported
key
were identical between C and Java.
-rob
HINT: In C, use the EVP_ family of functions (not the RSA_ family).
/*-------------------------------------------------------------+
| Working code for exporting JVM-created keys for libcrypto. |
| Use d2i_PublicKey() and d2i_PrivateKey() for imports. |
+-------------------------------------------------------------*/
RSAKeyPairGenerator kpg = new RSAKeyPairGenerator();
RSAKeyGenerationParameters kgParms = new
RSAKeyGenerationParameters
(BigInteger.valueOf(0x11), sr, 768, 25);
kpg.init(kgParms);
AsymmetricCipherKeyPair kp = kpg.generateKeyPair();
// Key extraction examples.
RSAKeyParameters pubParms = (RSAKeyParameters)kp.getPublic();
RSAKeyParameters privPrivParms =
(RSAKeyParameters)kp.getPrivate();
RSAPrivateCrtKeyParameters privParms =
(RSAPrivateCrtKeyParameters)kp.getPrivate();
BigInteger pubMod = pubParms.getModulus();
BigInteger pubExpo = pubParms.getExponent();
RSAPublicKeyStructure pubStruct = new RSAPublicKeyStructure
(pubMod, pubExpo);
BigInteger privMod = privParms.getModulus();
BigInteger privPublicExpo = privParms.getPublicExponent();
BigInteger privPrivateExpo = privPrivParms.getExponent();
BigInteger privP = privParms.getP();
BigInteger privQ = privParms.getQ();
BigInteger privDP = privParms.getDP();
BigInteger privDQ = privParms.getDQ();
BigInteger privQInv = privParms.getQInv();
RSAPrivateKeyStructure privStruct = new RSAPrivateKeyStructure
(privMod, privPublicExpo, privPrivateExpo, privP, privQ,
privDP, privDQ, privQInv);
try
{
FileOutputStream fos = new FileOutputStream(keyFilename);
DEROutputStream derOut = new DEROutputStream(fos);
derOut.writeObject(pubStruct.getDERObject());
derOut.close();
}
catch ( java.io.IOException badIO )
{
System.out.println(badIO.getMessage());
badIO.printStackTrace();
System.exit(1);
}