DUKPT使用Java实现的过程以及如何将十六进制字符串转换为DES密钥(ByteArray)

时间:2012-05-31 00:06:45

标签: java encryption tripledes

我正在尝试实现VISA DUKPT算法,以便从事务KSN生成每个事务的唯一密钥。我一步一步地遵循ANS X9.24-1:2009提供的信息,但我得到的IPEK与示例中提供的IPEK不同。 对于加密/解密/加密,我使用的是充气城堡API。 示例中提供的密钥(BDK)是0123456789ABCDEFFEDCBA9876543210 我知道这是一个双加密密钥长度意味着

  • key1(加密DES)= 0123456789ABCDEF
  • key2(解密DES)= FEDCBA9876543210
  • key3(加密DES)= key1 = 0123456789ABCDEF

我知道在使用DES时,您只能使用8字节密钥,因此16个十六进制字符串应转换为8字节数组。 (如果我在这里做某事,我有疑问。我从教程中得到这部分代码)

public byte[] hexStringToByteArray(String hexstring) {
        int i = 0;
        if (hexstring == null || hexstring.length() <= 0) {
            return null;
        }
        String stringvector = "0123456789ABCDEF";
        byte[] bytevector = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
                             0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F};
        byte[] out = new byte[hexstring.length() / 2];
        while (i < hexstring.length() - 1) {
            byte ch = 0x00;
            //Convert high nibble charater to a hex byte
            ch = (byte) (ch | bytevector[stringvector.indexOf(hexstring.charAt(i))]);
            ch = (byte) (ch << 4); //move this to the high bit

            //Convert the low nibble to a hexbyte
            ch = (byte) (ch | bytevector[stringvector.indexOf(hexstring.charAt(i + 1))]); //next hex value
            out[i / 2] = ch;
            i++;
            i++;
        }
        return out;
    } 

这是我唯一怀疑的部分(如何在Java中将十六进制字符串转换为DES密钥(ByteArray))。为了实现TripleDES,我正在使用充气城堡。

计算IPEK的过程说明如下:

从基础派生密钥(BDK)推导初始密钥(IPEK)。

初始PIN输入设备密钥(最初加载到PIN输入设备中的密钥)由以下过程生成:

  • 将整个密钥序列号(包括21位加密计数器)右对齐复制到10字节寄存器中。如果密钥序列号小于10个字节,则用十六进制“FF”字节填充到左侧。
  • 将此10字节寄存器的21个最低有效位设置为零。
  • 取这个10字节寄存器的8个最重要的字节,并使用双长度派生密钥加密/解密/加密这8个字节。 使用步骤3生成的密文作为初始密钥的左半部分。
  • 从步骤2的10字节寄存器中取8个最重要的字节,并使用与十六进制C0C0 C0C0 0000 0000 C0C0 C0C0 0000 0000异或的双长度导出密钥作为密钥对这8个字节进行加密/解密/加密。
  • 使用步骤5生成的密文作为Initial Key的右半部分。

我已逐字逐句地按照前面的解释来获得关键的左半部分

67450505DF3A84FF

根据标准的预期值是

6AC292FAA1315B4D

提供的KSN是9876543210E00000

在开始加密/解密/加密之前按照步骤1-3执行后,将要处理的文本为:FFFF9876543210E0

我的TripleDES实施是:

import java.io.UnsupportedEncodingException;
import java.security.*;
import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;

/**
 *
 * @author aealvarenga
 */
public class TripleDesCipherFromDES {

    public byte[] desEncryptionECBCipher(String key, String text) throws NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, InvalidKeyException, UnsupportedEncodingException, IllegalBlockSizeException, BadPaddingException {
        Security.addProvider(new BouncyCastleProvider());        
        SecretKey keySpec = new SecretKeySpec(this.hexStringToByteArray(key), "DES");
        final Cipher encrypter = Cipher.getInstance("DES/ECB/ZeroBytePadding", "BC");
        encrypter.init(Cipher.ENCRYPT_MODE, keySpec);
        final byte[] plainTextBytes = text.getBytes("utf-8");
        final byte[] cipherText = encrypter.doFinal(plainTextBytes);
        return cipherText;
    }

    public String desDecriptionECBCipher(String key, byte[] cipherText) throws NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, UnsupportedEncodingException, BadPaddingException {
        Security.addProvider(new BouncyCastleProvider());
        SecretKey keySpec = new SecretKeySpec(this.hexStringToByteArray(key), "DES");
        final Cipher decrypter = Cipher.getInstance("DES/ECB/ZeroBytePadding", "BC");        
        decrypter.init(Cipher.DECRYPT_MODE, keySpec);
        final byte[] plainText = decrypter.doFinal(cipherText);
        return new String(plainText, "UTF-8");
    }

    public byte[] desEncryptionCBCCipher(String key, String text) throws NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, InvalidKeyException, UnsupportedEncodingException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException {
        Security.addProvider(new BouncyCastleProvider());
        byte[] iv = new byte[]{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
        IvParameterSpec ivSpec = new IvParameterSpec(iv);


        SecretKey keySpec = new SecretKeySpec(this.hexStringToByteArray(key), "DES");
        final Cipher encrypter = Cipher.getInstance("DES/CBC/ZeroBytePadding", "BC");
        encrypter.init(Cipher.ENCRYPT_MODE, keySpec,ivSpec);
        final byte[] plainTextBytes = text.getBytes("utf-8");
        final byte[] cipherText = encrypter.doFinal(plainTextBytes);
        return cipherText;
    }    

    public String desDecriptionCBCCipher(String key, byte[] cipherText) throws NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, UnsupportedEncodingException, BadPaddingException, InvalidAlgorithmParameterException {
        Security.addProvider(new BouncyCastleProvider());
        byte[] iv = new byte[]{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
        IvParameterSpec ivSpec = new IvParameterSpec(iv);        
        SecretKey keySpec = new SecretKeySpec(this.hexStringToByteArray(key), "DES");
        final Cipher decrypter = Cipher.getInstance("DES/CBC/ZeroBytePadding", "BC");        
        decrypter.init(Cipher.DECRYPT_MODE, keySpec,ivSpec);
        final byte[] plainText = decrypter.doFinal(cipherText);
        return new String(plainText, "UTF-8");
    }

    public String asciiToHex(String ascii) {
        StringBuilder hex = new StringBuilder();
        for (int i = 0; i < ascii.length(); i++) {
            hex.append(Integer.toHexString(ascii.charAt(i)));
        }
        return hex.toString();
    }

    public byte[] hexStringToByteArray(String hexstring) {
        int i = 0;
        if (hexstring == null || hexstring.length() <= 0) {
            return null;
        }
        String stringvector = "0123456789ABCDEF";
        byte[] bytevector = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F};
        byte[] out = new byte[hexstring.length() / 2];
        while (i < hexstring.length() - 1) {
            byte ch = 0x00;
            //Convert high nibble charater to a hex byte
            ch = (byte) (ch | bytevector[stringvector.indexOf(hexstring.charAt(i))]);
            ch = (byte) (ch << 4); //move this to the high bit

            //Convert the low nibble to a hexbyte
            ch = (byte) (ch | bytevector[stringvector.indexOf(hexstring.charAt(i + 1))]); //next hex value
            out[i / 2] = ch;
            i++;
            i++;
        }
        return out;
    }    

    public String tdesedeECBCipher(String text, String doubleLenghtKey) throws NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, InvalidKeyException, UnsupportedEncodingException, IllegalBlockSizeException, BadPaddingException {
        //key definition
        String key1 = doubleLenghtKey.substring(0, 16);
        String key2 = doubleLenghtKey.substring(16, 32);
        String key3 = key1;

        byte[] codedText = new TripleDesCipherFromDES().desEncryptionECBCipher(key1, text);
        String decodedText = new TripleDesCipherFromDES().desDecriptionECBCipher(key2, codedText);
        byte[] codedTextFinal = new TripleDesCipherFromDES().desEncryptionECBCipher(key3, decodedText);

      return new String(Hex.encode(codedTextFinal));
    }

    public String tdesedeCBCCipher(String text, String doubleLenghtKey) throws NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, InvalidKeyException, UnsupportedEncodingException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException {
        //key definition
        String key1 = doubleLenghtKey.substring(0, 16);
        String key2 = doubleLenghtKey.substring(16, 32);
        String key3 = key1;

        byte[] codedText = new TripleDesCipherFromDES().desEncryptionCBCCipher(key1, text);
        String decodedText = new TripleDesCipherFromDES().desDecriptionCBCCipher(key2, codedText);
        byte[] codedTextFinal = new TripleDesCipherFromDES().desEncryptionCBCCipher(key3, decodedText);

       return new String(Hex.encode(codedTextFinal));
    }    

    public static void main(String[] args) throws Exception {
        String text = "FFFF9876543210E0";        
        String key =  "0123456789ABCDEFFEDCBA9876543210";

        System.out.println(new TripleDesCipherFromDES().tdesedeECBCipher(text,key));
        System.out.println(new TripleDesCipherFromDES().tdesedeCBCCipher(text,key));
    }
}

如您所见,我尝试使用ECB模式作为标准推荐,也尝试使用IV为00000000的CBC模式,但这两种方法似乎都不起作用。

我需要一个建议。

0 个答案:

没有答案