赞
踩
加密算法分为可逆、不可逆加密算法。而不可逆加密算法又分为对称加密和非对称加密
HMAC
是需要密钥的!
MD5
,HMAC
,SHA1
、SHA-224
、SHA-256
、SHA-384
,和SHA-512
。其中SHA-224、SHA-256、SHA-384,和SHA-512我们可以统称为SHA2
加密算法,SHA加密算法的安全性要比MD5更高,而SHA2加密算法比SHA1的要高。其中SHA后面的数字表示的是加密后的字符串长度,SHA1默认会产生一个160
位的信息摘要。DES
、3DES
、AES128
、AES192
、AES256
RSA
、SM2
,RS256 (采用SHA-256 的 RSA 签名)
==
”结尾的字符串。如:Z38cPD5XbiPZ41LKQmhZAw==
!
MD5 信息摘要算法(英语:MD5 Message-Digest Algorithm),一种被广泛使用的密码散列函数,可以产生出一个
128
位(16字节)的散列值(hash value),用于确保信息传输完整一致。
MD5算法有以下特点:
public static String md5(String text) {
MessageDigest messageDigest = null;
try {
messageDigest = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
byte[] bytes = messageDigest.digest(text.getBytes());
//也可以使用base64转码成字符串
// return Base64.getEncoder().encodeToString(bytes);
//使用 Hex转码
return Hex.encodeHexString(bytes);
}
HMAC算法更像是一种加密算法,它引入了密钥,其安全性已经不完全依赖于所使用的Hash算法。
HMAC是密钥相关的哈希运算消息认证码(Hash-based Message Authentication Code)的缩写,由H.Krawezyk,M.Bellare,R.Canetti于1996年提出的一种基于Hash函数和密钥进行消息认证的方法,并于1997年作为RFC2104被公布,并在IPSec和其他网络协议(如SSL)中得以广泛应用,现在已经成为事实上的Internet安全标准。它可以与任何迭代散列函数捆绑使用。
public static String hmacSha256(String text, SecretKeySpec sk) {
Mac mac = null;
try {
mac = Mac.getInstance("HmacSHA256");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
try {
mac.init();
} catch (Exception e) {
e.printStackTrace();
}
byte[] rawHmac = mac.doFinal(text.getBytes());
return Base64.getEncoder().encodeToString(rawHmac);
}
安全散列算法(英语:Secure Hash Algorithm,缩写为SHA)是一个密码散列函数家族,是FIPS所认证的安全散列算法。能计算出一个数字消息所对应到的,长度固定的字符串(又称消息摘要)的算法。且若输入的消息不同,它们对应到不同字符串的机率很高。SHA-1加密算法有碰撞的可能性,虽然很小。
public static String sha256(String text) {
MessageDigest messageDigest = null;
try {
messageDigest = MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
byte[] bytes = messageDigest.digest(text.getBytes());
return Hex.encodeHexString(bytes);
}
可逆加密算法又分为 对称加密 和 分对称加密
对称加密算法是应用比较早的算法,在数据加密和解密的时用的都是同一个密钥,这就造成了密钥管理困难的问题。常见的对称加密算法有DES
、3DES
、AES128
、AES192
、AES256
(默认安装的 JDK 尚不支持 AES256,需要安装对应的 jce 补丁进行升级 jce1.7,jce1.8)。其中AES后面的数字代表的是密钥长度。对称加密算法的安全性相对较低,比较适用的场景就是内网环境中的加解密。
DES是对称加密算法领域中的典型算法,其密钥默认长度为56位。
// 加密 public static String encrypt(byte[] dataSource, String password){ try { SecureRandom random = new SecureRandom(); DESKeySpec desKeySpec = new DESKeySpec(password.getBytes()); //创建一个密匙工厂,然后用它把DESKeySpec转换成 SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("DES"); SecretKey secretKey = secretKeyFactory.generateSecret(desKeySpec); //Cipher对象实际完成加密操作 Cipher cipher = Cipher.getInstance("DES"); //用密匙初始化Cipher对象 cipher.init(Cipher.ENCRYPT_MODE, secretKey, random); //正式执行加密操作 return Base64.encodeBase64String(cipher.doFinal(dataSource)); } catch (Throwable e) { e.printStackTrace(); } return null; } // 解密 public static String decrypt(String src, String password) throws Exception{ // DES算法要求有一个可信任的随机数源 SecureRandom random = new SecureRandom(); // 创建一个DESKeySpec对象 DESKeySpec desKeySpec = new DESKeySpec(password.getBytes()); // 创建一个密匙工厂 SecretKeyFactory keyFactory= SecretKeyFactory.getInstance("DES"); // 将DESKeySpec对象转换成SecretKey对象 SecretKey secretKey = keyFactory.generateSecret(desKeySpec); // Cipher对象实际完成解密操作 Cipher cipher = Cipher.getInstance("DES"); // 用密匙初始化Cipher对象 cipher.init(Cipher.DECRYPT_MODE, secretKey, random); // 真正开始解密操作 return new String(cipher.doFinal(Base64.decodeBase64(src))); }
3DES(即Triple DES)是DES向AES过渡的加密算法,它使用3条56位的密钥对数据进行三次加密。是DES的一个更安全的变形。它以DES为基本模块,通过组合分组方法设计出分组加密算法。比起最初的DES,3DES更为安全。密钥长度默认为168位,还可以选择128位。
// 加密 public static String encryptThreeDESECB(String src, String key) { try{ DESedeKeySpec dks = new DESedeKeySpec(key.getBytes("UTF-8")); SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede"); SecretKey securekey = keyFactory.generateSecret(dks); Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding"); cipher.init(Cipher.ENCRYPT_MODE, securekey); byte[] b = cipher.doFinal(src.getBytes("UTF-8")); String ss = new String(Base64.encodeBase64(b)); ss = ss.replaceAll("\\+", "-"); ss = ss.replaceAll( "/", "_"); return ss; } catch(Exception ex){ ex.printStackTrace(); return src; } } // 解密 public static String decryptThreeDESECB(String src, String key) { try{ src = src.replaceAll("-", "+"); src = src.replaceAll("_", "/"); byte[] bytesrc = Base64.decodeBase64(src.getBytes("UTF-8")); // --解密的key DESedeKeySpec dks = new DESedeKeySpec(key.getBytes("UTF-8")); SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede"); SecretKey securekey = keyFactory.generateSecret(dks); // --Chipher对象解密 Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding"); cipher.init(Cipher.DECRYPT_MODE, securekey); byte[] retByte = cipher.doFinal(bytesrc); return new String(retByte, "UTF-8"); } catch(Exception ex){ ex.printStackTrace(); return src; } }
AES高级数据加密标准,能够有效抵御已知的针对DES算法的所有攻击,默认密钥长度为128位,还可以供选择192位,256位。这里顺便提一句这个位指的是bit。
private static final String defaultCharset = "UTF-8"; private static final String KEY_AES = "AES"; private static final String KEY_MD5 = "MD5"; private static MessageDigest md5Digest; static { try { md5Digest = MessageDigest.getInstance(KEY_MD5); } catch (NoSuchAlgorithmException e) { } } /** * 加密 */ public static String encrypt(String data, String key) { return doAES(data, key, Cipher.ENCRYPT_MODE); } /** * 解密 */ public static String decrypt(String data, String key) { return doAES(data, key, Cipher.DECRYPT_MODE); } /** * 加解密 */ private static String doAES(String data, String key, int mode) { try { boolean encrypt = mode == Cipher.ENCRYPT_MODE; byte[] content; if (encrypt) { content = data.getBytes(defaultCharset); } else { content = Base64.decodeBase64(data.getBytes()); } SecretKeySpec keySpec = new SecretKeySpec(md5Digest.digest(key.getBytes(defaultCharset)) , KEY_AES); Cipher cipher = Cipher.getInstance(KEY_AES);// 创建密码器 cipher.init(mode, keySpec);// 初始化 byte[] result = cipher.doFinal(content); if (encrypt) { return new String(Base64.encodeBase64(result)); } else { return new String(result, defaultCharset); } } catch (Exception e) { } return null; }
非对称加密算法有两个密钥,这两个密钥完全不同但又完全匹配。只有使用匹配的一对公钥和私钥,才能完成对明文的加密和解密过程。常见的非对称加密有RSA、SM2等。
RSA密钥至少为500位长,一般推荐使用1024位
//非对称密钥算法 public static final String KEY_ALGORITHM = "RSA"; /** * 密钥长度,DH算法的默认密钥长度是1024 * 密钥长度必须是64的倍数,在512到65536位之间 */ private static final int KEY_SIZE = 1024; //公钥 private static final String PUBLIC_KEY = "RSAPublicKey"; //私钥 private static final String PRIVATE_KEY = "RSAPrivateKey"; /** * 初始化密钥对 * * @return Map 甲方密钥的Map */ public static Map<String, Object> initKey() throws Exception { //实例化密钥生成器 KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM); //初始化密钥生成器 keyPairGenerator.initialize(KEY_SIZE); //生成密钥对 KeyPair keyPair = keyPairGenerator.generateKeyPair(); //甲方公钥 RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); //甲方私钥 RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); //将密钥存储在map中 Map<String, Object> keyMap = new HashMap<String, Object>(); keyMap.put(PUBLIC_KEY, publicKey); keyMap.put(PRIVATE_KEY, privateKey); return keyMap; } /** * 私钥加密 * * @param data 待加密数据 * @param key 密钥 * @return byte[] 加密数据 */ public static byte[] encryptByPrivateKey(byte[] data, byte[] key) throws Exception { //取得私钥 PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(key); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); //生成私钥 PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec); //数据加密 Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.ENCRYPT_MODE, privateKey); return cipher.doFinal(data); } /** * 公钥加密 * * @param data 待加密数据 * @param key 密钥 * @return byte[] 加密数据 */ public static byte[] encryptByPublicKey(byte[] data, byte[] key) throws Exception { //实例化密钥工厂 KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); //初始化公钥 //密钥材料转换 X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(key); //产生公钥 PublicKey pubKey = keyFactory.generatePublic(x509KeySpec); //数据加密 Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.ENCRYPT_MODE, pubKey); return cipher.doFinal(data); } /** * 私钥解密 * * @param data 待解密数据 * @param key 密钥 * @return byte[] 解密数据 */ public static byte[] decryptByPrivateKey(byte[] data, byte[] key) throws Exception { //取得私钥 PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(key); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); //生成私钥 PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec); //数据解密 Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.DECRYPT_MODE, privateKey); return cipher.doFinal(data); } /** * 公钥解密 * * @param data 待解密数据 * @param key 密钥 * @return byte[] 解密数据 */ public static byte[] decryptByPublicKey(byte[] data, byte[] key) throws Exception { //实例化密钥工厂 KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); //初始化公钥 //密钥材料转换 X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(key); //产生公钥 PublicKey pubKey = keyFactory.generatePublic(x509KeySpec); //数据解密 Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.DECRYPT_MODE, pubKey); return cipher.doFinal(data); } /** * 取得私钥 * * @param keyMap 密钥map * @return byte[] 私钥 */ public static byte[] getPrivateKey(Map<String, Object> keyMap) { Key key = (Key) keyMap.get(PRIVATE_KEY); return key.getEncoded(); } /** * 取得公钥 * * @param keyMap 密钥map * @return byte[] 公钥 */ public static byte[] getPublicKey(Map<String, Object> keyMap) throws Exception { Key key = (Key) keyMap.get(PUBLIC_KEY); return key.getEncoded(); }
Base64是网络上最常见的用于传输8Bit字节代码的编码方式之一。Base64编码可用于在HTTP环境下传递较长的标识信息。采用Base64Base64编码解码具有不可读性,即所编码的数据不会被人用肉眼所直接看到。注意:Base64只是一种编码方式,不算加密方法。
java.util.Base64.getEncoder().encodeToString(bytes);
在线Base64编码工具:http://www.jsons.cn/img2base64/
在系统架构中,对于用户密码的保护,通常都会进行加密。我们通常对密码进行加密,然后存放在数据库中,在用户进行登录的时候,将其输入的密码进行加密然后与数据库中存放的密文进行比较,以验证用户密码是否正确。 目前,MD5和BCrypt比较流行。相对来说,BCrypt比MD5更安全。
//这个是盐 29个字符,随机生成
String gensalt = BCrypt.gensalt();
System.out.println(gensalt);
//根据盐对密码进行加密
String password = BCrypt.hashpw("password666", gensalt);
System.out.println(password);//加密后的字符串前29位就是盐
//实现对密码的校验。BCrypt不支持反运算,只支持密码校验。
boolean checkpw = BCrypt.checkpw("password666", "$2a$10$61ogZY7EXsMDWeVGQpDq3OBF1.phaUu7.xrwLyWFTOu8woE08zMIW");
System.out.println(checkpw);
BCrypt的使用:以登录为例
对密码加密,并入库
@Override
public void add(User user){
String password = BCrypt.hashpw(User.getPassword(), BCrypt.gensalt());
user.setPassword(password);
userMapper.insert(user); //加密结果入库
}
登录时,校验密码是否正确
@Override
public boolean login(User user) {
//根据登录名查询管理员
User u1=new User();
u1.setLoginName(User.getLoginName());
u1.setStatus("1");
User u2 = UserMapper.selectOne(u1);//数据库查询出的对象
if(u2==null){
return false;
}else{
//验证密码, Bcrypt为spring的包, 第一个参数为明文密码, 第二个参数为密文密码
return BCrypt.checkpw(u1.getPassword(),u2.getPassword());
}
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。