.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的文档,有如下描述:
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"
根据前面的代码,我们已经选择了正确的算法,那么加密不同的原因应该就是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; } }