2011-03-03 15 views
7

Java'da RSA şifreleme/şifre çözme işlemini başarıyla yapıyorum. Anahtarı ben böyle yarattım.Java'da RSA anahtar nesnesini XML'ye dışa aktarma

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

Ama şimdi sistemimi .Net koduyla bütünleştirmem gerekiyor. (Bu .Net kod yalnızca XML formatında anahtarları kabul edebilir gibi) mümkün mü aşağıdaki biçimde XML içine bu keypair nesne vermek:

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

gerçekten, çok kötü bir fikir. – Hut8

+0

Seri hale getirilebilir arabirimi uygulayan anahtar kutusu için kendi sarmalayıcı sınıfınızı oluşturun. ReadObject() ',' writeObject() 've' readObjectNoData() 'yöntemlerini geçersiz kılın. –

+0

@ bowenl2 Diğer platformlarla entegre olmanın iyi bir yolunu önerebilir misiniz? – dvl

cevap

11

bu deneyin:

// 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>"); 

Bu içten 'CRT' temsilini kullanan tüm RSA anahtarı çiftleri için çalışmak ve ihracat sağlayacaktır; Bu, JDK'nın gösterdiğiniz kodla varsayılan olarak oluşturacağı anahtar çiftleri için geçerlidir.

(Burada yerine bir dosyaya yazma System.out tuşuna basmak, ancak fikir.)

+1

Bir metni şifrelemek için bu kodu C# kullandığımda, şunu elde ettim: ** CryptographicException (Hatalı Veri) ** –

0

Bunu yerine XML çıkışı öyle ki XMLObjectOutputStream çeşit olabilir here'da olduğu gibi özel bir ikili biçimin.

3

Thomas PORNIN çözümü temelde doğru olduğunu ama benim için işe yaramadı mesela yöntemlerle, çünkü getModulus(), sayısal bir dizeyle sonuçlanan BigInteger döndürürken, standart .Net XML biçiminde Base64 kodlu bayt kullanılır.

Bayt almak için "getModulus(). ToByteArray()" kullanılır. Sonra dizinin ilk elemanını (Exponent hariç) kırpmam gerekiyor çünkü istenmeyen bir sıfır bayt var. (BigInteger imzalı olduğundan, ön bitin işaretini gösterebilmesi için fazladan bir bayt eklediğini varsayalım).

GitHub'da the code gönderdim.

ana biraz:

(böylece özel anahtar maruz bırakarak) bir keypair hiçbir şifreleme ile bu şekilde saklanması
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

, bunları el ile yapmak yerine RSAKeyValue etiketleri arasına yerleştirmenin bir yolu yoktur, örneğin otomatik olarak dönüştürülür. NET biçimi veya benzer bir şey? – Gravity

+0

@Gravity Bir tane bulamadım. Tüm egzersiz bana açık bir şey eksik olduğumu hissettirdi. – codybartfast

+0

Ben de bulamadım, kodunuzu github üzerinde gördüm, umarım işe yarar, ben – Gravity