字节数组的快速位移 - CMAC子键

时间:2015-05-20 13:02:28

标签: performance cryptography bit-manipulation bit-shift javacard

我需要在 JavaCard 中尽可能快地实现16字节数组的左移位。

我试过这段代码:

private static final void rotateLeft(final byte[] output, final byte[] input) {
         short carry = 0;
         short i = (short) 16;
         do {
             --i;
             carry = (short)((input[i] << 1) | carry);
             output[i] = (byte)carry;
             carry = (short)((carry >> 8) & 1);
         } while (i > 0);
}

任何想法如何改善表现?我正在考虑一些Util.getShort(...)Util.setShort(...)魔法,但我没有设法让它比上面的实现更快。

这是CMAC子项计算的一部分,不幸的是,这种情况很常见。如果你知道一些更快的计算CMAC子项的方法(一个循环中的子键或类似的东西),请告诉我。

3 个答案:

答案 0 :(得分:4)

当谈到速度,已知长度,硬编码版本是最快的(但很难看)。如果您需要移位多个位,请确保相应地更新代码。

self.automaticallyAdjustsScrollViewInsets = false

并使用RAM字节数组!

答案 1 :(得分:2)

使用相同的密钥(即相同的DESFire EV1会话密钥)重复签名时,缓存CMAC子密钥可能会有所帮助。对于给定的键,子键始终相同。

我认为David的答案可能会更快,如果它使用两个局部变量来缓存从输入数组的相同偏移读取两次的值(根据我对JCOP的观察,即使对于瞬态数组,阵列访问也非常昂贵)。

编辑:我可以提供以下实现,使用short进行4位右移(对于支持它的卡,32位int变体会更快):

short pom=0; // X000 to be stored next
short pom2; // loaded value
short pom3; // 0XXX to be stored next
short curOffset=PARAMS_TRACK2_OFFSET;
while(curOffset<16) {
    pom2=Util.getShort(mem_PARAMS, curOffset);
    pom3=(short)(pom2>>>4);
    curOffset=Util.setShort(mem_RAM, curOffset, (short)(pom|pom3));
    pom=(short)(pom2<<12);
}

请注意,此代码假定源和目标中的偏移量相同。

如果需要,您可以展开此循环并使用常量参数。

答案 2 :(得分:1)

这是旋转我可以想到的任意位数的最快算法(我旋转了8个字节的数组,您可以轻松地将其转换为移位16):

使用EEPROM为您的班次创建一个掩码表。遮罩只是从右边开始增加1秒的数量:

final static byte[] ROTL_MASK = {
    (byte) 0x00, //shift 0: 00000000 //this one is never used, we don't do shift 0.
    (byte) 0x01, //shift 1: 00000001
    (byte) 0x03, //shift 2: 00000011
    (byte) 0x07, //shift 3: 00000111
    (byte) 0x0F, //shift 4: 00001111
    (byte) 0x1F, //shift 5: 00011111
    (byte) 0x3F, //shift 6: 00111111
    (byte) 0x7F  //shift 7: 01111111
};

然后,如果shift大于8,则首先使用Util.arrayCopyNonAtomic快速交换字节:

final static byte BITS = 8;
//swap whole bytes:
Util.arrayCopyNonAtomic(in, (short) (shift/BITS), out, (short) 0, (short) (8-(shift/BITS)));
Util.arrayCopyNonAtomic(in, (short) 0, out, (short) (8-(shift/BITS)), (short) (shift/BITS));
shift %= BITS; //now we need to shift only up to 8 remaining bits

if (shift > 0) {
    //apply masks
    byte mask = ROTL_MASK[shift];
    byte comp = (byte) (8 - shift);

    //rotate using masks
    out[8] = in[0]; // out[8] is any auxiliary variable, careful with bounds!
    out[0] = (byte)((byte)(in[0] << shift) | (byte)((in[1] >> comp) & mask));
    out[1] = (byte)((byte)(in[1] << shift) | (byte)((in[2] >> comp) & mask));
    out[2] = (byte)((byte)(in[2] << shift) | (byte)((in[3] >> comp) & mask));
    out[3] = (byte)((byte)(in[3] << shift) | (byte)((in[4] >> comp) & mask));
    out[4] = (byte)((byte)(in[4] << shift) | (byte)((in[5] >> comp) & mask));
    out[5] = (byte)((byte)(in[5] << shift) | (byte)((in[6] >> comp) & mask));
    out[6] = (byte)((byte)(in[6] << shift) | (byte)((in[7] >> comp) & mask));
    out[7] = (byte)((byte)(in[7] << shift) | (byte)((in[8] >> comp) & mask));
}

您还可以删除mask变量,而直接使用对该表的引用。

使用这种而不是天真的实现逐位旋转的方法大约要快450%-500%。