//这是调用的测试程序:
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";
/** *
方法描述:根据自己的密钥实现des加密
* * @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; } }/** *
方法描述:根据密钥解密
* * @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; } }/** *
方法描述:正式加密操作
* * @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; }
/** *
方法描述:不足8的倍数,后面追加空格
* * @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])); 这段是做什么的?
卧槽 可以的 大神大神 膜拜一下 谢了~
UTF-8
另外, 原代码中的pkcs5Pad的补码方式是不对的。 请参考 https://blog.csdn.net/stewart/article/details/52462273
不用楼上说的那么麻烦直接将这行代码
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 的整数倍。
厉害了 都是大神啊
引用来自“melon_jj”的评论
不用楼上说的那么麻烦直接将这行代码
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 的整数倍。
回复 @Jordan裔 : 需要交流学习的话可以加群826183079
回复 @Jordan裔 : 好吧
实在不好意思
我也想给你采纳 可是在你回答之前 我已经给楼上的哥们采纳过了 不能重复采纳了