Java 常用加密解密算法及应用示例
摘要:在Java开发中,加密解密技术是保护数据安全的重要手段。无论是存储敏感信息(如用户密码、个人信息)还是传输加密数据,都需要用到加密算法。不同的加密算法运用的场景也不同,因此选择合适的加密解密算法也是至关重要。
一、加密算法分类
加密算法的种类繁多,主要可以归纳为以下几大类:
一、对称加密算法
定义:加密和解密使用相同密钥的加密算法。
特点:加密强度高,效率高,但密钥分发和管理较为复杂。
常见算法:
DES:一种使用对称密钥加密的块算法,由IBM公司于1975年研发,是广泛应用的早期对称加密算法之一,但由于密钥长度较短(56位),安全性已逐渐降低。
3DES:DES算法的一个更安全的变形,使用3条56位的密钥对数据进行三次加密,提高了安全性,是DES算法向AES算法过渡的算法。
AES:高级加密标准(Advanced Encryption Standard),是一种分块加密算法,用于替代原先的DES算法。AES算法由三种不同的算法组成,分别使用128、192或256位加密密钥,具有高强度、高速度和易于实现的特点。
RC4:一种流密码算法,由Ron Rivest于1987年创建,通过生成一个伪随机数流与明文进行异或运算来实现加密,具有速度快、简单易用、灵活性高以及适用范围广的特点。
其他还包括Blowfish、IDEA、RC5、RC6等算法。
二、非对称加密算法
定义:非对称加密算法是指加密和解密使用不同密钥的加密算法,通常包含公钥和私钥。公钥用于加密,私钥用于解密(或反之用于验签)。
特点:加密速度慢,但强度高,适用于密钥交换和数字签名等场景。
常见算法:
RSA:一种基于公钥加密的算法,广泛应用于SSL证书中的密钥交换和数字签名过程,助力网站实现HTTPS加密,确保网络通信安全。
ECC:基于椭圆曲线密码学的加密算法,相比于RSA算法,ECC算法提供了更高的安全性和更短的密钥长度。
其他还包括Diffie-Hellman、El Gamal、DSA(数字签名用)等算法。
三、哈希算法
定义:也叫安全散列算法、消息摘要算法、杂凑算法,是一种将任意长度的输入数据输出为固定长度数据的算法,具有单向性,即不能通过输出数据反推出输入数据。
特点:可实现数据签名、数据完整性校验等功能。
常见算法:
MD5:一种加密散列函数算法,将任意长度的信息作为输入,并转换为128位(16字节)的固定长度信息,主要用于验证文件是否被篡改。但近年来,由于其哈希值长度较短,安全性逐渐受到质疑。
SHA系列:包括SHA-1、SHA-2(SHA-224、SHA-256、SHA-384、SHA-512)等算法,其中SHA-1算法可以生成160位(20字节)散列值,而SHA-2算法则是SHA-1算法的继承者,提供了更高的安全性。SHA系列算法广泛应用于文件传输校验、代码签名证书等领域。
其他还包括MD2、MD4、HAVAL等算法,但部分算法由于安全性问题已逐渐被淘汰。
##二、加密算法实现
本文将介绍几种Java中常用的加密解密算法,并提供相应的使用示例。
对称加密算法
DES算法
DES(Data Encryption Standard)是一种古老的对称加密算法,它以64位为分组长度,密钥长度为56位,8位用于奇偶校验。
在Java中,可以使用javax.crypto.Cipher类来执行DES加密和解密。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
| import com.alibaba.fastjson.JSON; import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import java.io.UnsupportedEncodingException; import java.nio.charset.StandardCharsets; import java.security.NoSuchAlgorithmException; import java.util.Base64;
public class DESUtil {
public static SecretKey generateDESKey() throws NoSuchAlgorithmException { KeyGenerator keyGenerator = KeyGenerator.getInstance("DES"); keyGenerator.init(56); return keyGenerator.generateKey(); }
public static SecretKey generateFixDESKey() throws UnsupportedEncodingException { String fixedKey = "qwerasdf";
return new SecretKeySpec(fixedKey.getBytes(StandardCharsets.UTF_8), "DES"); }
public static String encrypt(String data, SecretKey secretKey) throws Exception { Cipher cipher = Cipher.getInstance("DES"); cipher.init(Cipher.ENCRYPT_MODE, secretKey); byte[] encryptedData = cipher.doFinal(data.getBytes()); return Base64.getEncoder().encodeToString(encryptedData); }
public static String decrypt(String data, SecretKey secretKey) throws Exception { byte[] encryptedData = Base64.getDecoder().decode(data); Cipher cipher = Cipher.getInstance("DES"); cipher.init(Cipher.DECRYPT_MODE, secretKey); byte[] decryptedData = cipher.doFinal(encryptedData); return new String(decryptedData); }
private DESUtil() { }
public static void main(String[] args) { try { SecretKey secretKey = generateFixDESKey();
System.out.println(JSON.toJSONString(secretKey));
String originalString = "Hello, World!"; String encryptedString = encrypt(originalString, secretKey); System.out.println("Encrypted: " + encryptedString);
String decryptedString = decrypt(encryptedString, secretKey); System.out.println("Decrypted: " + decryptedString); } catch (Exception e) { e.printStackTrace(); } } }
|
AES算法
AES(Advanced Encryption Standard)是一种高级加密标准,是目前广泛使用的加密算法之一,提供多种密钥长度(如128位、192位、256位)。
在Java中,可以使用javax.crypto.Cipher类来执行AES加密和解密。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
| import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import java.nio.charset.StandardCharsets; import java.security.NoSuchAlgorithmException; import java.util.Base64;
public class AESUtil {
private static final String AES_ALGORITHM = "AES";
public static SecretKey generateAESKey() throws NoSuchAlgorithmException { KeyGenerator keyGenerator = KeyGenerator.getInstance(AES_ALGORITHM); keyGenerator.init(128); return keyGenerator.generateKey(); }
public static SecretKey generateFixAESKey() throws NoSuchAlgorithmException { String fixedKey = "qwerasdfzxcvbnml";
return new SecretKeySpec(fixedKey.getBytes(StandardCharsets.UTF_8), "AES"); }
public static String encrypt(String data, SecretKey secretKey) throws Exception { Cipher cipher = Cipher.getInstance(AES_ALGORITHM); cipher.init(Cipher.ENCRYPT_MODE, secretKey); byte[] encryptedData = cipher.doFinal(data.getBytes()); return Base64.getEncoder().encodeToString(encryptedData); }
public static String decrypt(String data, SecretKey secretKey) throws Exception { byte[] encryptedData = Base64.getDecoder().decode(data); Cipher cipher = Cipher.getInstance(AES_ALGORITHM); cipher.init(Cipher.DECRYPT_MODE, secretKey); byte[] decryptedData = cipher.doFinal(encryptedData); return new String(decryptedData); }
private AESUtil() { }
public static void main(String[] args) { try { SecretKey secretKey = generateFixAESKey();
String originalString = "Hello, World!"; String encryptedString = encrypt(originalString, secretKey); System.out.println("Encrypted: " + encryptedString);
String decryptedString = decrypt(encryptedString, secretKey); System.out.println("Decrypted: " + decryptedString); } catch (Exception e) { e.printStackTrace(); } } }
|
我们也可以使用组合算法来进行进一步的加密
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
| import javax.crypto.Cipher; import javax.crypto.SecretKey; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import java.nio.charset.StandardCharsets; import java.security.spec.AlgorithmParameterSpec; import java.util.Base64;
public class AESUtil {
private static final String AES_KEY = "qwerasdfzxcvbnml"; private static final String AES_ALGORITHM = "AES";
private static final String AES_CBC_PKCS5_PADDING = "AES/CBC/PKCS5Padding";
public static SecretKey generateAESKey() { return new SecretKeySpec(AES_KEY.getBytes(StandardCharsets.UTF_8), AES_ALGORITHM); }
public static AlgorithmParameterSpec generateIvParam() { return new IvParameterSpec(AES_KEY.getBytes()); }
public static String encrypt(String data, SecretKey secretKey, AlgorithmParameterSpec parameterSpec) throws Exception { Cipher cipher = Cipher.getInstance(AES_CBC_PKCS5_PADDING); cipher.init(Cipher.ENCRYPT_MODE, secretKey, parameterSpec); byte[] encryptedData = cipher.doFinal(data.getBytes()); return Base64.getEncoder().encodeToString(encryptedData); }
public static String decrypt(String data, SecretKey secretKey, AlgorithmParameterSpec parameterSpec) throws Exception { byte[] encryptedData = Base64.getDecoder().decode(data); Cipher cipher = Cipher.getInstance(AES_CBC_PKCS5_PADDING); cipher.init(Cipher.DECRYPT_MODE, secretKey, parameterSpec); byte[] decryptedData = cipher.doFinal(encryptedData); return new String(decryptedData); }
private AESUtil2() { }
public static void main(String[] args) { try { SecretKey secretKey = generateAESKey(); AlgorithmParameterSpec ivParam = generateIvParam();
String originalString = "Hello, World!"; String encryptedString = encrypt(originalString, secretKey, ivParam); System.out.println("Encrypted: " + encryptedString);
String decryptedString = decrypt(encryptedString, secretKey, ivParam); System.out.println("Decrypted: " + decryptedString); } catch (Exception e) { e.printStackTrace(); } } }
|
非对称加密算法
RSA算法
RSA(Rivest-Shamir-Adleman)是一种非对称加密算法,它包含公钥和私钥。公钥用于加密,私钥用于解密。
Java的KeyPairGenerator和Cipher类可以用来生成密钥对和执行加密解密操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247
| import javax.crypto.Cipher; import java.security.*; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.Base64; import java.util.HashMap; import java.util.Map;
public class RSAUtil {
private static final String RSA_KEY_ALGORITHM = "RSA";
private static final String RSA_SIGNATURE_ALGORITHM = "SHA1withRSA"; private static final String RSA2_SIGNATURE_ALGORITHM = "SHA256withRSA";
private static final int KEY_SIZE = 2048;
public static Map<String, String> generateKey() { KeyPairGenerator keygen; try { keygen = KeyPairGenerator.getInstance(RSA_KEY_ALGORITHM); } catch (NoSuchAlgorithmException e) { throw new RuntimeException("RSA初始化密钥出现错误,算法异常"); } SecureRandom secrand = new SecureRandom(); secrand.setSeed("Alian".getBytes()); keygen.initialize(KEY_SIZE, secrand); KeyPair keyPair = keygen.genKeyPair(); byte[] pub_key = keyPair.getPublic().getEncoded(); String publicKeyStr = Base64.getEncoder().encodeToString(pub_key); byte[] pri_key = keyPair.getPrivate().getEncoded(); String privateKeyStr = Base64.getEncoder().encodeToString(pri_key); Map<String, String> keyPairMap = new HashMap<>(); keyPairMap.put("publicKeyStr", publicKeyStr); keyPairMap.put("privateKeyStr", privateKeyStr); return keyPairMap; }
public static String encryptByPublicKey(String data, String publicKeyStr) throws Exception { byte[] pubKey = Base64.getDecoder().decode(publicKeyStr); X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(pubKey); KeyFactory keyFactory = KeyFactory.getInstance(RSA_KEY_ALGORITHM); PublicKey publicKey = keyFactory.generatePublic(x509KeySpec); Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.ENCRYPT_MODE, publicKey); byte[] encrypt = cipher.doFinal(data.getBytes()); return Base64.getEncoder().encodeToString(encrypt); }
public static String decryptByPrivateKey(String data, String privateKeyStr) throws Exception { byte[] priKey = Base64.getDecoder().decode(privateKeyStr); PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(priKey); KeyFactory keyFactory = KeyFactory.getInstance(RSA_KEY_ALGORITHM); PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec); Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.DECRYPT_MODE, privateKey); byte[] decrypt = cipher.doFinal(Base64.getDecoder().decode(data)); return new String(decrypt); }
public static String encryptByPrivateKey(String data, String privateKeyStr) throws Exception { byte[] priKey = Base64.getDecoder().decode(privateKeyStr); PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(priKey); KeyFactory keyFactory = KeyFactory.getInstance(RSA_KEY_ALGORITHM); PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec); Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.ENCRYPT_MODE, privateKey); byte[] encrypt = cipher.doFinal(data.getBytes()); return Base64.getEncoder().encodeToString(encrypt); }
public static String decryptByPublicKey(String data, String publicKeyStr) throws Exception { byte[] pubKey = Base64.getDecoder().decode(publicKeyStr); X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(pubKey); KeyFactory keyFactory = KeyFactory.getInstance(RSA_KEY_ALGORITHM); PublicKey publicKey = keyFactory.generatePublic(x509KeySpec); Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.DECRYPT_MODE, publicKey); byte[] decrypt = cipher.doFinal(Base64.getDecoder().decode(data)); return new String(decrypt); }
public static String sign(byte[] data, byte[] priKey, String signType) throws Exception { PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(priKey); KeyFactory keyFactory = KeyFactory.getInstance(RSA_KEY_ALGORITHM); PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec); String algorithm = RSA_KEY_ALGORITHM.equals(signType) ? RSA_SIGNATURE_ALGORITHM : RSA2_SIGNATURE_ALGORITHM; Signature signature = Signature.getInstance(algorithm); signature.initSign(privateKey); signature.update(data); byte[] sign = signature.sign(); return Base64.getEncoder().encodeToString(sign); }
public static boolean verify(byte[] data, byte[] sign, byte[] pubKey, String signType) throws Exception { KeyFactory keyFactory = KeyFactory.getInstance(RSA_KEY_ALGORITHM); X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(pubKey); PublicKey publicKey = keyFactory.generatePublic(x509KeySpec); String algorithm = RSA_KEY_ALGORITHM.equals(signType) ? RSA_SIGNATURE_ALGORITHM : RSA2_SIGNATURE_ALGORITHM; Signature signature = Signature.getInstance(algorithm); signature.initVerify(publicKey); signature.update(data); return signature.verify(sign); }
public static void main(String[] args) throws Exception { Map<String, String> keyMap = RSAUtil2.generateKey(); String publicKeyStr = keyMap.get("publicKeyStr"); String privateKeyStr = keyMap.get("privateKeyStr"); System.out.println("-----------------生成的公钥和私钥------------------------------"); System.out.println("获取到的公钥:" + publicKeyStr); System.out.println("获取到的私钥:" + privateKeyStr); String data = "tranSeq=1920542585&amount=100&payType=wechat"; System.out.println("-----------------加密和解密------------------------------"); System.out.println("待加密的数据:" + data); String encrypt = RSAUtil2.encryptByPublicKey(data, publicKeyStr); System.out.println("加密后数据:" + encrypt); String decrypt = RSAUtil2.decryptByPrivateKey(encrypt, privateKeyStr); System.out.println("解密后数据:" + decrypt);
System.out.println("待签名的数据:" + data); String sign = RSAUtil2.sign(data.getBytes(), Base64.getDecoder().decode(privateKeyStr), "RSA"); System.out.println("数字签名结果:" + sign); boolean verify = RSAUtil2.verify(data.getBytes(), Base64.getDecoder().decode(sign), Base64.getDecoder().decode(publicKeyStr), "RSA"); System.out.println("数字签名验证结果:" + verify);
} }
|
使用RSA进行加密和解密时,由于RSA算法的性能问题,通常不直接用于加密大量数据,而是用于加密对称加密算法的密钥(如AES密钥),然后使用该对称密钥加密实际数据。
注意事项:
密钥对的生成、存储和传输需要特别小心,以避免私钥泄露。
在实际应用中,密钥对可能需要持久化存储到文件系统或数据库中,但应确保存储的安全性。
加密和解密过程中,数据编码(如getBytes())应使用统一的字符集(如UTF-8),以避免乱码问题。
哈希算法
MD5算法
MD5(Message-Digest Algorithm 5)是一种常用的哈希算法,它可以接受任意长度的输入(信息),并输出一个128位的哈希值,通常以32位十六进制数表示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| import java.security.MessageDigest; import java.security.NoSuchAlgorithmException;
public class MD5Util {
public static String getMD5(String data) throws NoSuchAlgorithmException { MessageDigest md = MessageDigest.getInstance("MD5"); md.update(data.getBytes()); byte[] digest = md.digest(); return bytesToHex(digest); }
private static String bytesToHex(byte[] bytes) { StringBuilder sb = new StringBuilder(); for (byte b : bytes) { sb.append(String.format("%02x", b)); } return sb.toString(); } private MD5Util() { }
public static void main(String[] args) { try { String originalString = "Hello, World!"; String md5String = MD5Util.getMD5(originalString); System.out.println("Original: " + originalString); System.out.println("MD5 Hash: " + md5String); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } } }
|
SHA-1算法
SHA-1(Secure Hash Algorithm 1)是一种加密哈希函数,它接收一个输入(信息)并输出一个160位的哈希值,通常以40位十六进制数表示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| import java.security.MessageDigest; import java.security.NoSuchAlgorithmException;
public class SHA1Util {
public static String getSHA1(String data) throws NoSuchAlgorithmException { MessageDigest md = MessageDigest.getInstance("SHA-1"); md.update(data.getBytes()); byte[] digest = md.digest(); return bytesToHex(digest); }
private static String bytesToHex(byte[] bytes) { StringBuilder sb = new StringBuilder(); for (byte b : bytes) { sb.append(String.format("%02x", b)); } return sb.toString(); }
private SHA1Util() { }
public static void main(String[] args) { try { String originalString = "Hello, World!"; String sha1String = SHA1Util.getSHA1(originalString); System.out.println("Original: " + originalString); System.out.println("SHA-1 Hash: " + sha1String); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } } }
|
SHA-256算法
它生成数据的固定长度(如256位)摘要,用于验证数据的完整性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| import java.security.MessageDigest; import java.security.NoSuchAlgorithmException;
public class SHA256Util {
public static String getSHA256(String data) throws NoSuchAlgorithmException { MessageDigest md = MessageDigest.getInstance("SHA-256"); md.update(data.getBytes()); byte[] digest = md.digest(); return bytesToHex(digest); }
private static String bytesToHex(byte[] bytes) { StringBuilder sb = new StringBuilder(); for (byte b : bytes) { sb.append(String.format("%02x", b)); } return sb.toString(); } private SHA256Util() { }
public static void main(String[] args) { try { String originalString = "Hello, World!"; String sha256String = SHA256Util.getSHA256(originalString); System.out.println("Original: " + originalString); System.out.println("SHA-256 Hash: " + sha256String); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } } }
|