参考
http://baike.baidu.com/view/350958.htm
http://blog.163.com/zhqh43@126/blog/static/4043302720093276344788/
背景
最近由于公司项目的需要,最近研究了3DES算法运用,我的公司有一个合作的公司,提供webservice接口,是C#写的,用到3DES加密算法,C#代码以下:
public static string Encrypt3DES(string a_strString, string a_strKey)
{
TripleDESCryptoServiceProvider DES = new TripleDESCryptoServiceProvider();
DES.Key = ASCIIEncoding.ASCII.GetBytes(a_strKey);
DES.Mode = CipherMode.ECB;
ICryptoTransform DESEncrypt = DES.CreateEncryptor();
byte[] Buffer = ASCIIEncoding.ASCII.GetBytes(a_strString);
return Convert.ToBase64String(DESEncrypt.TransformFinalBlock(Buffer, 0, Buffer.Length));
}
public static string Decrypt3DES(string a_strString, string a_strKey)
{
TripleDESCryptoServiceProvider DES = new TripleDESCryptoServiceProvider();
DES.Key = ASCIIEncoding.ASCII.GetBytes(a_strKey);
DES.Mode = CipherMode.ECB;
DES.Padding = System.Security.Cryptography.PaddingMode.PKCS7;
ICryptoTransform DESDecrypt = DES.CreateDecryptor();
string result = "";
try
{
byte[] Buffer = Convert.FromBase64String(a_strString);
result = ASCIIEncoding.ASCII.GetString(DESDecrypt.TransformFinalBlock(Buffer, 0, Buffer.Length));
}
catch (Exception e)
{
}
return result;
}
解法
直接使用公司框架中的3DES算法类,代码如下:
package com.cn.crypt.implement;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.Security;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
import org.apache.log4j.Logger;
/**
* <p>
* Title: 3DES加密算法实现
* </p>
*
* <p>
* Description: 3DES加密算法实现
* </p>
*
* <p>
* Copyright: Copyright (c) 2007
* </p>
*
* <p>
* Company: com.cn
* </p>
*
* @author LinPeng
* @version 1.0
*/
public class Crypto3DESImpl implements Crypto3DSModule {
/**
* logger 日志
*/
public static Logger logger = Logger.getLogger(Crypto3DESImpl.class);
/**
* 将byte数组转换为表示16进制值的字符串, 如:byte[]{8,18}转换为:0813, 和public static byte[]
* hexStr2ByteArr(String strIn) 互为可逆的转换过程
*
* @param arrB
* 需要转换的byte数组
* @return 转换后的字符串
* @throws Exception
* 本方法不处理任何异常,所有异常全部抛出
*/
private static String byteArr2HexStr(byte[] arrB) throws Exception {
int iLen = arrB.length;
// 每个byte用两个字符才能表示,所以字符串的长度是数组长度的两倍
StringBuffer sb = new StringBuffer(iLen * 2);
for (int i = 0; i < iLen; i++) {
int intTmp = arrB[i];
// 把负数转换为正数
while (intTmp < 0) {
intTmp = intTmp + 256;
}
// 小于0F的数需要在前面补0
if (intTmp < 16) {
sb.append("0");
}
sb.append(Integer.toString(intTmp, 16));
}
return sb.toString();
}
/**
* 将表示16进制值的字符串转换为byte数组, 和public static String byteArr2HexStr(byte[] arrB)
* 互为可逆的转换过程
*
* @param strIn
* 需要转换的字符串
* @return 转换后的byte数组
* @throws Exception
* 本方法不处理任何异常,所有异常全部抛出
* @author <a href="mailto:zhangji@aspire-tech.com">ZhangJi</a>
*/
private static byte[] hexStr2ByteArr(String strIn) throws Exception {
byte[] arrB = strIn.getBytes();
int iLen = arrB.length;
// 两个字符表示一个字节,所以字节数组长度是字符串长度除以2
byte[] arrOut = new byte[iLen / 2];
for (int i = 0; i < iLen; i = i + 2) {
String strTmp = new String(arrB, i, 2);
arrOut[i / 2] = (byte) Integer.parseInt(strTmp, 16);
}
return arrOut;
}
// 加密和解密函数的使用用法实例
public static void main(String[] args) throws Exception {
Crypto3DESImpl des = new Crypto3DESImpl();
// 设置算法
des.setDesAlgorithm("DES");
// 设置密钥
des.setKeyString("18947f2c467c4763fd2492cf");
String str = des.decrypt("8394bef13776eae45547cb484e075963f9a7e9542301f87a82ef9a4dcaf4b0c5e1bcc66c34ecabf1b8d8012a7357c85271ae3ca2a19887cb6228677a84acd22ae3aa4a230a30f91557fa8677fe6c8edb81cf8e93f3128cb841a3b863f0a790bfc9bbc8c6c5979df32ca3f7fb1ffff1ad0e30bf8bf14c1a778808d82064de6b85d46eb3c1c0b8465e124eb113e5d56e519aa7e92819993ac9");
logger.debug(str);
}
/**
* 3desAlgorithm 3des加密算法,可用 DES,DESede,Blowfish
*/
public String desAlgorithm;
/**
* keyString 加密密钥
*/
String keyString;
public Crypto3DESImpl() {
Security.addProvider(new com.sun.crypto.provider.SunJCE());
}
/**
* decrypt 3DES单参数解密函数
*
* @param src
* byte[]
* @return byte[]
* @throws Exception
*/
private byte[] decrypt(byte[] src) throws Exception {
byte[] keybyte = keyString.getBytes();
// 生成密钥
Key deskey = getKey(keybyte);
Cipher decryptCipher = Cipher.getInstance(desAlgorithm);
decryptCipher.init(Cipher.DECRYPT_MODE, deskey);
return decryptCipher.doFinal(src);
}
/**
* decrypt 3DES单参数解密函数
*
* @param src
* String
* @return String
* @throws Exception
*/
public String decrypt(String src) throws Exception {
byte[] srcBytes = Crypto3DESImpl.hexStr2ByteArr(src);
return new String(this.decrypt(srcBytes));
}
/**
* encrypt 3DES单参数加密函数
*
* @param src
* byte[] 输入字符数组
* @return byte[] 返回字符数组
* @throws NoSuchPaddingException
* @throws NoSuchAlgorithmException
* @throws InvalidKeyException
* @throws BadPaddingException
* @throws IllegalBlockSizeException
* @throws Exception
*/
public byte[] encrypt(byte[] src) throws NoSuchPaddingException,
NoSuchAlgorithmException, InvalidKeyException, BadPaddingException,
IllegalBlockSizeException, Exception {
byte[] keybyte = keyString.getBytes();
// 生成密钥
Key deskey = getKey(keybyte);
// 加密
Cipher c1 = Cipher.getInstance(desAlgorithm);
c1.init(Cipher.ENCRYPT_MODE, deskey);
return c1.doFinal(src);
}
/**
* encrypt 3DES单参数加密函数
*
* @param src
* String
* @return String
* @throws Exception
*/
public String encrypt(String src) throws Exception {
byte[] srcBytes = src.getBytes();
return Crypto3DESImpl.byteArr2HexStr(this.encrypt(srcBytes));
}
public String getDesAlgorithm() {
return desAlgorithm;
}
/**
* 从指定字符串生成密钥,密钥所需的字节数组长度为8位 不足8位时后面补0,超出8位只取前8位
*
* @param arrBTmp
* 构成该字符串的字节数组
* @return 生成的密钥
* @throws Exception
*/
private Key getKey(byte[] arrBTmp) throws Exception {
// 创建一个空的8位字节数组(默认值为0)
byte[] arrB = new byte[8];
// 将原始字节数组转换为8位
for (int i = 0; i < arrBTmp.length && i < arrB.length; i++) {
arrB[i] = arrBTmp[i];
}
// 生成密钥
Key key = new SecretKeySpec(arrB, desAlgorithm);
return key;
}
public String getKeyString() {
return keyString;
}
public void setDesAlgorithm(String desAlgorithm) {
this.desAlgorithm = desAlgorithm;
}
public void setKeyString(String keyString) {
this.keyString = keyString;
}
}
测试之后发现,C#加密与解密完全与上面的java代码3DES结果不一样,不知道怎么回事,难道是我们框架代码有问题,那我就开始在网上搜索3DES相关例子,发现3DES还有两个重要参数:模式与填充方式,又仔细看了看C#代码中提到了ECB与PKCS7,正是3DES重要参数,但我还是不会写,又在网上找,代码如下:
package com.cn.crypt.implement;
import java.net.URLEncoder;
import java.security.Security;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import com.cn.crypt.IDESecbpkcs7;
/**
* @author 刘宗安
* @version 1.0 功能 :釆用3DES标准以模式为ECB、填充方式为PKCS7加密数据
*/
public class DESecbpkcs7Impl implements IDESecbpkcs7
{
private Cipher cipher = null;
// base64编码
private BASE64Encoder base64Encode = new BASE64Encoder();
private BASE64Decoder base64Decode = new BASE64Decoder();
// 密钥
private String key = "";
// 过滤换行
private boolean filter = true;
public String getKey()
{
return key;
}
public boolean getFilter()
{
return filter;
}
/**
* 设置密钥
* @param key
*/
public void setKey(String key)
{
this.key = key;
}
public void setFilter(boolean filter)
{
this.filter = filter;
}
private final Cipher initCipher(int mode)
{
try
{
// 添加新安全算法:PKCS7
Security.addProvider(new BouncyCastleProvider());
String algorithm = "DESede/ECB/PKCS7Padding";
SecretKey desKey = new SecretKeySpec((new BASE64Decoder()).decodeBuffer(key), algorithm);
//SecretKey desKey = new SecretKeySpec(key.getBytes("ASCII"), algorithm);
Cipher tcipher = Cipher.getInstance(algorithm);
tcipher.init(mode, desKey);
return tcipher;
} catch (Exception e)
{
e.printStackTrace();
}
return null;
}
/**
* 加密以charset编码做为密文
*
* @param src
* 明文
* @param charset
* 编码,例:UTF8、BASE64
* @return
*/
public String encrypt(String src, String charset)
{
try
{
return URLEncoder.encode(encrypt(src), charset);
} catch (Exception e)
{
e.printStackTrace();
}
return null;
}
/**
* 解密
* @param src 二进制数组
* @return
* @throws Exception
*/
private byte[] decrypt(byte[] src) throws Exception
{
cipher = initCipher(Cipher.DECRYPT_MODE);
return cipher.doFinal(src);
}
/**
* 解密
* @param src 密文
* @return
* @throws Exception
*/
public String decrypt(String src) throws Exception
{
byte[] bt=base64Decode.decodeBuffer(src);
byte[] sbt=decrypt(bt);
return new String(sbt,"ASCII");
}
/**
* 加密以base64做为密文
*
* @param src
* 明文
* @return 密文
*/
public String encrypt(String src)
{
cipher = initCipher(Cipher.ENCRYPT_MODE);
byte[] dd = encrypt(src.getBytes());
String str = base64Encode.encode(dd);
str = str.replaceAll("\r", "");
str = str.replaceAll("\n", "");
return str;
}
/**
*
* @param src
* @return
*/
public byte[] encrypt(byte[] src)
{
try
{
return cipher.doFinal(src);
} catch (Exception e)
{
e.printStackTrace();
}
return null;
}
public static void main(String[] args) throws Exception
{
DESecbpkcs7Impl cWebService3DES = new DESecbpkcs7Impl();
Security.addProvider(new com.sun.crypto.provider.SunJCE());
cWebService3DES.key = "18947f2c467c4763fd2492cf".toUpperCase();
System.out.println("18947f2c467c4763fd2492cf".toUpperCase());
String s = cWebService3DES
.encrypt("<?xml version=\"1.0\" encoding=\"utf-8\" ?><SXData><UserID>bjtele-union</UserID><EnCode>9289a37b0f5cb18abb5aa4d33e85afe9</EnCode></SXData>");
s = s.replaceAll("\r", "");
s = s.replaceAll("\n", "");
System.out.println(s);
System.out.println(cWebService3DES.decrypt(s));
}
}
测试之后,发现与C#还是不一样,这下我可晕,不知道从哪里修改好?哎,真不知道从何下手了,又继续找原因,后来发现上面C#代码中存在这一段代码:
DES.Key = ASCIIEncoding.ASCII.GetBytes(a_strKey);
呵呵,将以前的BASE64编码代码
SecretKey desKey = new SecretKeySpec((new BASE64Decoder()).decodeBuffer(key), algorithm);
修改java代码KEY为ASCII:
SecretKey desKey = new SecretKeySpec(key.getBytes("ASCII"), algorithm);
这一下终于调试成功了,最后还要提醒一下将加密后的二进制数组以base64编码进行显示,代码如下:
String str = base64Encode.encode(dd);
OK
分享到:
相关推荐
北京联通全网有关网上订购和点播接口URL加密算法 * *采用3DES加密, ECB模式/使用PKCS7方式填充不足位, *目前给的密钥是192位(24个字节)经过BASE64编码后的可见字符串
3DES加密算法,使用openssl库,ECB算法,pkcs7padding填充模式(借鉴网上的算法,并经过自己的改良,可以实现加密与解密)
根据原"与JAVA的关于DES/CBC/PKCS5Padding 互相解密" 代码修改,解决中文乱码问题。与在线加密网站结果一致
分享一个php对称加密算法DES和AES类,支持密钥:64/128/256 bit(字节长度8/16/32),支持算法:DES/AES(根据密钥长度自动匹配使用:DES:64bit AES:128/256bit),支持模式:CBC/ECB/OFB/CFB,密文编码:base64字符...
实现了AES/ECB/PKCS5Padding、AES/CBC/PKCS5Padding 密钥长度128/192/256bit,密钥0填充。是标准的AES算法,支持在线AES加解密网站互解。 本源码从CSDN一位前辈的源码基础上做了更改,增加支持加密返回BASE64,更加...
}常用对称加密算法类支持密钥:64/128/256 bit(字节长度8/16/32)支持算法:DES/AES(根据密钥长度自动匹配使用:DES:64bit AES:128/256bit)支持模式:CBC/ECB/OFB/CFB密文编码:base64字符串/十六进制字符串/二...
常用的填充方式有PKCS5Padding、PKCS7Padding、zeropadding CBC模式比ECB模式安全,ECB模式比CBC模式快。 推荐使用CBC模式。 相同密码的加密结果不会变化,是固定的。 这个标准用来替代原先的DES key的字节长度只能...
基于openssl静态库的DES+base64+MD5的加解密C++Demo,其中DES采用ECB模式,pkcs5padding的填充方法;兼容JAVA,C#的DES,可应用于与网络服务器通信过程中的加解密,并且已经验证OK。 与C#/java互通的DES加密解密代码。
一、简介 1.aes加密简单来说,在密码学中又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES,...3.在这里我们只接受常用的ECB方式 + pkcs7padding(与pkcs5padding值相同)填充
E.3. 加密算法 171 E.3.1. CBC 171 E.3.2. 消息的完整性ICV在显式安全通道初始化中的使用 171 E.3.3. 消息的完整性ICV在隐式安全通道初始化中的使用 172 E.3.4. ICV的加密 172 E.4. 加密用法 172 E.4.1. DES会话密钥...