-
-
Save nicoruti/996995dacb97990d6db8 to your computer and use it in GitHub Desktop.
import java.math.BigInteger; | |
import java.security.KeyPair; | |
import java.security.KeyPairGenerator; | |
import java.security.SecureRandom; | |
import java.security.Security; | |
import java.security.spec.RSAKeyGenParameterSpec; | |
import org.bouncycastle.jce.provider.BouncyCastleProvider; | |
import org.nustaq.serialization.FSTConfiguration; | |
public class TestSerializeKeyFST { | |
// Fermat F4, largest known fermat prime | |
private static final BigInteger PUBLIC_EXP = new BigInteger("10001", 16);; | |
private static final int STRENGTH = 1024; | |
public static void main(String[] args) throws Exception { | |
// install BouncyCastle provider | |
Security.addProvider(new BouncyCastleProvider()); | |
// generate a keypair | |
KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA", "BC"); | |
RSAKeyGenParameterSpec params = new RSAKeyGenParameterSpec(STRENGTH, PUBLIC_EXP); | |
gen.initialize(params, new SecureRandom()); | |
KeyPair keyPair = gen.generateKeyPair(); | |
FSTConfiguration fst = FSTConfiguration.createDefaultConfiguration(); | |
// serialize | |
byte[] serialized = fst.asByteArray(keyPair); | |
// deserialize --> crash | |
KeyPair deserialized = (KeyPair) fst.asObject(serialized); | |
} | |
} |
(Rant incoming)
BCRSAPublicKey.java from bouncy cancle chooses to serialize using the following whacky hack:
private void readObject(
ObjectInputStream in)
throws IOException, ClassNotFoundException
{
in.defaultReadObject();
try
{
algorithmIdentifier = AlgorithmIdentifier.getInstance(in.readObject());
}
catch (OptionalDataException e)
{
algorithmIdentifier = DEFAULT_ALGORITHM_IDENTIFIER;
}
catch (EOFException e)
{
algorithmIdentifier = DEFAULT_ALGORITHM_IDENTIFIER;
}
}
private void writeObject(
ObjectOutputStream out)
throws IOException
{
out.defaultWriteObject();
if (!algorithmIdentifier.equals(DEFAULT_ALGORITHM_IDENTIFIER))
{
out.writeObject(algorithmIdentifier.getEncoded());
}
}
If you look at it, it always reads two Objects from the stream but writes one OR two objects, then relies on Exception handling to recover. With FST this leads to a corrupted stream, so reading fails.
The concept of JDK's http://docs.oracle.com/javase/6/docs/api/java/io/OptionalDataException.html is broken as the detection of "optionaldata" can fail if the next Object in the stream by chance creates a byte sequence resembling a valid object.
You should probably file a bug report to bouncy castly library. In addition relying on exception handling for normal operation also is a big performance killer.
A valid implementation would write always an ALGORITHM_IDENTFIER (byte) so its deterministic if one or two objects can be read at reader side.
I have to figure out on how to fix that. The problem is, that detection of "non-object data" would require writing special tags in front of objects and native data (=waste a lot of performance to support stupid coding). Also its dirty as the bytes in the stream might form a valid object by accident (so spurious failure in rare cases). Additionally they catch silently an EOFException which can lead to extremely hard-to-spot errors in case you have to deal with corrupted streams/IO bugs.
I assume bcastles does this in order to keep backward compatibility as JDK serialization fails to provide reliable mechanisms to deal with versioning (however its not too hard to implement that manually).
Also they made OptionalDataException private, so I can't throw it from my code ... WTF
This code throws the following exception: