Java实现与.net对应的3DES加密解密

阅读更多

.net的3DES加密解密代码:

public static string TripleDESDecrypt(string pToDecrypt, string sKey)
        {
            TripleDESCryptoServiceProvider des = new TripleDESCryptoServiceProvider();
            des.Mode = CipherMode.ECB;
            des.Padding = PaddingMode.Zeros;
            byte[] inputByteArray = new byte[pToDecrypt.Length / 2]; // pToDecrypt.Length / 2 = 8
            for (int x = 0; x < pToDecrypt.Length / 2; x++) // pToDecrypt.Length = 16
            {
                string s = pToDecrypt.Substring(x * 2, 2);
                int i = (Convert.ToInt32(s, 16));
                inputByteArray[x] = (byte)i;
            }

            des.Key = ASCIIEncoding.ASCII.GetBytes(sKey); // {byte[24]}
            MemoryStream ms = new MemoryStream();
            CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write);
            cs.Write(inputByteArray, 0, inputByteArray.Length);
            cs.FlushFinalBlock();
            StringBuilder ret = new StringBuilder();
            return System.Text.Encoding.Default.GetString(ms.ToArray());
        }

        public static string TripleDESEncrypt(string pToEncrypt, string sKey)   // 加密
        {
            try {
                TripleDESCryptoServiceProvider des = new TripleDESCryptoServiceProvider();
                des.Key = ASCIIEncoding.ASCII.GetBytes(sKey);
                des.Mode = CipherMode.ECB;
                des.Padding = PaddingMode.Zeros;
                MemoryStream ms = new MemoryStream();
                CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write);
                byte[] inputByteArray = Encoding.Default.GetBytes(pToEncrypt);
                cs.Write(inputByteArray, 0, inputByteArray.Length);
                cs.FlushFinalBlock(); ;
                StringBuilder ret = new StringBuilder();
                foreach (byte b in ms.ToArray()) {
                    ret.AppendFormat("{0:X2}", b);
                }
                ret.ToString();
                return ret.ToString();
            } catch (Exception ex) {
                return ex.Message;
            }
        } 

 

现在把上面的代码用java实现,要求加解密后的内容与.net一致.

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

   public static byte[] desEncrypt(String message, String key) throws 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的文档,有如下描述:

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"

根据前面的代码,我们已经选择了正确的算法,那么加密不同的原因应该就是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才能保证通信。

Appendix A of this document contains a list of standard names that can be used to specify the algorithm name, mode, and padding scheme components of a transformation.(Appendix A 此链接规定了java加密算法的 名称/加密运算模式/填充模式,可参考.)

 

从上面.net的代码可以看出,

des.Key = ASCIIEncoding.ASCII.GetBytes(sKey); // 加密密匙
des.Mode = CipherMode.ECB; // 运算模式
des.Padding = PaddingMode.Zeros; //填充模式

 

因此,对应的java代码应该为:

Security.addProvider(new com.sun.crypto.provider.SunJCE());
SecretKey desKey = new SecretKeySpec("your key".getBytes("utf-8"), ALGORITHM_KEY);
Cipher tcipher = Cipher.getInstance("DESede/ECB/NoPadding");
tcipher.init(Cipher.DECRYPT_MODE, desKey);

 

完整的代码如下:

import java.io.UnsupportedEncodingException;
import java.security.Security;
import java.util.Properties;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

public class TripleDesUtils {
	private static final String ALGORITHM_KEY = "DESede";
	private static final String ALGORITHM_CIPHER_INIT = "DESede/ECB/NoPadding";

	/**
	 * 字节数组转化为大写16进制字符串
	 *
	 * @param b
	 * @return
	 */
	private static String byte2Hex(byte[] b) {
		String hs = "";
		String stmp = "";
		for (int n = 0; n < b.length; n++) {
			stmp = (java.lang.Integer.toHexString(b[n] & 0XFF));
			if (stmp.length() == 1) {
				hs = hs + "0" + stmp;
			} else {
				hs = hs + stmp;
			}
		}
		return hs.toUpperCase();
	}

	public static void main(String[] args) throws Exception {
		Properties pro = PropertiesUtils.getProperties("3des.properties");
		String algorithm_key = pro.getProperty("3des_algorithm_key");
		TripleDesUtils t = new TripleDesUtils();
		t.key = algorithm_key;

		System.out.println("加密后的:" + t.encrypt_ECB("2014-5-7"));
		System.out.println("解密后的:" + t.decrypt_ECB("50E09194AB312A08").trim());
	}


	/**
	 * 字符串转字节数组
	 *
	 * @param s
	 * @return
	 */
	private static byte[] str2ByteArray(String s) {
		int byteArrayLength = s.length() / 2;
		byte[] b = new byte[byteArrayLength];
		for (int i = 0; i < byteArrayLength; i++) {
			byte b0 = (byte) Integer.valueOf(s.substring(i * 2, i * 2 + 2), 16).intValue();
			b[i] = b0;
		}
		return b;
	}

	private Cipher cipher = null;

	// 密钥
	private String key = "";

	private byte[] decrypt_ECB(byte[] src) {
			cipher = initCipher(Cipher.DECRYPT_MODE);
			try {
				return cipher.doFinal(src);
			} catch (IllegalBlockSizeException e) {
				e.printStackTrace();
			} catch (BadPaddingException e) {
				e.printStackTrace();
			}
			return null;
	}

	public String decrypt_ECB(String src) {
		byte[] b = decrypt_ECB(str2ByteArray(src));
		return new String(b);
	}

	private byte[] encrypt_ECB(byte[] src) {
		try {
			cipher = initCipher(Cipher.ENCRYPT_MODE);
			return cipher.doFinal(src);
		} catch (IllegalBlockSizeException e) {
			e.printStackTrace();
		} catch (BadPaddingException e) {
			e.printStackTrace();
		}
		return null;
	}

	public String encrypt_ECB(String src) {
		byte[] b;
		try {
			b = encrypt_ECB(src.getBytes("utf-8"));
			return byte2Hex(b);
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return null;
	}

	public String getKey() {
		return key;
	}

	private final Cipher initCipher(int mode) {
		try {
			Security.addProvider(new com.sun.crypto.provider.SunJCE());
//			Security.addProvider(new BouncyCastleProvider());
			SecretKey desKey = new SecretKeySpec(key.getBytes("utf-8"), ALGORITHM_KEY);
			Cipher tcipher = Cipher.getInstance(ALGORITHM_CIPHER_INIT);
			tcipher.init(mode, desKey);
			return tcipher;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	public void setKey(String key) {
		this.key = key;
	}
}

 

你可能感兴趣的:(3des,des,加密,解密)