-1

我正在尝试使用支持 MD5 的 Java Card 散列一条 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. 我使用此链接在 MD5 哈希上测试了我的数据,但发现它无法正常工作!我不知道为什么当我使用尽可能简单的代码时这个算法没有正确响应!谁能告诉我这个问题?

  2. 有没有办法向卡发送/接收 256 字节的数据?

  3. GPSShell 有什么更好的替代品?


更新 1:我已经看到了这个链接,但它并没有解决我的问题。

更新 2:对问题 1 的回答返回 GPSShell 和在线计算器中的 Hex 和 ASCII 数据差异。

4

1 回答 1

5

MD5 散列不同于通过某些在线工具生成的散列。问题出在哪里?

有两个问题导致在线工具生成的哈希和小程序生成的哈希不同:

  1. 第一个问题是输入数据格式。您使用的在线工具 ( http://www.xorbin.com/tools/md5-hash-calculator ) 将输入视为 ASCII 字符串。因此,如果您输入 ASCII 字符串“1122334455667788”,您将获得哈希值8a1bb284d84b7e7df32cba6d8e89eac9(十六进制数)。但是,您在小程序中散列的数据不是 ASCII 字符串“1122334455667788”(它的十六进制表示是31313232333334343535363637373838)。相反,您散列十六进制数字1122334455667788。这会产生 MD5 散列dd254cdc958e53abaa67da9f797125f5。您可以使用此在线计算器进行检查:http ://www.fileformat.info/tool/hash.htm?hex=1122334455667788 。

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

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

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

有没有办法向卡发送/接收 256 字节的数据?

如果您的卡支持扩展长度的 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-tool。您还可以创建自己的应用程序,通过 PC/SC API(例如 Java 中的 Java Smartcard API)发送 APDU。

于 2017-03-05T15:27:49.733 回答