3DES 的加密算法

import java.security.Key;
import java.security.spec.KeySpec;
 
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
 
public class BcTest {
 
    // 3DES key = 00 01 02 03 04 05 06 07 01 02 03 04 05 06 07 08 02 03 04 05 06 07 08 09
    // data ("01234567") = 30 31 32 33 34 35 36 37
    // 3des cipher = 5a b3 fd 7b 2a ca b2 95
    // cipher mode = DESede/ECB/NoPadding
    public static void main(String[] args) throws Exception {
 
        byte[] key1 = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7 };
        byte[] key2 = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
        byte[] key3 = new byte[] { 2, 3, 4, 5, 6, 7, 8, 9 };
        byte[] data = "01234567".getBytes();  // 由于未采用填充模式,因此原文长度必须为 8 的倍数
 
        // 3DES ciphertext = EK3(DK2(EK1(plaintext)))
        byte[] crypt = encrypt(decrypt(encrypt(data, key1), key2), key3);
 
        // 3DES plaintext = DK1(EK2(DK3(ciphertext)))
        byte[] plain = decrypt(encrypt(decrypt(crypt, key3), key2), key1);
 
        System.out.println("  key: " + ByteUtil.bytes2HexSpace(key1) + " "
                + ByteUtil.bytes2HexSpace(key2) + " "
                + ByteUtil.bytes2HexSpace(key3));
        System.out.println(" data: " + ByteUtil.bytes2HexSpace(data));
        System.out.println("crypt: " + ByteUtil.bytes2HexSpace(crypt));
        System.out.println("plain: " + ByteUtil.bytes2HexSpace(plain));
    }
 
    public static byte[] decrypt(byte[] crypt, byte[] key) throws Exception {
        Key k = toKey(key);
        Cipher cipher = Cipher.getInstance("DES/ECB/NoPadding");
        cipher.init(Cipher.DECRYPT_MODE, k);
        return cipher.doFinal(crypt);
    }
 
    public static byte[] encrypt(byte[] data, byte[] key) throws Exception {
        Key k = toKey(key);
        Cipher cipher = Cipher.getInstance("DES/ECB/NoPadding");
        cipher.init(Cipher.ENCRYPT_MODE, k);
        return cipher.doFinal(data);
    }
 
    public static SecretKey toKey(byte[] key) throws Exception {
        KeySpec dks = new DESKeySpec(key);
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
        return keyFactory.generateSecret(dks);
    }
}
 
class ByteUtil {
 
    private static final char HEX[] = "0123456789abcdef".toCharArray();
 
    public static String bytes2HexSpace(byte bys[]) {
        char chs[] = new char[(bys.length * 2 + bys.length) - 1];
        int i = 0;
        int offset = 0;
        for (; i < bys.length; i++) {
            if (i > 0)
                chs[offset++] = ' ';
            chs[offset++] = HEX[bys[i] >> 4 & 15];
            chs[offset++] = HEX[bys[i] & 15];
        }
        return new String(chs);
    }
}
上面 DES 的加密模式采用 ECB,填充方式为不进行填充。

实际上 JCE 提供了 3DES 的加密算法,算法名为 DESede,并不需要自己通过 DES 去实现 3DES。只要把上面加密算法中有关 DES 改为 DESede,toKey 方法那个 KeySpec 的引用类由 DESKeySpec 改为 DESedeKeySpec 就可以了。

使用cipher可以很容易的实现3des加密,但是跟其他平台开发的3des加密对接来说,通常会有一些问题。基本的程序如下:

   public static byte[] desEncrypt(String message, String keythrows Exception {
        Cipher cipher 
= Cipher.getInstance("DESede");

        DESKeySpec desKeySpec 
= new DESKeySpec(key.getBytes("UTF-8"));
        SecretKeyFactory keyFactory 
= SecretKeyFactory.getInstance("DESede");
        SecretKey secretKey 
= keyFactory.generateSecret(desKeySpec);
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);

        
return cipher.doFinal(message.getBytes("UTF-8"));
    』

 

我们跟其他平台对接发现对同样输入加密以后结果不同,看看jdk的文档,有如下描述:

A transformation is a string that describes the operation (or set of operations) to be performed on the given input, to produce some output.

A transformation is of the form:

 

  • "algorithm/mode/padding" or

     

  • "algorithm"

(in the latter case, provider-specific default values for the mode and padding scheme are used).

根据前面的代码,我们已经选择了正确的算法,那么加密不同的原因应该就是mode和padding了。

he SunJCE provider uses ECB as the default mode, and PKCS5Padding as the default padding scheme for DES, DES-EDE and Blowfish ciphers. This means that in the case of the SunJCE provider,
    Cipher c1 = Cipher.getInstance("DES/ECB/PKCS5Padding");
and
    Cipher c1 = Cipher.getInstance("DES");
are equivalent statements.

对于其他语言开发的3des,一定要采用相同的mode和padding才能保证通信。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值