DES 加密小程序 returns 接收任何命令时出错
DES Crypto applet returns errror on reception of any command
在下面您会看到一个简单的 Java 卡片小程序,它被编写为使用不同的 DES
和 3DES
算法加密和解密数据。
这些是支持的命令:
00 C0 00 00 | KeyLength | KeyValue
: 设置DES/3DES键。 (8 byte for DES, 16/24 bytes for 2Key/3Key 3DES algorithm)
00 C1 XX YY | DataLength | DataValue
: 对于 DES Encryption/Decryption
00 C2 XX YY | DataLength | DataValue
: 对于 2Key 3DES Encryption/Decryption
00 C3 XX YY | DataLength | DataValue
: 对于 3Key 3DES Encryption/Decryption
XX = 0x00
: DES_CBC_ISO9797_M1
XX = 0x01
: DES_CBC_ISO9797_M2
XX = 0x02
: DES_CBC_NOPAD
XX = 0x03
: DES_CBC_PKCS5
XX = 0x04
: DES_ECB_ISO9797_M1
XX = 0x05
: DES_ECB_ISO9797_M2
XX = 0x06
: DES_ECB_NOPAD
XX = 0x07
: DES_ECB_PKCS5
YY = 0x00
: Encrypt
YY = 0x01
: Decrypt
程序:
package cryptoPack;
import javacard.framework.APDU;
import javacard.framework.Applet;
import javacard.framework.ISO7816;
import javacard.framework.ISOException;
import javacard.framework.JCSystem;
import javacard.framework.Util;
import javacard.security.DESKey;
import javacard.security.KeyBuilder;
import javacardx.crypto.Cipher;
public class CryptoDES extends Applet {
// Array for the encryption/decryption key
private byte[] TheDES_Key = { (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00 };
// Defining required Keys
DESKey MyDES1Key = (DESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_DES,
KeyBuilder.LENGTH_DES, false);
DESKey MyDES2Key = (DESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_DES,
KeyBuilder.LENGTH_DES3_2KEY, false);
DESKey MyDES3Key = (DESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_DES,
KeyBuilder.LENGTH_DES3_3KEY, false);
// Defining required cipher
Cipher MyCipher;
// Defining switch case variables for supported instructions
final byte SetKey = (byte) 0xC0;
final byte OneKeyDES = (byte) 0xC1;
final byte TwoKeyDES = (byte) 0xC2;
final byte ThreeKeyDES = (byte) 0xC3;
// Defining switch case variables for cipher algorithms
final byte DES_CBC_ISO9797_M1 = (byte) 0x00;
final byte DES_CBC_ISO9797_M2 = (byte) 0x01;
final byte DES_CBC_NOPAD = (byte) 0x02;
final byte DES_CBC_PKCS5 = (byte) 0x03;
final byte DES_ECB_ISO9797_M1 = (byte) 0x04;
final byte DES_ECB_ISO9797_M2 = (byte) 0x05;
final byte DES_ECB_NOPAD = (byte) 0x06;
final byte DES_ECB_PKCS5 = (byte) 0x07;
// Defining Proprietary Status Words
final short KeyInNotSetGood = 0x6440;
// A flag to be sure that the configured key has the same length that the
// algorithm needs.
byte ConfiguredKeyLength = 0;
private CryptoDES() {
}
public static void install(byte bArray[], short bOffset, byte bLength)
throws ISOException {
new CryptoDES().register();
}
public void process(APDU apdu) throws ISOException {
// Assigning 0 to "ConfiguredKeyLength" to force the user to use ...
// ... "SetKey" command, after applet selection.
if (selectingApplet()) {
ConfiguredKeyLength = 0;
return;
}
byte[] buffer = apdu.getBuffer();
// Checking the CLA field in the APDU command.
if (buffer[ISO7816.OFFSET_CLA] != 0) {
ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
}
// Checking the P1 and P2 fields in the APDU command.
if (buffer[ISO7816.OFFSET_P1] > 7 || buffer[ISO7816.OFFSET_P2] > 1) {
ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
}
// Analyzing the command.
try {
switch (buffer[ISO7816.OFFSET_INS]) {
case SetKey:
SetCryptoKeyAndInitCipher(apdu);
break;
case OneKeyDES:
OneKeyDESCrypto(apdu);
DoEncryptDecrypt(apdu);
break;
case TwoKeyDES:
TwoKeyDESCrypto(apdu);
DoEncryptDecrypt(apdu);
break;
case (byte) ThreeKeyDES:
ThreeKeyDESCrypto(apdu);
DoEncryptDecrypt(apdu);
break;
default:
ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
}
} catch (Exception e) {
if (e instanceof CryptoException) {
ISOException.throwIt(((CryptoException) e).getReason());
}
ISOException.throwIt(ISO7816.SW_UNKNOWN);
}
}
public void SetCryptoKeyAndInitCipher(APDU apdu) throws ISOException {
byte[] buffer = apdu.getBuffer();
// Key must has a length of 8, 16 or 24 bytes
if (buffer[ISO7816.OFFSET_LC] == 8 || buffer[ISO7816.OFFSET_LC] == 16
|| buffer[ISO7816.OFFSET_LC] == 24) {
Util.arrayCopyNonAtomic(buffer, ISO7816.OFFSET_CDATA, TheDES_Key,
(short) 0, ISO7816.OFFSET_LC);
ConfiguredKeyLength = buffer[ISO7816.OFFSET_LC];
} else {
ISOException.throwIt(ISO7816.SW_DATA_INVALID);
}
switch (buffer[ISO7816.OFFSET_P1]) {
case DES_CBC_ISO9797_M1:
MyCipher.getInstance(Cipher.ALG_DES_CBC_ISO9797_M1, false);
break;
case DES_CBC_ISO9797_M2:
MyCipher.getInstance(Cipher.ALG_DES_CBC_ISO9797_M2, false);
break;
case DES_CBC_NOPAD:
MyCipher.getInstance(Cipher.ALG_DES_CBC_NOPAD, false);
break;
case DES_CBC_PKCS5:
MyCipher.getInstance(Cipher.ALG_DES_CBC_PKCS5, false);
break;
case DES_ECB_ISO9797_M1:
MyCipher.getInstance(Cipher.ALG_DES_ECB_ISO9797_M1, false);
break;
case DES_ECB_ISO9797_M2:
MyCipher.getInstance(Cipher.ALG_DES_ECB_ISO9797_M2, false);
break;
case DES_ECB_NOPAD:
MyCipher.getInstance(Cipher.ALG_DES_ECB_NOPAD, false);
break;
case DES_ECB_PKCS5:
MyCipher.getInstance(Cipher.ALG_DES_ECB_PKCS5, false);
break;
}
}
public void OneKeyDESCrypto(APDU apdu) throws ISOException {
byte[] buffer = apdu.getBuffer();
// Check to see if the configured key is the required key for this ...
// ... algorithm or not
if (ConfiguredKeyLength != 8) {
ISOException.throwIt(KeyInNotSetGood);
}
MyDES1Key.setKey(TheDES_Key, (short) 0);
if (buffer[ISO7816.OFFSET_P2] == 1) {
MyCipher.init(MyDES1Key, Cipher.MODE_ENCRYPT);
} else {
MyCipher.init(MyDES1Key, Cipher.MODE_DECRYPT);
}
}
public void TwoKeyDESCrypto(APDU apdu) throws ISOException {
byte[] buffer = apdu.getBuffer();
// Check to see if the configured key is the required key for this ...
// ... algorithm or not
if (ConfiguredKeyLength != 16) {
ISOException.throwIt(KeyInNotSetGood);
}
MyDES2Key.setKey(TheDES_Key, (short) 0);
if (buffer[ISO7816.OFFSET_P2] == 1) {
MyCipher.init(MyDES2Key, Cipher.MODE_ENCRYPT);
} else {
MyCipher.init(MyDES2Key, Cipher.MODE_DECRYPT);
}
}
public void ThreeKeyDESCrypto(APDU apdu) throws ISOException {
byte[] buffer = apdu.getBuffer();
// Check to see if the configured key is the required key for this ...
// ... algorithm or not
if (ConfiguredKeyLength != 24) {
ISOException.throwIt(KeyInNotSetGood);
}
MyDES3Key.setKey(TheDES_Key, (short) 0);
if (buffer[ISO7816.OFFSET_P2] == 1) {
MyCipher.init(MyDES3Key, Cipher.MODE_ENCRYPT);
} else {
MyCipher.init(MyDES3Key, Cipher.MODE_DECRYPT);
}
}
public void DoEncryptDecrypt(APDU apdu) {
byte[] buffer = apdu.getBuffer();
byte[] CipheredData = JCSystem.makeTransientByteArray((short) 32,
JCSystem.CLEAR_ON_DESELECT);
short datalen = apdu.setIncomingAndReceive();
if ((datalen % 8) != 0) {
ISOException.throwIt(ISO7816.SW_DATA_INVALID);
}
MyCipher.doFinal(buffer, (short) 0, datalen, CipheredData, (short) 0);
Util.arrayCopyNonAtomic(CipheredData, (short) 0, buffer, (short) 0,
datalen);
apdu.setOutgoingAndSend((short) 0, datalen);
}
}
运行-时间输出:
OSC: opensc-tool.exe -s 00a404000b0102030405060708090000 -s 00c10000081122334455667788 -s 00c20000081011121314151617
Using reader with a card: ACS CCID USB Reader 0
//Selecting the applet
Sending: 00 A4 04 00 0B 01 02 03 04 05 06 07 08 09 00 00
Received (SW1=0x90, SW2=0x00)
//Assign 1122334455667788 as the crypto key
Sending: 00 C1 00 00 08 11 22 33 44 55 66 77 88
Received (SW1=0x6F, SW2=0x00)
//Request to "encrypt" "1011121314151617" with "DES_CBC_ISO9797_M1"
Sending: 00 C2 00 00 08 10 11 12 13 14 15 16 17
Received (SW1=0x6F, SW2=0x00)
问题:
- 专业的程序员如何编写上述程序才能使其更高效、更安全? (任何改进:变量的声明和定义范围,变量类型等)
- 为什么小程序 returns 在接收其支持的任何 APDU 命令时出错?
更新:
2.1: 我的 IDE (Eclipse), warn 我 The static method getInstance(byte,boolean)
from the type Cipher should be accessed in a static 呀什么意思?我为什么要?
2.2:在上面的程序中,我假设输入数据的长度小于 32 字节,并且也是 8
字节的倍数。如何使长度可变?一种解决方案是使用 new
关键字,但我认为这是最糟糕的解决方案。有什么建议吗?
Q1
Whosebug 并不意味着要成为同行代码审查的网站。尽管如此,还是有一些明显的观察结果:
- 遵循 Java 代码约定:
myCipher
代替 MyCipher
,KEY_IN_NOT_SET_GOOD
代替 KeyInNotSetGood
等(参见 https://google-styleguide.googlecode.com/svn/trunk/javaguide.html) .这些规则可以大大提高你代码的可读性。
- 切勿以非静态方式使用静态方法(使用
Cipher.getInstance(...)
而不是 myCipher.getInstance(...)
)。 (static
标记 - https://docs.oracle.com/javase/tutorial/java/javaOO/classvars.html)
- 用 try-catch 块包围
process
方法的全部内容,并处理您捕获的所有异常。然后根据异常的类型和原因设置状态字。否则你只会得到 6F00
,几乎没有任何信息。
ConfiguredKeyLength
必须存储在 RAM 中。你的方式很快就会毁坏卡(每个 SELECT 重写 EEPROM 单元)。
Q2
首先,有一个很常见的错误:
Util.arrayCopyNonAtomic(buffer, ISO7816.OFFSET_CDATA, TheDES_Key,
(short) 0, ISO7816.OFFSET_LC);
而不是
Util.arrayCopyNonAtomic(buffer, ISO7816.OFFSET_CDATA, TheDES_Key,
(short) 0, buffer[ISO7816.OFFSET_LC]);
(顺便说一下,一周前我在 Whosebug 告诉你的人是你吗?)
第二个问题:你不打电话
apdu.setIncomingAndReceive();
在接触 APDU 缓冲区的数据部分之前。这会引起很多麻烦。
第三个问题:你创建Cipher实例的方式不对。写:
MyCipher = Cipher.getInstance(Cipher.ALG_DES_CBC_NOPAD, false);
而不是
MyCipher.getInstance(Cipher.ALG_DES_CBC_NOPAD, false);
这就是为什么你得到 NullPointerException
- MyCipher
始终保持 null
.
在下面您会看到一个简单的 Java 卡片小程序,它被编写为使用不同的 DES
和 3DES
算法加密和解密数据。
这些是支持的命令:
00 C0 00 00 | KeyLength | KeyValue
: 设置DES/3DES键。 (8 byte for DES, 16/24 bytes for 2Key/3Key 3DES algorithm)00 C1 XX YY | DataLength | DataValue
: 对于 DES Encryption/Decryption00 C2 XX YY | DataLength | DataValue
: 对于 2Key 3DES Encryption/Decryption00 C3 XX YY | DataLength | DataValue
: 对于 3Key 3DES Encryption/Decryption
XX = 0x00
: DES_CBC_ISO9797_M1
XX = 0x01
: DES_CBC_ISO9797_M2
XX = 0x02
: DES_CBC_NOPAD
XX = 0x03
: DES_CBC_PKCS5
XX = 0x04
: DES_ECB_ISO9797_M1
XX = 0x05
: DES_ECB_ISO9797_M2
XX = 0x06
: DES_ECB_NOPAD
XX = 0x07
: DES_ECB_PKCS5
YY = 0x00
: Encrypt
YY = 0x01
: Decrypt
程序:
package cryptoPack;
import javacard.framework.APDU;
import javacard.framework.Applet;
import javacard.framework.ISO7816;
import javacard.framework.ISOException;
import javacard.framework.JCSystem;
import javacard.framework.Util;
import javacard.security.DESKey;
import javacard.security.KeyBuilder;
import javacardx.crypto.Cipher;
public class CryptoDES extends Applet {
// Array for the encryption/decryption key
private byte[] TheDES_Key = { (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00 };
// Defining required Keys
DESKey MyDES1Key = (DESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_DES,
KeyBuilder.LENGTH_DES, false);
DESKey MyDES2Key = (DESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_DES,
KeyBuilder.LENGTH_DES3_2KEY, false);
DESKey MyDES3Key = (DESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_DES,
KeyBuilder.LENGTH_DES3_3KEY, false);
// Defining required cipher
Cipher MyCipher;
// Defining switch case variables for supported instructions
final byte SetKey = (byte) 0xC0;
final byte OneKeyDES = (byte) 0xC1;
final byte TwoKeyDES = (byte) 0xC2;
final byte ThreeKeyDES = (byte) 0xC3;
// Defining switch case variables for cipher algorithms
final byte DES_CBC_ISO9797_M1 = (byte) 0x00;
final byte DES_CBC_ISO9797_M2 = (byte) 0x01;
final byte DES_CBC_NOPAD = (byte) 0x02;
final byte DES_CBC_PKCS5 = (byte) 0x03;
final byte DES_ECB_ISO9797_M1 = (byte) 0x04;
final byte DES_ECB_ISO9797_M2 = (byte) 0x05;
final byte DES_ECB_NOPAD = (byte) 0x06;
final byte DES_ECB_PKCS5 = (byte) 0x07;
// Defining Proprietary Status Words
final short KeyInNotSetGood = 0x6440;
// A flag to be sure that the configured key has the same length that the
// algorithm needs.
byte ConfiguredKeyLength = 0;
private CryptoDES() {
}
public static void install(byte bArray[], short bOffset, byte bLength)
throws ISOException {
new CryptoDES().register();
}
public void process(APDU apdu) throws ISOException {
// Assigning 0 to "ConfiguredKeyLength" to force the user to use ...
// ... "SetKey" command, after applet selection.
if (selectingApplet()) {
ConfiguredKeyLength = 0;
return;
}
byte[] buffer = apdu.getBuffer();
// Checking the CLA field in the APDU command.
if (buffer[ISO7816.OFFSET_CLA] != 0) {
ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
}
// Checking the P1 and P2 fields in the APDU command.
if (buffer[ISO7816.OFFSET_P1] > 7 || buffer[ISO7816.OFFSET_P2] > 1) {
ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
}
// Analyzing the command.
try {
switch (buffer[ISO7816.OFFSET_INS]) {
case SetKey:
SetCryptoKeyAndInitCipher(apdu);
break;
case OneKeyDES:
OneKeyDESCrypto(apdu);
DoEncryptDecrypt(apdu);
break;
case TwoKeyDES:
TwoKeyDESCrypto(apdu);
DoEncryptDecrypt(apdu);
break;
case (byte) ThreeKeyDES:
ThreeKeyDESCrypto(apdu);
DoEncryptDecrypt(apdu);
break;
default:
ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
}
} catch (Exception e) {
if (e instanceof CryptoException) {
ISOException.throwIt(((CryptoException) e).getReason());
}
ISOException.throwIt(ISO7816.SW_UNKNOWN);
}
}
public void SetCryptoKeyAndInitCipher(APDU apdu) throws ISOException {
byte[] buffer = apdu.getBuffer();
// Key must has a length of 8, 16 or 24 bytes
if (buffer[ISO7816.OFFSET_LC] == 8 || buffer[ISO7816.OFFSET_LC] == 16
|| buffer[ISO7816.OFFSET_LC] == 24) {
Util.arrayCopyNonAtomic(buffer, ISO7816.OFFSET_CDATA, TheDES_Key,
(short) 0, ISO7816.OFFSET_LC);
ConfiguredKeyLength = buffer[ISO7816.OFFSET_LC];
} else {
ISOException.throwIt(ISO7816.SW_DATA_INVALID);
}
switch (buffer[ISO7816.OFFSET_P1]) {
case DES_CBC_ISO9797_M1:
MyCipher.getInstance(Cipher.ALG_DES_CBC_ISO9797_M1, false);
break;
case DES_CBC_ISO9797_M2:
MyCipher.getInstance(Cipher.ALG_DES_CBC_ISO9797_M2, false);
break;
case DES_CBC_NOPAD:
MyCipher.getInstance(Cipher.ALG_DES_CBC_NOPAD, false);
break;
case DES_CBC_PKCS5:
MyCipher.getInstance(Cipher.ALG_DES_CBC_PKCS5, false);
break;
case DES_ECB_ISO9797_M1:
MyCipher.getInstance(Cipher.ALG_DES_ECB_ISO9797_M1, false);
break;
case DES_ECB_ISO9797_M2:
MyCipher.getInstance(Cipher.ALG_DES_ECB_ISO9797_M2, false);
break;
case DES_ECB_NOPAD:
MyCipher.getInstance(Cipher.ALG_DES_ECB_NOPAD, false);
break;
case DES_ECB_PKCS5:
MyCipher.getInstance(Cipher.ALG_DES_ECB_PKCS5, false);
break;
}
}
public void OneKeyDESCrypto(APDU apdu) throws ISOException {
byte[] buffer = apdu.getBuffer();
// Check to see if the configured key is the required key for this ...
// ... algorithm or not
if (ConfiguredKeyLength != 8) {
ISOException.throwIt(KeyInNotSetGood);
}
MyDES1Key.setKey(TheDES_Key, (short) 0);
if (buffer[ISO7816.OFFSET_P2] == 1) {
MyCipher.init(MyDES1Key, Cipher.MODE_ENCRYPT);
} else {
MyCipher.init(MyDES1Key, Cipher.MODE_DECRYPT);
}
}
public void TwoKeyDESCrypto(APDU apdu) throws ISOException {
byte[] buffer = apdu.getBuffer();
// Check to see if the configured key is the required key for this ...
// ... algorithm or not
if (ConfiguredKeyLength != 16) {
ISOException.throwIt(KeyInNotSetGood);
}
MyDES2Key.setKey(TheDES_Key, (short) 0);
if (buffer[ISO7816.OFFSET_P2] == 1) {
MyCipher.init(MyDES2Key, Cipher.MODE_ENCRYPT);
} else {
MyCipher.init(MyDES2Key, Cipher.MODE_DECRYPT);
}
}
public void ThreeKeyDESCrypto(APDU apdu) throws ISOException {
byte[] buffer = apdu.getBuffer();
// Check to see if the configured key is the required key for this ...
// ... algorithm or not
if (ConfiguredKeyLength != 24) {
ISOException.throwIt(KeyInNotSetGood);
}
MyDES3Key.setKey(TheDES_Key, (short) 0);
if (buffer[ISO7816.OFFSET_P2] == 1) {
MyCipher.init(MyDES3Key, Cipher.MODE_ENCRYPT);
} else {
MyCipher.init(MyDES3Key, Cipher.MODE_DECRYPT);
}
}
public void DoEncryptDecrypt(APDU apdu) {
byte[] buffer = apdu.getBuffer();
byte[] CipheredData = JCSystem.makeTransientByteArray((short) 32,
JCSystem.CLEAR_ON_DESELECT);
short datalen = apdu.setIncomingAndReceive();
if ((datalen % 8) != 0) {
ISOException.throwIt(ISO7816.SW_DATA_INVALID);
}
MyCipher.doFinal(buffer, (short) 0, datalen, CipheredData, (short) 0);
Util.arrayCopyNonAtomic(CipheredData, (short) 0, buffer, (short) 0,
datalen);
apdu.setOutgoingAndSend((short) 0, datalen);
}
}
运行-时间输出:
OSC: opensc-tool.exe -s 00a404000b0102030405060708090000 -s 00c10000081122334455667788 -s 00c20000081011121314151617
Using reader with a card: ACS CCID USB Reader 0
//Selecting the applet
Sending: 00 A4 04 00 0B 01 02 03 04 05 06 07 08 09 00 00
Received (SW1=0x90, SW2=0x00)
//Assign 1122334455667788 as the crypto key
Sending: 00 C1 00 00 08 11 22 33 44 55 66 77 88
Received (SW1=0x6F, SW2=0x00)
//Request to "encrypt" "1011121314151617" with "DES_CBC_ISO9797_M1"
Sending: 00 C2 00 00 08 10 11 12 13 14 15 16 17
Received (SW1=0x6F, SW2=0x00)
问题:
- 专业的程序员如何编写上述程序才能使其更高效、更安全? (任何改进:变量的声明和定义范围,变量类型等)
- 为什么小程序 returns 在接收其支持的任何 APDU 命令时出错?
更新:
2.1: 我的 IDE (Eclipse), warn 我 The static method getInstance(byte,boolean)
from the type Cipher should be accessed in a static 呀什么意思?我为什么要?
2.2:在上面的程序中,我假设输入数据的长度小于 32 字节,并且也是 8
字节的倍数。如何使长度可变?一种解决方案是使用 new
关键字,但我认为这是最糟糕的解决方案。有什么建议吗?
Q1
Whosebug 并不意味着要成为同行代码审查的网站。尽管如此,还是有一些明显的观察结果:
- 遵循 Java 代码约定:
myCipher
代替MyCipher
,KEY_IN_NOT_SET_GOOD
代替KeyInNotSetGood
等(参见 https://google-styleguide.googlecode.com/svn/trunk/javaguide.html) .这些规则可以大大提高你代码的可读性。 - 切勿以非静态方式使用静态方法(使用
Cipher.getInstance(...)
而不是myCipher.getInstance(...)
)。 (static
标记 - https://docs.oracle.com/javase/tutorial/java/javaOO/classvars.html) - 用 try-catch 块包围
process
方法的全部内容,并处理您捕获的所有异常。然后根据异常的类型和原因设置状态字。否则你只会得到6F00
,几乎没有任何信息。 ConfiguredKeyLength
必须存储在 RAM 中。你的方式很快就会毁坏卡(每个 SELECT 重写 EEPROM 单元)。
Q2
首先,有一个很常见的错误:
Util.arrayCopyNonAtomic(buffer, ISO7816.OFFSET_CDATA, TheDES_Key,
(short) 0, ISO7816.OFFSET_LC);
而不是
Util.arrayCopyNonAtomic(buffer, ISO7816.OFFSET_CDATA, TheDES_Key,
(short) 0, buffer[ISO7816.OFFSET_LC]);
(顺便说一下,一周前我在 Whosebug 告诉你的人是你吗?)
第二个问题:你不打电话
apdu.setIncomingAndReceive();
在接触 APDU 缓冲区的数据部分之前。这会引起很多麻烦。
第三个问题:你创建Cipher实例的方式不对。写:
MyCipher = Cipher.getInstance(Cipher.ALG_DES_CBC_NOPAD, false);
而不是
MyCipher.getInstance(Cipher.ALG_DES_CBC_NOPAD, false);
这就是为什么你得到 NullPointerException
- MyCipher
始终保持 null
.