java - 如何在java中构建模数为64字节的rsa key

标签 java rsa public-key-encryption javacard

我有一个 java 卡小程序,它将生成一个 RSA 私钥对(每个 512 位)。并发送公钥模数和指数(模数为64字节)

在主机应用程序 (java) 中,我需要使用相同的指数和模数重新构建 rsa 公钥,但是当我尝试使用以下代码重建时,我遇到了错误。

Java卡代码:

// this one to create the key pair
  rsa_KeyPair = new KeyPair(KeyPair.ALG_RSA_CRT, KeyBuilder.LENGTH_RSA_512);
  rsa_KeyPair.genKeyPair();
  rsa_PublicKey = (RSAPublicKey) rsa_KeyPair.getPublic();
  rsa_PrivateCrtKey 0= (RSAPrivateCrtKey) rsa_KeyPair.getPrivate();
  cipherRSA = Cipher.getInstance(Cipher.ALG_RSA_PKCS1, false);

//this is to send the modulus
  byte[] buffer = apdu.getBuffer();
  rsa_PublicKey.getModulus(buffer, ISO7816.OFFSET_CDATA);
  apdu.setOutgoing();
  apdu.setOutgoingLength((short) 64);
  apdu.sendBytesLong(buffer, ISO7816.OFFSET_CDATA, (short) 64);

这部分代码工作正常。我能够将模数完美地发送到主机端。

以下主机应用程序的 Java 代码:

//command for retrieving modulus
resp = channel.transmit(new CommandAPDU(cmdMod));
BigInteger modulus = new BigInteger(resp.getData());

我得到了预期的 64 字节模数,但是当我从中得到一个大整数时,它显示了一个大的负值。

//command for retrieving exponent
resp = channel.transmit(new CommandAPDU(cmdExp)); 
BigInteger modulus = new BigInteger(resp.getData());
byte[] input = { (byte) 0x92, (byte) 0x84, (byte) 0x3B,
        (byte) 0xD3, (byte) 0x5D, (byte) 0x8A, (byte) 0x6B,
        (byte) 0x56, (byte) 0xDA, (byte) 0xEA, (byte) 0xE0,
        (byte) 0x2F, (byte) 0x6D, (byte) 0xAA, (byte) 0x62,
        (byte) 0x4B, (byte) 0x38, (byte) 0xCE, (byte) 0xD4,
        (byte) 0x70, (byte) 0xA2, (byte) 0x16, (byte) 0x35,
        (byte) 0xCC, (byte) 0xEE, (byte) 0xB8, (byte) 0x31,
        (byte) 0x13, (byte) 0x37, (byte) 0x40, (byte) 0xBE,
        (byte) 0xA1, (byte) 0xCD, (byte) 0x84, (byte) 0xD9,
        (byte) 0xF3, (byte) 0xE6, (byte) 0xCE, (byte) 0x26,
        (byte) 0x0A, (byte) 0xC1, (byte) 0x40, (byte) 0xED,
        (byte) 0x20, (byte) 0x8F, (byte) 0x3D, (byte) 0x9F,
        (byte) 0x0D, (byte) 0xE7, (byte) 0x19, (byte) 0xC8,
        (byte) 0x87, (byte) 0x96, (byte) 0x29, (byte) 0xF2,
        (byte) 0x63, (byte) 0x34, (byte) 0x6D, (byte) 0x10,
        (byte) 0xB9, (byte) 0xFB, (byte) 0xB4, (byte) 0x75,
        (byte) 0xE9 };

RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA")
        .generatePublic(new RSAPublicKeySpec(modulus, exponent));

Cipher cipher = null;

cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, pubKey);

byte[] cipherText = cipher.doFinal(input);

错误:

javax.crypto.BadPaddingException: Message is larger than modulus
    at sun.security.rsa.RSACore.parseMsg(Unknown Source)
    at sun.security.rsa.RSACore.crypt(Unknown Source)
    at sun.security.rsa.RSACore.rsa(Unknown Source)
    at com.sun.crypto.provider.RSACipher.doFinal(RSACipher.java:355)
    at com.sun.crypto.provider.RSACipher.engineDoFinal(RSACipher.java:389)
    at javax.crypto.Cipher.doFinal(Cipher.java:2121)
    at testAuth.main(testAuth.java:150)

我检查了卡片的回复。我正在正确获取模数的所有 64 个字节。但是当我制作大整数时,我得到了一个很大的负值。我该怎么办?

最佳答案

问题是 BigInteger 默认编码为带符号的大端表示法。如果您使用构造函数解码字节,它会做相反的事情,即它需要一个带符号的值。现在大多数密码学都是在(大)无符号 整数上执行的。这是因为计算是在一个数学组内执行的(模数计算)。这些计算总是对正数执行,RSA 也不异常(exception)。

现在模数的大小等于 RSA key 的 key 大小(不是 key 强度)。这意味着 512 位的 RSA key 在编码为未签名的大端数字时具有恰好 512 位的模数。对于数字,这意味着最高有效位总是设置为“1”。但是,该位用于指示编码为二补码值的无符号数的符号位。换句话说,任何具有可被 8 整除的 key 大小的模数在被解释为有符号值时都将为负数。

解决方案当然是使用构造函数,您可以在其中自行指定符号位:

BigInteger(int signum, byte[] magnitude)

其中 magnitude 是无符号表示,在您的情况下:

new BigInteger(1, resp.getData());

Java Card 在 API 中使用无符号表示,因为它更注重密码学。那里不需要复杂的方法。


请注意,相反 - 从编码的带符号 BigInteger 创建静态大小的字节数组更加棘手,请参阅 this answer有关如何执行该特定转换的信息。

关于java - 如何在java中构建模数为64字节的rsa key ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27187461/

相关文章:

java - 通过 REST 发送包含加密数据的字节数组

java - 如何正确生成 grpc java auth 示例所需的 .pem 文件?

java - 从android中的json获取数组

.net - 使用 X509Certificate2 和 ECC 公钥加载证书

java - 从jar文件中读取文件,使用netbeans生成的jar

Python 密码学导出 key 到 DER

php - 加密PHP,解密Java

java - iOS 和 JAva 中的 AES 和 RSA 加密

java - 在java中将xls转换为xlsx

java - Maven 格式错误的 POM(无效 token )