大家好,我是小羽
哈哈哈,其实只是周末看了小舞而已啦,铁铁们没追更的,赶快去补一下这集,特效炸裂。好了,不扯了,进入正题,最近做的项目,涉及到一些加密算法的选择,小羽在这里顺便也给大家做个总结,一起加深对加密的相关认识。
目前比较常用的加密算法总结起来就是单向加密和双向加密了,其实很简单,理解也不难。但是小羽觉得还是很有必要对其原理进行清晰的认知的,这样在我们的开发中才会得心应手。毕竟对于我们研发来说,数据安全是第一位,加密算法对维护软件的数据安全起着举足轻重的作用。来跟着小羽看看这些算法都用在了哪些方面,怎么用的,代码具体如何实现的。慢慢读完,你会对这些小密码有更深入的了解。
今天给大家带来的的是关于加密算法的来世今生。
其实早在古希腊时期,人类发明了置换密码。到1881年世界上的第一个电话保密专利出现。二战期间,德国军方启用“恩尼格玛”密码机,密码学在战争中起着非常重要的作用。
在1997年,美国国家标准局公布实施了“美国数据加密标准(DES)”,民间力量开始全面介入密码学的研究和应用中,采用的加密算法有 DES、RSA、SHA
等。随着对加密强度需求的不断提高,近期又出现了AES、ECC
等。
好了,历史讲完了,该进入正文了,先来看看使用加密算法对我们有啥好处。
使用密码学可以达到以下目的:
保密性:防止用户的标识或数据被读取。
数据完整性:防止数据被更改。
身份验证:确保数据发自特定的一方。
单向加密 通俗来说,就是通过对数据进行摘要计算生成密文,密文不可逆推还原。算法代表:MD5、SHA、HMAC等。
MD5
-- message-digest algorithm 5 (信息-摘要算法)缩写,广泛用于加密和解密技术,常用于文件校验。不管文件多大,经过MD5后都能生成唯一的 MD5
值。好比现在的 ISO 校验,都是 MD5 校验,把 ISO 经过 MD5 后产生 MD5 的值。一般下载 linux-ISO
的朋友都见过下载链接旁边放着 MD5 的串。就是用来验证文件是否一致的。
加密工具类如下:
/**
* MD5加密
*
* @param data
* @return
* @throws Exception
*/
public static byte[] encryptMD5(byte[] data) throws Exception {
MessageDigest md5 = MessageDigest.getInstance(KEY_MD5);
md5.update(data);
return md5.digest();
}
SHA
(Secure Hash Algorithm,安全散列算法),数字签名等密码学应用中重要的工具,被广泛地应用于电子商务等信息安全领域。虽然, SHA 与 MD5 通过碰撞法都被破解了,但是 SHA 仍然是公认的安全加密算法,较之MD5更为安全。
加密工具类如下:
/**
* SHA加密
*
* @param data
* @return
* @throws Exception
*/
public static byte[] encryptSHA(byte[] data) throws Exception {
MessageDigest sha = MessageDigest.getInstance(KEY_SHA);
sha.update(data);
return sha.digest();
}
}
HMAC
(Hash Message Authentication Code ,散列消息鉴别码,基于密钥的 Hash 算法的认证协议。消息鉴别码实现鉴别的原理是,用公开函数和密钥产生一个固定长度的值作为认证标识,用这个标识鉴别消息的完整性。使用一个密钥生成一个固定大小的小数据块,即 MAC
,并将其加入到消息中,然后传输。接收方利用与发送方共享的密钥进行鉴别认证等。
加密工具类如下:
/**
* 初始化HMAC密钥
*
* @return
* @throws Exception
*/
public static String initMacKey() throws Exception {
KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_MAC);
SecretKey secretKey = keyGenerator.generateKey();
return encryptBASE64(secretKey.getEncoded());
}
/**
* HMAC加密
*
* @param data
* @param key
* @return
* @throws Exception
*/
public static byte[] encryptHMAC(byte[] data, String key) throws Exception {
SecretKey secretKey = new SecretKeySpec(decryptBASE64(key), KEY_MAC);
Mac mac = Mac.getInstance(secretKey.getAlgorithm());
mac.init(secretKey);
return mac.doFinal(data);
}
双向加密 双向加密又称为可逆加密,即生成密文后,在需要的时候可以反解为明文,双向加密分为对称加密和非对称加密。
对称加密算法是应用较早的加密算法,技术成熟。在对称加密算法中,数据发信方将明文(原始数据)和加密密钥一起经过特殊加密算法处理后,使其变成复杂的加密密文发送出去。在对称加密算法中,使用的密钥只有一个,发收信双方都使用这个密钥对数据进行加密和解密,这就要求解密方事先必须知道加密密钥。对称加密算法的特点是8算法公开、计算量小、加密速度快、加密效率高。不足之处是,交易双方都使用同样钥匙,安全性得不到保证*。对称加密算法在分布式网络系统上使用较为困难,主要是因为密钥管理困难,使用成本较高。
数据加密过程:在对称加密算法中,数据发送方将明文(原始数据)和加密密钥一起经过特殊加密处理,生成复杂的加密密文进行发送。
数据解密过程:数据接收方收到密文后,若想读取原数据,则需要使用加密使用的密钥及相同算法的逆算法对加密的密文进行解密,才能使其恢复成可读明文。
常用算法:DES、3DES、AES、TDEA、Blowfish、RC2、RC4、RC5、IDEA、Skipjack 等。下面主要介绍常用的 DES、3DES、AES
加密算法。
DES 加密算法是一种分组密码,以 64
位为分组对数据加密,它的密钥长度是 56
位,加密解密用同一算法。DES 加密算法是对密钥进行保密,而公开算法,包括加密和解密算法。这样,只有掌握了和发送方相同密钥的人才能解读由DES加密算法加密的密文数据。因此,破译 DES 加密算法实际上就是搜索密钥的编码。对于 56 位长度的密钥来说,如果用穷举法来进行搜索的话,其运算次数为 256
。
随着计算机系统能力的不断发展, DES 的安全性比它刚出现时会弱得多,然而从非关键性质的实际出发,仍可以认为它是足够的。不过, DES 现在仅用于旧系统的鉴定,而更多地选择新的加密标准。
加密工具类如下:
/**
* 加密
*
* @param datasource 待加密数据
* @param key
* @return byte数组
*/
public static byte[] enCrypto(byte[] datasource, String key) throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, BadPaddingException, IllegalBlockSizeException {
SecureRandom random = new SecureRandom();
DESKeySpec desKey = new DESKeySpec(key.getBytes());
// 创建一个密匙工厂,然后用它把DESKeySpec转换成
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey securekey = keyFactory.generateSecret(desKey);
// Cipher对象实际完成加密操作
Cipher cipher = Cipher.getInstance("DES");
// 用密匙初始化Cipher对象
cipher.init(Cipher.ENCRYPT_MODE, securekey, random);
// 现在,获取数据并加密
// 正式执行加密操作
return cipher.doFinal(datasource);
}
DES 是三重数据加密算法块密码的通称。它相当于是对每个数据块应用三次 DES 加密算法。由于计算机运算能力的增强,原版DES密码的密钥长度变得容易被暴力破解;3DES即是设计用来提供一种相对简单的方法,即通过增加 DES
的密钥长度来避免类似的攻击,而不是设计一种全新的块密码算法。
3DES 是 DES 向 AES 过渡的加密算法,加密算法,其具体实现如下:设 Ek()
和 Dk()
代表 DES 算法的加密和解密过程, K
代表 DES 算法使用的密钥, M
代表明文, C
代表密文。加密过程为:C=Ek3(Dk2(Ek1(M)))
加密工具类如下:
/**
* 方法描述:3DES加密
*
* @param plainText 明文
* @param secretKey 密钥
* @param iv 加密向量
* @return String 密文
* @throws Exception
*/
public static String encode(String plainText, String secretKey, String iv)
throws Exception {
Key deskey = null;
DESedeKeySpec spec = new DESedeKeySpec(secretKey.getBytes());
SecretKeyFactory keyfactory = SecretKeyFactory.getInstance("desede");
deskey = keyfactory.generateSecret(spec);
Cipher cipher = Cipher.getInstance("desede/CBC/PKCS5Padding");
IvParameterSpec ips = new IvParameterSpec(iv.getBytes());
cipher.init(Cipher.ENCRYPT_MODE, deskey, ips);
byte[] encryptData = cipher.doFinal(plainText.getBytes(encoding));
return Base64.encode(encryptData);
}
AES 加密算法是密码学中的高级加密标准,该加密算法采用对称分组密码体制,密钥长度的最少支持为 128
、192
、 256
,分组长度 128
位,算法应易于各种硬件和软件实现。这种加密算法是美国联邦政府采用的区块加密标准,这个标准用来替代原先的 DES
,已经被多方分析且广为全世界所使用。
AES 加密算法被设计为支持 128/192/256
位(/32=nb)数据块大小(即分组长度);支持 128/192/256
位(/32=nk) 密码长度,,在 10 进制里,对应 34×1038、62×1057、1.1×1077
个密钥。
加密工具类如下:
/**
* AES加密
* @param data 要加密的字符串
* @param key 加密key
* @param iv 密码加密算法中的IV
* @return 加密后的字符串
*/
public static String encrypt(String data, String key, String iv) {
try {
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
int blockSize = cipher.getBlockSize();
byte[] dataBytes = data.getBytes();
int plaintextLength = dataBytes.length;
if (plaintextLength % blockSize != 0) {
plaintextLength = plaintextLength + (blockSize - (plaintextLength % blockSize));
}
byte[] plaintext = new byte[plaintextLength];
System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length);
SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), Constant.STRING_AES);
IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes(Constant.STRING_UTF_8));
cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
byte[] encrypted = cipher.doFinal(plaintext);
String encrypt = Base64.getEncoder().encodeToString(encrypted); //BASE64加密
encrypt = encrypt.replaceAll(new String(Constant.STRING_CARRIAGE_RETURN), Constant.STRING_BLANK);
encrypt = encrypt.replaceAll(new String(Constant.STRING_LINE_FEED), Constant.STRING_BLANK);
return encrypt;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
不对称加密算法使用两把完全不同但又是完全匹配的一对钥匙—公钥和私钥。在使用不对称加密算法加密文件时,只有使用匹配的一对公钥和私钥,才能完成对明文的加密和解密过程。采用不对称加密算法,收发信双方在通信之前,收信方必须将自己早已随机生成的公钥送给发信方,而自己保留私钥。由于不对称算法拥有两个密钥,因而特别适用于分布式系统中的数据加密。广泛应用的不对称加密算法有 RSA
算法和美国国家标准局提出的 DSA
。以不对称加密算法为基础的加密技术应用非常广泛。
工作流程:
1、乙方生成一对密钥(公钥和私钥)并将公钥向其它方公开。
2、得到该公钥的甲方使用该密钥对机密信息进行加密后再发送给乙方。
3、乙方再用自己保存的另一把专用密钥(私钥)对加密后的信息进行解密。乙方只能用其专用密钥(私钥)解密由对应的公钥加密后的信息。
在传输过程中,即使攻击者截获了传输的密文,并得到了乙的公钥,也无法破解密文,因为只有乙的私钥才能解密密文。
同样,如果乙要回复加密信息给甲,那么需要甲先公布甲的公钥给乙用于加密,甲自己保存甲的私钥用于解密。
RSA 加密算法是目前最有影响力的公钥加密算法,并且被普遍认为是目前最优秀的公钥方案之一。RSA 是第一个能同时用于加密和数宇签名的算法,它能够抵抗到目前为止已知的所有密码攻击,已被 ISO
推荐为公钥数据加密标准。RSA 加密算法基于一个十分简单的数论事实:将两个大素数相乘十分容易,但那时想要,但那时想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥。
加密工具类如下:
/**
* RSA公钥加密
*
* @param str 加密字符串
* @param publicKey 公钥
* @return 密文
* @throws Exception 加密过程中的异常信息
*/
public static String encrypt( String str, String publicKey ) throws Exception{
//base64编码的公钥
byte[] decoded = Base64.decodeBase64(publicKey);
RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
//RSA加密
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
String outStr = Base64.encodeBase64String(cipher.doFinal(str.getBytes("UTF-8")));
return outStr;
}
DSA 是基于整数有限域离散对数难题的,其安全性与 RSA 相比差不多。DSA 的一个重要特点是两个素数公开,这样,当使用别人的 p 和 q 时,即使不知道私钥,你也能确认它们是否是随机产生的,还是作了手脚。RSA算法却做不到。DSA 只是一种算法,和 RSA 不同之处在于它不能用作加密和解密,也不能进行密钥交换,只用于签名,它比RSA要快很多.
加密流程如下:
椭圆加密算法(ECC)是一种公钥加密体制,最初由 Koblitz
和 Miller
两人于 1985 年提出,其数学基础是利用椭圆曲线上的有理点构成 Abel
加法群上椭圆离散对数的计算困难性。公钥密码体制根据其所依据的难题一般分为三类:大整数分解问题类、离散对数问题类、椭圆曲线类。有时也把椭圆曲线类归为离散对数类。椭圆曲线密码体制是目前已知的公钥体制中,对每比特所提供加密强度最高的一种体制。解椭圆曲线上的离散对数问题的最好算法是 Pollard rho
方法,其时间复杂度为,是完全指数阶的。
加密工具类如下:
/**
* 加密
* @param data
* @param publicKey
* @return
* @throws Exception
*/
public static byte[] encrypt(byte[] data, String publicKey)
throws Exception {
byte[] keyBytes = BASE64Decoder.decodeBuffer(publicKey);
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(ECCEnum.ALGORITHM.value());
ECPublicKey pubKey = (ECPublicKey) keyFactory
.generatePublic(x509KeySpec);
Cipher cipher = new NullCipher();
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
return cipher.doFinal(data);
}
采用非对称加密算法管理对称算法的密钥,用对称加密算法加密数据,即提高了加密速度,又实现了解密的安全
RSA 建议采用 1024
位的数字, ECC 建议采用160
位, AES 采用128
位即可
在管理方面:公钥密码算法只需要较少的资源就可以实现目的,在密钥的分配上,两者之间相差一个指数级别(一个是n一个是n2)。所以公钥密码算法不适应广域网的使用,而且更重要的一点是它不支持数字签名。
在安全方面:由于公钥密码算法基于未解决的数学难题,在破解上几乎不可能。对于私钥密码算法,到了AES虽说从理论来说是不可能破解的,但从计算机的发展角度来看。公钥更具有优越性。