我试图使用支持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);
}
}
这也是我使用GPShell的测试:
send_apdu -sc 1 -APDU 80050000081122334455667788
Command --> 80050000081122334455667788
Wrapped command --> 80050000081122334455667788
Response <-- DD254CDC958E53AB9000
send_APDU() returns 0x80209000 (9000: Success. No error.)
我有不同的问题:
答案 0 :(得分:4)
有两个问题会导致在线工具中生成的哈希值与applet中生成的哈希值之间存在差异:
第一个问题是输入数据格式。您使用的在线工具(http://www.xorbin.com/tools/md5-hash-calculator)将输入威胁为ASCII字符串。因此,如果输入ASCII字符串“1122334455667788”,您将获得哈希值8a1bb284d84b7e7df32cba6d8e89eac9
(十六进制数)。但是,您在applet中散列的数据不是ASCII字符串“1122334455667788”(它的十六进制重复将是31313232333334343535363637373838
)。相反,您对十六进制数1122334455667788
进行哈希处理。这导致MD5哈希dd254cdc958e53abaa67da9f797125f5
。您可以使用此在线计算器进行检查:http://www.fileformat.info/tool/hash.htm?hex=1122334455667788。
第二个问题是您从applet返回的哈希值的长度。您只返回mLen
个字节(输入值的大小)而不是哈希值的全长。 MD5哈希值有128位(16字节)。因此,您通常希望从applet返回所有16个字节:
mDig.doFinal(buffer, (short)ISO7816.OFFSET_CDATA, mLen, buffer, (short)0);
apdu.setOutgoingAndSend((short)0, (short)16);
请注意,不需要使用中间字节数组(尤其不是静态数组),因为MessageDigest.doFinal()
支持使用相同的数组进行输入和输出,即使范围重叠。
如果您的卡支持扩展长度的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
这在很大程度上取决于你想要达到的目标。允许您将APDU发送到智能卡的其他工具是,例如, GScriptor或opensc-tool。您还可以创建自己的应用程序,通过PC / SC API(例如Java中的Java智能卡API)发送APDU。