没有根基也许可以建一座小屋,但绝对不能造一座坚固的大厦。
private final static String DES = "DES";
public static void main(String[] args) throws Exception {
String data = "123 456";
String key = "wang!@#$";
System.err.println(encrypt(data, key));
System.err.println(decrypt(encrypt(data, key), key));
}
/**
* Description 根据键值进行加密
* @param data
* @param key 加密键byte数组
* @return
* @throws Exception
*/
public static String encrypt(String data, String key) throws Exception {
byte[] bt = encrypt(data.getBytes(), key.getBytes());
String strs = new BASE64Encoder().encode(bt);
return strs;
}
/**
* Description 根据键值进行解密
* @param data
* @param key 加密键byte数组
* @return
* @throws IOException
* @throws Exception
*/
public static String decrypt(String data, String key) throws IOException,
Exception {
if (data == null)
return null;
BASE64Decoder decoder = new BASE64Decoder();
byte[] buf = decoder.decodeBuffer(data);
byte[] bt = decrypt(buf,key.getBytes());
return new String(bt);
}
/**
* Description 根据键值进行加密
* @param data
* @param key 加密键byte数组
* @return
* @throws Exception
*/
private static byte[] encrypt(byte[] data, byte[] key) throws Exception {
// 生成一个可信任的随机数源
SecureRandom sr = new SecureRandom();
// 从原始密钥数据创建DESKeySpec对象
DESKeySpec dks = new DESKeySpec(key);
// 创建一个密钥工厂,然后用它把DESKeySpec转换成SecretKey对象
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES);
SecretKey securekey = keyFactory.generateSecret(dks);
// Cipher对象实际完成加密操作
Cipher cipher = Cipher.getInstance(DES);
// 用密钥初始化Cipher对象
cipher.init(Cipher.ENCRYPT_MODE, securekey, sr);
return cipher.doFinal(data);
}
/**
* Description 根据键值进行解密
* @param data
* @param key 加密键byte数组
* @return
* @throws Exception
*/
private static byte[] decrypt(byte[] data, byte[] key) throws Exception {
// 生成一个可信任的随机数源
SecureRandom sr = new SecureRandom();
// 从原始密钥数据创建DESKeySpec对象
DESKeySpec dks = new DESKeySpec(key);
// 创建一个密钥工厂,然后用它把DESKeySpec转换成SecretKey对象
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES);
SecretKey securekey = keyFactory.generateSecret(dks);
// Cipher对象实际完成解密操作
Cipher cipher = Cipher.getInstance(DES);
// 用密钥初始化Cipher对象
cipher.init(Cipher.DECRYPT_MODE, securekey, sr);
return cipher.doFinal(data);
}
5fiw/XhRJ0E=
123 456
DESKeySpec
类的时候有下面一段,其中var1是我们传的秘钥。可以看到他进行了截取。只截取前八个字节。public DESKeySpec(byte[] var1, int var2) throws InvalidKeyException {
if (var1.length - var2 < 8) {
throw new InvalidKeyException("Wrong key size");
} else {
this.key = new byte[8];
System.arraycopy(var1, var2, this.key, 0, 8);
}
}
3.2.2 AES
AES加密算法是密码学中的高级加密标准,该加密算法采用对称分组密码体制,密钥长度的最少支持为128、192、256,分组长度128位,算法应易于各种硬件和软件实现。这种加密算法是美国联邦政府采用的区块加密标准,AES标准用来替代原先的DES,已经被多方分析且广为全世界所使用。
Cipher
类的时候有几个注意点:public static void main(String[] args) throws Exception {
/*
* 此处使用AES-128-ECB加密模式,key需要为16位。
*/
String cKey = "1234567890123456";
// 需要加密的字串
String cSrc = "buxuewushu";
System.out.println(cSrc);
// 加密
String enString = Encrypt(cSrc, cKey);
System.out.println("加密后的字串是:" + enString);
// 解密
String DeString = Decrypt(enString, cKey);
System.out.println("解密后的字串是:" + DeString);
}
// 加密
public static String Encrypt(String sSrc, String sKey) throws Exception {
if (sKey == null) {
System.out.print("Key为空null");
return null;
}
// 判断Key是否为16位
if (sKey.length() != 16) {
System.out.print("Key长度不是16位");
return null;
}
byte[] raw = sKey.getBytes("utf-8");
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");//"算法/模式/补码方式"
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted = cipher.doFinal(sSrc.getBytes("utf-8"));
return new Base64().encodeToString(encrypted);//此处使用BASE64做转码功能,同时能起到2次加密的作用。
}
// 解密
public static String Decrypt(String sSrc, String sKey) throws Exception {
try {
// 判断Key是否正确
if (sKey == null) {
System.out.print("Key为空null");
return null;
}
// 判断Key是否为16位
if (sKey.length() != 16) {
System.out.print("Key长度不是16位");
return null;
}
byte[] raw = sKey.getBytes("utf-8");
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] encrypted1 = new Base64().decode(sSrc);//先用base64解密
try {
byte[] original = cipher.doFinal(encrypted1);
String originalString = new String(original,"utf-8");
return originalString;
} catch (Exception e) {
System.out.println(e.toString());
return null;
}
} catch (Exception ex) {
System.out.println(ex.toString());
return null;
}
}
-- 生成公钥和私钥
openssl genrsa -out key.pem 1024
-out 指定生成文件,此文件包含公钥和私钥两部分,所以即可以加密,也可以解密
1024 生成密钥的长度
public static KeyPair buildKeyPair() throws NoSuchAlgorithmException {
final int keySize = 2048;
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(RSA_ALGORITHM);
keyPairGenerator.initialize(keySize);
return keyPairGenerator.genKeyPair();
}
--- 加密
public static byte[] encrypt(PublicKey publicKey, String message) throws Exception {
Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return cipher.doFinal(message.getBytes(UTF8));
}
--- 解密
public static byte[] decrypt(PrivateKey privateKey, byte [] encrypted) throws Exception {
Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return cipher.doFinal(encrypted);
}
/**
* 使用RSA签名
*/
private static String signWithRSA(String content, PrivateKey privateKey) throws Exception {
Signature signature = Signature.getInstance("SHA1WithRSA");
signature.initSign(privateKey);
signature.update(content.getBytes("utf-8"));
byte[] signed = signature.sign();
return base64Encode(signed);
}
/**
* 使用RSA验签
*/
private static boolean checkSignWithRSA(String content, PublicKey publicKey,String sign) throws Exception {
Signature signature = Signature.getInstance("SHA1WithRSA");
signature.initVerify(publicKey);
signature.update(content.getBytes("utf-8"));
return signature.verify(base64Decode(sign));
}
SHA1WithRSA
,它的意思是用SHA算法进行签名,用RSA算法进行加密。30(数据类型结构)21(总长度)30(数据类型)09(长度)06 05 2B 0E 03 02 1A 0500【数据具体类型不清楚-请专家指正】 04 (数据类型) 14 (长度) + SHA1签名数据
XXXWithRSA
,这个XXX代表的就是使用什么摘要算法进行加签,至于摘要算法是什么,随后会有详细的说明。public static void main(String[] args) throws Exception {
KeyPair keyPair = buildKeyPair();
byte[] encryptData = encrypt(keyPair.getPublic(), "不学无数");
System.out.println(String.format("加密后的数据:%s",base64Encode(encryptData)));
System.out.println(String.format("解密后的数据:%s",new String(decrypt(keyPair.getPrivate(),encryptData),UTF8)));
String context = "加签的字符串";
String sign = signWithRSA(context, keyPair.getPrivate());
System.out.println(String.format("生成的签名:%s",sign));
Boolean checkSignWithRSA = checkSignWithRSA(context, keyPair.getPublic(), sign);
System.out.println(String.format("校验的结果:%s",checkSignWithRSA.toString()));
}
加密后的数据:Bi8b4eqEp+rNRhDaij8vVlNwKuICbPJfFmyzmEXKuAgEgzMPb8hAmYiGN+rbUKWeZYJKJd0fiOXv
6YrYqd7fdast/m443qQreRLxdQFScwvCvj9g1YnPzbU2Q/jIwqAPopTyPHNNngBmFki+R/6V4DYt
HA5gniaUMYzynHdD+/W+x8ZYmwiuuS63+7wXqL36aLKe0H50wELOpSn45Gvni8u+5zPIoHV7PBiz
trCnQvne5LxFKDprrS3td1/76qyupFd+Ul3hsd+gjbAyN2MlXcAFMrGVaRkopWwc9hP1BsPvS52q
/8jOVdbeyU9BziVhViz1V0TtGW8bfbEnIStc3Q==
解密后的数据:不学无数
生成的签名:wvUXtr2UI0tUXmyMTTUBft8oc1dhvtXSBrFFetI5ZoxMm91TbXRWD31Pgqkg72ADxx9TEOAM3Bm1
kyzfBCZZpoq6Y9SM4+jdJ4sMTVtw0wACPglnPDAGs8sG7nnLhXWNQ1Y4pl4ziY6uLxF1TzQLFTxu
NAS7nyljbG69wrb9R3Sv5t8r1I54rYCVGSVFmTrGf+dSCjxABZv6mH8nygVif7zN1vU1+nSDKcON
Vtrpv0xCQHVBqnHPA6OiDm5GzBQxjD5aQt8mfgv8JJrB52TEa4JPYoC5Zw4JHlL++OvPwMpJgnuG
yg5vnWhxE2ncTzM+/pZ+CnXF2Dqv/JMQOfX6tA==
校验的结果:true
public static String getMD5Str(String str) throws Exception {
try {
// 生成一个MD5加密计算摘要
MessageDigest md = MessageDigest.getInstance("MD5");
// 计算md5函数
md.update(str.getBytes());
// digest()最后确定返回md5 hash值,返回值为8为字符串。因为md5 hash值是16位的hex值,实际上就是8位的字符
// BigInteger函数则将8位的字符串转换成16位hex值,用字符串来表示;得到字符串形式的hash值
return new BigInteger(1, md .digest()).toString(16);
} catch (Exception e) {
throw new Exception("MD5加密出现错误,"+e.toString());
}
}
线下活动推荐:
时间:3月12日(周日)14:00-18:00
主题:得物技术沙龙-前端中后台系统架构专题
地点:浙江省杭州市西湖区学院路77号黄龙万科中心 B 座 12 楼培训室
活动亮点:本次沙龙邀请了阿里巴巴、字节跳动、得物技术 等前端专家,围绕中后台前端架构来分享和讨论,解决你工作中的难点和痛点,不仅可以现场与大咖1v1交流,还可以认识行业大咖。
报名方式:点击阅读原文
参与「转发抽奖」:杭州线下得物技术沙龙——前端中后台系统架构专场,快来报名参加
*文/ 不学无数的程序员
关注得物技术,每周一三五晚18:30更新技术干货