目录
1. 摘要算法
常见的摘要算法主要有两种,MD5和SHA1。
摘要算法并不是一种加密算法,因为不可逆,无法从密文还原出明文。
摘要算法主要用途有
- 消息完整性验证:发送消息时,将发送数据与MD5值一起发送,然后可以从MD5值来验证接收到的消息是否完整。常见的有下载文件等场景,服务端提供一个文件的下载地址和文件的MD5值,客户端再下载完成后验证文件的MD5,如果与服务端的值不同,说明下载出问题了,需要重新下载。
- 安全访问认证:如数据库存储登录密码的MD5值,这样就可以保证即使管理员也无法查看到常用密码;
- 数字签名:常见的场景有对接口参数进行签名,来实现服务端对客户端的可靠性验证。客户端和服务端各自持有一个秘钥key,网络接口请求时,通过对时间戳timestamp+接口参数+秘钥key进行MD5计算,然后将MD5值作为参数传给服务端,服务端通过相同的加密算法来验证MD5值是否相同,通过这样来验证客户端的可信性,有效防止网络爬虫;
MD5算法
MD5输出一个32位长度的16进制字符串。Kotlin下使用方法如下
fun getMd5(str: String): String {
var md: MessageDigest? = null
try {
md = MessageDigest.getInstance("MD5")
md.update(str.toByteArray())
return BigInteger(1, md!!.digest()).toString(16)
} catch (e: NoSuchAlgorithmException) {
e.printStackTrace()
}
return ""
}
我们验证下他的执行效率, 代码如下:
class LkUtilsTest {
@Test
fun testMd5() {
val begin = System.currentTimeMillis()
val result = LKUtil.getMd5("123456789012345678990")
val end = System.currentTimeMillis()
println("cost:" + (end - begin) + ":" + result)
}
}
结果如下
cost:28:7f3ee0d5fd4769b75c34dcc56fc271bf
可以看到用了28ms
MD5的算法过程
查考文章 https://blog.csdn.net/u012611878/article/details/54000607
MD5的算法过程可以简要描述为:MD5以512位分组来处理输入的信息,且每一分组又被划分为16个32位的子分组,又经过一系列的处理后,算法的输出由是个32位分组组成,将这是个32位分组级联后将产生一个128位散列值。
- 第一步、填充。如果输入信息长度(bit)对512求余的结果不等于448,就需要填充使得对512求余的结果等于448,就需要填充使得对512求余的结果等于448。填充的方法是填充一个1和n个0(注意这里都是bit级别的1和0),填充完成后,信息的长度就是N*512+448(bit);
- 第二步、记录信息的长度,用64位来存储填充前信息的长度。这64位加在第一步结果的后面,这样的信息长度就变成N*512+448+64=(N+1)*512位。
- 第三步、装入标准的幻数(四个整数),标准的幻数是A=OX67452301L,B=OXEFCDAB89L,C=OX98BADCFEL,D=OX10325476L。至于为什么是这四个数,我暂时没有搞清楚。
- 第四步、四轮循环运算:循环的次数是分组的个数(N+1),运算的规则如下
- 第4.1 步、每一个分组(512个字节)细分为16个小组,每个小组64位(8个字节)
- 第4.2 步、先认识四个线性函数,定义如下
F(X,Y,Z)=(X&Y)|((~X)&Z)
G(X,Y,Z)=(X&Z)|(Y&(~Z))
H(X,Y,Z)=X^Y^Z
I(X,Y,Z)=Y^(X|(~Z))
- 第4.3步、设Mj表示第j个子分组(从0到16),有以下4个函数
FF(a,b,c,d,Mj,s,ti)表示a=b+((a+F(b,c,d)+Mj+ti)<<<s)
GG(a,b,c,d,Mj,s,ti)表示a=b+((a+G(b,c,d)+Mj+ti)<<<s)
HH(a,b,c,d,Mj,s,ti)表示a=b+((a+H(b,c,d)+Mj+ti)<<<s)
II(a,b,c,d,Mj,s,ti)表示a=b+((a+I(b,c,d)+Mj+ti)<<<s)
- 第4.4步,四轮运算
第一轮
a=FF(a,b,c,d,M0,7,0xd76aa478)
b=FF(d,a,b,c,M1,12,0xe8c7b756)
c=FF(c,d,a,b,M2,17,0x242070db)
d=FF(b,c,d,a,M3,22,0xc1bdceee)
a=FF(a,b,c,d,M4,7,0xf57c0faf)
b=FF(d,a,b,c,M5,12,0x4787c62a)
c=FF(c,d,a,b,M6,17,0xa8304613)
d=FF(b,c,d,a,M7,22,0xfd469501)
a=FF(a,b,c,d,M8,7,0x698098d8)
b=FF(d,a,b,c,M9,12,0x8b44f7af)
c=FF(c,d,a,b,M10,17,0xffff5bb1)
d=FF(b,c,d,a,M11,22,0x895cd7be)
a=FF(a,b,c,d,M12,7,0x6b901122)
b=FF(d,a,b,c,M13,12,0xfd987193)
c=FF(c,d,a,b,M14,17,0xa679438e)
d=FF(b,c,d,a,M15,22,0x49b40821)
第二轮
a=GG(a,b,c,d,M1,5,0xf61e2562)
b=GG(d,a,b,c,M6,9,0xc040b340)
c=GG(c,d,a,b,M11,14,0x265e5a51)
d=GG(b,c,d,a,M0,20,0xe9b6c7aa)
a=GG(a,b,c,d,M5,5,0xd62f105d)
b=GG(d,a,b,c,M10,9,0x02441453)
c=GG(c,d,a,b,M15,14,0xd8a1e681)
d=GG(b,c,d,a,M4,20,0xe7d3fbc8)
a=GG(a,b,c,d,M9,5,0x21e1cde6)
b=GG(d,a,b,c,M14,9,0xc33707d6)
c=GG(c,d,a,b,M3,14,0xf4d50d87)
d=GG(b,c,d,a,M8,20,0x455a14ed)
a=GG(a,b,c,d,M13,5,0xa9e3e905)
b=GG(d,a,b,c,M2,9,0xfcefa3f8)
c=GG(c,d,a,b,M7,14,0x676f02d9)
d=GG(b,c,d,a,M12,20,0x8d2a4c8a)
第三轮
a=HH(a,b,c,d,M5,4,0xfffa3942)
b=HH(d,a,b,c,M8,11,0x8771f681)
c=HH(c,d,a,b,M11,16,0x6d9d6122)
d=HH(b,c,d,a,M14,23,0xfde5380c)
a=HH(a,b,c,d,M1,4,0xa4beea44)
b=HH(d,a,b,c,M4,11,0x4bdecfa9)
c=HH(c,d,a,b,M7,16,0xf6bb4b60)
d=HH(b,c,d,a,M10,23,0xbebfbc70)
a=HH(a,b,c,d,M13,4,0x289b7ec6)
b=HH(d,a,b,c,M0,11,0xeaa127fa)
c=HH(c,d,a,b,M3,16,0xd4ef3085)
d=HH(b,c,d,a,M6,23,0x04881d05)
a=HH(a,b,c,d,M9,4,0xd9d4d039)
b=HH(d,a,b,c,M12,11,0xe6db99e5)
c=HH(c,d,a,b,M15,16,0x1fa27cf8)
d=HH(b,c,d,a,M2,23,0xc4ac5665)
第四轮
a=II(a,b,c,d,M0,6,0xf4292244)
b=II(d,a,b,c,M7,10,0x432aff97)
c=II(c,d,a,b,M14,15,0xab9423a7)
d=II(b,c,d,a,M5,21,0xfc93a039)
a=II(a,b,c,d,M12,6,0x655b59c3)
b=II(d,a,b,c,M3,10,0x8f0ccc92)
c=II(c,d,a,b,M10,15,0xffeff47d)
d=II(b,c,d,a,M1,21,0x85845dd1)
a=II(a,b,c,d,M8,6,0x6fa87e4f)
b=II(d,a,b,c,M15,10,0xfe2ce6e0)
c=II(c,d,a,b,M6,15,0xa3014314)
d=II(b,c,d,a,M13,21,0x4e0811a1)
a=II(a,b,c,d,M4,6,0xf7537e82)
b=II(d,a,b,c,M11,10,0xbd3af235)
c=II(c,d,a,b,M2,15,0x2ad7d2bb)
d=II(b,c,d,a,M9,21,0xeb86d391)
- 第4.5步 将每轮循环的结果a,b,c,d分别累加,然后进行下一轮循环
我们手撸一下MD5的过程(注:我算出来的结果与官方的结果不一样,我也不知道哪里错了,反正就是这个意思,累死了,懒得看了)
package com.plbear.lxc.utils
import kotlin.experimental.and
class Md5 {
companion object {
val hex = charArrayOf('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F')
//标准的幻数
const val A = 0x67452301L
const val B = 0xefcdab89L
const val C = 0x98badcfeL
const val D = 0x10325476L
//下面这些S11-S44实际是一个4*4的矩阵,在四轮循环运算中用到
const val S11 = 7
const val S12 = 12
const val S13 = 17
const val S14 = 22
const val S21 = 5
const val S22 = 9
const val S23 = 14
const val S24 = 20
const val S31 = 4
const val S32 = 11
const val S33 = 16
const val S34 = 23
const val S41 = 6
const val S42 = 10
const val S43 = 15
const val S44 = 21
private fun F(x: Long, y: Long, z: Long): Long {
return (x and y) or (x.inv() and z)
}
private fun G(x: Long, y: Long, z: Long): Long {
return (x and z) or (y and z.inv())
}
private fun H(x: Long, y: Long, z: Long): Long {
return x xor y xor z
}
private fun I(x: Long, y: Long, z: Long): Long {
return y xor (x xor z.inv())
}
private fun FF(tmpA: Long, b: Long, c: Long, d: Long, x: Long, s: Int, ac: Long): Long {
var a = tmpA
a += (F(b, c, d) and 0xFFFFFFFFL) + x + ac
a = ((a and 0xFFFFFFFFL) shl s.toInt()) or ((a and 0xFFFFFFFFL) ushr (32 - s.toInt()))
a += b
return a and 0xFFFFFFFFL
}
private fun GG(tmpA: Long, b: Long, c: Long, d: Long, x: Long, s: Int, ac: Long): Long {
var a = tmpA
a += (G(b, c, d) and 0xFFFFFFFFL) + x + ac
a = ((a and 0xFFFFFFFFL) shl s.toInt()) or ((a and 0xFFFFFFFFL) ushr (32 - s.toInt()))
a += b
return a and 0xFFFFFFFFL
}
private fun HH(tmpA: Long, b: Long, c: Long, d: Long, x: Long, s: Int, ac: Long): Long {
var a = tmpA
a += (H(b, c, d) and 0xFFFFFFFFL) + x + ac
a = ((a and 0xFFFFFFFFL) shl s.toInt()) or ((a and 0xFFFFFFFFL) ushr (32 - s.toInt()))
a += b
return a and 0xFFFFFFFF
}
private fun II(tmpA: Long, b: Long, c: Long, d: Long, x: Long, s: Int, ac: Long): Long {
var a = tmpA
a += (I(b, c, d) and 0xFFFFFFFFL) + x + ac
a = ((a and 0xFFFFFFFFL) shl s.toInt()) or ((a and 0xFFFFFFFFL) ushr (32 - s.toInt()))
a += b
return a and 0xFFFFFFFF
}
}
val result = arrayOf(A, B, C, D)
fun md5(input: String): String {
val inputBytes = input.toByteArray()
val byteLength = inputBytes.size //长度(字节长度)
var groupCount = byteLength / 64 //完整分组的个数
var groups: LongArray
//处理每一个完整的分组
for (step in (0 until groupCount)) {
groups = divGroup(inputBytes, step * 6)
trans(groups) //处理分组,核心算法
}
val rest = byteLength % 64
val tempBytes = ByteArray(64) { 0 }
if (rest <= 56) {
for (i in 0 until rest) {
tempBytes[i] = inputBytes[byteLength - rest + 1]
}
if (rest < 56) {
tempBytes[rest] = (1 shl 7).toByte()
for (i in 1 until 56 - rest) {
tempBytes[rest + 1] = 0
}
}
var len = (byteLength shl 3).toLong()
for (i in 0 until 8) {
tempBytes[56 + i] = (len and 0xFFL).toByte()
len = len shr 8
}
groups = divGroup(tempBytes, 0)
trans(groups)
} else {
for (i in 0 until rest) {
tempBytes[i] = inputBytes[byteLength - rest + 1]
}
tempBytes[rest] = (1 shl 7).toByte()
for (i in (rest + 1) until 64) {
tempBytes[i] = 0
}
groups = divGroup(tempBytes, 0)
trans(groups)
for (i in 0 until 56) {
tempBytes[i] = 0
}
var len = (byteLength shl 3).toLong()
for (i in 0 until 8){
tempBytes[56 + i] = (len and 0xFFL).toByte()
len = len shr 8
}
groups = divGroup(tempBytes,0)
trans(groups)
}
var resStr = ""
var temp = 0L
for (i in 0 until 4){
for (j in 0 until 4){
temp = result[i] and 0x0FL
val a = hex[temp.toInt()]
result[i] = result[i] shr 4
temp = result[i] and 0x0FL
resStr += hex[temp.toInt()].toString() + a.toString()
result[i] = result[i] shr 4
}
}
return resStr
}
/**
* 将每个大组(512bit)分为16个小组,每个小组64(bit),每个小组恰好是一个long数据
*/
private fun divGroup(inputBytes: ByteArray, index: Int): LongArray {
val result = LongArray(16) { 0 }
for (i in 0 until 16) {
result[i] = b2iu(inputBytes[4 * i + index]) or
(b2iu(inputBytes[4 * i + 1 + index]) shl 8) or
(b2iu(inputBytes[4 * i + 2 + index]) shl 16) or
(b2iu(inputBytes[4 * i + 3 + index]) shl 24)
}
return result
}
/**
* 这个时候不存在符号位(符号位存储不再代表正负),所以Byte转为Long的时候需要处理下
*/
private fun b2iu(b: Byte): Long {
return if (b < 0) ((b and 0x7F.toByte()) + 128).toLong() else b.toLong()
}
/**
* 核心计算方法,四轮运算
*/
private fun trans(groups: LongArray) {
var a = result[0]
var b = result[1]
var c = result[2]
var d = result[3]
/*第一轮*/
a = FF(a, b, c, d, groups[0], S11, 0xd76aa478L) /* 1 */
d = FF(d, a, b, c, groups[1], S12, 0xe8c7b756L) /* 2 */
c = FF(c, d, a, b, groups[2], S13, 0x242070dbL) /* 3 */
b = FF(b, c, d, a, groups[3], S14, 0xc1bdceeeL) /* 4 */
a = FF(a, b, c, d, groups[4], S11, 0xf57c0fafL) /* 5 */
d = FF(d, a, b, c, groups[5], S12, 0x4787c62aL) /* 6 */
c = FF(c, d, a, b, groups[6], S13, 0xa8304613L) /* 7 */
b = FF(b, c, d, a, groups[7], S14, 0xfd469501L) /* 8 */
a = FF(a, b, c, d, groups[8], S11, 0x698098d8L) /* 9 */
d = FF(d, a, b, c, groups[9], S12, 0x8b44f7afL) /* 10 */
c = FF(c, d, a, b, groups[10], S13, 0xffff5bb1L) /* 11 */
b = FF(b, c, d, a, groups[11], S14, 0x895cd7beL) /* 12 */
a = FF(a, b, c, d, groups[12], S11, 0x6b901122L) /* 13 */
d = FF(d, a, b, c, groups[13], S12, 0xfd987193L) /* 14 */
c = FF(c, d, a, b, groups[14], S13, 0xa679438eL) /* 15 */
b = FF(b, c, d, a, groups[15], S14, 0x49b40821L) /* 16 */
/*第二轮*/
a = GG(a, b, c, d, groups[1], S21, 0xf61e2562L) /* 17 */
d = GG(d, a, b, c, groups[6], S22, 0xc040b340L) /* 18 */
c = GG(c, d, a, b, groups[11], S23, 0x265e5a51L) /* 19 */
b = GG(b, c, d, a, groups[0], S24, 0xe9b6c7aaL) /* 20 */
a = GG(a, b, c, d, groups[5], S21, 0xd62f105dL) /* 21 */
d = GG(d, a, b, c, groups[10], S22, 0x2441453L) /* 22 */
c = GG(c, d, a, b, groups[15], S23, 0xd8a1e681L) /* 23 */
b = GG(b, c, d, a, groups[4], S24, 0xe7d3fbc8L) /* 24 */
a = GG(a, b, c, d, groups[9], S21, 0x21e1cde6L) /* 25 */
d = GG(d, a, b, c, groups[14], S22, 0xc33707d6L) /* 26 */
c = GG(c, d, a, b, groups[3], S23, 0xf4d50d87L) /* 27 */
b = GG(b, c, d, a, groups[8], S24, 0x455a14edL) /* 28 */
a = GG(a, b, c, d, groups[13], S21, 0xa9e3e905L) /* 29 */
d = GG(d, a, b, c, groups[2], S22, 0xfcefa3f8L) /* 30 */
c = GG(c, d, a, b, groups[7], S23, 0x676f02d9L) /* 31 */
b = GG(b, c, d, a, groups[12], S24, 0x8d2a4c8aL) /* 32 */
/*第三轮*/
a = HH(a, b, c, d, groups[5], S31, 0xfffa3942L) /* 33 */
d = HH(d, a, b, c, groups[8], S32, 0x8771f681L) /* 34 */
c = HH(c, d, a, b, groups[11], S33, 0x6d9d6122L) /* 35 */
b = HH(b, c, d, a, groups[14], S34, 0xfde5380cL) /* 36 */
a = HH(a, b, c, d, groups[1], S31, 0xa4beea44L) /* 37 */
d = HH(d, a, b, c, groups[4], S32, 0x4bdecfa9L) /* 38 */
c = HH(c, d, a, b, groups[7], S33, 0xf6bb4b60L) /* 39 */
b = HH(b, c, d, a, groups[10], S34, 0xbebfbc70L) /* 40 */
a = HH(a, b, c, d, groups[13], S31, 0x289b7ec6L) /* 41 */
d = HH(d, a, b, c, groups[0], S32, 0xeaa127faL) /* 42 */
c = HH(c, d, a, b, groups[3], S33, 0xd4ef3085L) /* 43 */
b = HH(b, c, d, a, groups[6], S34, 0x4881d05L) /* 44 */
a = HH(a, b, c, d, groups[9], S31, 0xd9d4d039L) /* 45 */
d = HH(d, a, b, c, groups[12], S32, 0xe6db99e5L) /* 46 */
c = HH(c, d, a, b, groups[15], S33, 0x1fa27cf8L) /* 47 */
b = HH(b, c, d, a, groups[2], S34, 0xc4ac5665L) /* 48 */
/*第四轮*/
a = II(a, b, c, d, groups[0], S41, 0xf4292244L) /* 49 */
d = II(d, a, b, c, groups[7], S42, 0x432aff97L) /* 50 */
c = II(c, d, a, b, groups[14], S43, 0xab9423a7L) /* 51 */
b = II(b, c, d, a, groups[5], S44, 0xfc93a039L) /* 52 */
a = II(a, b, c, d, groups[12], S41, 0x655b59c3L) /* 53 */
d = II(d, a, b, c, groups[3], S42, 0x8f0ccc92L) /* 54 */
c = II(c, d, a, b, groups[10], S43, 0xffeff47dL) /* 55 */
b = II(b, c, d, a, groups[1], S44, 0x85845dd1L) /* 56 */
a = II(a, b, c, d, groups[8], S41, 0x6fa87e4fL) /* 57 */
d = II(d, a, b, c, groups[15], S42, 0xfe2ce6e0L) /* 58 */
c = II(c, d, a, b, groups[6], S43, 0xa3014314L) /* 59 */
b = II(b, c, d, a, groups[13], S44, 0x4e0811a1L) /* 60 */
a = II(a, b, c, d, groups[4], S41, 0xf7537e82L) /* 61 */
d = II(d, a, b, c, groups[11], S42, 0xbd3af235L) /* 62 */
c = II(c, d, a, b, groups[2], S43, 0x2ad7d2bbL) /* 63 */
b = II(b, c, d, a, groups[9], S44, 0xeb86d391L) /* 64 */
/*加入到之前计算的结果当中*/
result[0] += a
result[1] += b
result[2] += c
result[3] += d
result[0] = result[0] and 0xFFFFFFFFL
result[1] = result[1] and 0xFFFFFFFFL
result[2] = result[2] and 0xFFFFFFFFL
result[3] = result[3] and 0xFFFFFFFFL
}
}
SHA1算法
用法
fun getSHA1(str: String): String {
kotlin.runCatching {
val sha = MessageDigest.getInstance("SHA-1")
sha.update(str.toByteArray())
return BigInteger(1, sha.digest()).toString(16)
}
return ""
}
测试代码
@Test
fun testSha1() {
val begin = System.currentTimeMillis()
val result = LKUtil.getSHA1("123456789012345678990")
val end = System.currentTimeMillis()
println("cost:" + (end - begin) + ":" + result);
}
测试结果
cost:46:3ae9b112ed472836b0fdd6b94d53b4fd31484d19
MD5与SHA1算法的比较
详细的比较结果请参看文档https://www.cnblogs.com/scu-cjx/p/6878853.html
简单来看,结果如下
差异 | MD5 | SHA1 |
摘要长度 | 128 | 160 |
运算时间 | 短(28ms) | 长(46ms) |
2. 对称加密
对称加密算法最主要的特点是加密秘钥和解密秘钥相同。相对来说,对称加密的加密速度更快,常见的应用场景有https在传输阶段的加密模式。
常见的对称加密算法有,AES和DES
- DES:比较老的算法,一共有三个参数入口(原文、秘钥、加密模式)。而3DES只是DES的一种模式,是以DES为基础更安全的变形。
- AES:高级加密标准,新一代标准,加密速度更快,安全性更高
AES加密算法
AES是分组密码,也就是把明文分成一组一组的,每组长度相同,每次加密一组数据,直到加密完整个明文。在AES标准规范中,分组长度只能是128位,也就是说,每个分组为16个Byte。秘钥的长度可以使用128位,192位或256位。秘钥的长度不同,推荐加密轮速也不同,具体如下表所示。
AES | 秘钥长度(Byte) | 分组长度(Byte) | 加密轮数 |
AES-128 | 4 | 4 | 10 |
AES-192 | 6 | 4 | 12 |
AES-256 | 8 | 4 | 14 |
加密的详细实现参看文章https://blog.csdn.net/qq_28205153/article/details/55798628
使用方法如下(Kotlin)
@Test
fun testAES() {
val content = "Hello World"
val key = "123456"
val begin = System.currentTimeMillis()
val bytes = encryptByAes(content.toByteArray(), key.toByteArray())
val mid = System.currentTimeMillis()
val source = decryptByAes(bytes, key.toByteArray())
val end = System.currentTimeMillis()
println("source:${String(source)} encrypt:${mid - begin} decrypt:${end - mid}")
}
private fun generateAesKey(key: ByteArray): SecretKey {
// 根据指定的RNG算法,创建安全随机数生成器
val random = SecureRandom.getInstance("SHA1PRNG")
// 设置 秘钥key的字节数组,作为安全随机数生成器的种子
random.setSeed(key)
// 创建AES算法生成器
val gen = KeyGenerator.getInstance("AES")
// 初始化算法生成器
gen.init(128, random)
//生成AES秘钥对象
return gen.generateKey()
}
private fun encryptByAes(source: ByteArray, key: ByteArray): ByteArray {
//生成秘钥对象
val secKey = generateAesKey(key)
//获取AES密码器
val cipher = Cipher.getInstance("AES")
// 初始化密码器(加密模型)
cipher.init(Cipher.ENCRYPT_MODE, secKey)
//加密数据, 返回密文
return cipher.doFinal(source)
}
private fun decryptByAes(source: ByteArray, key: ByteArray): ByteArray {
// 生成秘钥对象
val secKey = generateAesKey(key)
// 获取AES密码器
val cipher = Cipher.getInstance("AES")
//初始AES密码器
cipher.init(Cipher.DECRYPT_MODE, secKey)
//解密数据,返回明文
return cipher.doFinal(source)
}
看下输出
source:Hello World 加密耗时:105ms 解密耗时:0ms
DES加密算法
详细的介绍可以参看文章https://www.cxyxiaowu.com/1478.html
其中,加密流程可以概括为
这里需要注意的是,原始秘钥长度必须为64位,否则会报错
看一下用法
@Test
fun testDes() {
val content = "Hello World"
val key = "12345678"
val begin = System.currentTimeMillis()
val bytes = encryptBytesByDes(content.toByteArray(), key.toByteArray())
val mid = System.currentTimeMillis()
val source = decryptByDes(bytes, key.toByteArray())
val end = System.currentTimeMillis()
println("source:${String(source)} 加密后长度:${bytes.size} 加密耗时:${mid - begin}ms 解密耗时:${end - mid}ms")
}
private fun generateDesKey(key: ByteArray): SecretKey {
//根据给定的原始秘钥来生成秘钥
val key = SecretKeySpec(key, "DES")
return key
}
private fun encryptBytesByDes(source: ByteArray, sourceKey: ByteArray): ByteArray {
val key = generateDesKey(sourceKey)
val cipher = Cipher.getInstance("DES")
cipher.init(Cipher.ENCRYPT_MODE, key)
return cipher.doFinal(source)
}
private fun decryptByDes(source: ByteArray, sourceKey: ByteArray): ByteArray {
val key = generateDesKey(sourceKey)
val cipher = Cipher.getInstance("DES")
cipher.init(Cipher.DECRYPT_MODE, key)
return cipher.doFinal(source)
}
看一下输出
source:Hello World 加密后长度:16 加密耗时:121ms 解密耗时:0ms
可以看到,他的加密耗时是要比AES要长的
我们补一个关于AES和DES算法比较的图,来自于https://yq.aliyun.com/articles/156277
名称 | 秘钥长度 | 运算速度 | 安全性 | 资源消耗 | |
DES | 56位 | 较快 | 低 | 中 | |
3DES | 112位或156位 | 慢 | 中 | 高 | |
AES | 128、192、256位 | 快 | 高 | 低 |
3. 非对称加密
非对称加密是指公钥和私钥不同的加密方式,用公钥加密,然后用私钥解密。或者用私钥加密,用公钥解密。
与对称加密比起来,非对称加密安全性更好,私钥完全是自己保存的,但是一般来说加密和解密速度更慢,一般只适用于对少量数据进行加密
RSA
关于原理解释可以参看 https://blog.csdn.net/qy20115549/article/details/83105736
看一下怎么调用
@Test
fun testRsa() {
val begin = System.currentTimeMillis()
val pair = genRsaPair()
val publishKey = pair.get(0)!!
val privateKey = pair.get(1)!!
val mid = System.currentTimeMillis()
println("publishKey:${publishKey} \n\n privateKey:$privateKey \n\n")
val source = "Hello World"
val encodeString = encodeByPublishRsa(source, publishKey)
val encodeOver = System.currentTimeMillis()
println("encodeString:$encodeString \n\n")
val decodeString = decodeByRsa(encodeString, privateKey)
println("decodeString:$decodeString \n\n")
val decodeOver = System.currentTimeMillis()
println("gen key cost:${mid - begin} encode cost:${encodeOver - mid} decode cost:${decodeOver - encodeOver}")
}
/**
* 生成RSA的秘钥对
*/
private fun genRsaPair(): HashMap<Int, String> {
val keyPairGen = KeyPairGenerator.getInstance("RSA")
//初始化秘钥对生成器, 秘钥大小为96-1024位
keyPairGen.initialize(1024, SecureRandom())
//生成一个秘钥对, 保存在keyPair中
val keyPair = keyPairGen.generateKeyPair()
val privateKey = keyPair.private as RSAPrivateKey //私钥
val publishKey = keyPair.public as RSAPublicKey //公钥
//得到公钥字符串
val publishKeyString = java.util.Base64.getEncoder().encodeToString(publishKey.encoded)
//得到私钥字符串
val privateKeyString = java.util.Base64.getEncoder().encodeToString(privateKey.encoded)
return HashMap<Int, String>().apply {
this[0] = publishKeyString
this[1] = privateKeyString
}
}
/**
* 通过rsa加密
*/
private fun encodeByPublishRsa(source: String, key: String): String {
val decode = java.util.Base64.getDecoder().decode(key)
val publishKey = KeyFactory.getInstance("RSA").generatePublic(X509EncodedKeySpec(decode))
val cipher = Cipher.getInstance("RSA")
cipher.init(Cipher.ENCRYPT_MODE, publishKey)
val outStr = java.util.Base64.getEncoder().encodeToString(cipher.doFinal(source.toByteArray()))
return outStr
}
/**
* 通过RSA解密
*/
private fun decodeByRsa(source: String, key: String): String {
val decode = java.util.Base64.getDecoder().decode(key)
val sourceByte = java.util.Base64.getDecoder().decode(source.toByteArray())
val privateKey = KeyFactory.getInstance("RSA").generatePrivate(PKCS8EncodedKeySpec(decode))
val cipher = Cipher.getInstance("RSA")
cipher.init(Cipher.DECRYPT_MODE, privateKey)
return String(cipher.doFinal(sourceByte))
}
看一下输出
publishKey:MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCjxcFMouLuHmVZTDjxc0JyGbGPSMp+r7mpgbOOJq/WePieTtelvPxdrnG8fj9HPFV7GAmyAUPPZmUKGV6e8/uoOJ/HKuXKu3NEW+xnaeMU+IKn+EA143h+t8fHnRyq5nO8PuF8bNBzC27mOVvN6oLtVijLxRScXOSsZk6SzQbHlQIDAQAB
privateKey:MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAKPFwUyi4u4eZVlMOPFzQnIZsY9Iyn6vuamBs44mr9Z4+J5O16W8/F2ucbx+P0c8VXsYCbIBQ89mZQoZXp7z+6g4n8cq5cq7c0Rb7Gdp4xT4gqf4QDXjeH63x8edHKrmc7w+4Xxs0HMLbuY5W83qgu1WKMvFFJxc5KxmTpLNBseVAgMBAAECgYAPPviovr0rd67tqjfe2mEEKDosYZVgR9Gb4xQpFpbl+2sBqctPhZFk0zmJV6NiaU534Bv+8zkx1JFxaD0zxPjXYMCI4hfi2LfB8K0XeCP/wldbpeNuGQ3uZ0hBHUP/HawoRU2O7lviaqoms0o20XQ6Yd8dy+geGi/FhnmGOSMrfQJBAOnMZwuSK3JsEJ2q55YcvL7hEeTKraNEYO+MnV8gSQEAy3N6K5akA/y5a+Hs987RxGU7LNFLwysS3ax8pKTS8ScCQQCzUwi8DuTJx2/P63l7QsLfv0trEarOR7FOREu0ZK4GtkoRG1uU+ZZZ64Hq+BWGL3enj4SO6l/VImzn7q+RAL7jAkBmArSXXOCuHS6mzLIdUk6cbnGzRSe8DBLLkqv7nIed823R5eVs5gWDWJgUzKNXTzmE/evRKmBuw92K7BueexeTAkEAno26WVzp2acnK7XOUbfzyhW/v0l9tqoZEVS9gyDJ5lFjJ8ECtrP/xj2/P1xe26g4qcTxtdNxLGgl1uRqA1GfdQJBAI7qc3l+77K3+Modr8boNqIIfoZqKKbwrPQRphgp/tUPZ80qLV2NSKT5K3e2EoI2DZ923IZPSAYV/ldN09H57HU=
encodeString:m7r4U+T3L8/Oa+BfvQ3Z2iXhlrf/nMTYinDvziGjFb+RfJWpGGcNzdEIYH5ruP5PTJnwXN4MOSS7M5nV4DiBjolwy+rlcA3460ubJqKXEHvGyqtxZABa839dKFwxysULJL2TOQEtWq2zlccdP/qTdALnxhmt62VVQin1r4jVlF4=
decodeString:Hello World
gen key cost:124 encode cost:34 decode cost:2
ps: 这么看非对称加密的时间开销也不大啊。。可能是因为我的数据量太小的原因吧
在代码中,我们可以看到X509和PKCS, 关于这种的解释如下
- X509是密码学中的公钥证书标准,含有公钥,分身信息和签名信息,详细参看维基百科吧 https://zh.wikipedia.org/wiki/X.509
- PKCS 是由美国RSA数据安全公司及其合作伙伴制定的一组公钥密码学标准,其中包括证书申请、证书更新、证书作废表发布、扩展证书内容以及数字签名、数字信封的格式等方面的一系列相关协议
DSA
既 Digital Signature Algorithm,数字签名算法,他是由美国国家标准与技术研究所(NIST)与1991年提出。和 RSA 不同的是 DSA 仅能用于数字签名,不能进行数据加密解密,其安全性和RSA相当,但其性能要比RSA快。
详细的不介绍了,累死了