Java Card setExponent() 方法在指数超过 10 个字节时失败

Posted

技术标签:

【中文标题】Java Card setExponent() 方法在指数超过 10 个字节时失败【英文标题】:Java Card setExponent() method fails when exponent has more than 10 bytes 【发布时间】:2016-04-28 20:04:30 【问题描述】:

我正在尝试使用 RSA CryptoSystem 中的构建在 Java Card 上实现 modPow 函数。代码看起来微不足道,但我已经发布了实现。

到目前为止我的代码:

    Cipher m_encryptCipherRSA = Cipher.getInstance(Cipher.ALG_RSA_NOPAD, false); // create the cipher
    RSAPublicKey m_rsaPublicKey = (RSAPublicKey) KeyBuilder.buildKey(KeyBuilder.TYPE_RSA_PUBLIC,KeyBuilder.LENGTH_RSA_1024,false);  // create the public key
    m_random = RandomData.getInstance(RandomData.ALG_SECURE_RANDOM);
    m_random.generateData(temp1, (short)0, MODULUS_LENGTH);
    m_rsaPublicKey.setModulus(temp1,(short)0, MODULUS_LENGTH); //generate modulus
    m_random.generateData(temp1,(short)0, (short) EXPONENT_LENGTH);
    m_rsaPublicKey.setExponent(temp1,(short)0, (short)EXPONENT_LENGTH); 

如果EXPONENT_LENGTH 不超过 10 个字节,则 cod 似乎可以正常工作。我拥有的 Java 卡限制了公共指数的维度。但是我的项目是基于长达128bytes 的数字。有没有办法根据这个硬件限制创建一个通用的modpow 函数?有没有另一种方法可以实现仍然可行的幂幂运算。

【问题讨论】:

当您使用EXPONENT_LENGTH > 10 时会发生什么?你得到什么状态词? @vojta 6f 00 这是未知错误。 请捕获抛出的异常并告诉我们它的类型(使用 instanceof 运算符)和原因(getReason() 方法的输出)。 @vojta 我设法通过使用私有指数而不是公共指数解决了这个问题。现在当输入为 1024 位长并且以大于 0x68 的八位字节开始时,我在 Rsa 上遇到了 dofinal 方法的问题. @vojta 我开始新问题here 有详细解释 【参考方案1】:

我设法通过使用私有指数解决了这个问题(似乎不受 RSA 密码系统的约束)。下面是工作代码。

    public byte[] modPow(byte[] x,short xOffset,short xLength,byte[] y,short yOffset,short yLength)

    Util.arrayCopy(y, yOffset, tempBuffer, (short)(Configuration.TEMP_OFFSET_EXPONENT+4), yLength);
    Util.arrayFillNonAtomic(tempBuffer, Configuration.TEMP_OFFSET_EXPONENT, (byte)4,(byte)0x00);
    mRsaPrivateKeyModPow.setExponent(tempBuffer,Configuration.TEMP_OFFSET_EXPONENT, (short)(yLength+4));
    mRsaCipherModPow.init(mRsaPrivateKeyModPow, Cipher.MODE_DECRYPT);
    Util.arrayCopy(x,xOffset,tempBuffer, Configuration.TEMP_OFFSET_RSA, Configuration.LENGTH_RSAOBJECT_MODULUS);
    mRsaCipherModPow.doFinal(tempBuffer,Configuration.TEMP_OFFSET_RSA, (short) (Configuration.LENGTH_RSAOBJECT_MODULUS), tempBuffer,Configuration.TEMP_OFFSET_RSA);
    mRsaPrivateKeyModPow.clearKey();
    return tempBuffer;

【讨论】:

【参考方案2】:

嗯,我尝试了RSAPublicKeyRSAPrivateKey 两种不同的卡,都运行良好:

package soqPack;

import javacard.framework.*;
import javacard.security.KeyBuilder;
import javacard.security.RSAPrivateKey;
import javacard.security.RSAPublicKey;
import javacard.security.RandomData;
import javacardx.biometry.BioBuilder;
import javacardx.crypto.Cipher;

public class modPowtest extends Applet 

    //Definition Of INS in APDU command
    public static final byte INS_MOD_POW = (byte) 0x00;

    //Switch cases to choose RSA Public key or RSA Private key for ModPow()
    //P1 in APDU command.
    public static final byte USE_PUB_KEY = (byte) 0x00;
    public static final byte USE_PRI_KEY = (byte) 0x01;

    //Required objects
    byte[] tempMem;
    Cipher myCipher;
    RSAPrivateKey rsaPriKey;
    RSAPublicKey rsaPubKey;
    RandomData random;

    public static void install(byte[] bArray, short bOffset, byte bLength) 
        new modPowtest();
    

    protected modPowtest() 
        myCipher = Cipher.getInstance(Cipher.ALG_RSA_PKCS1, false);
        rsaPriKey = (RSAPrivateKey) KeyBuilder.buildKey(KeyBuilder.TYPE_RSA_PRIVATE, KeyBuilder.LENGTH_RSA_1024, false);
        rsaPubKey = (RSAPublicKey) KeyBuilder.buildKey(KeyBuilder.TYPE_RSA_PUBLIC, KeyBuilder.LENGTH_RSA_1024, false);
        tempMem = JCSystem.makeTransientByteArray((short) 0x80, JCSystem.CLEAR_ON_DESELECT);
        random = RandomData.getInstance(RandomData.ALG_PSEUDO_RANDOM);
        register();
    

    public void process(APDU apdu) 
        if (selectingApplet()) 
            return;
        

        byte[] buffer = apdu.getBuffer();
        switch (buffer[ISO7816.OFFSET_INS]) 
            case INS_MOD_POW:
                modPow(apdu);
                break;
            default:
                ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
        
    

    public void modPow(APDU apdu) 
        byte[] buffer = apdu.getBuffer();
        switch (buffer[ISO7816.OFFSET_P1]) 
            case USE_PUB_KEY:
                random.generateData(tempMem, (short) 0x00, (short) 0x80);
                rsaPubKey.setModulus(tempMem, (short) 0x00, (short) 0x80);
                random.generateData(tempMem, (short) 0x00, (short) 0x03);
                rsaPubKey.setExponent(tempMem, (short) 0x00, (short) 0x03);
                break;
            case USE_PRI_KEY:
                random.generateData(tempMem, (short) 0x00, (short) 0x80);
                rsaPriKey.setModulus(tempMem, (short) 0x00, (short) 0x80);
                random.generateData(tempMem, (short) 0x00, (short) 0x03);
                rsaPriKey.setExponent(tempMem, (short) 0x00, (short) 0x03);
                break;
            default:
                ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
        

    

工作如下:

Download Cap begin...
Download Cap successful.
Install Applet begin...
Install Applet successful.
Select Applet begin...
Select Applet successful.

Send: 00 00 00 00 00
Recv: 90 00

Send: 00 00 01 00 00
Recv: 90 00

更新:(与您在 cmets 和here 中的新问题相关):

我也将tempMem[0] 的值在setModulussetExponent 方法之前更改为0x69,它仍然可以正常工作。

【讨论】:

我读到setExponent() 可能会失败,如果指数的大小大于 4 个字节。从 oracle 文档中我发现了这个All implementations must support exponent values up to 4 bytes in length. Implementations may also support exponent values greater than 4 bytes in length. 这是link。 我从 here 开始处理新问题。在我看来,模值有问题。我猜它小于 RSA 的 x 值,算法失败。

以上是关于Java Card setExponent() 方法在指数超过 10 个字节时失败的主要内容,如果未能解决你的问题,请参考以下文章

如何在 java 中做这个 Card 类?

2017ICPC沈阳网络赛 HDU 6025 -- card card card(最大子段和)

在 Java Card 上编码 publicKey

java计算年龄

在 Java Card 平台上使用 grpc

瞬态内存中的 Java Card 对象实例