Экспорт ключевого объекта RSA в XML в Java - PullRequest
8 голосов
/ 03 марта 2011

Я успешно использую шифрование / дешифрование RSA на Java. Вот как я сгенерировал ключ.

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

Но теперь мне нужно интегрировать мою систему с кодом .Net. Можно ли экспортировать этот объект KeyPair в XML в следующем формате (поскольку этот код .Net может принимать ключи только в формате XML):

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

Ответы [ 3 ]

14 голосов
/ 03 марта 2011

Попробуйте это:

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

Это будет работать для всех пар ключей RSA, которые внутренне используют представление 'CRT' и разрешают экспорт; в этом случае пары ключей, которые JDK сгенерирует по умолчанию с указанным вами кодом.

(Здесь я печатаю ключ на System.out вместо того, чтобы записать его в файл, но вы поняли идею.)

4 голосов
/ 07 ноября 2015

Решение Томаса Порнина является по существу правильным, но оно не сработало для меня, потому что методы, например, getModulus (), возвращают BigInteger, что приводит к числовой строке, тогда как в стандартном формате .Net XML используются байты в кодировке Base64.

Я использовал getModulus (). ToByteArray (), чтобы получить байты.Затем мне нужно было обрезать первый элемент массива (кроме Exponent), потому что есть нежелательный нулевой байт.(Полагаю, поскольку BigInteger подписан, он добавляет дополнительный байт, чтобы старший бит мог указывать знак).

Я отправил код на GitHub.

Основнойбит это:

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 голосов
/ 03 марта 2011

Вы можете иметь некоторую форму XMLObjectOutputStream, так что он выводит в XML вместо проприетарного двоичного формата, как в здесь .

...