欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-06-15 16:42:17
...

.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;
	}
}