AES对称加密RSA非对称加密和MD5不可逆加密代码示例
加密算法可以分为三大类:
- 对称加密算法:AES,DES ,国密sm4(ecb模式),加密和解密用的是同一个密钥,加解密速度快,适合大量数据(本地文件加密、VPN、TLS数据部分)
- 非对称加密算法: RSA,加密和解密用的是一对公钥和私钥,速度慢,适合小数据(数字签名、HTTPS证书、密钥交换)
- MD5:是一种哈希算法,不是加密算法。它的主要作用是将任意长度的数据转换为固定长度(128位/16字节)的“摘要”,适用于文件上传下载的校验, redis/Memcached中key的生成(原key太长,用md5缩短成固定长度)
登陆密码加密流程:
web端用公钥加密密码,server端用私钥解码,将解出的明文用MD5加密后存入数据库或与数据库的密码比较,这种方式会有中间人攻击的问题,只能用https方式,
如果用http方式,需要在web端生成公钥和私钥,将公钥发给server端,server端生成一串随机字符串并用公钥加密发给web端,web端用私钥解码并拼接上密码组成新的
字符串,将随机字符串作为AES加密算法的密码对密码进行加密发送给server端,server端使用随机字符串对新的字符串进行解密,server端系解析解密后的字符串,校验随机字符串是否一致.
AES:
加密解密工具类: import org.bouncycastle.crypto.DataLengthException; import org.bouncycastle.crypto.InvalidCipherTextException; import org.bouncycastle.crypto.engines.AESFastEngine; import org.bouncycastle.crypto.modes.GCMBlockCipher; import org.bouncycastle.crypto.params.AEADParameters; import org.bouncycastle.crypto.params.KeyParameter; import java.nio.charset.StandardCharsets; import java.security.SecureRandom; import java.util.Base64; /** * AES-GCM-256 工具类 加解密方法中已调用 Base64 方法 */ public class AesGcm256Util { private static final SecureRandom SECURE_RANDOM = new SecureRandom(); public static final int NONCE_BIT_SIZE = 128; public static final int MAC_BIT_SIZE = 128; public static final int KEY_BIT_SIZE = 256; private AesGcm256Util() {} /** * 编码 * * @param hexStr 文本 * @return 字节数组 */ public static byte[] hexToByte(String hexStr) { int len = hexStr.length(); byte[] data = new byte[len / 2]; for (int i = 0; i < len; i += 2) { data[i / 2] = (byte)((Character.digit(hexStr.charAt(i), 16) << 4) + Character.digit(hexStr.charAt(i + 1), 16)); } return data; }/** * 加密 * * @param plainText 明文文本 * @param key 密钥 * @param iv 向量 * @return 加密字符串 */ public static String encrypt(String plainText, byte[] key, byte[] iv) { String sr; try { byte[] plainBytes = plainText.getBytes(StandardCharsets.UTF_8); GCMBlockCipher cipher = new GCMBlockCipher(new AESFastEngine()); AEADParameters parameters = new AEADParameters(new KeyParameter(key), MAC_BIT_SIZE, iv, null); cipher.init(true, parameters); byte[] encryptedBytes = new byte[cipher.getOutputSize(plainBytes.length)]; int retLen = cipher.processBytes(plainBytes, 0, plainBytes.length, encryptedBytes, 0); cipher.doFinal(encryptedBytes, retLen); sr = Base64.getEncoder().encodeToString(encryptedBytes); } catch (Exception ex) { throw new RuntimeException(ex.getMessage()); } return sr; } /** * 解密 * * @param encryptedText 已加密文本 * @param key 密钥 * @param iv 向量 * @return 已解密文本 */ public static String decrypt(String encryptedText, byte[] key, byte[] iv) { String sr; try { byte[] encryptedBytes = Base64.getDecoder().decode(encryptedText); GCMBlockCipher cipher = new GCMBlockCipher(new AESFastEngine()); AEADParameters parameters = new AEADParameters(new KeyParameter(key), MAC_BIT_SIZE, iv, null); cipher.init(false, parameters); byte[] plainBytes = new byte[cipher.getOutputSize(encryptedBytes.length)]; int retLen = cipher.processBytes(encryptedBytes, 0, encryptedBytes.length, plainBytes, 0); cipher.doFinal(plainBytes, retLen); sr = new String(plainBytes, StandardCharsets.UTF_8); } catch (IllegalArgumentException | IllegalStateException | DataLengthException | InvalidCipherTextException ex) { throw new RuntimeException(ex.getMessage()); } return sr; } }
调用工具类对明文加密获得密文:
AesGcm256Util.encrypt(JsonUtils.toJson(list), AesGcm256Util.hexToByte(AesSecretKey), AesGcm256Util.hexToByte(iv))
RSA:
package login; import javax.crypto.Cipher; import java.security.*; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.Base64; public class RSAUtil { static final Base64.Decoder decoder = Base64.getDecoder(); static final Base64.Encoder encoder = Base64.getEncoder(); public static void main(String[] args) throws Exception { // 随机生成一对密钥(包含公钥和私钥) KeyPair keyPair = generateKeyPair(); // 获取 公钥 和 私钥 RSAPublicKey pubKey = (RSAPublicKey) keyPair.getPublic(); // 创建 已编码的公钥规格 X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(pubKey.getEncoded()); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec); RSAPrivateKey priKey = (RSAPrivateKey) keyPair.getPrivate(); // 创建 已编码的私钥规格 PKCS8EncodedKeySpec pkcs8EncodedKeySpec5 = new PKCS8EncodedKeySpec(priKey.getEncoded()); PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec5); // 原文数据 String data = "你好, World!"; // 客户端: 用公钥加密原文, 返回加密后的数据 byte[] cipherData = encrypt(data.getBytes(), publicKey); // 服务端: 用私钥解密数据, 返回原文 byte[] plainData = decrypt(cipherData, privateKey); // 输出密文 System.out.println(new String(cipherData)); // 输出查看解密后的原文 System.out.println(new String(plainData)); // 结果打印: 你好, World } /** * 随机生成密钥对(包含公钥和私钥) */ private static KeyPair generateKeyPair() throws Exception { // 获取指定算法的密钥对生成器 KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA"); // 初始化密钥对生成器(密钥长度要适中, 太短不安全, 太长加密/解密速度慢) gen.initialize(2048); // 随机生成一对密钥(包含公钥和私钥) KeyPair keyPair = gen.generateKeyPair(); RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic(); RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate(); //公钥私钥base64编码 String publicKeyString = new String(encoder.encode(rsaPublicKey.getEncoded())); String privateKeyString = new String(encoder.encode(rsaPrivateKey.getEncoded())); return keyPair; } /** * 公钥加密数据 */ private static byte[] encrypt(byte[] plainData, PublicKey pubKey) throws Exception { // 获取指定算法的密码器 Cipher cipher = Cipher.getInstance("RSA"); // 初始化密码器(公钥加密模型) cipher.init(Cipher.ENCRYPT_MODE, pubKey); // 加密数据, 返回加密后的密文 return cipher.doFinal(plainData); } /** * 私钥解密数据 */ private static byte[] decrypt(byte[] cipherData, PrivateKey priKey) throws Exception { // 获取指定算法的密码器 Cipher cipher = Cipher.getInstance("RSA"); // 初始化密码器(私钥解密模型) cipher.init(Cipher.DECRYPT_MODE, priKey); // 解密数据, 返回解密后的明文 return cipher.doFinal(cipherData); } }
MD5加盐:
package login; import java.io.UnsupportedEncodingException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; public class PasswordEncoder { private final static String[] hexDigits = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" }; private Object salt; private String algorithm; public PasswordEncoder(Object salt, String algorithm) { this.salt = salt; this.algorithm = algorithm; } public String encode(String rawPass) { String result = null; try { //参数可以是"MD5","SHA"等 MessageDigest md = MessageDigest.getInstance(algorithm); //加密后的字符串 result = byteArrayToHexString(md.digest(mergePasswordAndSalt(rawPass).getBytes("utf-8"))); } catch (Exception ex) { } return result; } public boolean isPasswordValid(String encPass, String rawPass) { String pass1 = "" + encPass; String pass2 = encode(rawPass); return pass1.equals(pass2); } private String mergePasswordAndSalt(String password) { if (password == null) { password = ""; } if ((salt == null) || "".equals(salt)) { return password; } else { return password + "{" + salt.toString() + "}"; } } /** * 转换字节数组为16进制字串 * @param b 字节数组 * @return 16进制字串 */ 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(); } private static String byteToHexString(byte b) { int n = b; if (n < 0) n = 256 + n; int d1 = n / 16; int d2 = n % 16; return hexDigits[d1] + hexDigits[d2]; } public static void main(String[] args) throws NoSuchAlgorithmException, UnsupportedEncodingException { String salt = "be5e0323a9195ade5f56695ed9f2eb6b036f3e6417115d0cbe2fb9d74d8740406838dc84f152014b39a2414fb3530a40bc028a9e87642bd03cf5c36a1f70801e"; PasswordEncoder encoderMd5 = new PasswordEncoder(salt, "MD5"); String encode = encoderMd5.encode("zxp52077"); System.out.println(encode); boolean passwordValid = encoderMd5.isPasswordValid("c21feb87d79fd42e4336e4c231785ff9", "test"); System.out.println(passwordValid); PasswordEncoder encoderSha = new PasswordEncoder(salt, "SHA"); String pass2 = encoderSha.encode("test"); System.out.println(pass2); boolean passwordValid2 = encoderSha.isPasswordValid("409cf43cbdc92e1979018b2e2fdc60c7f07673e9", "test"); System.out.println(passwordValid2); } }
对称加密和非对称加密经常结合使用,比如: 客户端从服务器获取公钥,之后用这个公钥加密AES对称加密的密钥,服务端用私钥解密,获得 AES 密钥,之后双方用对称加密(AES)传输数据,高效安全
浙公网安备 33010602011771号