我正在尝试在JavaCard智能卡上实施RFC-2104 HMAC。我似乎得到了错误的结果。我是否遗漏或误解了RFC-2104中的某些内容?
代码:
public class HMACSHA {
private MessageDigest md = null;
private static final byte IPAD = (byte) 0x36;
private static final byte OPAD = (byte) 0x5c;
private byte[] secretIpad;
private byte[] secretOpad;
private byte[] secretKey;
private short outSize = 20;
private short blockSize = 64;
private short ctr = 0;
/**
* Init HMAC algo from RFC-2104. Setup the blocksize of the algo. Default SHA-1.
*
* @param hashAlgo
* @param hmacKey
*/
public void init(byte hashAlgo, byte[] hmacKey) {
md = MessageDigest.getInstance(hashAlgo, false);
if (hashAlgo == 4) {
outSize = (short) 32; // SHA-256
} else if (hashAlgo == 5) {
outSize = (short) 48; // SHA-384
blockSize = (short) 128;
} else if (hashAlgo == 6) {
outSize = (short) 64; // SHA-512
blockSize = (short) 128;
}
secretIpad = JCSystem.makeTransientByteArray((short) blockSize, JCSystem.CLEAR_ON_RESET);
secretOpad = JCSystem.makeTransientByteArray((short) blockSize, JCSystem.CLEAR_ON_RESET);
secretKey = JCSystem.makeTransientByteArray((short) blockSize, JCSystem.CLEAR_ON_RESET);
// Block size == key size. Adjust key.
if ((short) hmacKey.length > blockSize) {
md.reset();
md.doFinal(hmacKey, (short) 0, (short) hmacKey.length, secretKey, (short) 0);
} else {
ArrayLogic.arrayCopyRepack(hmacKey, (short) 0, (short) hmacKey.length, secretKey, (short) 0);
}
// Setup IPAD & OPAD secrets
for (ctr = (short) 0; ctr < blockSize; ctr++) {
secretIpad[ctr] = (byte) (secretKey[ctr] ^ IPAD);
secretOpad[ctr] = (byte) (secretKey[ctr] ^ OPAD);
}
ctr = (short) 0;
}
public void doFinal(byte[] msg, short offset, short length, byte[] workBuff, short workOffset, byte[] outMsg, short outOffset) {
if (md != null) {
// hash(i_key_pad ∥ message)
md.reset();
ArrayLogic.arrayCopyRepack(secretIpad, (short) 0, (short) secretIpad.length, workBuff, workOffset);
ArrayLogic.arrayCopyRepack(msg, offset, length, workBuff, (short) (workOffset + secretIpad.length));
md.doFinal(workBuff, workOffset, (short) (secretIpad.length + length), outMsg, outOffset);
//hash(o_key_pad ∥ i_pad-hashed)
md.reset();
ArrayLogic.arrayCopyRepack(secretOpad, (short) 0, (short) secretOpad.length, workBuff, workOffset);
ArrayLogic.arrayCopyRepack(outMsg, outOffset, (short) outSize, workBuff, (short) (workOffset + secretOpad.length));
md.doFinal(workBuff, workOffset, (short) (secretOpad.length + outSize), outMsg, outOffset);
}
}
}
用法是在主applet类中设置足够大小的缓冲区,然后调用如下例子:
byte[] hmacBuff = JCSystem.makeTransientByteArray((short) 128, JCSystem.CLEAR_ON_RESET);
hmac.init(MessageDigest.ALG_SHA_256, hmacKey);
hmac.doFinal(incomingMsg, (short) 0, (short) incomingMsg.length, hmacBuff, (short) 0, outgoingMsg, (short) 0);
我使用以下参数对标准Java实现进行了双重检查:
HMAC Key Bytes(16):8A560AB02C32377FE3D1BEABE666A19B
HMAC Challenge Bytes(16):8B4F35ADB59D27ABFE95A3CAAB0B613B
HMAC Result Bytes(32):646B96BA38B73847D080E25F843C1E1DE3E8D973DBE6AFC6D402604554E7A7F6
卡的结果是5CB05D1B2CD3F711A853F7166366246743C58509E84D6B8B6C37FF00D6F07619
。假设HMAC密钥在JavaCard和示例桌面应用程序中正确同步。我在HMAC源代码中遗漏了什么吗?
答案 0 :(得分:4)
这些行导致了这个问题:
if (hashAlgo == 4) {
outSize = (short) 32; // SHA-256
//!!! missing: blockSize = (short) 64;
} else if (hashAlgo == 5) {
outSize = (short) 48; // SHA-384
blockSize = (short) 128;
} else if (hashAlgo == 6) {
outSize = (short) 64; // SHA-512
blockSize = (short) 128;
}
对于SHA-256,blockSize
保持不变,因此SHA-384或SHA-512之后的SHA-256继承了错误的值(128而不是64)。
还有一些事情需要改进:
outSize
不是必需的,请改用md.getLength()
。 outSize
不能存储在持久性内存中,而是经常重写。这也适用于blockSize
。MessageDigest
时都不会创建init
的新实例,您将耗尽持久性内存。在构造函数中创建所需的所有实例。ctr
不得存储在持久性内存中。它是一个临时变量,应该移动到RAM。你经常重写这个变量,它可能会损坏你的卡。ArrayLogic.arrayCopyRepack
应替换为标准Java Card库中的Util.arrayCopyNonAtomic
- 您的applet将更快,更便携init
(secretKey
,secretIpad
,secretOpad
)。顺便说一下,你可以只有一个缓冲区,只保留偏移量...... md.reset()
,您不必每次都在md.doFinal(...)
最后(明显)注意:如果您的卡支持,请始终使用Signature.ALG_HMAC_SHA_XXX
。它将比你自己在Java Card中实现的任何解决方案快得多。