Java加解密工具類源碼示例
一、對稱加密算法
加密和解密使用相同密鑰的加密算法。常用的算法包括DES、3DES、AES、DESX、Blowfish、RC4、RC5、RC6。
DES(Data Encryption Standard):數(shù)據(jù)加密標(biāo)準(zhǔn),速度較快,適用于加密大量數(shù)據(jù)的場合。
3DES(Triple DES):是基于DES,對一塊數(shù)據(jù)用三個不同的密鑰進(jìn)行三次加密,強(qiáng)度更高。
AES(Advanced Encryption Standard):高級加密標(biāo)準(zhǔn),速度快,安全級別高【128位秘鑰】;
二、非對稱加密算法
加密和解密使用不同密鑰的加密算法,也稱為公私鑰加密。常見的算法包括RSA、DSA(數(shù)字簽名用)、ECC(移動設(shè)備用)、Diffie-Hellman、El Gamal。
- RSA:由 RSA 公司發(fā)明,是一個支持變長密鑰的公共密鑰算法,需要加密的文件塊的長度也是可變的;【建議1024位秘鑰】
- DSA:數(shù)字簽名算法,是一種標(biāo)準(zhǔn)的 DSS(數(shù)字簽名標(biāo)準(zhǔn))
- ECC:橢圓曲線密碼編碼學(xué)【建議160位秘鑰】。
ECC VS RSA
- 1)抗攻擊性強(qiáng)。相同的密鑰長度,其抗攻擊性要強(qiáng)很多倍。
- 2)計算量小,處理速度快。ECC總的速度比RSA、DSA要快得多。
- 3)存儲空間占用小。ECC的密鑰尺寸和系統(tǒng)參數(shù)與RSA、DSA相比要小得多,意味著它所占的存貯空間要小得多。這對于加密算法在IC卡上的應(yīng)用具有特別重要的意義。
- 4)帶寬要求低。當(dāng)對長消息進(jìn)行加解密時,三類密碼系統(tǒng)有相同的帶寬要求,但應(yīng)用于短消息時ECC帶寬要求卻低得多。帶寬要求低使ECC在無線網(wǎng)絡(luò)領(lǐng)域具有廣泛的應(yīng)用前景。
三、散列算法
除法散列法 平方散列法 斐波那契(Fibonacci)散列法 隨機(jī)數(shù)法
單向散列函數(shù)一般用于產(chǎn)生消息摘要,密鑰加密等,常用的算法包括MD2、MD4、MD5、HAVAL、SHA、SHA-1、HMAC、HMAC-MD5、HMAC-SHA1。
- MD5(Message Digest Algorithm 5):是RSA數(shù)據(jù)安全公司開發(fā)的一種單向散列算法,非可逆,相同的明文產(chǎn)生相同的密文。
- SHA(Secure Hash Algorithm):可以對任意長度的數(shù)據(jù)運(yùn)算生成一個160位的數(shù)值;
SHA-1 VS MD5 [二者均由MD4導(dǎo)出]
- 1)SHA-1摘要比MD5摘要長32位。使用強(qiáng)行技術(shù),產(chǎn)生任何一個報文使其摘要等于給定報摘要的難度對MD5是2^(128)數(shù)量級的操作,而對SHA-1則是2^(160)數(shù)量級的操作。這樣,SHA-1對強(qiáng)行攻擊有更大的強(qiáng)度。
- 2)MD5易受密碼分析的攻擊,SHA-1顯得不易受這樣的攻擊。
- 3)在相同的硬件上,SHA-1的運(yùn)行速度比MD5慢。
四、加密算法的選擇
1.單方密碼存儲建議直接使用散列算法(MD5即可,配合密碼更新策略)。
2.內(nèi)部信息加密傳輸建議使用對稱加密效率跟高(AES)。
3.外部數(shù)據(jù)傳輸建議使用非對稱加密,秘鑰保存更安全(RSA)。
4.HTTPS高級用法:采用非對稱加密算法管理對稱算法的密鑰,然后用對稱加密算法加密數(shù)據(jù),這樣我們就集成了兩類加密算法的優(yōu)點,既實現(xiàn)了加密速度快的優(yōu)點,又實現(xiàn)了安全方便管理密鑰的優(yōu)點。
五、上源碼
5.1 AES對稱加密
import lombok.extern.slf4j.Slf4j; import org.apache.commons.codec.binary.Base64; import org.apache.commons.lang3.ArrayUtils; import org.springframework.util.StringUtils; import javax.crypto.Cipher; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import java.nio.charset.StandardCharsets; /** * <p> * AES加密工具 * </p> * * @author ocean * @version 1.0.0 * @date 2023/5/4 14:51 */ @Slf4j public class AESUtils { // 秘鑰 16 private static final String SECRET_KEY = "1111111111111111"; // 秘鑰 24 //private static final String SECRET_KEY = "111111111111111122222222"; // 秘鑰 32 //private static final String SECRET_KEY = "11111111111111112222222233333333"; // 算法 private static final String ALGORITHM = "AES"; private static final String UTF8 = StandardCharsets.UTF_8.name(); /** * 字符串加密 * * @param message 明文字符串 * @param secretKey 秘鑰 * @return 加密字符串 */ public static String encryption(String message, String secretKey) { if (!StringUtils.hasLength(message)) { log.error("encryption message should not be null or empty."); } byte[] encodeBytes = encryption(message.getBytes(StandardCharsets.UTF_8), secretKey); return Base64.encodeBase64String(encodeBytes); } /** * 字符串加密 * * @param messageBytes 明文字節(jié)數(shù)組 * @param secretKey 秘鑰 * @return 加密字節(jié)數(shù)組 */ public static byte[] encryption(byte[] messageBytes, String secretKey) { if (ArrayUtils.isEmpty(messageBytes)) { log.error("encryption message should not be empty."); } if (!StringUtils.hasLength(secretKey)) { log.error("secretKey {}, encryption key should not be null or empty.", secretKey); } Cipher cipher = getCipher(secretKey, Cipher.ENCRYPT_MODE); byte[] encryptionBytes = null; try { encryptionBytes = cipher.doFinal(messageBytes); } catch (Exception e) { log.error("encryption fail. ", e); } return encryptionBytes; } /** * 字符串加密 * * @param encryptionMessage 加密字符串 * @param secretKey 秘鑰 * @return 明文字符串 */ public static String decrypt(String encryptionMessage, String secretKey) { if (!StringUtils.hasLength(encryptionMessage)) { log.error("decrypt encryptionMessage should not be null or empty."); } byte[] decodeBytes = decrypt(Base64.decodeBase64(encryptionMessage.getBytes(StandardCharsets.UTF_8)), secretKey); return new String(decodeBytes, StandardCharsets.UTF_8); } /** * 字符串加密 * * @param encryptedBytes 加密字節(jié)數(shù)組 * @param secretKey 秘鑰 * @return 明文字節(jié)數(shù)組 */ public static byte[] decrypt(byte[] encryptedBytes, String secretKey) { if (ArrayUtils.isEmpty(encryptedBytes)) { log.error("decrypt encryptedBytes should not be empty."); } if (!StringUtils.hasLength(secretKey)) { log.error("secretKey {}, decrypt key should not be null or empty.", secretKey); } Cipher cipher = getCipher(secretKey, Cipher.DECRYPT_MODE); byte[] decodeBytes = null; try { decodeBytes = cipher.doFinal(encryptedBytes); } catch (Exception e) { log.error("decrypt fail. ", e); } return decodeBytes; } private static Cipher getCipher(String key, int mode) { Cipher cipher = null; SecretKey secretKey; try { cipher = Cipher.getInstance(ALGORITHM); byte[] keyBytes = key.getBytes(UTF8); secretKey = new SecretKeySpec(keyBytes, ALGORITHM); cipher.init(mode, secretKey); } catch (Exception e) { log.error("getAESCipher fail. ", e); } return cipher; } public static void main(String[] args) { String data = "ocean測試!@#"; log.info("AES秘鑰長度只能為16、24、32:{}", SECRET_KEY.getBytes(StandardCharsets.UTF_8).length); String encryptionData = encryption(data, SECRET_KEY); log.info("加密后:{}", encryptionData); String decryptData = decrypt(encryptionData, SECRET_KEY); log.info("解密后:{}", decryptData); } }
5.2 RSA非對稱加密
PSCK#8 - PSCK#1 <!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on --> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk15on</artifactId> <version>1.52</version> </dependency>
import java.io.StringWriter; import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.Signature; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.HashMap; import java.util.Map; import javax.crypto.Cipher; import org.apache.commons.codec.binary.Base64; import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.util.io.pem.PemObject; import org.bouncycastle.util.io.pem.PemWriter; import sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder; public class RsaUtils { public static final int KEY_SIZE = 2048; public static final String ALGORITHM = "RSA"; public static final String PUBLIC_KEY = "xxxxpublicKeyxxxx"; public static final String PRIVATE_KEY = "xxxxprivateKeyxxxx"; public static final String CLEAR_TEXT_STRING = "明文字符串"; public static BASE64Encoder encoder = new BASE64Encoder(); public static BASE64Decoder decoder = new BASE64Decoder(); public static void main(String[] args) throws Exception { // PSCK#8 Map<String, String> keyMap = RsaUtil.generateKeyBytes(); System.out.println("PSCK#8-PRIVATEKEY:"+ keyMap.get(RsaUtil.PRIVATE_KEY)); System.out.println("PSCK#8-PUBLICKEY:" + keyMap.get(RsaUtil.PUBLIC_KEY)); PublicKey publicKey8 = RsaUtil.restorePublicKey(keyMap.get(RsaUtil.PUBLIC_KEY)); PrivateKey privateKey8 = RsaUtil.restorePrivateKey(keyMap.get(RsaUtil.PRIVATE_KEY)); // ============公鑰加密-私鑰解密============ Cipher cipher = Cipher.getInstance(ALGORITHM); cipher.init(Cipher.ENCRYPT_MODE, publicKey8); String messageEn = Base64.encodeBase64String(cipher.doFinal(CLEAR_TEXT_STRING.getBytes("UTF-8"))); System.out.println(CLEAR_TEXT_STRING + "\t加密后的字符串為:" + messageEn); cipher.init(Cipher.DECRYPT_MODE, privateKey8); String messageDe = new String(cipher.doFinal(Base64.decodeBase64(messageEn.getBytes("UTF-8")))); System.out.println("還原后的字符串為:" + messageDe); // ============公鑰加密-私鑰解密============ // ============PSCK#8>PSCK#1============ byte[] privBytes = privateKey8.getEncoded(); PrivateKeyInfo pkInfo = PrivateKeyInfo.getInstance(privBytes); ASN1Encodable encodable = pkInfo.getPrivateKey(); ASN1Primitive primitive = encodable.toASN1Primitive(); byte[] privateKeyPKCS1 = primitive.getEncoded(); PemObject pemObject = new PemObject("RSA PRIVATE KEY", privateKeyPKCS1); StringWriter stringWriter = new StringWriter(); PemWriter pemWriter = new PemWriter(stringWriter); pemWriter.writeObject(pemObject); pemWriter.close(); String pemString = stringWriter.toString(); System.out.println("PSCK#1-PRIVATEKEY:" + pemString); byte[] pubBytes = publicKey8.getEncoded(); SubjectPublicKeyInfo spkInfo = SubjectPublicKeyInfo .getInstance(pubBytes); ASN1Primitive punlic = spkInfo.parsePublicKey(); byte[] publicKeyPKCS1 = punlic.getEncoded(); PemObject punlicpemObject = new PemObject("RSA PUBLIC KEY", publicKeyPKCS1); StringWriter punlicstringWriter = new StringWriter(); PemWriter punlicpemWriter = new PemWriter(punlicstringWriter); punlicpemWriter.writeObject(punlicpemObject); punlicpemWriter.close(); String publicemString = punlicstringWriter.toString(); System.out.println("PSCK#8-PUBLICKEY:" + publicemString); // ============PSCK#8>PSCK#1============ // ============私鑰簽名公鑰驗簽============ // PSCK#8-PRIVATEKEY 私鑰簽名 Signature signature = Signature.getInstance("SHA256WithRSA"); signature.initSign(privateKey8); signature.update(CLEAR_TEXT_STRING.getBytes()); byte[] signed = signature.sign(); String sign = encoder.encode(signed); // PSCK#8-PUBLICKEY 公鑰驗簽 signature.initVerify(publicKey8); signature.update(CLEAR_TEXT_STRING.getBytes()); boolean verify = signature.verify(decoder.decodeBuffer(sign)); System.out.println("CLEAR_TEXT_STRING:" + CLEAR_TEXT_STRING); System.out.println("SIGN:" + sign.replaceAll("\r|\n", "")); System.out.println(verify); // ============私鑰簽名公鑰驗簽============ } /** * 公私鑰生成 * * @return */ public static Map<String, String> generateKeyBytes() { try { KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM); keyPairGenerator.initialize(KEY_SIZE); KeyPair keyPair = keyPairGenerator.generateKeyPair(); RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); Map<String, String> keyMap = new HashMap<String, String>(); keyMap.put(PUBLIC_KEY, new String(Base64.encodeBase64(publicKey.getEncoded()))); keyMap.put(PRIVATE_KEY, new String(Base64.encodeBase64(privateKey.getEncoded()))); return keyMap; } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return null; } /** * 公鑰生成 * @param key * @return */ public static PublicKey restorePublicKey(String key) { X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64.decodeBase64(key)); try { KeyFactory factory = KeyFactory.getInstance(ALGORITHM); PublicKey publicKey = factory.generatePublic(x509EncodedKeySpec); return publicKey; } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { e.printStackTrace(); } return null; } /** * 私鑰生成 * @param key * @return */ public static PrivateKey restorePrivateKey(String key) { PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(key)); try { KeyFactory factory = KeyFactory.getInstance(ALGORITHM); PrivateKey privateKey = factory .generatePrivate(pkcs8EncodedKeySpec); return privateKey; } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { e.printStackTrace(); } return null; } }
5.3 MD5散列算法
import lombok.extern.slf4j.Slf4j; import java.security.MessageDigest; @Slf4j public class MD5Util { public static final int SIZE_FACTOR = 2; private static final String[] hexDigits = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"}; public static String MD5Encode(String origin, String charsetname) { String resultString = null; try { resultString = origin; MessageDigest md = MessageDigest.getInstance("MD5"); if (charsetname == null || "".equals(charsetname)) { resultString = byteArrayToHexString(md.digest(resultString.getBytes())); } else { resultString = byteArrayToHexString(md.digest(resultString.getBytes(charsetname))); } } catch (Exception exception) { log.error("MD5Util MD5Encode error", exception); } return resultString; } 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; } int d1 = n / 16; int d2 = n % 16; return hexDigits[d1] + hexDigits[d2]; } public static String encode(String str) { try { byte[] hash = MessageDigest.getInstance("MD5").digest(str.getBytes("utf-8")); StringBuilder hex = new StringBuilder(hash.length * SIZE_FACTOR); for (byte b : hash) { hex.append(String.format("%02x", b)); } return hex.toString(); } catch (Exception e) { log.error("MD5 encode error for {}, error is {}", str, e.getMessage(), e); } return null; } }
總結(jié)
到此這篇關(guān)于Java加解密工具類的文章就介紹到這了,更多相關(guān)Java加解密工具類內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解SpringBoot結(jié)合swagger2快速生成簡單的接口文檔
這篇文章主要介紹了詳解SpringBoot結(jié)合swagger2快速生成簡單的接口文檔,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-05-05@Valid 校驗無效,BindingResult未獲得錯誤的解決
這篇文章主要介紹了@Valid 校驗無效,BindingResult未獲得錯誤的解決,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-10-10SpringMVC前端和后端數(shù)據(jù)交互總結(jié)
本篇文章主要介紹了SpringMVC前端和后端數(shù)據(jù)交互總結(jié),具有一定的參考價值,感興趣的小伙伴們可以參考一下。2017-03-03Java8?Stream?collect(Collectors.toMap())的使用
這篇文章主要介紹了Java8?Stream?collect(Collectors.toMap())的使用,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-05-05