2011-03-03 36 views
7

我正在Java中成功運行RSA加密/解密。這就是我生成密鑰的方式。將Java中的RSA密鑰對象導出爲XML

 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(path)); 
     KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); 
     kpg.initialize(1024); 
     KeyPair keypair = kpg.generateKeyPair(); 
     oos.writeObject(keypair); 

但現在我需要整合我的系統與.Net代碼。是否有可能這個密鑰對對象導出成XML的格式如下(爲Net代碼只能接受以XML格式鍵):

<RSAKeyValue> 
    <Modulus>.....</Modulus> 
    <Exponent>......</Exponent> 
    <P>.....</P> 
    <Q>....</Q> 
    <DP>.......</DP> 
    <DQ>......</DQ> 
    <InverseQ>.........</InverseQ> 
    <D>........</D> 
</RSAKeyValue> 
+1

存儲密鑰對這種方式不加密(因此留下你的私鑰暴露)是一個非常,非常糟糕的主意。 – Hut8 2011-03-03 09:23:03

+0

爲實現Serializable接口的密鑰對創建自己的包裝類。覆蓋'readObject()','writeObject()'和'readObjectNoData()'方法。 – 2011-03-03 13:00:24

+0

@ bowenl2你能提出任何與其他平臺集成的好方法嗎? – dvl 2011-03-05 07:18:58

回答

11

試試這個:

// key pair is in 'kp' 
KeyFactory kf = KeyFactory.getInstance("RSA"); 
RSAPrivateCrtKeySpec ks = kf.getKeySpec(
    kp.getPrivate(), RSAPrivateCrtKeySpec.class); 
System.out.println("<RSAKeyValue>"); 
System.out.println(" <Modulus>" + ks.getModulus() + "</Modulus>"); 
System.out.println(" <Exponent>" + ks.getPublicExponent() + "</Exponent>"); 
System.out.println(" <P>" + ks.getPrimeP() + "</P>"); 
System.out.println(" <Q>" + ks.getPrimeQ() + "</Q>"); 
System.out.println(" <DP>" + ks.getPrimeExponentP() + "</DP>"); 
System.out.println(" <DQ>" + ks.getPrimeExponentQ() + "</DQ>"); 
System.out.println(" <InverseQ>" + ks.getCrtCoefficient() + "</InverseQ>"); 
System.out.println(" <D>" + ks.getPrivateExponent() + "</D>"); 
System.out.println("</RSAKeyValue>"); 

這將爲它在內部使用「CRT」表示所有的RSA密鑰對工作,並允許出口;對於JDK默認使用您顯示的代碼生成的密鑰對,情況就是這樣。

(在這裏我打印出來的關鍵就System.out,而不是將其寫入到文件中,但你的想法。)

+1

當我在C#中使用此代碼來加密文本時,我得到:** CryptographicException(Bad Data)** – 2013-04-15 20:58:47

0

你可以有某種形式的XMLObjectOutputStream的,使得它輸出到XML,而不是的專有二進制格式,如here

3

托馬斯Pornin的解決方案基本上是正確的,但我沒有工作,因爲這些方法,例如getModulus(),返回BigInteger,它會生成一個數字字符串,而標準的.Net XML格式使用Base64編碼的字節。

我用「getModulus()。toByteArray()」來獲取字節。然後我需要修剪數組的第一個元素(Exponent除外),因爲有一個不需要的零字節。 (我認爲是因爲BigInteger簽名後會增加一個額外的字節,所以前導位可以表示符號)。

我已在GitHub上發佈the code

主要位:

static String getPrivateKeyAsXml(PrivateKey privateKey) throws Exception{ 
    KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); 
    RSAPrivateCrtKeySpec spec = keyFactory.getKeySpec(privateKey, RSAPrivateCrtKeySpec.class); 
    StringBuilder sb = new StringBuilder(); 

    sb.append("<RSAKeyValue>" + NL); 
    sb.append(getElement("Modulus", spec.getModulus())); 
    sb.append(getElement("Exponent", spec.getPublicExponent())); 
    sb.append(getElement("P", spec.getPrimeP())); 
    sb.append(getElement("Q", spec.getPrimeQ())); 
    sb.append(getElement("DP", spec.getPrimeExponentP())); 
    sb.append(getElement("DQ", spec.getPrimeExponentQ())); 
    sb.append(getElement("InverseQ", spec.getCrtCoefficient())); 
    sb.append(getElement("D", spec.getPrivateExponent())); 
    sb.append("</RSAKeyValue>"); 

    return sb.toString(); 
} 

static String getElement(String name, BigInteger bigInt) throws Exception { 
    byte[] bytesFromBigInt = getBytesFromBigInt(bigInt); 
    String elementContent = getBase64(bytesFromBigInt); 
    return String.format(" <%s>%s</%s>%s", name, elementContent, name, NL); 
} 

static byte[] getBytesFromBigInt(BigInteger bigInt){ 
    byte[] bytes = bigInt.toByteArray(); 
    int length = bytes.length; 

    // This is a bit ugly. I'm not 100% sure of this but I presume 
    // that as Java represents the values using BigIntegers, which are 
    // signed, the byte representation contains an 'extra' byte that 
    // contains the bit which indicates the sign. 
    // 
    // In any case, it creates arrays of 129 bytes rather than the 
    // expected 128 bytes. So if the array's length is odd and the 
    // leading byte is zero then trim the leading byte. 
    if(length % 2 != 0 && bytes[0] == 0) { 
     bytes = Arrays.copyOfRange(bytes, 1, length); 
    } 

    return bytes; 
} 

static String getBase64(byte[] bytes){ 
    return Base64.getEncoder().encodeToString(bytes); 
} 
+0

是否無法將它們放在RSAKeyValue標籤之間,而不是手動執行此操作,例如自動轉換爲。 NET格式或類似的東西? – Gravity 2016-03-12 15:37:49

+0

@重力我找不到一個。整個練習讓我覺得我失去了一些明顯的東西。 – codybartfast 2016-03-13 07:46:35

+0

我找不到任何一個,我在github上看到了你的代碼,我希望它能正常工作,我正在嘗試與你完全相同 – Gravity 2016-03-14 09:51:55