如何在Java中序列化和反序列化RSA KeyPair

3
我想在我的Java应用程序中实现一些非常基本的安全性,但我在最初的阶段遇到了困难。
我想要做的是: 1-生成RSA密钥对 2-以序列化的形式将这些密钥存储在我的数据库中,以便在下次运行应用程序时重新创建它们 3-反序列化它们,以便将它们返回为对象形式,并可以使用它们来加密/解密内容。
问题是,我无法在任何地方找到关于如何执行此操作的简明说明。 我尝试了标准的Java序列化/反序列化方法,但它们并不起作用。我的代码如下:
    public static KeyPair Bin2KeyPair(byte[] data){
    try{
        ByteArrayInputStream b = new ByteArrayInputStream(data);
        ObjectInputStream o = new ObjectInputStream(b);
        Object obj =o.readObject();
        return((KeyPair)obj);
    }catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

public static byte[] KeyPair2Bin(KeyPair kp){

    ByteArrayOutputStream b = new ByteArrayOutputStream();
    ObjectOutputStream o;
    try {
        o = new ObjectOutputStream(b);
        o.writeObject(kp);
        return b.toByteArray();
    } catch (IOException e) {
        e.printStackTrace();
    }   
    return  null;
}

我遇到的问题是第一个方法失败了,抛出了ClassCastException异常,告诉我无法将对象强制转换为"KeyPair"。而第二个方法可以正常工作(将密钥序列化为字节数组)。有没有关于如何正确执行此操作的提示?
编辑:以下是异常信息(在第一个方法的“return((KeyPair)obj);”处抛出):
java.lang.ClassCastException: [B cannot be cast to java.security.KeyPair
at DARCOServer.security.SecurityManager.String2KeyPair(SecurityManager.java:34)
at DARCOServer.security.SecurityManager.GenerateServerKeys(SecurityManager.java:122)
at DARCOServer.MainClass.main(MainClass.java:13)

你使用的是哪个版本的Java?我用Sun的1.7版本很好用。 - Diego Basch
如果您遇到异常,请发布完整的异常堆栈跟踪。 - President James K. Polk
在我的Mac OSX上,使用JDK6也能正常工作。 - President James K. Polk
@Master_T你说异常来自第一个方法Bin2KeyPair。然而,堆栈跟踪却表明它来自String2KeyPair方法。为什么会有差异? - Brent Worden
String2KeyPair建议您已经保存/恢复了一个字符串。它是一个字符串还是字节数组? - pd40
抱歉,那是一个拒绝请求,我正在使用base64编码,但为了方便阅读,我将其改为二进制格式。无论如何,我通过使用BouncyCastle SPI而不是默认的JDK SPI解决了这个问题,现在它可以正常工作了,如果有人遇到同样的问题,可以参考一下。 - Master_T
2个回答

4
这对我有效:
@Test
public void serializeTest() throws Exception {

    KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
    KeyPair keyPair = kpg.generateKeyPair();
    ByteArrayOutputStream b = new ByteArrayOutputStream();
    ObjectOutputStream o =  new ObjectOutputStream(b);
    o.writeObject(keyPair);
    byte[] res = b.toByteArray();

    o.close();
    b.close(); 

    ByteArrayInputStream bi = new ByteArrayInputStream(res);
    ObjectInputStream oi = new ObjectInputStream(bi);
    Object obj = oi.readObject();
    assertTrue(obj instanceof KeyPair);

    oi.close();
    bi.close(); 
}

你忘记关闭 ObjectOutputStream()了。@pd40 实际上,你需要关闭所有的 *Stream 对象。 - Cacho Santa
1
由于某种原因,在Android(API级别16,Jelly Bean 4.1)上,当尝试使用此代码时,我会收到“java.io.NotSerializableException:org.apache.harmony.xnet.provider.jsse.OpenSSLKey”的错误。我在模拟器上进行了测试,您的答案适用于Android 6.0,但不适用于4.1。(对于任何在Android上尝试在Java中序列化和反序列化RSA KeyPair的人) - tuxayo

1

回答自己,以防有人遇到同样的问题:

不知道是什么原因,但使用BouncyCastle SPI而不是默认的JDK SPI似乎为我解决了这个问题,现在它正常工作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接