I'm trying to send a PublicKey (java.security.PublicKey) from a Kryonet server to a client by using connection.sendTCP(key);
I get this exception when doing so:
Exception in thread "pool-1-thread-1" java.lang.IllegalArgumentException: Class is not registered: sun.security.rsa.RSAPublicKeyImpl
Note: To register this class use: kryo.register(sun.security.rsa.RSAPublicKeyImpl.class);
at com.esotericsoftware.kryo.Kryo.getRegistration(Kryo.java:443)
at com.esotericsoftware.kryo.util.DefaultClassResolver.writeClass(DefaultClassResolver.java:73)
at com.esotericsoftware.kryo.Kryo.writeClass(Kryo.java:475)
at com.esotericsoftware.kryo.Kryo.writeClassAndObject(Kryo.java:568)
at com.esotericsoftware.kryonet.KryoSerialization.write(KryoSerialization.java:50)
at com.esotericsoftware.kryonet.TcpConnection.send(TcpConnection.java:192)
at com.esotericsoftware.kryonet.Connection.sendTCP(Connection.java:59)
at darpix.accountManager.AccountManager$1.received(AccountManager.java:93)
at com.esotericsoftware.kryonet.Listener$QueuedListener$3.run(Listener.java:102)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
I have registered these five classes:
k.register(AccountRequest.class);
k.register(AccountResponse.class);
k.register(KeyResponse.class);
k.register(PublicKey.class);
k.register(byte[].class);
I haven't used RSAPublicKeyImpl anywhere in my code and I can't seem to find it anywhere in the libraries I'm using.
Probably not a full answer but too much for comments.
Java crypto (JCA/JCE) publishes (documents) a series of generic 'facade' classes like Signature Cipher Key
etc. but the actual implementation classes for a large variety of algorithms and variants are provided by a variable set of cryptoproviders, may vary across cryptoproviders or versions, and are not published or stable -- except for the conformance to their parent classes and interfaces that is required by OO rules. Many though by no means all of these implementation classes are under sun.*
or com.sun.*
.
Usual Java serialization and deserialization is not defined to work on crypto objects. A correct way to transmit or store a key is not to use the key object but instead an encoding of the key, which is a standardized byte sequence defined to be stable across implementations and versions.
In the sender you can call Key.getEncoded()
which is inherited by PublicKey
and PrivateKey
among others, although the encodings they use are different (X.509 and PKCS#8 respectively) and send the resulting bytes. In the receiver use KeyFactory.getInstance(algorithm[,provider])
to obtain a key factory for the correct algorithm, then call .generatePublic
or .generatePrivate
with respectively an X509EncodedKeySpec
or PKCS8EncodedKeySpec
containing the X.509 or PKCS#8 encoding. Note the receiver needs to know the algorithm, which may need to be sent in addition; this is technically redundant because an algorithm identifier is included in the (standard) PKCS#8 and X.509 encodings but not trivial to extract.
I don't know how (or if) to integrate this with kryo.
Note that externalizing a private key unencrypted is supported, but often insecure. It is usually preferable to transmit or store keypairs containing a private key in a KeyStore
, which is serialized to or deserialized from a stream (often a file) in encrypted form using .store
and .load
. Although public keys do not need to be encrypted, it is often insecure to transmit or store them without authentication which is usually done by putting them in a certificate, usually an X.509v3 certificate, which similarly is encoded as a byte sequence (that is actually pretty widely implemented).