浅析五种最常用的Java加密算法,以后可以直接拿来用了

本文涉及的产品
密钥管理服务KMS,1000个密钥,100个凭据,1个月
简介: 信息加密是现在几乎所有项目都需要用到的技术,身份认证、单点登陆、信息通讯、支付交易等场景中经常会需要用到加密算法,所谓加密算法,就是将原本的明文通过一系列算法操作变成密文。接下来就介绍一下目前比较常用的一些加密算法,本期不涉及算法底层,以应用介绍和代码展示为主。如果只想了解原理,可跳过代码部分,代码可直接拿来使用。

听说微信搜索《Java鱼仔》会变更强哦!


本文收录于JavaStarter ,里面有我完整的Java系列文章,学习或面试都可以看看哦


(一)关于加密算法


信息加密是现在几乎所有项目都需要用到的技术,身份认证、单点登陆、信息通讯、支付交易等场景中经常会需要用到加密算法,所谓加密算法,就是将原本的明文通过一系列算法操作变成密文。接下来就介绍一下目前比较常用的一些加密算法,本期不涉及算法底层,以应用介绍和代码展示为主。


如果只想了解原理,可跳过代码部分,代码可直接拿来使用。


(二)MD5算法


准确来讲,MD5不是一种加密算法,而是一种摘要算法,MD5能将明文输出为128bits的字符串,这个字符串是无法再被转换成明文的。网上一些MD5解密网站也只是保存了一些字符串对应的md5串,通过已经记录的md5串来找出原文。


我做过的几个项目中经常见到MD5用在加密上的场景。比如对密码的加密,生成一个密码后,使用MD5生成一个128位字符串保存在数据库中,用户输入密码后也先生成MD5串,再去数据库里比较。因此我们在找回密码时是无法得到原来的密码的,因为明文密码根本不会被保存。


publicclassMD5 {
/*** 生成MD5* @param str* @return*/publicStringencode(Stringstr) {
byte[] result=null;
try {
MessageDigestmd=MessageDigest.getInstance("MD5");
md.update(str.getBytes("UTF-8"));
result=md.digest();
        } catch (Exceptione) {
e.printStackTrace();
returnnull;
        }
returnparseByte2HexStr(result);
    }
/*** 将二进制转换成十六进制** @param buf* @return*/privateStringparseByte2HexStr(bytebuf[]) {
StringBuffersb=newStringBuffer();
for (inti=0; i<buf.length; i++) {
Stringhex=Integer.toHexString(buf[i] &0xFF);
if (hex.length() ==1) {
hex='0'+hex;
            }
sb.append(hex.toUpperCase());
        }
returnsb.toString();
    }
publicstaticvoidmain(String[] args) {
MD5md5=newMD5();
Stringcontent="测试test";
System.out.println(md5.encode(content));
    }
}

(三)SHA1算法


SHA1也是和MD5类似的信息摘要算法,但是它比MD5更加安全。


publicclassSHA1 {
publicStringencode(Stringstr) {
try {
MessageDigestmd=MessageDigest.getInstance("SHA-1");
md.update(str.getBytes("utf-8"));
byte[] digest=md.digest();
returnbyteToHexString(digest);
        } catch (Exceptione) {
e.printStackTrace();
returnnull;
        }
    }
publicstaticStringbyteToHexString(byte[] bytes) {
returnString.valueOf(Hex.encodeHex(bytes));
    }
publicstaticvoidmain(String[] args) {
SHA1sha1=newSHA1();
Stringcontent="测试test";
System.out.println(sha1.encode(content));
    }
}

(四)AES算法


AES是很常见的对称加密算法,所谓对称加密,就是通过密钥加密后可以再通过密钥解密。我接触过的某个国企现在内部就是采用AES的方式实现集成登陆。第三方系统提供一个接收用户信息的接口,该国企将用户信息AES加密后通过这个接口传递给第三方系统,第三方系统自行实现登陆操作。这里需要注意的是密钥十分重要,如果密钥丢失,就有信息泄漏的风险。


publicclassAES {
/*** 将传入的明文转换为密文* @param str* @param pwd* @return*/publicStringencode(Stringstr,Stringpwd) {
byte[] result=null;
try {
KeyGeneratorkgen=KeyGenerator.getInstance("AES");
SecureRandomrandom=SecureRandom.getInstance("SHA1PRNG");
random.setSeed(pwd.getBytes());
kgen.init(128, random);
SecretKeysecretKey=kgen.generateKey();
byte[] enCodeFormat=secretKey.getEncoded();
SecretKeySpeckey=newSecretKeySpec(enCodeFormat, "AES");
// 创建密码器Ciphercipher=Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] byteContent=str.getBytes();
result=cipher.doFinal(byteContent);
        } catch (Exceptione) {
returnnull;
        }
returnparseByte2HexStr(result);
    }
/*** 将传入的密文转换为明文* @param str* @param pwd* @return*/publicStringdecode(Stringstr,Stringpwd) {
byte[] result=null;
byte[] content=parseHexStr2Byte(str);
try {
KeyGeneratorkgen=KeyGenerator.getInstance("AES");
SecureRandomrandom=SecureRandom.getInstance("SHA1PRNG");
random.setSeed(pwd.getBytes());
kgen.init(128, random);
SecretKeysecretKey=kgen.generateKey();
byte[] enCodeFormat=secretKey.getEncoded();
SecretKeySpeckey=newSecretKeySpec(enCodeFormat, "AES");
// 创建密码器Ciphercipher=Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key);
result=cipher.doFinal(content);
        } catch (Exceptione) {
e.printStackTrace();
returnnull;
        }
returnnewString(result);
    }
/*** 将二进制转换成十六进制** @param buf* @return*/privateStringparseByte2HexStr(bytebuf[]) {
StringBuffersb=newStringBuffer();
for (inti=0; i<buf.length; i++) {
Stringhex=Integer.toHexString(buf[i] &0xFF);
if (hex.length() ==1) {
hex='0'+hex;
            }
sb.append(hex.toUpperCase());
        }
returnsb.toString();
    }
/*** 将十六进制转换为二进制** @param hexStr* @return*/privatebyte[] parseHexStr2Byte(StringhexStr) {
if (hexStr.length() <1) {
returnnull;
        }
byte[] result=newbyte[hexStr.length() /2];
for (inti=0; i<hexStr.length() /2; i++) {
inthigh=Integer.parseInt(hexStr.substring(i*2, i*2+1), 16);
intlow=Integer.parseInt(hexStr.substring(i*2+1, i*2+2), 16);
result[i] = (byte) (high*16+low);
        }
returnresult;
    }
publicstaticvoidmain(String[] args) {
AESaes=newAES();
Stringcontent="测试加密";
// AES的密钥长度最好是16位(不是必须)Stringpwd="javayznbjavayznb";
// 加密System.out.println("加密前:"+content);
StringencodeResultStr=aes.encode(content,pwd);
System.out.println("加密后:"+encodeResultStr);
// 解密StringdecodeResultStr=aes.decode(encodeResultStr,pwd);
System.out.println("解密后:"+decodeResultStr);
    }
}

(五)DES


DES也是一种对称加密算法,但是在安全性、效率和灵活性上比AES略差,但是也能保证安全,DES也需要通过密钥进行加密,通过密钥进行解密,因此密钥很重要:


publicclassDES {
/*** 将传入的明文转换为密文* @param str* @param pwd* @return*/publicStringencode(Stringstr,Stringpwd) {
byte[] result=null;
try {
DESKeySpeckeySpec=newDESKeySpec(pwd.getBytes());
SecretKeyFactorykeyFactory=SecretKeyFactory.getInstance("DES");
SecretKeykey=keyFactory.generateSecret(keySpec);
Ciphercipher=Cipher.getInstance("DES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] byteContent=str.getBytes();
result=cipher.doFinal(byteContent);
        } catch (Exceptione) {
e.printStackTrace();
returnnull;
        }
returnparseByte2HexStr(result);
    }
/*** 将传入的密文转换为明文* @param str* @param pwd* @return*/publicStringdecode(Stringstr,Stringpwd) {
byte[] result=null;
byte[] content=parseHexStr2Byte(str);
try {
DESKeySpeckeySpec=newDESKeySpec(pwd.getBytes());
SecretKeyFactorykeyFactory=SecretKeyFactory.getInstance("DES");
SecretKeykey=keyFactory.generateSecret(keySpec);
Ciphercipher=Cipher.getInstance("DES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key);
result=cipher.doFinal(content);
        } catch (Exceptione) {
e.printStackTrace();
returnnull;
        }
returnnewString(result);
    }
/*** 将二进制转换成十六进制** @param buf* @return*/privateStringparseByte2HexStr(bytebuf[]) {
StringBuffersb=newStringBuffer();
for (inti=0; i<buf.length; i++) {
Stringhex=Integer.toHexString(buf[i] &0xFF);
if (hex.length() ==1) {
hex='0'+hex;
            }
sb.append(hex.toUpperCase());
        }
returnsb.toString();
    }
/*** 将十六进制转换为二进制** @param hexStr* @return*/privatebyte[] parseHexStr2Byte(StringhexStr) {
if (hexStr.length() <1) {
returnnull;
        }
byte[] result=newbyte[hexStr.length() /2];
for (inti=0; i<hexStr.length() /2; i++) {
inthigh=Integer.parseInt(hexStr.substring(i*2, i*2+1), 16);
intlow=Integer.parseInt(hexStr.substring(i*2+1, i*2+2), 16);
result[i] = (byte) (high*16+low);
        }
returnresult;
    }
publicstaticvoidmain(String[] args) {
DESdes=newDES();
Stringcontent="测试test";
// DES的密钥长度必须是8位(小于8位则会报错,8位之后对加密结果不会产生影响)Stringpwd="javayznb";
// 加密System.out.println("加密前:"+content);
StringencodeResultStr=des.encode(content,pwd);
System.out.println("加密后:"+encodeResultStr);
//解密StringdecodeResultStr=des.decode(encodeResultStr,pwd);
System.out.println("解密后:"+decodeResultStr);
    }
}

(六)RSA


RSA是目前最具影响力的公钥加密算法,并且可以用于加密和验签。支付宝支付对接时用的加密方式就是RSA。在RSA中,存在一对密钥,分别称为公钥和私钥,通过私钥由个人保存,公钥可能多人持有


RSA的主要应用场景就是加密和验签,加密就不用说了,验签是指通过私钥对消息进行签名,使得消息无法篡改和伪造。


加密方式:B传加密数据给A


1、A生成公钥和私钥,私钥自己保留,公钥任何人可以获取。


2、B拿到公钥,将数据通过公钥加密


3、A收到密文,通过私钥解密。


验签方式:A传消息给B 1、A生成公钥和私钥,私钥自己保留,公钥任何人可以获取。

2、A使用私钥对消息加签,并将加签后的消息传给B。


3、B通过公钥验签,如果返回是true则说明消息是A发过来的且未被篡改。


publicclassTestRSA {
/*** RSA最大加密明文大小*/privatestaticfinalintMAX_ENCRYPT_BLOCK=117;
/*** RSA最大解密密文大小*/privatestaticfinalintMAX_DECRYPT_BLOCK=128;
/*** 获取密钥对** @return 密钥对*/publicstaticKeyPairgetKeyPair() throwsException {
KeyPairGeneratorgenerator=KeyPairGenerator.getInstance("RSA");
generator.initialize(1024);
returngenerator.generateKeyPair();
    }
/*** 获取私钥** @param privateKey 私钥字符串* @return*/publicstaticPrivateKeygetPrivateKey(StringprivateKey) throwsException {
KeyFactorykeyFactory=KeyFactory.getInstance("RSA");
byte[] decodedKey=Base64.decodeBase64(privateKey.getBytes());
PKCS8EncodedKeySpeckeySpec=newPKCS8EncodedKeySpec(decodedKey);
returnkeyFactory.generatePrivate(keySpec);
    }
/*** 获取公钥** @param publicKey 公钥字符串* @return*/publicstaticPublicKeygetPublicKey(StringpublicKey) throwsException {
KeyFactorykeyFactory=KeyFactory.getInstance("RSA");
byte[] decodedKey=Base64.decodeBase64(publicKey.getBytes());
X509EncodedKeySpeckeySpec=newX509EncodedKeySpec(decodedKey);
returnkeyFactory.generatePublic(keySpec);
    }
/*** RSA加密** @param data 待加密数据* @param publicKey 公钥* @return*/publicstaticStringencrypt(Stringdata, PublicKeypublicKey) throwsException {
Ciphercipher=Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
intinputLen=data.getBytes().length;
ByteArrayOutputStreamout=newByteArrayOutputStream();
intoffset=0;
byte[] cache;
inti=0;
// 对数据分段加密while (inputLen-offset>0) {
if (inputLen-offset>MAX_ENCRYPT_BLOCK) {
cache=cipher.doFinal(data.getBytes(), offset, MAX_ENCRYPT_BLOCK);
            } else {
cache=cipher.doFinal(data.getBytes(), offset, inputLen-offset);
            }
out.write(cache, 0, cache.length);
i++;
offset=i*MAX_ENCRYPT_BLOCK;
        }
byte[] encryptedData=out.toByteArray();
out.close();
// 获取加密内容使用base64进行编码,并以UTF-8为标准转化成字符串// 加密后的字符串returnnewString(Base64.encodeBase64String(encryptedData));
    }
/*** RSA解密** @param data 待解密数据* @param privateKey 私钥* @return*/publicstaticStringdecrypt(Stringdata, PrivateKeyprivateKey) throwsException {
Ciphercipher=Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] dataBytes=Base64.decodeBase64(data);
intinputLen=dataBytes.length;
ByteArrayOutputStreamout=newByteArrayOutputStream();
intoffset=0;
byte[] cache;
inti=0;
// 对数据分段解密while (inputLen-offset>0) {
if (inputLen-offset>MAX_DECRYPT_BLOCK) {
cache=cipher.doFinal(dataBytes, offset, MAX_DECRYPT_BLOCK);
            } else {
cache=cipher.doFinal(dataBytes, offset, inputLen-offset);
            }
out.write(cache, 0, cache.length);
i++;
offset=i*MAX_DECRYPT_BLOCK;
        }
byte[] decryptedData=out.toByteArray();
out.close();
// 解密后的内容returnnewString(decryptedData, "UTF-8");
    }
/*** 签名** @param data 待签名数据* @param privateKey 私钥* @return 签名*/publicstaticStringsign(Stringdata, PrivateKeyprivateKey) throwsException {
byte[] keyBytes=privateKey.getEncoded();
PKCS8EncodedKeySpeckeySpec=newPKCS8EncodedKeySpec(keyBytes);
KeyFactorykeyFactory=KeyFactory.getInstance("RSA");
PrivateKeykey=keyFactory.generatePrivate(keySpec);
Signaturesignature=Signature.getInstance("MD5withRSA");
signature.initSign(key);
signature.update(data.getBytes());
returnnewString(Base64.encodeBase64(signature.sign()));
    }
/*** 验签** @param srcData 原始字符串* @param publicKey 公钥* @param sign 签名* @return 是否验签通过*/publicstaticbooleanverify(StringsrcData, PublicKeypublicKey, Stringsign) throwsException {
byte[] keyBytes=publicKey.getEncoded();
X509EncodedKeySpeckeySpec=newX509EncodedKeySpec(keyBytes);
KeyFactorykeyFactory=KeyFactory.getInstance("RSA");
PublicKeykey=keyFactory.generatePublic(keySpec);
Signaturesignature=Signature.getInstance("MD5withRSA");
signature.initVerify(key);
signature.update(srcData.getBytes());
returnsignature.verify(Base64.decodeBase64(sign.getBytes()));
    }
publicstaticvoidmain(String[] args) {
try {
// 生成密钥对KeyPairkeyPair=getKeyPair();
StringprivateKey=newString(Base64.encodeBase64(keyPair.getPrivate().getEncoded()));
StringpublicKey=newString(Base64.encodeBase64(keyPair.getPublic().getEncoded()));
System.out.println("私钥:"+privateKey);
System.out.println("公钥:"+publicKey);
// RSA加密Stringdata="待加密的文字内容";
StringencryptData=encrypt(data, getPublicKey(publicKey));
System.out.println("加密后内容:"+encryptData);
// RSA解密StringdecryptData=decrypt(encryptData, getPrivateKey(privateKey));
System.out.println("解密后内容:"+decryptData);
// RSA签名Stringsign=sign(data, getPrivateKey(privateKey));
System.out.println("加签后:"+sign);
// RSA验签booleanresult=verify(data, getPublicKey(publicKey), sign);
System.out.print("验签结果:"+result);
        } catch (Exceptione) {
e.printStackTrace();
System.out.print("加解密异常");
        }
    }
}

(七)总结


关于加密这个问题不管是工作中还是面试中都会被提及,也必须要掌握。不要求加密的代码能手写,但是要知道每种加密算法是干什么的,是什么样的效果。

相关文章
|
2月前
|
存储 人工智能 算法
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
这篇文章详细介绍了Dijkstra和Floyd算法,这两种算法分别用于解决单源和多源最短路径问题,并且提供了Java语言的实现代码。
91 3
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
|
4月前
|
搜索推荐 算法 Java
手写快排:教你用Java写出高效排序算法!
快速排序(QuickSort)是经典的排序算法之一,基于分治思想,平均时间复杂度为O(n log n),广泛应用于各种场合。在这篇文章中,我们将手写一个Java版本的快速排序,从基础实现到优化策略,并逐步解析代码背后的逻辑。
175 1
|
2月前
|
Java Maven 数据安全/隐私保护
如何实现Java打包程序的加密代码混淆,避免被反编译?
【10月更文挑战第15天】如何实现Java打包程序的加密代码混淆,避免被反编译?
110 2
|
2月前
|
算法 搜索推荐 Java
java 后端 使用 Graphics2D 制作海报,画echarts图,带工具类,各种细节:如头像切割成圆形,文字换行算法(完美实验success),解决画上文字、图片后不清晰问题
这篇文章介绍了如何使用Java后端技术,结合Graphics2D和Echarts等工具,生成包含个性化信息和图表的海报,并提供了详细的代码实现和GitHub项目链接。
141 0
java 后端 使用 Graphics2D 制作海报,画echarts图,带工具类,各种细节:如头像切割成圆形,文字换行算法(完美实验success),解决画上文字、图片后不清晰问题
|
2月前
|
安全 算法 Java
数据库信息/密码加盐加密 —— Java代码手写+集成两种方式,手把手教学!保证能用!
本文提供了在数据库中对密码等敏感信息进行加盐加密的详细教程,包括手写MD5加密算法和使用Spring Security的BCryptPasswordEncoder进行加密,并强调了使用BCryptPasswordEncoder时需要注意的Spring Security配置问题。
189 0
数据库信息/密码加盐加密 —— Java代码手写+集成两种方式,手把手教学!保证能用!
|
2月前
|
算法 Java Linux
java制作海报一:java使用Graphics2D 在图片上写字,文字换行算法详解
这篇文章介绍了如何在Java中使用Graphics2D在图片上绘制文字,并实现自动换行的功能。
141 0
|
2月前
|
算法 Java 测试技术
数据结构 —— Java自定义代码实现顺序表,包含测试用例以及ArrayList的使用以及相关算法题
文章详细介绍了如何用Java自定义实现一个顺序表类,包括插入、删除、获取数据元素、求数据个数等功能,并对顺序表进行了测试,最后还提及了Java中自带的顺序表实现类ArrayList。
32 0
|
4月前
|
存储 算法 Java
在Java中使用MD5对用户输入密码进行加密存储、同时登录验证。
这篇文章详细介绍了在Java项目中如何使用MD5算法对用户密码进行加密存储和登录验证,包括加入依赖、编写MD5工具类、注册时的密码加密和登录时的密码验证等步骤,并通过示例代码和数据库存储信息展示了测试效果。
在Java中使用MD5对用户输入密码进行加密存储、同时登录验证。
|
3月前
|
安全 Java 数据安全/隐私保护
- 代码加密混淆工具-Java 编程安全性
在Java编程领域,保护代码安全与知识产权至关重要。本文探讨了代码加密混淆工具的重要性,并介绍了五款流行工具:ProGuard、DexGuard、Jscrambler、DashO 和 Ipa Guard。这些工具通过压缩、优化、混淆和加密等手段,提升代码安全性,保护知识产权。ProGuard 是开源工具,用于压缩和混淆Java代码;DexGuard 专为Android应用程序设计,提供强大加密功能;Jscrambler 基于云,保护Web和移动应用的JavaScript及HTML5代码;DashO 支持多种Java平台和
249 1
|
4月前
|
设计模式 缓存 算法
揭秘策略模式:如何用Java设计模式轻松切换算法?
【8月更文挑战第30天】设计模式是解决软件开发中特定问题的可重用方案。其中,策略模式是一种常用的行为型模式,允许在运行时选择算法行为。它通过定义一系列可互换的算法来封装具体的实现,使算法的变化与客户端分离。例如,在电商系统中,可以通过定义 `DiscountStrategy` 接口和多种折扣策略类(如 `FidelityDiscount`、`BulkDiscount` 和 `NoDiscount`),在运行时动态切换不同的折扣逻辑。这样,`ShoppingCart` 类无需关心具体折扣计算细节,只需设置不同的策略即可实现灵活的价格计算,符合开闭原则并提高代码的可维护性和扩展性。
68 2