代码如下:
public class Test { @org.junit.Test public void test(){ //加密内容 String source = "加密加密加12abc"; //加密密钥 String key = "chiscdc_fsws_@%^"; String encrypt = EncryptUtil.encryptByKey(source,key); System.out.println("加密后:"+encrypt); String decrypt = EncryptUtil.decryptByKey(encrypt,key); System.out.println("解密后:"+decrypt); } }
public class EncryptUtil { /** * 密钥算法 */ private static final String ALGORITHM = "DES"; /** * 加解密算法/工作模式/填充方式 */ private static final String ALGORITHM_STR = "DES/ECB/NoPadding"; private static final String CHARSET = "UTF-8"; /** * 填充内容 */ private static final String PAD_STR = "\0"; /** * <p>方法描述:根据自己的密钥实现des加密</p> * * @MethodAuthor yzd, 2018/7/23,encryptByKey * */ public static String encryptByKey(String souce,String key) { try { return encryptByDes(pkcs5Pad(souce), pkcs5Pad(key)); } catch (Exception e) { e.printStackTrace(); return null; } } /** * <p>方法描述:根据密钥解密</p> * * @MethodAuthor yzd, 2018/7/23,decryptByKey * */ public static String decryptByKey(String souce,String key) { try { return decryptByDes(souce, pkcs5Pad(key)).trim(); } catch (Exception e) { e.printStackTrace(); return null; } } /** * <p>方法描述:正式加密操作</p> * * @MethodAuthor yzd, 2018/7/23,decryptByKey * */ private static String encryptByDes( String souce, String key) throws Exception { // DES算法要求有一个可信任的随机数源 SecureRandom sr = new SecureRandom(); // 从原始密匙数据创建DESKeySpec对象 DESKeySpec dks = new DESKeySpec(key.getBytes(CHARSET)); // 创建一个密匙工厂,然后用它把DESKeySpec转换成 一个SecretKey对象 SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM); SecretKey key1 = keyFactory.generateSecret(dks); // Cipher对象实际完成加密操作 Cipher cipher = Cipher.getInstance(ALGORITHM_STR); // 用密匙初始化Cipher对象 cipher.init(Cipher.ENCRYPT_MODE, key1, sr); // 现在,获取数据并加密 byte encryptedData[] = cipher.doFinal(souce.getBytes(CHARSET)); return byteArr2HexStr(encryptedData); } public static String byteArr2HexStr(byte[] arrB) { 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(); } private static String decryptByDes(String souce, String key) throws Exception { // DES算法要求有一个可信任的随机数源 SecureRandom sr = new SecureRandom(); // 从原始密匙数据创建DESKeySpec对象 DESKeySpec dks = new DESKeySpec(key.getBytes(CHARSET)); // 创建一个密匙工厂,然后用它把DESKeySpec转换成 一个SecretKey对象 SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM); SecretKey key1 = keyFactory.generateSecret(dks); // Cipher对象实际完成加密操作 Cipher cipher = Cipher.getInstance(ALGORITHM_STR); // 用密匙初始化Cipher对象 cipher.init(Cipher.DECRYPT_MODE, key1, sr); // 将加密报文用BASE64算法转化为字节数组 byte[] encryptedData = hexStr2ByteArr(souce); // 用DES算法解密报文 byte decryptedData[] = cipher.doFinal(encryptedData); return new String(decryptedData, CHARSET); } public 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; } /** * <p>方法描述:不足8的倍数,后面追加空格</p> * * @MethodAuthor yzd, 2018/7/27,pkcs5Pad * */ private static String pkcs5Pad(final String souce) { // 密文和密钥的长度必须是8的倍数 if (0 == souce.length() % 8) { return souce; } StringBuffer tmp = new StringBuffer(souce); while (0 != tmp.length() % 8) { tmp.append(PAD_STR); } return tmp.toString(); } }
运行后结果:
<p>//这是调用的测试程序:</p>
public static void test(){
//加密内容
String source = "加密加密加12abc";
//加密密钥
String key = "chiscdc_fsws_@%^";
String encrypt = EncryptUtil.encryptByKey(source,key);
System.out.println("加密后:"+encrypt);
String decrypt = EncryptUtil.decryptByKey(encrypt,key);
System.out.println("解密后:"+decrypt);
}
//这是 EncryptUtil :
import java.io.UnsupportedEncodingException;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.xml.transform.Source;
public class EncryptUtil {
/**
* 密钥算法
*/
private static final String ALGORITHM = "DES";
/**
* 加解密算法/工作模式/填充方式
*/
private static final String ALGORITHM_STR = "DES/ECB/NoPadding";
private static final String CHARSET = "UTF-8";
/**
* 填充内容
*/
private static final String PAD_STR = "\0";
/**
* <p>方法描述:根据自己的密钥实现des加密</p>
*
* @MethodAuthor yzd, 2018/7/23,encryptByKey
*
*/
public static String encryptByKey(String souce, String key) {
try {
return encryptByDes(pkcs5Pad(souce), pkcs5Pad(key));
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* <p>方法描述:根据密钥解密</p>
*
* @MethodAuthor yzd, 2018/7/23,decryptByKey
*
*/
public static String decryptByKey(String souceString,String key) {
try {
byte [] source = hexStringToBytes(souceString);
return decryptByDes(source, pkcs5Pad(key)).trim();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* <p>方法描述:正式加密操作</p>
*
* @MethodAuthor yzd, 2018/7/23,decryptByKey
*
*/
private static String encryptByDes( byte[] souce, byte[] bs)
throws Exception {
// DES算法要求有一个可信任的随机数源
SecureRandom sr = new SecureRandom();
// 从原始密匙数据创建DESKeySpec对象
DESKeySpec dks = new DESKeySpec(bs);
// 创建一个密匙工厂,然后用它把DESKeySpec转换成 一个SecretKey对象
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
SecretKey key1 = keyFactory.generateSecret(dks);
// Cipher对象实际完成加密操作
Cipher cipher = Cipher.getInstance(ALGORITHM_STR);
// 用密匙初始化Cipher对象
cipher.init(Cipher.ENCRYPT_MODE, key1, sr);
// 现在,获取数据并加密
byte encryptedData[] = cipher.doFinal(souce);
return byteArr2HexStr(encryptedData);
}
public static String byteArr2HexStr(byte[] arrB) {
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();
}
public static byte[] hexStringToBytes(String hexString) {
if (hexString == null) {
return null;
}
if (hexString.length() <= 0){
return new byte[0];
}
hexString = hexString.toUpperCase();
int length = hexString.length() / 2;
char[] hexChars = hexString.toCharArray();
byte[] result = new byte[length];
for (int i = 0; i < length; i++) {
int step = i * 2;
result[i] = (byte) (charToByte(hexChars[step]) << 4 | charToByte(hexChars[step + 1]));
}
return result;
}
private static final String HEX_STRING_MAPPING = "0123456789ABCDEF";
private static byte charToByte(char c) {
return (byte) HEX_STRING_MAPPING.indexOf(c);
}
private static String decryptByDes(byte[] souce, byte[] bs)
throws Exception {
// DES算法要求有一个可信任的随机数源
SecureRandom sr = new SecureRandom();
// 从原始密匙数据创建DESKeySpec对象
DESKeySpec dks = new DESKeySpec(bs);
// 创建一个密匙工厂,然后用它把DESKeySpec转换成 一个SecretKey对象
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
SecretKey key1 = keyFactory.generateSecret(dks);
// Cipher对象实际完成加密操作
Cipher cipher = Cipher.getInstance(ALGORITHM_STR);
// 用密匙初始化Cipher对象
cipher.init(Cipher.DECRYPT_MODE, key1, sr);
// 将加密报文用BASE64算法转化为字节数组
byte[] encryptedData =souce;
// 用DES算法解密报文
byte decryptedData[] = cipher.doFinal(encryptedData);
return new String(decryptedData, CHARSET);
}
public static byte[] hexStr2ByteArr(byte[] byIn) throws Exception {
byte[] arrB = byIn;
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;
}
/**
* <p>方法描述:不足8的倍数,后面追加空格</p>
*
* @MethodAuthor yzd, 2018/7/27,pkcs5Pad
*
*/
private static byte[] pkcs5Pad(final String inSouce) {
byte[] bySource = new byte[0];
try {
bySource = inSouce.getBytes(CHARSET);
// 密文和密钥的长度必须是8的倍数
if (0 == bySource.length % 8) {
return bySource;
}
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
int length = bySource.length;
int nPaddedLength = (length / 8 + 1) * 8;
byte[] byReturn = new byte[nPaddedLength];
System.arraycopy(bySource, 0, byReturn, 0, length);
int i = length;
while (i < nPaddedLength) {
byReturn[i] = (byte) (nPaddedLength - length);
i++;
}
return byReturn;
}
}
原因在于: 输入的原文必须是BYTE数据,汉字的话,使用UTF-8获取其BYTE值。
DES加密时,是需要按分组长度为8字节补齐的。
大神 小弟不才 请问 result[i] = (byte) (charToByte(hexChars[step]) << 4 | charToByte(hexChars[step + 1])); 这段是做什么的?
卧槽 可以的 大神大神 膜拜一下 谢了~
<p>UTF-8</p>
<p>另外, 原代码中的pkcs5Pad的补码方式是不对的。 请参考 https://blog.csdn.net/stewart/article/details/52462273</p>
<p>不用楼上说的那么麻烦直接将这行代码</p>
private static final String ALGORITHM_STR = "DES/ECB/NoPadding"
改为
public static final String CIPHER_ALGORITHM = "DES/ECB/PKCS5Padding ";
即可
错误原因:
DES、AES 或者 3DES 属于块加密算法,一般来说原文必须是 8 的整数倍,所以块加密算法除子加密模式之外,还涉及到一个填充模式。 如果一定要用 NoPadding 的话,那么必须保证原文字节是 8 的倍数,否则的话需要使用其他的填充模式。 在 Sun JCE 中默认的填充模式除了 NoPadding 之外,还有: PKCS5Padding 和 ISO10126Padding PKCS5Padding 的填充规则是: 填充至符合块大小的整数倍,填充值为填充数量数。例如: 原始:FF FF FF FF FF FF FF FF FF 填充:FF FF FF FF FF FF FF FF FF 07 07 07 07 07 07 07 ISO10126Padding 的填充规则是: 填充至符合块大小的整数倍,填充值最后一个字节为填充的数量数,其他字节随机处理。例如: 原始:FF FF FF FF FF FF FF FF FF 填充:FF FF FF FF FF FF FF FF FF 3F 7A B4 09 14 36 07 使用填充模式后原文字节并不需要是 8 的整数倍,采用填充模式之后,块加密的密文长度为: (N / 8 * 8) + 8 如上,假如原文长度为 15 个字节,密文长度就是 16 个字节。假如原文长度为 16 个字节,密文长度就为 24 个字节。也就是说,采用填充模式后必须进行填充,哪怕是 8 的整数倍。
厉害了 都是大神啊
<div class='ref'><h4>引用来自“melon_jj”的评论</h4><p>不用楼上说的那么麻烦直接将这行代码</p>
private static final String ALGORITHM_STR = "DES/ECB/NoPadding"
改为
public static final String CIPHER_ALGORITHM = "DES/ECB/PKCS5Padding ";
即可
错误原因:
DES、AES 或者 3DES 属于块加密算法,一般来说原文必须是 8 的整数倍,所以块加密算法除子加密模式之外,还涉及到一个填充模式。 如果一定要用 NoPadding 的话,那么必须保证原文字节是 8 的倍数,否则的话需要使用其他的填充模式。 在 Sun JCE 中默认的填充模式除了 NoPadding 之外,还有: PKCS5Padding 和 ISO10126Padding PKCS5Padding 的填充规则是: 填充至符合块大小的整数倍,填充值为填充数量数。例如: 原始:FF FF FF FF FF FF FF FF FF 填充:FF FF FF FF FF FF FF FF FF 07 07 07 07 07 07 07 ISO10126Padding 的填充规则是: 填充至符合块大小的整数倍,填充值最后一个字节为填充的数量数,其他字节随机处理。例如: 原始:FF FF FF FF FF FF FF FF FF 填充:FF FF FF FF FF FF FF FF FF 3F 7A B4 09 14 36 07 使用填充模式后原文字节并不需要是 8 的整数倍,采用填充模式之后,块加密的密文长度为: (N / 8 * 8) + 8 如上,假如原文长度为 15 个字节,密文长度就是 16 个字节。假如原文长度为 16 个字节,密文长度就为 24 个字节。也就是说,采用填充模式后必须进行填充,哪怕是 8 的整数倍。
回复 <a class="referer" target="_blank">@Jordan裔</a> : 需要交流学习的话可以加群826183079
回复 <a class="referer" target="_blank">@Jordan裔</a> : 好吧
实在不好意思
我也想给你采纳 可是在你回答之前 我已经给楼上的哥们采纳过了 不能重复采纳了
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。