加密算法我们整体可以分为:可逆加密和不可逆加密,可逆加密又可以分为:对称加密和非对称加密。
一、不可逆加密
常见的不可逆加密算法有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位的信息摘要。
不可逆加密算法最大的特点就是密钥,但是HMAC是需要密钥的【手动狗头】。
由于这些加密都是不可逆的,因此比较常用的场景就是用户密码加密,其验证过程就是通过比较两个加密后的字符串是否一样来确认身份的。网上也有很多自称是可以破解MD5密码的网站,其原理也是一样,就是有一个巨大的资源库,存放了许多字符串及对应的MD5加密后的字符串,通过你输入的MD5加密串来进行比较,如果过你的密码复杂度比较低,还是有很大机率验证出来的。
1.1 MD5
MD5信息摘要算法(英语:MD5 Message-Digest Algorithm),一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致。
MD5算法有以下特点:
1、压缩性:无论数据长度是多少,计算出来的MD5值长度相同
2、容易计算性:由原数据容易计算出MD5值
3、抗修改性:即便修改一个字节,计算出来的MD5值也会巨大差异
4、抗碰撞性:知道数据和MD5值,很小概率找到相同MD5值相同的原数据。
publicstaticStringmd5(Stringtext){MessageDigestmessageDigest=null;try{messageDigest=MessageDigest.getInstance("MD5");}catch(NoSuchAlgorithmExceptione){e.printStackTrace();}byte[]bytes=messageDigest.digest(text.getBytes());returnHex.encodeHexString(bytes);}
1.2 SHA系列
安全散列算法(英语:Secure Hash Algorithm,缩写为SHA)是一个密码散列函数家族,是FIPS所认证的安全散列算法。能计算出一个数字消息所对应到的,长度固定的字符串(又称消息摘要)的算法。且若输入的消息不同,它们对应到不同字符串的机率很高。
2005年8月17日的CRYPTO会议尾声中王小云、姚期智、姚储枫再度发表更有效率的SHA-1攻击法,能在2的63次方个计算复杂度内找到碰撞。
也就是说SHA-1加密算法有碰撞的可能性,虽然很小。
publicstaticStringsha256(Stringtext){MessageDigestmessageDigest=null;try{messageDigest=MessageDigest.getInstance("SHA-256");}catch(NoSuchAlgorithmExceptione){e.printStackTrace();}byte[]bytes=messageDigest.digest(text.getBytes());returnHex.encodeHexString(bytes);}
1.3 HMAC系列
HMAC是密钥相关的哈希运算消息认证码(Hash-based Message Authentication Code)的缩写,由H.Krawezyk,M.Bellare,R.Canetti于1996年提出的一种基于Hash函数和密钥进行消息认证的方法,并于1997年作为RFC2104被公布,并在IPSec和其他网络协议(如SSL)中得以广泛应用,现在已经成为事实上的Internet安全标准。它可以与任何迭代散列函数捆绑使用。
HMAC算法更像是一种加密算法,它引入了密钥,其安全性已经不完全依赖于所使用的Hash算法
publicstaticStringhmacSha256(Stringtext,SecretKeySpecsk){Macmac=null;try{mac=Mac.getInstance("HmacSHA256");}catch(NoSuchAlgorithmExceptione){e.printStackTrace();}try{mac.init(sk);}catch(InvalidKeyExceptione){e.printStackTrace();}byte[]rawHmac=mac.doFinal(text.getBytes());returnnewString(Base64.encodeBase64(rawHmac));
如果要使用不可逆加密,推荐使用SHA256、SHA384、SHA512以及HMAC-SHA256、HMAC-SHA384、HMAC-SHA512这几种算法。
二、对称加密算法
对称加密算法是应用比较早的算法,在数据加密和解密的时用的都是同一个密钥,这就造成了密钥管理困难的问题。常见的对称加密算法有DES、3DES、AES128、AES192、AES256 (默认安装的 JDK 尚不支持 AES256,需要安装对应的 jce 补丁进行升级 jce1.7,jce1.8)。其中AES后面的数字代表的是密钥长度。对称加密算法的安全性相对较低,比较适用的场景就是内网环境中的加解密。
2.1 DES
DES是对称加密算法领域中的典型算法,其密钥默认长度为56位。
/加密publicstaticStringencrypt(byte[]dataSource,Stringpassword){try{SecureRandomrandom=newSecureRandom();DESKeySpecdesKeySpec=newDESKeySpec(password.getBytes());//创建一个密匙工厂,然后用它把DESKeySpec转换成SecretKeyFactorysecretKeyFactory=SecretKeyFactory.getInstance("DES");SecretKeysecretKey=secretKeyFactory.generateSecret(desKeySpec);//Cipher对象实际完成加密操作Ciphercipher=Cipher.getInstance("DES");//用密匙初始化Cipher对象cipher.init(Cipher.ENCRYPT_MODE,secretKey,random);//正式执行加密操作returnBase64.encodeBase64String(cipher.doFinal(dataSource));}catch(Throwablee){e.printStackTrace();}returnnull;}//解密publicstaticStringdecrypt(Stringsrc,Stringpassword)throwsException{//DES算法要求有一个可信任的随机数源SecureRandomrandom=newSecureRandom();//创建一个DESKeySpec对象DESKeySpecdesKeySpec=newDESKeySpec(password.getBytes());//创建一个密匙工厂SecretKeyFactorykeyFactory=SecretKeyFactory.getInstance("DES");//将DESKeySpec对象转换成SecretKey对象SecretKeysecretKey=keyFactory.generateSecret(desKeySpec);//Cipher对象实际完成解密操作Ciphercipher=Cipher.getInstance("DES");//用密匙初始化Cipher对象cipher.init(Cipher.DECRYPT_MODE,secretKey,random);//真正开始解密操作returnnewString(cipher.doFinal(Base64.decodeBase64(src)));}
2.2 3DES
3DES(即Triple DES)是DES向AES过渡的加密算法,它使用3条56位的密钥对数据进行三次加密。是DES的一个更安全的变形。它以DES为基本模块,通过组合分组方法设计出分组加密算法。比起最初的DES,3DES更为安全。密钥长度默认为168位,还可以选择128位。
publicstaticStringencryptThreeDESECB(Stringsrc,Stringkey){try{DESedeKeySpecdks=newDESedeKeySpec(key.getBytes("UTF-8"));SecretKeyFactorykeyFactory=SecretKeyFactory.getInstance("DESede");SecretKeysecurekey=keyFactory.generateSecret(dks);Ciphercipher=Cipher.getInstance("DESede/ECB/PKCS5Padding");cipher.init(Cipher.ENCRYPT_MODE,securekey);byte[]b=cipher.doFinal(src.getBytes("UTF-8"));Stringss=newString(Base64.encodeBase64(b));ss=ss.replaceAll("\\+","-");ss=ss.replaceAll("/","_");returnss;}catch(Exceptionex){ex.printStackTrace();returnsrc;}}publicstaticStringdecryptThreeDESECB(Stringsrc,Stringkey){try{src=src.replaceAll("-","+");src=src.replaceAll("_","/");byte[]bytesrc=Base64.decodeBase64(src.getBytes("UTF-8"));//DESedeKeySpecdks=newDESedeKeySpec(key.getBytes("UTF-8"));SecretKeyFactorykeyFactory=SecretKeyFactory.getInstance("DESede");SecretKeysecurekey=keyFactory.generateSecret(dks);//Ciphercipher=Cipher.getInstance("DESede/ECB/PKCS5Padding");cipher.init(Cipher.DECRYPT_MODE,securekey);byte[]retByte=cipher.doFinal(bytesrc);returnnewString(retByte,"UTF-8");}catch(Exceptionex){ex.printStackTrace();returnsrc;}}
2.3 AES
AES 高级数据加密标准,能够有效抵御已知的针对DES算法的所有攻击,默认密钥长度为128位,还可以供选择192位,256位。这里顺便提一句这个位指的是bit。
privatestaticfinalStringdefaultCharset="UTF-8";privatestaticfinalStringKEY_AES="AES";privatestaticfinalStringKEY_MD5="MD5";privatestaticMessageDigestmd5Digest;static{try{md5Digest=MessageDigest.getInstance(KEY_MD5);}catch(NoSuchAlgorithmExceptione){}}/***加密*/publicstaticStringencrypt(Stringdata,Stringkey){returndoAES(data,key,Cipher.ENCRYPT_MODE);}/***解密*/publicstaticStringdecrypt(Stringdata,Stringkey){returndoAES(data,key,Cipher.DECRYPT_MODE);}/***加解密*/privatestaticStringdoAES(Stringdata,Stringkey,intmode){try{booleanencrypt=mode==Cipher.ENCRYPT_MODE;byte[]content;if(encrypt){content=data.getBytes(defaultCharset);}else{content=Base64.decodeBase64(data.getBytes());}SecretKeySpeckeySpec=newSecretKeySpec(md5Digest.digest(key.getBytes(defaultCharset)),KEY_AES);Ciphercipher=Cipher.getInstance(KEY_AES);//创建密码器cipher.init(mode,keySpec);//初始化byte[]result=cipher.doFinal(content);if(encrypt){returnnewString(Base64.encodeBase64(result));}else{returnnewString(result,defaultCharset);}}catch(Exceptione){}returnnull;}
推荐使用对称加密算法有:AES128、AES192、AES256。
三、非对称加密算法
非对称加密算法有两个密钥,这两个密钥完全不同但又完全匹配。只有使用匹配的一对公钥和私钥,才能完成对明文的加密和解密过程。常见的非对称加密有RSA、SM2等。
3.1 RSA
RSA密钥至少为500位长,一般推荐使用1024位。
//非对称密钥算法publicstaticfinalStringKEY_ALGORITHM="RSA";/***密钥长度,DH算法的默认密钥长度是1024*密钥长度必须是64的倍数,在512到65536位之间*/privatestaticfinalintKEY_SIZE=1024;//公钥privatestaticfinalStringPUBLIC_KEY="RSAPublicKey";//私钥privatestaticfinalStringPRIVATE_KEY="RSAPrivateKey";/***初始化密钥对**@returnMap甲方密钥的Map*/publicstaticMap<String,Object>initKey()throwsException{//实例化密钥生成器KeyPairGeneratorkeyPairGenerator=KeyPairGenerator.getInstance(KEY_ALGORITHM);//初始化密钥生成器keyPairGenerator.initialize(KEY_SIZE);//生成密钥对KeyPairkeyPair=keyPairGenerator.generateKeyPair();//甲方公钥RSAPublicKeypublicKey=(RSAPublicKey)keyPair.getPublic();//甲方私钥RSAPrivateKeyprivateKey=(RSAPrivateKey)keyPair.getPrivate();//将密钥存储在map中Map<String,Object>keyMap=newHashMap<String,Object>();keyMap.put(PUBLIC_KEY,publicKey);keyMap.put(PRIVATE_KEY,privateKey);returnkeyMap;}/***私钥加密**@paramdata待加密数据*@paramkey密钥*@returnbyte[]加密数据*/publicstaticbyte[]encryptByPrivateKey(byte[]data,byte[]key)throwsException{//取得私钥PKCS8EncodedKeySpecpkcs8KeySpec=newPKCS8EncodedKeySpec(key);KeyFactorykeyFactory=KeyFactory.getInstance(KEY_ALGORITHM);//生成私钥PrivateKeyprivateKey=keyFactory.generatePrivate(pkcs8KeySpec);//数据加密Ciphercipher=Cipher.getInstance(keyFactory.getAlgorithm());cipher.init(Cipher.ENCRYPT_MODE,privateKey);returncipher.doFinal(data);}/***公钥加密**@paramdata待加密数据*@paramkey密钥*@returnbyte[]加密数据*/publicstaticbyte[]encryptByPublicKey(byte[]data,byte[]key)throwsException{//实例化密钥工厂KeyFactorykeyFactory=KeyFactory.getInstance(KEY_ALGORITHM);//初始化公钥//密钥材料转换X509EncodedKeySpecx509KeySpec=newX509EncodedKeySpec(key);//产生公钥PublicKeypubKey=keyFactory.generatePublic(x509KeySpec);//数据加密Ciphercipher=Cipher.getInstance(keyFactory.getAlgorithm());cipher.init(Cipher.ENCRYPT_MODE,pubKey);returncipher.doFinal(data);}/***私钥解密**@paramdata待解密数据*@paramkey密钥*@returnbyte[]解密数据*/publicstaticbyte[]decryptByPrivateKey(byte[]data,byte[]key)throwsException{//取得私钥PKCS8EncodedKeySpecpkcs8KeySpec=newPKCS8EncodedKeySpec(key);KeyFactorykeyFactory=KeyFactory.getInstance(KEY_ALGORITHM);//生成私钥PrivateKeyprivateKey=keyFactory.generatePrivate(pkcs8KeySpec);//数据解密Ciphercipher=Cipher.getInstance(keyFactory.getAlgorithm());cipher.init(Cipher.DECRYPT_MODE,privateKey);returncipher.doFinal(data);}/***公钥解密**@paramdata待解密数据*@paramkey密钥*@returnbyte[]解密数据*/publicstaticbyte[]decryptByPublicKey(byte[]data,byte[]key)throwsException{//实例化密钥工厂KeyFactorykeyFactory=KeyFactory.getInstance(KEY_ALGORITHM);//初始化公钥//密钥材料转换X509EncodedKeySpecx509KeySpec=newX509EncodedKeySpec(key);//产生公钥PublicKeypubKey=keyFactory.generatePublic(x509KeySpec);//数据解密Ciphercipher=Cipher.getInstance(keyFactory.getAlgorithm());cipher.init(Cipher.DECRYPT_MODE,pubKey);returncipher.doFinal(data);}/***取得私钥**@paramkeyMap密钥map*@returnbyte[]私钥*/publicstaticbyte[]getPrivateKey(Map<String,Object>keyMap){Keykey=(Key)keyMap.get(PRIVATE_KEY);returnkey.getEncoded();}/***取得公钥**@paramkeyMap密钥map*@returnbyte[]公钥*/publicstaticbyte[]getPublicKey(Map<String,Object>keyMap)throwsException{Keykey=(Key)keyMap.get(PUBLIC_KEY);returnkey.getEncoded();}
四、加密盐
加密盐也是比较常听到的一个概念,盐就是一个随机字符串用来和我们的加密串拼接后进行加密。加盐主要是为了提供加密字符串的安全性。假如有一个加盐后的加密串,黑客通过一定手段这个加密串,他拿到的明文,并不是我们加密前的字符串,而是加密前的字符串和盐组合的字符串,这样相对来说又增加了字符串的安全性。
文中的一些算法来源于网络,可直接复制使用。
比较推荐的几个加密算法有:
- 不可逆加密:SHA256、SHA384、SHA512以及HMAC-SHA256、HMAC-SHA384、HMAC-SHA512
- 对称加密算法:AES、3DES
- 非对称加密算法:RSA
本文转载自微信公众号「 Java旅途」,可以通过以下二维码关注。转载本文请联系 Java旅途公众号。