【问题标题】:how to build a rsa key with a modulus of 64 bytes in java如何在java中构建模数为64字节的rsa密钥
【发布时间】:2014-11-28 11:12:10
【问题描述】:

我有一个 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 个字节。但是当我制作大整数时,我得到了一个很大的负值。我该怎么办?

【问题讨论】:

标签: java rsa public-key-encryption javacard


【解决方案1】:

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

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

解决办法当然是使用可以自己指明符号位的构造函数:

BigInteger(int signum, byte[] magnitude)

在您的情况下,幅度是无符号表示:

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

Java Card 在 API 中使用无符号表示,因为它更面向加密。不需要复杂的方法。


请注意,反过来 - 从编码的签名 BigInteger 创建一个静态大小的字节数组更加棘手,有关如何执行特定转换的信息,请参阅 this answer

【讨论】:

  • 我在查看我的一些答案时找到了这个答案。它尚未被接受。这解决了你的问题吗?如果是,请接受,如果不是,请指出您遇到的问题。
  • 是的。这解决了这个问题。非常感谢你。抱歉耽搁了。 PS:我不能投票,因为我是新用户,我对此没有足够的声誉。但无论如何,非常感谢你.. :)
  • 没关系,接受更重要,因为它表明问题已得到回答。反正我已经有足够的声望了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-05-18
  • 2012-09-21
  • 2017-04-26
  • 2010-12-07
  • 2017-01-30
  • 1970-01-01
  • 2012-01-20
相关资源
最近更新 更多