博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java常见加密使用和分析
阅读量:3925 次
发布时间:2019-05-23

本文共 11075 字,大约阅读时间需要 36 分钟。

Java常见加密使用和分析

最近项目里碰到很多加解密的场景,使用多种加密的方式,大概整理了一下,一共有一下几种

加密方式 安全性 是否可逆
1 MD5 不可逆
2 AES 可逆
3 RSA 可逆
4 Base64 可逆

1.MD5加密

MD5即Message-Digest Algorithm 5(信息-摘要算法5),用于确保信息传输完整一致。是计算机广泛使用的杂凑算法之一(又译摘要算法、哈希算法)

MD5的一般在项目中的使用场景是密码加密,在校验密码时直接比较加密后的密文,对于这种不需要解密和展示的字段我们可以直接采用MD5的方式进行加密。MD5的本质就是将数据进行hash取得数据摘要,在一定程度上来说,MD5是无法被破解的。当然也可以通过撞库的方式来进行尝试破解,这个投入成本也是非常大的。为了避免撞库的命中率,还可以对MD5进行加盐。投入不同的随机字符串与数据进行拼接,亦或者在hash完的数据进行&运算。降低MD5撞库破解的威胁性。


Java中的使用MD5

public class MD5Util {
//默认盐 public static String LOCAL_SALT = "23543dfggeelysdafaqj23ou89ZXcj@#$@#$#@KJdjklj;D../dSF.,"; //md5加密类 private static MessageDigest md5; static {
try {
//获取md5实例 md5 = MessageDigest.getInstance("MD5"); } catch (NoSuchAlgorithmException e) {
e.printStackTrace(); } } /** * MD5加密 * @param data * @return */ public static String encrypt(String data){
//md5加密 return byteArrayToHexString(md5.digest(data.getBytes())); } /** * MD5加盐加密 * @param data * @param salt * @return */ public static String encrypt(String data,String salt){
//加盐 data +=salt; //md5加密 return byteArrayToHexString(md5.digest(data.getBytes())); } //这里主要是遍历8个byte,转化为16位进制的字符,即0-F private static String byteArrayToHexString(byte[] b) {
StringBuffer resultSb = new StringBuffer(); for (int i = 0; i < b.length; i++) {
resultSb.append(byteToHexString(b[i])); } return resultSb.toString(); } //这里是针对单个byte,256的byte通过16拆分为d1和d2 private static String byteToHexString(byte b) {
int n = b; if(n < 0) {
n += 256; } int d1 = n / 16; int d2 = n % 16; return hexDigits[d1] + hexDigits[d2]; } private static final String hexDigits[] = {
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"};}

java中获取到MessageDigest的md5实例后就可以完成MD5加密。

2.AES加密

高级加密标准(AES,Advanced Encryption Standard)为最常见的对称加密算法(微信小程序加密传输就是用这个加密算法的)。也就是我们常说的对称密钥加密,加密和解密用相同的密钥。

加密原理:轮密钥加实际是一种Vernam密码形式,其本身不难被破解。另外三个阶段一起提供了混淆、扩散和非线性功能。这三个阶段没有涉及密钥,就它们自身而言,并未提供算法的安全性。然而,该算法经历一个分组的XOR加密(轮密钥加),再对该分组混淆扩散(其他三个阶段),再接着又是XOR加密,如此交替进行,这种方式非常有效非常安全。

可逆原理:每个阶段均可逆。对字节代替、行移位和列混淆,在解密算法中用它们相对应的逆函数。轮密钥加的逆就是用同样的轮密钥和分组相异或,其原理就是A⊕B⊕B = A。和大多数分组密码一样,AES解密算法按逆序利用扩展密钥,然而其解密算法和加密算法并不一样,这是由AES的特定结构决定的。图5.3中加密和解密流程在纵向上是相反的,在每个水平点上,state数组在加密和解密函数中都是一样的。

AES加密的使用场景一般是在敏感信息在数据传输过程,微信小程序使用的AES加密传输数据。因为AES加解使用的是同一个密钥,AES可逆,如果密钥泄露也就意味着数据可以被解密。数据在频繁传输过程中,可能需要动态变更密钥来保证数据传输的安全性。


Java中AES加密

/** * AES对称密钥加解密 */public class AESUtil {
/** * 生成AES密钥 * @return * @throws NoSuchAlgorithmException */ public static String generateKey() throws NoSuchAlgorithmException {
KeyGenerator keyGenerator = KeyGenerator.getInstance("RSA"); //初始化生成器 keyGenerator.init(1024, new SecureRandom()); //生成AES密钥 SecretKey secretKey = keyGenerator.generateKey(); byte[] keyByte = secretKey.getEncoded(); return HexBin.encode(keyByte); } /** * 生成AES密钥 * @param keySize 密钥最大长度 * @return * @throws NoSuchAlgorithmException */ public static String generateKey(Integer keySize) throws NoSuchAlgorithmException {
KeyGenerator keyGenerator = KeyGenerator.getInstance("RSA"); //初始化生成器 keyGenerator.init(keySize, new SecureRandom()); //生成AES密钥 SecretKey secretKey = keyGenerator.generateKey(); byte[] keyByte = secretKey.getEncoded(); return HexBin.encode(keyByte); } /** * AES加密 * @param str * @param secreKey * @return * @throws Exception */ public static String encrypt( String str, String secreKey ) throws Exception{
//密钥 Key key = new SecretKeySpec(HexBin.decode(secreKey),"AES"); Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); //初始化加密 cipher.init(Cipher.ENCRYPT_MODE, key); byte[] result = cipher.doFinal(str.getBytes()); return HexBin.encode(result); } /** * AES解密 * @param str * @param secreKey * @return * @throws Exception */ public static String decrypt(String str,String secreKey) throws Exception{
Key key = new SecretKeySpec(HexBin.decode(secreKey),"AES"); Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); //初始化解密 cipher.init(Cipher.DECRYPT_MODE, key); byte[] result = cipher.doFinal(str.getBytes()); return new String(result); }}

java中的AES的加密完全依赖 Cipher类。RSA加解密使用也是这个类。

3.RSA加密

RSA是一种非对称加密算法。现在,很多登陆表单的密码的都采用RSA加密,例如京东中的登陆使用公钥对密码进行加密。

RSA这个加密算法就是经常听到非对称密钥加密,顾名思义,RSA加解密使用的不是同一个密钥,RSA中存在两个密钥,一个是公钥,一个是私钥,公钥暴露给数据发送端,私钥在数据接收端保留,数据发送端在数据传输前使用公钥加密数据,数据接受端在接收到数据时使用私钥解密,拿到真实数据。来保证数据传输的安全性。

RSA主要使用大整数分解这个数学难题进行设计,巧妙地利用了数论的概念,如今,只有短的 RSA 密钥才有可能被强力方式解破。长度足够长的密钥是安全系数时很高的。


Java中RSA加密

/** * RSA加解密工具类 * @author machenike */public class RASUtil {
/** * 密钥对存储场所 */ private static KeyStore keyStore = new LocalKeyStore(); /** * 当前线程持有的公钥 */ private static ThreadLocal
currentPublicKey = new ThreadLocal<>(); /** * 生成RSA密钥对 * @return * @throws NoSuchAlgorithmException */ public static String[] generateKeyPair(){
// KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象 KeyPairGenerator keyPairGen = null; try {
keyPairGen = KeyPairGenerator.getInstance("RSA"); } catch (NoSuchAlgorithmException e) {
e.printStackTrace(); e.printStackTrace(); return null; } // 初始化密钥对生成器,密钥大小为96-1024位 keyPairGen.initialize(1024,new SecureRandom()); // 生成一个密钥对,保存在keyPair中 KeyPair keyPair = keyPairGen.generateKeyPair(); // 得到私钥 RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); // 得到公钥 RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); String publicKeyString = new String(Base64.encodeBase64(publicKey.getEncoded())); // 得到私钥字符串 String privateKeyString = new String(Base64.encodeBase64((privateKey.getEncoded()))); // 将公钥和私钥保存到String数组 String[] result = new String[2]; result[0] = publicKeyString; result[1] = privateKeyString; return result; } /** * 生成RSA密钥对 * @param keySize 密钥最大长度 * @return * @throws NoSuchAlgorithmException */ public static String[] generateKeyPair(Integer keySize){
// KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象 KeyPairGenerator keyPairGen = null; try {
keyPairGen = KeyPairGenerator.getInstance("RSA"); } catch (NoSuchAlgorithmException e) {
e.printStackTrace(); return null; } // 初始化密钥对生成器,密钥大小为96-1024位 keyPairGen.initialize(keySize,new SecureRandom()); // 生成一个密钥对,保存在keyPair中 KeyPair keyPair = keyPairGen.generateKeyPair(); /* 得到私钥 */ RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); // 得到公钥 RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); String publicKeyString = new String(Base64.encodeBase64(publicKey.getEncoded())); // 得到私钥字符串 String privateKeyString = new String(Base64.encodeBase64((privateKey.getEncoded()))); // 将公钥和私钥保存到String数组 String[] result = new String[2]; result[0] = publicKeyString; result[1] = privateKeyString; return result; } /** * RSA公钥加密 * * @param str * 加密字符串 * @param publicKey * 公钥 * @return 密文 * @throws Exception * 加密过程中的异常信息 */ public static String encrypt( String str, String publicKey ) throws Exception{
//base64编码的公钥 byte[] decoded = Base64.decodeBase64(publicKey); RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded)); //RSA加密 Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, pubKey); String outStr = Base64.encodeBase64String(cipher.doFinal(str.getBytes("UTF-8"))); return outStr; } /** * 使用私钥进行RSA解密 * * @param str * 加密字符串 * @param privateKey * 私钥 * @return 铭文 * @throws Exception * 解密过程中的异常信息 */ public static String decrypt(String str, String privateKey) throws Exception{
//64位解码加密后的字符串 byte[] inputByte = Base64.decodeBase64(str.getBytes("UTF-8")); //base64编码的私钥 byte[] decoded = Base64.decodeBase64(privateKey); RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded)); //RSA解密 Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.DECRYPT_MODE, priKey); String outStr = new String(cipher.doFinal(inputByte)); return outStr; } /** * 通过当前的线程的公钥进行RSA私钥解密 * * @param str * 加密字符串 * 私钥 * @return 铭文 * @throws Exception * 解密过程中的异常信息 */ public static String decrypt(String str) throws Exception{
//64位解码加密后的字符串 byte[] inputByte = Base64.decodeBase64(str.getBytes("UTF-8")); //base64编码的私钥 byte[] decoded = Base64.decodeBase64(keyStore.getPrivateKey(currentPublicKey.get())); RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded)); //RSA解密 Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.DECRYPT_MODE, priKey); String outStr = new String(cipher.doFinal(inputByte)); return outStr; } /** * 获取当前线程得公共键 * @param currentPublicKey */ public static void setCurrentPublicKey(String currentPublicKey){
RASUtil.currentPublicKey.set(currentPublicKey); } /** * 设定存储密钥的实现 * @param keyStore */ public static void setKeyStore(KeyStroke keyStore){
keyStore = keyStore; }}

使用KeyPairGenerator生成密钥对,同时服务端会将公钥返回到客户端,客户端是RSA进行加密,而私钥保存在系统内部,不对外暴露,收到数据时使用cipher进行解密。保证数据传输的安全性,就算数据被抓包抓到,只要数据没有经过后台,那么数据就是无法解密。

4.Base64加密

Base64编码是从二进制到字符的过程,可用于在HTTP环境下传递较长的标识信息。采用Base64编码具有不可读性,需要解码后才能阅读

其实base64不算是一种加密方式,只能说是一种特定的编码方式,目的是为了方便数据传输。比如图片可以转成base64字符串进行传输,接收完数据后,在进行base64解码就可把图片还原出来。


Java中Base64

/** * Base64解码编码工具类 */public class Base64Util {
//解码器 private static final Base64.Decoder decoder = Base64.getDecoder(); //编码器 private static final Base64.Encoder encoder = Base64.getEncoder(); /** * Base64编码 * @param data * @return */ public static String encode(String data){
return encoder.encodeToString(data.getBytes()); } /** * Base64解码 * @param data * @return */ public static String decode(String data){
return new String(decoder.decode(data.getBytes())); }}

上面所有的常用方法我都已经整理集成到我的安全包里。

https://github.com/DavidLei08/s-encrypt.git

转载地址:http://lhugn.baihongyu.com/

你可能感兴趣的文章
Leetcode 136. 只出现一次的数字
查看>>
Leetcode 11. 盛最多水的容器
查看>>
Leetcode 121. 买卖股票的最佳时机
查看>>
Leetcode 123. 买卖股票的最佳时机 III
查看>>
Leetcode 24. 两两交换链表中的节点
查看>>
Leetcode 100. 相同的树
查看>>
Leetcode 101. 对称二叉树
查看>>
Leetcode 108. 将有序数组转换为二叉搜索树
查看>>
Leetcode 303. 区域和检索 - 数组不可变
查看>>
Leetcode 110. 平衡二叉树
查看>>
Leetcode 111. 二叉树的最小深度
查看>>
Leetcode 226. 翻转二叉树
查看>>
Leetcode 617. 合并二叉树
查看>>
Leetcode 654. 最大二叉树
查看>>
Leetcode 304. 二维区域和检索 - 矩阵不可变
查看>>
Leetcode 45. 跳跃游戏 II
查看>>
模式2. 工厂方法模式-Java
查看>>
模式1. 简单工厂模式-Java
查看>>
模式6.原型模式-Java
查看>>
Leetcode 146. LRU 缓存机制
查看>>