KeySpec rountripping questions
For RSA at least there are 2 ways to turn a key into a KeySpec and back: one that uses KeySpec classes specific to that kind of algorithm and keys, i.e., RSAPublicKeySpec + RSAPrivateKeySpec, and another the uses "generic" ASN.1-style specs, i.e., X509EncodedKeySpec + PKCS8EncodedKeySpec. Apart from the fact that roundtripping through RSAPrivateKeySpec does not work anyhow (this looks like a bug to me; it does work with RSAPublicKeySpec), is there any reason to prefer one to the other? The code is:
boolean pub = key1instanceof PublicKey;
byte[] encoded = key1.getEncoded();
// ASN.1 spec roundtripping
KeySpec spec2 = pub ?new X509EncodedKeySpec(encoded) :new PKCS8EncodedKeySpec(encoded);
Key key2 = pub ? kf.generatePublic(spec2) : kf.generatePrivate(spec2);
System.out.println("ASN.1 spec roundtrip ok: " + key1.equals(key2));
// RSA spec roundtripping
BigInteger mod = ((RSAKey)key1).getModulus();
BigInteger exp = pub ? ((RSAPublicKey)key1).getPublicExponent(): ((RSAPrivateKey)key1).getPrivateExponent();
KeySpec spec3 = pub ?new RSAPublicKeySpec(mod, exp) :new RSAPrivateKeySpec(mod, exp);
Key key3 = pub ? kf.generatePublic(spec3) : kf.generatePrivate(spec3);
System.out.println("RSA spec roundtrip ok: " + key1.equals(key3));
[1667 byte] By [
xolotla] at [2007-10-3 4:24:16]

Your RSA spec examples potentially lose information. You actually do lose the information in the RSA private key spec roundtrip, that's why that one fails. The RSA private key is almost certainly an instance of RSAPrivateCrtKey, which contains several more fields beside the exponent.
Your example shows that it is trickier and more error-prone to use the RSA specs versus the ASN.1 specs. ASN.1 KeySpecs and KeyFactories are very similar to ObjectInputStream and ObjectOutputStream. The difference is that the ASN.1 encodings use public standards, like PKCS1 and X509, to encode the object, whereas ObjectOutputStream uses a java standard.
You are right, it was an RSAPrivateCrtKey instance; now I can roundtrip just fine either way. Clearly indeed the ASN.1 is the simpler route: no switch, just one parameter to save.
By the way, is this binary ASN (I believe there is such a thing), i.e., is there is no way to turn the encoded bytes into something human-readable? Mere curiosity.
PS: It strikes me as rather odd that RSAKey does not extend Key; in fact the whole java.security.interfaces package is a bit strange. What can have motivated this bizarre design?
This is really what is called the DER-encoding of the ASN.1 structure SubjectPublicKeyInfo that you see in the Javadocs for X509EncodedKeySpec. The standard method for turning the bytes into something readable is to use base64 encoding.
I have generally found that when I don't understand why Sun's class designers did something a certain way, it is usually due to my own limited knowledge in OO design. For the crypto classes, I have often thought that it is a case of abstraction run amok. But I also bet that, if I could talk to the person at Sun who designed them, I would realize they really did it the right way.