如何在 Java Card 2.2.1 上生成 MD5 散列?

How can I generate an MD5 hash on Java Card 2.2.1?

我正在尝试使用支持 MD5 的 Java 卡散列 8 字节的消息(可能需要将其扩大到 128)。这是我的源代码:

package net.sourceforge.globalplatform.jc.helloworld;
import javacard.framework.*;
import javacard.security.*;
import javacardx.crypto.Cipher;

import javax.print.attribute.standard.MediaSize;
import java.util.logging.Level;

public class HelloWorldApplet extends Applet {

final static byte  APPLET_CLA    = (byte)0x80;
final static byte  HASH          = (byte)0x05;

public static byte[] Message;

MessageDigest mDig = MessageDigest.getInstance(MessageDigest.ALG_MD5, true);

public static void install(byte[] bArray, short bOffset, byte bLength)
{
    Message = new byte[256];
    new HelloWorldApplet().register(bArray, (short) (bOffset + 1), bArray[bOffset]);
}

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

    byte[] buffer = apdu.getBuffer();
    if (buffer[ISO7816.OFFSET_CLA] == APPLET_CLA) {

        switch (buffer[ISO7816.OFFSET_INS]) {

            case HASH:
                hash_message(apdu);
                break;

            default:
                ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
        }
    } else {
        ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
    }
}

public void hash_message(APDU apdu) {
    byte[] buffer = apdu.getBuffer();
    short mLen = apdu.setIncomingAndReceive();
    mDig.reset();
    mDig.doFinal(buffer, (short) ISO7816.OFFSET_CDATA, mLen, Message, (short) 0);
    Util.arrayCopy(Message,(short)0,buffer,(short)0, mLen);
    apdu.setOutgoingAndSend((short)0,mLen);
}

}

这也是我使用 GPSshell 进行的测试:

send_apdu -sc 1 -APDU 80050000081122334455667788
Command --> 80050000081122334455667788
Wrapped command --> 80050000081122334455667788
Response <-- DD254CDC958E53AB9000
send_APDU() returns 0x80209000 (9000: Success. No error.)

我有不同的问题:

  1. 我使用 this link 在 MD5 哈希上测试了我的数据,发现它无法正常工作!我不知道为什么这个算法在我使用尽可能简单的代码时不能正确响应!谁能告诉我问题所在?

  2. 有什么办法可以send/receive256字节的数据to/from卡吗?

  3. 什么是 GPSshell 的更好替代品?


更新 1:我已经看到 link 但它没有解决我的问题。

更新 2:问题 1 的答案 returns GPSshell 和在线计算器中的十六进制和 ASCII 数据差异。

MD5 哈希值与通过某些在线工具生成的哈希值不同。问题出在哪里?

有两个问题导致在线工具生成的hash和小程序生成的hash不一样:

  1. 第一个问题是输入数据格式。您使用的在线工具 (http://www.xorbin.com/tools/md5-hash-calculator) treats the input as ASCII string. Hence, if you input the ASCII string "1122334455667788", you'll get the hash value 8a1bb284d84b7e7df32cba6d8e89eac9 (hexadecimal number). However, the data you hash in the applet is not the ASCII string "1122334455667788" (it's hexadecimal repesentation would be 31313232333334343535363637373838). Instead, you hash the hexadecimal number 1122334455667788. This results in the MD5 hash dd254cdc958e53abaa67da9f797125f5. You can check this with this online calculator: http://www.fileformat.info/tool/hash.htm?hex=1122334455667788.

  2. 第二个问题是您return从您的小程序中获取的散列值的长度。你只有 return mLen 字节(输入值的大小)而不是哈希值的全长。 MD5 散列总是有 128 位(16 字节)。因此,您通常希望 return 来自您的小程序的所有 16 个字节:

    mDig.doFinal(buffer, (short)ISO7816.OFFSET_CDATA, mLen, buffer, (short)0);
    apdu.setOutgoingAndSend((short)0, (short)16);
    

    请注意,无需使用中间字节数组(尤其不是静态字节数组),因为 MessageDigest.doFinal() 支持对输入和输出使用相同的数组,即使范围重叠也是如此。

有什么办法可以send/receive 256字节的数据to/from 卡吗?

如果您的卡支持扩展长度的 APDU,您可以使用它们在一个命令 APDU 中传输超过 255 字节的数据。当使用扩展长度的 APDU 时,典型的方法是将输入数据拆分到多个 APDU。例如,您可以使用 P2 来区分第一个、中间的和最后一个命令 APDU:

public void hash_message(APDU apdu) {
    byte[] buffer = apdu.getBuffer();
    byte p2 = buffer[ISO7816.OFFSET_P2];

    if (p2 != (byte)0x02) {
        if (p2 == (byte)0x01) {
            mDig.reset();
        }

        short bytesLeft = (short) (buffer[ISO7816.OFFSET_LC] & 0x00FF);
        short readCount = apdu.setIncomingAndReceive();
        while (bytesLeft > 0) {
            mDig.update(buffer, (short)ISO7816.OFFSET_CDATA, readCount);
            bytesLeft -= readCount;
            readCount = apdu.receiveBytes((short)ISO7816.OFFSET_CDATA);
        }
    } else {
        mDig.doFinal(buffer, (short)ISO7816.OFFSET_CDATA, (short)0, buffer, (short)0);
        apdu.setOutgoingAndSend((short)0, (short)16);
    }
}

然后您可以通过发送 APDU 开始生成新的哈希值:

80 05 0001 08 1122334455667788

您可以像这样使用 APDU 继续将更多数据输入到哈希生成中:

80 05 0000 Lc DATA

最后,您可以使用以下形式的 APDU 计算生成的哈希值:

80 05 0002 00

什么是 GPSshell 的更好替代品?

这在很大程度上取决于您想要实现的目标。允许您将 APDU 发送到智能卡的其他工具有,例如GScriptor 或 opensc 工具。您还可以创建自己的应用程序,通过 PC/SC API 发送 APDU(例如 Java Smartcard API in Java)。