使用 RSA 进行模乘会导致 Java Card 上出现错误

2023-12-13

你好,我正在开发一个关于 Java Card 的项目,这意味着大量的模乘。我设法使用 RSA 加密系统在这个平台上实现模乘,但它似乎适用于某些数字。

public byte[] modMultiply(byte[] x, short xOffset, short xLength, byte[] y,
        short yOffset, short yLength, short tempOutoffset) {

    //copy x value to temporary rambuffer
    Util.arrayCopy(x, xOffset, tempBuffer, tempOutoffset, xLength);


    // copy the y value to match th size of rsa_object
    Util.arrayFillNonAtomic(eempromTempBuffer, (short)0, (byte) (Configuration.LENGTH_RSAOBJECT_MODULUS-1),(byte)0x00);
    Util.arrayCopy(y,yOffset,eempromTempBuffer,(short)(Configuration.LENGTH_RSAOBJECT_MODULUS - yLength),yLength);

    // x+y
    if (JBigInteger.add(x,xOffset,xLength, eempromTempBuffer,
            (short)0,Configuration.LENGTH_MODULUS)) ;
    if(this.isGreater(x, xOffset, xLength, tempBuffer,Configuration.TEMP_OFFSET_MODULUS, Configuration.LENGTH_MODULUS)>0)
    {
        JBigInteger.subtract(x,xOffset,xLength, tempBuffer,
                Configuration.TEMP_OFFSET_MODULUS, Configuration.LENGTH_MODULUS);
    }

    //(x+y)2
    mRsaCipherForSquaring.init(mRsaPublicKekForSquare, Cipher.MODE_ENCRYPT);

    mRsaCipherForSquaring.doFinal(x, xOffset, Configuration.LENGTH_RSAOBJECT_MODULUS, x,
            xOffset); // OK

    mRsaCipherForSquaring.doFinal(tempBuffer, tempOutoffset, Configuration.LENGTH_RSAOBJECT_MODULUS, tempBuffer, tempOutoffset); // OK


    if (JBigInteger.subtract(x, xOffset, Configuration.LENGTH_MODULUS, tempBuffer, tempOutoffset,
            Configuration.LENGTH_MODULUS)) {
        JBigInteger.add(x, xOffset, Configuration.LENGTH_MODULUS, tempBuffer,
                Configuration.TEMP_OFFSET_MODULUS, Configuration.LENGTH_MODULUS);
    } 

    mRsaCipherForSquaring.doFinal(eempromTempBuffer, yOffset, Configuration.LENGTH_RSAOBJECT_MODULUS, eempromTempBuffer, yOffset); //OK 


    if (JBigInteger.subtract(x, xOffset, Configuration.LENGTH_MODULUS, eempromTempBuffer, yOffset,
            Configuration.LENGTH_MODULUS)) {

        JBigInteger.add(x, xOffset, Configuration.LENGTH_MODULUS, tempBuffer,
                Configuration.TEMP_OFFSET_MODULUS, Configuration.LENGTH_MODULUS);

    }
    // ((x+y)^2 - x^2 -y^2)/2
    JBigInteger.modular_division_by_2(x, xOffset,Configuration. LENGTH_MODULUS, tempBuffer, Configuration.TEMP_OFFSET_MODULUS, Configuration.LENGTH_MODULUS);
    return x;
}


public static boolean add(byte[] x, short xOffset, short xLength, byte[] y,
        short yOffset, short yLength) {
    short digit_mask = 0xff;
    short digit_len = 0x08;
    short result = 0;
    short i = (short) (xLength + xOffset - 1);
    short j = (short) (yLength + yOffset - 1);

    for (; i >= xOffset; i--, j--) {
        result = (short) (result + (short) (x[i] & digit_mask) + (short) (y[j] & digit_mask));

        x[i] = (byte) (result & digit_mask);
        result = (short) ((result >> digit_len) & digit_mask);
    }
    while (result > 0 && i >= xOffset) {
        result = (short) (result + (short) (x[i] & digit_mask));
        x[i] = (byte) (result & digit_mask);
        result = (short) ((result >> digit_len) & digit_mask);
        i--;
    }

    return result != 0;
}
public static boolean subtract(byte[] x, short xOffset, short xLength, byte[] y,
        short yOffset, short yLength) {
    short digit_mask = 0xff;
    short i = (short) (xLength + xOffset - 1);
    short j = (short) (yLength + yOffset - 1);
    short carry = 0;
    short subtraction_result = 0;

    for (; i >= xOffset && j >= yOffset; i--, j--) {
        subtraction_result = (short) ((x[i] & digit_mask)
                - (y[j] & digit_mask) - carry);
        x[i] = (byte) (subtraction_result & digit_mask);
        carry = (short) (subtraction_result < 0 ? 1 : 0);
    }
    for (; i >= xOffset && carry > 0; i--) {
        if (x[i] != 0)
            carry = 0;
        x[i] -= 1;
    }

    return carry > 0;
}



 public short isGreater(byte[] x,short xOffset,short xLength,byte[] y ,short yOffset,short yLength)
    {
        if(xLength > yLength)
            return (short)1;
        if(xLength < yLength)
            return (short)(-1);
        short digit_mask = 0xff;
        short digit_len = 0x08;
        short result = 0;
        short i = (short) (xLength + xOffset - 1);
        short j = (short) (yLength + yOffset - 1);

        for (; i >= xOffset; i--, j--) {
            result = (short) (result + (short) (x[i] & digit_mask) - (short) (y[j] & digit_mask));
            if(result > 0)
                return (short)1;
            if(result < 0)
                return (short)-1;
        }
        return 0;
    }

该代码对于较小的数字适用,但对于较大的数字则失败


下面是一个非常简单的单元测试,其中包含代码的(希望)工作变体:

package test.java.so;

import java.math.BigInteger;
import java.util.Random;

import javacard.framework.JCSystem;
import javacard.framework.Util;
import javacard.security.KeyBuilder;
import javacard.security.RSAPublicKey;
import javacardx.crypto.Cipher;

import org.apache.commons.lang3.ArrayUtils;
import org.bouncycastle.util.Arrays;
import org.junit.Assert;
import org.junit.Test;

import sutil.test.AbstractTest;

public class So36966764_Test extends AbstractTest {

    private static final int NUM_BITS = 1024;

    // Dummy
    static class Configuration {
        public static final short LENGTH_MODULUS = NUM_BITS/8;
        public static final short LENGTH_RSAOBJECT_MODULUS = LENGTH_MODULUS;
        public static final short TEMP_OFFSET_MODULUS = 0;
        public static final short TEMP_OFFSET_RESULT = LENGTH_MODULUS;
    }

    private byte[] tempBuffer = JCSystem.makeTransientByteArray((short)(Configuration.TEMP_OFFSET_RESULT+Configuration.LENGTH_MODULUS), JCSystem.CLEAR_ON_DESELECT);
    private byte[] eempromTempBuffer = new byte[Configuration.LENGTH_MODULUS]; // Why EEPROM?
    private RSAPublicKey mRsaPublicKekForSquare = (RSAPublicKey)KeyBuilder.buildKey(KeyBuilder.TYPE_RSA_PUBLIC, (short)NUM_BITS, false);
    private Cipher mRsaCipherForSquaring = Cipher.getInstance(Cipher.ALG_RSA_NOPAD, false);

    // Assuming xLength==yLength==LENGTH_MODULUS
    public byte[] modMultiply(byte[] x, short xOffset, short xLength, byte[] y, short yOffset, short yLength, short tempOutoffset) {

        //copy x value to temporary rambuffer
        Util.arrayCopy(x, xOffset, tempBuffer, tempOutoffset, xLength);

        // copy the y value to match th size of rsa_object
        Util.arrayFillNonAtomic(eempromTempBuffer, (short)0, (short) (Configuration.LENGTH_RSAOBJECT_MODULUS-1),(byte)0x00);
        Util.arrayCopy(y,yOffset,eempromTempBuffer,(short)(Configuration.LENGTH_RSAOBJECT_MODULUS - yLength),yLength);

        // x+y
        if(add(x,xOffset,xLength, eempromTempBuffer, (short)0,Configuration.LENGTH_MODULUS)) {
            subtract(x,xOffset,xLength, tempBuffer, Configuration.TEMP_OFFSET_MODULUS, Configuration.LENGTH_MODULUS);
        }
        while(isGreater(x, xOffset, xLength, tempBuffer,Configuration.TEMP_OFFSET_MODULUS, Configuration.LENGTH_MODULUS)>0) {
            subtract(x,xOffset,xLength, tempBuffer,Configuration.TEMP_OFFSET_MODULUS, Configuration.LENGTH_MODULUS);
        }

        //(x+y)2
        mRsaCipherForSquaring.init(mRsaPublicKekForSquare, Cipher.MODE_ENCRYPT);
        mRsaCipherForSquaring.doFinal(x, xOffset, Configuration.LENGTH_RSAOBJECT_MODULUS, x, xOffset); // OK

        mRsaCipherForSquaring.doFinal(tempBuffer, tempOutoffset, Configuration.LENGTH_RSAOBJECT_MODULUS, tempBuffer, tempOutoffset); // OK

        if (subtract(x, xOffset, Configuration.LENGTH_MODULUS, tempBuffer, tempOutoffset,
                Configuration.LENGTH_MODULUS)) {
            add(x, xOffset, Configuration.LENGTH_MODULUS, tempBuffer,
                    Configuration.TEMP_OFFSET_MODULUS, Configuration.LENGTH_MODULUS);
        }

        /*WRONG OFFSET mRsaCipherForSquaring.doFinal(eempromTempBuffer, yOffset, Configuration.LENGTH_RSAOBJECT_MODULUS, eempromTempBuffer, yOffset); */
        mRsaCipherForSquaring.doFinal(eempromTempBuffer, (short)0, Configuration.LENGTH_RSAOBJECT_MODULUS, eempromTempBuffer, (short)0); //OK

        /*WRONG OFFSET if (subtract(x, xOffset, Configuration.LENGTH_MODULUS, eempromTempBuffer, yOffset,*/
        if (subtract(x, xOffset, Configuration.LENGTH_MODULUS, eempromTempBuffer, (short)0,Configuration.LENGTH_MODULUS)) {
            add(x, xOffset, Configuration.LENGTH_MODULUS, tempBuffer,
                    Configuration.TEMP_OFFSET_MODULUS, Configuration.LENGTH_MODULUS);
        }
        // ((x+y)^2 - x^2 -y^2)/2
        modular_division_by_2(x, xOffset,Configuration. LENGTH_MODULUS, tempBuffer, Configuration.TEMP_OFFSET_MODULUS, Configuration.LENGTH_MODULUS);
        return x;
    }

    public static boolean add(byte[] x, short xOffset, short xLength, byte[] y, short yOffset, short yLength) {
        short digit_mask = 0xff;
        short digit_len = 0x08;
        short result = 0;
        short i = (short) (xLength + xOffset - 1);
        short j = (short) (yLength + yOffset - 1);

        for (; i >= xOffset; i--, j--) {
            result = (short) (result + (short) (x[i] & digit_mask) + (short) (y[j] & digit_mask));

            x[i] = (byte) (result & digit_mask);
            result = (short) ((result >> digit_len) & digit_mask);
        }
        while (result > 0 && i >= xOffset) {
            result = (short) (result + (short) (x[i] & digit_mask));
            x[i] = (byte) (result & digit_mask);
            result = (short) ((result >> digit_len) & digit_mask);
            i--;
        }

        return result != 0;
    }

    public static boolean subtract(byte[] x, short xOffset, short xLength, byte[] y, short yOffset, short yLength) {
        short digit_mask = 0xff;
        short i = (short) (xLength + xOffset - 1);
        short j = (short) (yLength + yOffset - 1);
        short carry = 0;
        short subtraction_result = 0;

        for (; i >= xOffset && j >= yOffset; i--, j--) {
            subtraction_result = (short) ((x[i] & digit_mask)
                    - (y[j] & digit_mask) - carry);
            x[i] = (byte) (subtraction_result & digit_mask);
            carry = (short) (subtraction_result < 0 ? 1 : 0);
        }
        for (; i >= xOffset && carry > 0; i--) {
            if (x[i] != 0)
                carry = 0;
            x[i] -= 1;
        }

        return carry > 0;
    }

    public short isGreater(byte[] x,short xOffset,short xLength,byte[] y ,short yOffset,short yLength)
    {
        // Beware: this part is not tested
        while(xLength>yLength) {
            if(x[xOffset++]!=0x00) {
                return 1; // x is greater
            }
            xLength--;
        }
        while(yLength>xLength) {
            if(y[yOffset++]!=0x00) {
                return -1; // y is greater
            }
            yLength--;
        }
        // Beware: this part is not tested END
        for(short i = 0; i < xLength; i++) {
            if (x[xOffset] != y[yOffset]) {
                short srcShort = (short)(x[xOffset]&(short)0xFF);
                short dstShort = (short)(y[yOffset]&(short)0xFF);
                return ( ((srcShort > dstShort) ? (byte)1 : (byte)-1));
            }
            xOffset++;
            yOffset++;
        }
        return 0;
    }

    private void modular_division_by_2(byte[] input, short inOffset, short inLength, byte[] modulus, short modulusOffset, short modulusLength) {
        short carry = 0;
        short digit_mask = 0xff;
        short digit_first_bit_mask = 0x80;
        short lastIndex = (short) (inOffset + inLength - 1);

        short i = inOffset;
        if ((byte) (input[lastIndex] & 0x01) != 0) {
            if (add(input, inOffset, inLength, modulus, modulusOffset,
                    modulusLength)) {
                carry = digit_first_bit_mask;
            }
        }

        for (; i <= lastIndex; i++) {
            if ((input[i] & 0x01) == 0) {
                input[i] = (byte) (((input[i] & digit_mask) >> 1) | carry);
                carry = 0;
            } else {
                input[i] = (byte) (((input[i] & digit_mask) >> 1) | carry);
                carry = digit_first_bit_mask;
            }
        }
    }

    @Test
    public void testModMultiply() {
        Random r = new Random(12345L);
        for(int iiii=0;iiii<10;iiii++) {
            BigInteger modulus = BigInteger.probablePrime(NUM_BITS, r);
            System.out.println(" M = " + modulus);
            byte[] modulusBytes = normalize(modulus.toByteArray());
            Util.arrayCopyNonAtomic(modulusBytes, (short)0, tempBuffer, Configuration.TEMP_OFFSET_MODULUS, Configuration.LENGTH_MODULUS);

            mRsaPublicKekForSquare.setModulus(modulusBytes, (short)0, (short)modulusBytes.length);
            mRsaPublicKekForSquare.setExponent(new byte[] {0x02}, (short)0, (short)1);

            for(int iii=0;iii<1000;iii++) {
                BigInteger x = new BigInteger(NUM_BITS, r).mod(modulus);
                System.out.println(" x = " + x);
                BigInteger y = new BigInteger(NUM_BITS, r).mod(modulus);
                System.out.println(" y = " + y);
                BigInteger accResult;
                {
                    byte[] xBytes = normalize(x.toByteArray());
                    byte[] yBytes = normalize(y.toByteArray());
                    byte[] accResultBytes = modMultiply(xBytes, (short)0, (short)xBytes.length, yBytes, (short)0, (short)yBytes.length, Configuration.TEMP_OFFSET_RESULT);
                    accResult = new BigInteger(1, accResultBytes);
                }
                System.out.println(" Qr = " + accResult);
                BigInteger realResult = x.multiply(y).mod(modulus);
                System.out.println(" Rr = " + realResult);
                Assert.assertEquals(realResult, accResult);
            }
        }
    }

    private byte[] normalize(byte[] xBytes) {
        if(xBytes.length<Configuration.LENGTH_MODULUS) {
            xBytes = ArrayUtils.addAll(new byte[Configuration.LENGTH_MODULUS-xBytes.length], xBytes);
        }
        if(xBytes.length>Configuration.LENGTH_MODULUS) {
            Assert.assertEquals(xBytes[0], 0x00);
            xBytes=Arrays.copyOfRange(xBytes, 1, xBytes.length);
        }
        return xBytes;
    }
}

什么(恕我直言)错了:

  1. The isGreater()方法——虽然可以使用减法来比较数字,但从最高有效字节开始比较相应的字节并在第一个不匹配时停止比较更容易(也更快)。 (在减法情况下,您需要完成减法并返回最终结果的符号 - 您的原始代码以第一个“不匹配”结束。)

  2. x+y溢出——您应该保留加法溢出情况的模减法(即当add()返回 true) 在您的最后一次编辑中。

  3. 偏移量为eempromTempBuffer-- 在你使用过的两个地方yOffset并且应该使用0(用“错误的偏移量”注释掉)。

  4. Casting Configuration.LENGTH_RSAOBJECT_MODULUS-1 to byte对于较大的模长度值来说不是一个好主意

一些(随机)评论:

  • 测试使用已经提到的jcardsim to work

  • 该代码假设长度为x and y都是LENGTH_MODULUS(也LENGTH_RSAOBJECT_MODULUS等于LENGTH_MODULUS)

  • 这不是一个好主意eempromTempBuffer在非易失性存储器中

  • 你的代码非常类似于这段代码这很有趣

  • 关于这个主题的有趣读物是here(第 4.2.3 节)。

祝你好运!

免责声明:我不是加密专家也不是数学家,所以请验证我的想法

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 RSA 进行模乘会导致 Java Card 上出现错误 的相关文章

随机推荐

  • matplotlib 不支持生成器作为输入

    我正在这个网站上运行笔记本https github com vsmolyakov experiments with python blob master chp01 ensemble methods ipynb用python练习ensemb
  • 将字符串参数从 xhtml 传递给函数或方法

    我有一个按钮 我想根据函数返回 true 还是 false 来呈现它 HTML
  • 在 Windows 和 Mac 上通过 VBA 宏发送带有工作簿的电子邮件

    我的以下代码在 PC 上运行正常 但在 Mac 上不起作用 我希望脚本能够识别当前操作系统并为该操作系统运行适当的命令集 而不是为 Windows 和 Mac 用户制作两个带有单独按钮的宏版本 该宏创建一封带有工作簿附件的电子邮件 该附件是
  • 如何让Linux JVM 64位上出现OutOfMemoryError

    在我的单元测试中 我故意尝试引发 OutOfMemoryError 异常 我使用如下简单的语句 byte block new byte 128 1024 1024 1024 该代码适用于 Win7 64 位和 jdk6u21 64 位 但是
  • 带有加密密码的 Sqlite 连接字符串

    我有一个加密数据库 使用 SQLite 密码 当我尝试使用连接字符串连接到数据库时 出现以下错误消息 SQL 逻辑错误无法使用 密码 连接字符串属性 库未构建加密支持 Imports System Data SQLite Public Cl
  • 如何使用 CEFSharp 访问元素?

    我是第一次使用 CEFSharp C 我很难弄清楚如何让浏览器执行除 browser Load 之外的任何操作 我已经在许多网站上搜索了几个小时 但似乎没有人有答案或有这个问题 我正在尝试访问网站元素 就好像它们是 C 表单控件一样 简而言
  • 更换括号时出现异常

    嘿 我想用下划线替换随机字母 仅第一个 为此 我使用以下行 String newSubstring substring replaceFirst randomLetter 除非有括号 或 否则效果很好 然后我得到以下异常 06 14 15
  • 从 Windows 服务访问 Google Drive

    我试图了解是否可以从传统的 Windows 服务访问 Google Drive 而无需用户参与 遵循以下指南https developers google com drive quickstart 我已经能够创建一个命令行应用程序 将文件上
  • 显式等待在基于 Angular 的 PayPal 沙箱上不起作用

    我对 Selenium Python 的 PayPal 沙箱自动化有疑问 一般来说 我为每个操作方法编写显式等待 例如send keys or click 进入按钮 但它们就是不起作用 我尝试了几乎所有可用的显式等待 我尝试调整方法 该方法
  • UI 设计 - 是否包含取消按钮?

    我们正在为新的业务线应用程序设计 UI 我们没有真正的限制 可以自由地设计我们认为合适的 UI UI 将在 WPF 中完成 面向 Windows 7 Vista 和 XP Pro 用户 许多对话框的右下角都包含 确定 和 取消 按钮 您觉得
  • 将 Google 地图应用程序移植到 Osmdroid - 覆盖问题

    我正在将一个基于 Google 地图的项目移植到 Osmdroid 以便使用 OpenStreetMaps 除了添加由许多直线和一些文本组成的覆盖层之外 该端口工作正常 在这两个项目中 我通过计时器线程和调用 redrawOverlay 的
  • 在 Raspberry pi 上打开连接 SQLite 时出错

    更新 我只是检查了我使用的最新 JDBC jar 它缺少映射 Linux arm libsqlitejdbc so 通过从某处下载此文件可以解决此问题吗 到处都找不到 编辑 问题似乎是这样的 但我不知道如何解决这个问题 Caused by
  • Google OAuth2:何时以及如何使用刷新令牌

    我安装了一个 C 应用程序 其代码可以获取授权代码并将其交换为访问令牌 我正在存储刷新令牌 我知道在某些时候我需要使用它来获取新的访问令牌 假设我定期调用以下方法来监视与我的云端硬盘帐户共享的文件
  • 使用 v1 API 中的 cURL 将 Push FCM 发送到多个设备

    我需要将 FCM 推送通知发送到多个设备 我不能为此使用 主题 因为我需要将其发送到特定的和多个令牌 在旧方法中 我使用 register ids 来实现此目的 但 Google 在 2023 年 6 月 20 日宣布 旧方法将于 2024
  • 两个日期和两个时间之间的mySQL查询

    我想查询 mySQL 表以提取两个日期和两次时间之间的数据 我知道如何使用 Between 调用对单个 日期时间 列执行此操作 但我的列是一个 日期 列和一个 时间 列 我可以在网上找到的所有解决方案都是针对单个日期时间列的 我的范围从 第
  • 如何使用 matplotlib fill_ Between 作为默认 ylim

    无填充 带填充 plt fill between n data 我想填写默认的 y 限制 另外我可以做渐变填充吗 您可以使用ax get ylim 得到 y 极限 ax fill between n ymin data 填充最小值和曲线之间
  • iOS 工作线程

    我想在 iPhone 上创建一个后台线程 每 10 毫秒执行一些代码 但在我迷失在苹果的并发编程指南和线程编程指南之前again 我想问这里是否有人可以帮助我 我想做的事 创建后台工作线程 每 10 毫秒触发一次方法的执行 可能通过在该线程
  • 为什么可以通过构造函数分配只读属性?

    我已经设置了属性Name是只读的 但仍然可以分配 class Person public string Name get public Person string name Name name 尝试为属性设置值Name var p new
  • android TrafficStats getUidRxBytes 不准确

    我编写了一个小 Android 应用程序 发送 Http 请求 接收来自服务器的响应 并计算传输和接收的字节数 代码如下 long receivedBytes TrafficStats getUidRxBytes uid lastNumer
  • 使用 RSA 进行模乘会导致 Java Card 上出现错误

    你好 我正在开发一个关于 Java Card 的项目 这意味着大量的模乘 我设法使用 RSA 加密系统在这个平台上实现模乘 但它似乎适用于某些数字 public byte modMultiply byte x short xOffset s