Java Card DES 生成器小程序输出与在线工具输出不同

2022-01-10 00:00:00 cryptography java javacard

下面的小程序用于对 APDU 数据字段进行 DES 加密/解密:

The below applet is written to do a DES encryption/Decryption on the APDU data field :

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.CryptoException;
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);

    byte ConfiguredKeyLength;

    // Defining required cipher
    Cipher MyCipher;

    // Defining switch case variables for supported instructions = INS in APDU command
    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 = P1 in APDU command
    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.

    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 (CryptoException e) {
            ISOException.throwIt(((CryptoException) e).getReason());
        }

    }

    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, buffer[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 = Cipher.getInstance(Cipher.ALG_DES_CBC_ISO9797_M1, false);
            break;
        case DES_CBC_ISO9797_M2:
            MyCipher = Cipher.getInstance(Cipher.ALG_DES_CBC_ISO9797_M2, false);
            break;
        case DES_CBC_NOPAD:
            MyCipher = Cipher.getInstance(Cipher.ALG_DES_CBC_NOPAD, false);
            break;
        case DES_CBC_PKCS5:
            MyCipher = Cipher.getInstance(Cipher.ALG_DES_CBC_PKCS5, false);
            break;
        case DES_ECB_ISO9797_M1:
            MyCipher = Cipher.getInstance(Cipher.ALG_DES_ECB_ISO9797_M1, false);
            break;
        case DES_ECB_ISO9797_M2:
            MyCipher = Cipher.getInstance(Cipher.ALG_DES_ECB_ISO9797_M2, false);
            break;
        case DES_ECB_NOPAD:
            MyCipher = Cipher.getInstance(Cipher.ALG_DES_ECB_NOPAD, false);
            break;
        case DES_ECB_PKCS5:
            MyCipher = Cipher.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);
    }

}

问题是它的输出不等于在线工具.例如我使用 this website 来计算 0x3030303030303030 的加密值有一个键 = 1122334455667788,这是输出:

The problem is that its output is not equal with online tools. for example I use this website to calculate encrypted value of 0x3030303030303030 with a key = 1122334455667788, and this is output :

现在我用我的小程序重复上述加密:

Now I repeat the above encryption with my applet:

OpenSC:: opensc-tool.exe -s 00a404000b0102030405060708090000 -s 00c0000008112233
4455667788 -s 00c10401083030303030303030
Using reader with a card: ACS CCID USB Reader 0
Sending: 00 A4 04 00 0B 01 02 03 04 05 06 07 08 09 00 00
Received (SW1=0x90, SW2=0x00)
Sending: 00 C0 00 00 08 11 22 33 44 55 66 77 88
Received (SW1=0x90, SW2=0x00)
Sending: 00 C1 04 01 08 30 30 30 30 30 30 30 30
Received (SW1=0x90, SW2=0x00):
8E 43 CF B8 91 02 01 38 .C.....8

OpenSC:: opensc-tool.exe -s 00a404000b0102030405060708090000 -s 00c0000008112233
4455667788 -s 00c10501083030303030303030
Using reader with a card: ACS CCID USB Reader 0
Sending: 00 A4 04 00 0B 01 02 03 04 05 06 07 08 09 00 00
Received (SW1=0x90, SW2=0x00)
Sending: 00 C0 00 00 08 11 22 33 44 55 66 77 88
Received (SW1=0x90, SW2=0x00)
Sending: 00 C1 05 01 08 30 30 30 30 30 30 30 30
Received (SW1=0x90, SW2=0x00):
A6 DE 1C D9 1B A9 EE D0 ........

OpenSC:: opensc-tool.exe -s 00a404000b0102030405060708090000 -s 00c0000008112233
4455667788 -s 00c10601083030303030303030
Using reader with a card: ACS CCID USB Reader 0
Sending: 00 A4 04 00 0B 01 02 03 04 05 06 07 08 09 00 00
Received (SW1=0x90, SW2=0x00)
Sending: 00 C0 00 00 08 11 22 33 44 55 66 77 88
Received (SW1=0x90, SW2=0x00)
Sending: 00 C1 06 01 08 30 30 30 30 30 30 30 30
Received (SW1=0x90, SW2=0x00):
0B FC BF EE 82 F4 8B 19 ........

OpenSC:: opensc-tool.exe -s 00a404000b0102030405060708090000 -s 00c0000008112233
4455667788 -s 00c10701083030303030303030
Using reader with a card: ACS CCID USB Reader 0
Sending: 00 A4 04 00 0B 01 02 03 04 05 06 07 08 09 00 00
Received (SW1=0x90, SW2=0x00)
Sending: 00 C0 00 00 08 11 22 33 44 55 66 77 88
Received (SW1=0x90, SW2=0x00)
Sending: 00 C1 07 01 08 30 30 30 30 30 30 30 30
Received (SW1=0x90, SW2=0x00):
AA 6E 4D 79 E5 0C B1 51 .nMy...Q

因为我不知道 DES_ECB_PKCS5DES_ECB_NOPADDES_ECB_ISO9797_M2DES_ECB_ISO9797_M1 中的哪一个被使用在线工具,我用我的卡中的所有这些进行了加密.但输出与在线工具不同.

As I didn't know which one of DES_ECB_PKCS5, DES_ECB_NOPAD, DES_ECB_ISO9797_M2 or DES_ECB_ISO9797_M1 being used by the online tool, I did the encryption with all of them in my card. but the output is different from the online tool.

  1. 怎么了?
  2. 在线工具使用的是上述密码中的哪一种?

推荐答案

因为我不知道 DES_ECB_PKCS5、DES_ECB_NOPAD 中的哪一个,在线工具使用的DES_ECB_ISO9797_M2或DES_ECB_ISO9797_M1

As I didn't know which one of DES_ECB_PKCS5, DES_ECB_NOPAD, DES_ECB_ISO9797_M2 or DES_ECB_ISO9797_M1 being used by the online tool

这就是问题所在.Blockmode,填充和其他东西非常重要(并且有超过4种组合).对于在线工具,字符集(一般的输入解释)也是一个问题.

That´s the problem. Blockmode, padding and other things are very important (and there are so much more than 4 combinations). And in case of online tools, charset stuff (input interpretation in general) is also a problem.

如果不详细了解在线工具,您将无法使用它.
只是不要使用它并搜索标准化的测试向量.

Without knowing the online tool in detail, you won´t get anything right with it.
Just don´t use it and search for standardized test vectors.

除此之外,您为什么要使用 DES!?别这样.
它不再安全了.

Other than that, why you´re using DES!? Stop that.
It´s not secure anymore.

相关文章