4

如何生成应与 .NET 环境兼容的基于 xml 的 RSA 密钥(私有、公共)。我在 PHP 中尝试了 phpseclib 模块。但它与.NET 不兼容。请建议我用 Java 生成基于 xml 的 RSA 密钥的任何方法?实际上我正在研究基于 linux 的系统。使用这些密钥我将执行加密和解密操作。像

<RSAKeyValue>
    <Modulus>4hjg1ibWXHIlH...ssmlBfMAListzrgk=</Modulus>
    <Exponent>AQAB</Exponent>
    <P>8QZCtrmJcr9uW7VRex+diH...jLHV5StmuBs1+vZZAQ==</P>
    <Q>8CUvJTv...yeDszMWNCQ==</Q>
    <DP>elh2Nv...cygE3657AQ==</DP>
    <DQ>MBUh5XC...+PfiMfX0EQ==</DQ>
    <InverseQ>oxvsj4WCbQ....LyjggXg==</InverseQ>
    <D>KrhmqzAVasx...uxQ5VGZmZ6yOAE=</D>
</RSAKeyValue>
4

2 回答 2

7

Java 中没有开箱即用的支持,但它仍然相当微不足道。首先,您使用 JCA 生成一个 RSA 密钥对KeyPairGenerator

然后,您需要将私钥转换为适当的接口(我们使用RSAPrivateCrtKey而不是RSAPrivateKey这样我们可以访问 CRT 部分),并使用 Apache Commons Codec 进行 Base64 编码。

public static void main(String[] args) throws Exception {
    KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
    KeyPair keyPair = keyPairGen.genKeyPair();
    RSAPrivateCrtKey privKey = (RSAPrivateCrtKey) keyPair.getPrivate();

    BigInteger n = privKey.getModulus();
    BigInteger e = privKey.getPublicExponent();
    BigInteger d = privKey.getPrivateExponent();
    BigInteger p = privKey.getPrimeP();
    BigInteger q = privKey.getPrimeQ();
    BigInteger dp = privKey.getPrimeExponentP();
    BigInteger dq = privKey.getPrimeExponentQ();
    BigInteger inverseQ = privKey.getCrtCoefficient(); 

    StringBuilder builder = new StringBuilder();
    builder.append("<RSAKeyValue>\n");
    write(builder, "Modulus", n);
    write(builder, "Exponent", e);
    write(builder, "P", p);
    write(builder, "Q", q);
    write(builder, "DP", dp);
    write(builder, "DQ", dq);
    write(builder, "InverseQ", inverseQ);
    write(builder, "D", d);
    builder.append("</RSAKeyValue>");

    System.out.println(builder.toString());
}

private static void write(StringBuilder builder, String tag, BigInteger bigInt) {
    builder.append("\t<");
    builder.append(tag);
    builder.append(">");
    builder.append(encode(bigInt));
    builder.append("</");
    builder.append(tag);
    builder.append(">\n");
}

private static String encode(BigInteger bigInt) {
    return new String(Base64.encodeInteger(bigInt), "ASCII");
}

如果您愿意,可以使用适当的 XML API,但我认为没有令人信服的理由不使用StringBuilder这种情况。此外,请随意内联BigInteger实例。我将它们声明为变量,以使 Java 方法和 XML 元素之间的映射更加明显。

于 2012-09-20T14:37:07.353 回答
0

如果有人想做反向操作 - 通过 xml 文件获取 RSAPrivateCrtKey,不要忘记使用正号参数创建 BigInteger 实例。

new BigInteger(1, Base64.getDecoder().decode(encodedBigInteger));

它避免了潜在的异常

java.security.SignatureException: Could not sign data
    at sun.security.rsa.RSASignature.engineSign(RSASignature.java:178)
    at java.security.Signature$Delegate.engineSign(Signature.java:1207)
    at java.security.Signature.sign(Signature.java:579)
    ... more
Caused by: javax.crypto.BadPaddingException: Message is larger than modulus
    at sun.security.rsa.RSACore.parseMsg(RSACore.java:214)
    at sun.security.rsa.RSACore.crtCrypt(RSACore.java:166)
    at sun.security.rsa.RSACore.rsa(RSACore.java:122)
    at sun.security.rsa.RSASignature.engineSign(RSASignature.java:175)
    ... 6 more
于 2019-01-10T11:22:28.847 回答