kotlin学习系列2_加密算法
1、对称加密算法
什么是对称加密算法?
链接: 百度百科_对称加密算法.
对称加密算法是应用较早的加密算法,技术成熟。在对称加密算法中,数据发信方将明文(原始数据)和加密密钥(key)一起经过特殊加密算法处理后,使其变成复杂的加密密文发送出去。收信方收到密文后,若想解读原文,则需要使用加密用过的密钥及相同算法的逆算法对密文进行解密,才能使其恢复成可读明文。在对称加密算法中,使用的密钥只有一个,发收信双方都使用这个密钥对数据进行加密和解密,这就要求解密方事先必须知道加密密钥。
1.1 凯撒加密算法
链接: 百度百科_凯撒加密.
凯撒加密是一种替代密码,通过将字母按顺序推后3位起到加密作用,如将字母A换作字母D,将字母B换作字母E。
已知秘钥
IDEA新建一个kotlin项目 代码如下:
package com.hlping.study
import java.lang.StringBuilder
fun main(args: Array<String>) {
//声明原字符串
var str="hello kotlin!"
//声明秘钥
var key=4
//加密并打印
var encrypt=ch2_CaesarCrypt().enCrypt(str,key)
println(encrypt)
//解密并打印
println(ch2_CaesarCrypt().deCrypt(encrypt,key))
}
class ch2_CaesarCrypt {
/**
* 加密
* @param command 待加密字符串
* @param key 秘钥
* @return 加密字符串
*/
fun enCrypt(command:String,key:Int):String {
var charArray=command.toCharArray()
return with(StringBuilder()) {
//遍历每一个字符,对ascii偏移
charArray.forEach {
//获取字符ascii
var ascii = it.toInt()
//转成字符
var res = (ascii + key).toChar()
append(res)
}
//返回结果
toString()
}
}
/**
* 解密
* @param command 待解密字符串
* @param key 秘钥
* @return 原字符串
*/
fun deCrypt(command:String,key:Int):String{
var charArray=command.toCharArray()
return with(StringBuilder()) {
//遍历每一个字符,对ascii偏移
charArray.forEach {
//获取字符ascii
var ascii = it.toInt()
//转成字符
var res = (ascii - key).toChar()
append(res)
}
//返回结果
toString()
}
}
}
输出
> Task :Ch2_CaesarCryptKt.main()
lipps$osxpmr%
hello kotlin!
未知秘钥(频度分析法)
链接: 百度百科_频度分析法.
频度分析法:将明文字母的出现频率与密文字母的频率相比较的过程。通过分析每个符号出现的频率而轻易地破译代换式密码。在每种语言中,冗长的文章中的字母表现出一种可对之进行分辨的频率。
e是英语中最常用的字母,其出现频率为八分之一。最好假定长长的密文中最常用的符号代表e。
1.2 DES
DES(Data Encryption Standard)
特点:可自己指定秘钥,可逆,有秘钥即可破解。
底层机制:操作二进制
步骤:
1、创建cipher对象
2、初始化cipher
3、加密/解密
IDEA新建一个kotlin项目 代码如下:
package com.hlping.study
import java.security.Key
import javax.crypto.Cipher
import javax.crypto.SecretKeyFactory
import javax.crypto.spec.DESKeySpec
object DEScrypt{
fun encrypt(input:String,password:String): ByteArray {
//1、创建cipher对象
var cipher = Cipher.getInstance("DES")
//2、初始化cipher
var kf=SecretKeyFactory.getInstance("DES")
var keySpec=DESKeySpec(password.toByteArray())
val key:Key?=kf.generateSecret(keySpec)
cipher.init(Cipher.ENCRYPT_MODE,key)
//3、加密/解密
return cipher.doFinal(input.toByteArray())
}
fun decrypt(input:ByteArray,password:String): ByteArray{
//1、创建cipher对象
var cipher = Cipher.getInstance("DES")
//2、初始化cipher
var kf=SecretKeyFactory.getInstance("DES")
var keySpec=DESKeySpec(password.toByteArray())
val key:Key?=kf.generateSecret(keySpec)
cipher.init(Cipher.DECRYPT_MODE,key)
//3、加密/解密
return cipher.doFinal(input)
}
}
fun main(args: Array<String>) {
//原文
var input="学习kotlin系列2-加密算法"
var password="12345678" //秘钥 8位 前7位参与加密解密,第8位位校验位
var res = DEScrypt.encrypt(input, password)
println("des加密=$res")
var decrypt=DEScrypt.decrypt(res,password)
println("des解密="+String(decrypt))
}
输出:
> Task :Ch5_DEScryptKt.main()
des加密=[B@e369b7
des解密=学习kotlin系列2-加密算法
为了防止加密解密出现乱码情况,建议使用Base64编码加密和解码。
1.3 AES
AES(Advanced Encryption Standard),比DES用的更多
特点:可自己指定秘钥,可逆,有秘钥即可破解。
底层机制:操作二进制
步骤:
1、创建cipher对象
2、初始化cipher
3、加密/解密
IDEA新建一个kotlin项目 代码如下:
package com.hlping.study
import javax.crypto.Cipher
import javax.crypto.spec.SecretKeySpec
object AEScrypt{
fun encrypt(input:String,password:String): ByteArray {
//1、创建cipher对象
var cipher = Cipher.getInstance("AES")
//2、初始化cipher
var keySpec= SecretKeySpec(password.toByteArray(),"AES")
cipher.init(Cipher.ENCRYPT_MODE,keySpec)
//3、加密/解密
return cipher.doFinal(input.toByteArray())
}
fun decrypt(input:ByteArray,password:String): ByteArray{
//1、创建cipher对象
var cipher = Cipher.getInstance("AES")
//2、初始化cipher
var keySpec= SecretKeySpec(password.toByteArray(),"AES")
cipher.init(Cipher.DECRYPT_MODE,keySpec)
//3、加密/解密
return cipher.doFinal(input)
}
}
fun main(args: Array<String>) {
//原文
var input="学习kotlin系列2-AES加密算法"
var password="1234567800000000" //秘钥 16位
var res = AEScrypt.encrypt(input, password)
println("des加密=$res")
var decrypt=AEScrypt.decrypt(res,password)
println("des解密="+String(decrypt))
}
输出:
> Task :Ch6_AEScryptKt.main()
des加密=[B@dbc5d3
des解密=学习kotlin系列2-AES加密算法
为了防止加密解密出现乱码情况,建议使用Base64编码加密和解码。
Base64:
import java.io.UnsupportedEncodingException
/**
* Base64编码解码
*/
object Base64 {
private val base64EncodeChars = charArrayOf('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/')
private val base64DecodeChars = byteArrayOf(-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1)
fun encode(data: ByteArray): String {
val sb = StringBuffer()
val len = data.size
var i = 0
var b1: Int
var b2: Int
var b3: Int
while (i < len) {
b1 = ((data[i++]).toInt() and 0xff).toInt()
if (i == len) {
sb.append(base64EncodeChars[b1.ushr(2)])
sb.append(base64EncodeChars[b1 and 0x3 shl 4])
sb.append("==")
break
}
b2 = (data[i++]).toInt() and 0xff
if (i == len) {
sb.append(base64EncodeChars[b1.ushr(2)])
sb.append(base64EncodeChars[b1 and 0x03 shl 4 or (b2 and 0xf0).ushr(4)])
sb.append(base64EncodeChars[b2 and 0x0f shl 2])
sb.append("=")
break
}
b3 = (data[i++]).toInt() and 0xff
sb.append(base64EncodeChars[b1.ushr(2)])
sb.append(base64EncodeChars[b1 and 0x03 shl 4 or (b2 and 0xf0).ushr(4)])
sb.append(base64EncodeChars[b2 and 0x0f shl 2 or (b3 and 0xc0).ushr(6)])
sb.append(base64EncodeChars[b3 and 0x3f])
}
return sb.toString()
}
@Throws(UnsupportedEncodingException::class)
fun decode(str: String): ByteArray {
val sb = StringBuffer()
val data = str.toByteArray(charset("US-ASCII"))
val len = data.size
var i = 0
var b1: Int
var b2: Int
var b3: Int
var b4: Int
while (i < len) {
/* b1 */
do {
b1 = base64DecodeChars[(data[i++]).toInt()].toInt()
} while (i < len && b1 == -1)
if (b1 == -1) break
/* b2 */
do {
b2 = base64DecodeChars[(data[i++]).toInt()].toInt()
} while (i < len && b2 == -1)
if (b2 == -1) break
sb.append((b1 shl 2 or (b2 and 0x30).ushr(4)).toChar())
/* b3 */
do {
b3 = data[i++].toInt()
if (b3 == 61) return sb.toString().toByteArray(charset("ISO-8859-1"))
b3 = base64DecodeChars[b3].toInt()
} while (i < len && b3 == -1)
if (b3 == -1) break
sb.append((b2 and 0x0f shl 4 or (b3 and 0x3c).ushr(2)).toChar())
/* b4 */
do {
b4 = data[i++].toInt()
if (b4 == 61) return sb.toString().toByteArray(charset("ISO-8859-1"))
b4 = base64DecodeChars[b4].toInt()
} while (i < len && b4 == -1)
if (b4 == -1) break
sb.append((b3 and 0x03 shl 6 or b4).toChar())
}
return sb.toString().toByteArray(charset("ISO-8859-1"))
}
}
1.4、加密算法的工作模式和填充模式
工作模式 & 填充模式
算法 | 工作模式 | 填充模式 |
---|---|---|
AES | CBC | NoPadding (128) |
AES | CBC | PKCS5Padding (128) |
AES | ECB | NoPadding (128) |
AES | ECB | PKCS5Padding (128) |
DES | CBC | NoPadding (56) |
DES | CBC | PKCS5Padding(56) |
DES | ECB | NoPadding(56) |
DES | ECB | PKCS5Padding (56) |
DESede | CBC | NoPadding (168) |
DESede | CBC | PKCS5Padding (168) |
DESede | ECB | NoPadding (168) |
DESede | ECB | PKCS5Padding (168) |
RSA | ECB | PKCS1Padding ( 1024,2048 ) |
RSA | ECB | OAEPWithSHA-1AndMGF1Padding ( 1024,2048 ) |
RSA | ECB | OAEPWithSHA-256AndMGF1Padding ( 1024,2048 ) |
ECB(电子密本方式): 数据按照8个字节一段进行DES加密或解密得到一段段的8个字节的密文或者明文,最后一段不足8个字节(一般补0或者F),按照需求补足8个字节进行计算(并行计算),之后按照顺序将计算所得的数据连在一起即可,各段数据之间互不影响。
优点 | 缺点 |
---|---|
简单;有利于并行计算;误差不会被传递; | 不能隐藏明文的模式;可能对明文进行主动攻击 |
CBC(Cipher Block Chaining 密文分组链接方式): 密文分组像链条一样相互连接在一起。在CBC模式中,首先将明文分组与前一个密文分组进行XOR(异或)运算,然后再进行加密。
优点 | 缺点 |
---|---|
不容易主动攻击,安全性好于ECB,适合传输长度长的报文,是SSL、IPSec的标准 | 不利于并行计算;误差传递;需要初始化向量IV |
3、非对称加密算法
3.1 RSA
RSA是1977年由罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的。当时他们三人都在麻省理工学院工作。RSA就是他们三人姓氏开头字母拼在一起组成的。链接: 百度百科_RSA算法.
- 秘钥对:公钥和私钥,必须由系统生成
- 公钥加密,私钥解密;私钥加密,公钥解密
- 公钥需要互换:解密方与加密方
- 缺点:加密速度慢
方式1: 机构A使用私钥PrivateKey_A加密文件,同时将机构A的公钥PublicKey_A交换给机构B,当机构B拿到机密文件使用机构A提供的公钥解密文件。
方式2: 机构A获得机构B提供的公钥并使用该公钥PublicKey_B加密文件,当机构B拿到机密文件使用私钥PrivateKey_B直接解密。
IDEA新建一个kotlin项目 代码如下:
package com.hlping.study
import Base64
import java.io.ByteArrayOutputStream
import java.lang.Exception
import java.security.Key
import java.security.KeyPairGenerator
import java.security.PrivateKey
import java.security.PublicKey
import java.util.*
import javax.crypto.Cipher
object RSAcrypt{
val transformation="RSA"
val ENCRYPT_MAX_SIZE=117 //每次最大加密长度
val DECRYPT_MAX_SIZE=256 //每次最大解密长度
/**
* 私钥加密
* @param input 密文
* @param privateKey 私钥
* @return 加密密文
*/
fun encryptByprivatekey(input:String,privateKey: PrivateKey): String {
//1、创建cipher对象
var cipher = Cipher.getInstance(transformation)
//2、初始化cipher对象
cipher.init(Cipher.ENCRYPT_MODE,privateKey)
val bos = ByteArrayOutputStream()
val byteArray = input.toByteArray()
var temp:ByteArray?=null
var offset=0 //当前偏移位置
//3、加密/解密
while (byteArray.size-offset>0){
//每次最大加密长度117个字节
if (byteArray.size-offset >= ENCRYPT_MAX_SIZE){
//剩余部分大雨117
//加密完整117个字节
temp=cipher.doFinal(byteArray,offset, ENCRYPT_MAX_SIZE)
//重新计算偏移
offset+= ENCRYPT_MAX_SIZE
}else{
//加密最后一段
temp=cipher.doFinal(byteArray,offset, byteArray.size-offset)
offset=byteArray.size
}
//存储到临时缓冲区
bos.write(temp)
}
bos.close()
return Base64.encode(bos.toByteArray())
}
/**
* 公钥加密
* @param input 密文
* @param publicKey 公钥
* @return 加密密文
*/
fun encryptBypublickey(input:String,publicKey: PublicKey): String {
//1、创建cipher对象
var cipher = Cipher.getInstance(transformation)
//2、初始化cipher对象
cipher.init(Cipher.ENCRYPT_MODE,publicKey)
val bos = ByteArrayOutputStream()
val byteArray = input.toByteArray()
var temp:ByteArray?=null
var offset=0 //当前偏移位置
//3、加密/解密
while (byteArray.size-offset>0){
//每次最大加密长度117个字节
if (byteArray.size-offset >= ENCRYPT_MAX_SIZE){
//剩余部分大雨117
//加密完整117个字节
temp=cipher.doFinal(byteArray,offset, ENCRYPT_MAX_SIZE)
//重新计算偏移
offset+= ENCRYPT_MAX_SIZE
}else{
//加密最后一段
temp=cipher.doFinal(byteArray,offset, byteArray.size-offset)
offset=byteArray.size
}
//存储到临时缓冲区
bos.write(temp)
}
bos.close()
return Base64.encode(bos.toByteArray())
}
/**
* 私钥解密
* @param input 密文
* @param privateKey 私钥
* @return 解密后字符串
*/
fun decryptByPrivateKey(input:String,privateKey: PrivateKey): String {
val byteArray = Base64.decode(input)
//1、创建cipher对象
var cipher = Cipher.getInstance(transformation)
//2、初始化cipher对象
cipher.init(Cipher.DECRYPT_MODE,privateKey)
val bos = ByteArrayOutputStream()
var temp:ByteArray?=null
var offset=0 //当前偏移位置
//3、加密/解密
while (byteArray.size-offset > 0){
//每次最大加密长度256个字节
if (byteArray.size-offset >= DECRYPT_MAX_SIZE){
//剩余部分大于256
//加密完整256个字节
temp=cipher.doFinal(byteArray,offset, DECRYPT_MAX_SIZE)
//重新计算偏移
offset+= DECRYPT_MAX_SIZE
}else{
//加密最后一段
temp=cipher.doFinal(byteArray,offset, byteArray.size-offset)
offset=byteArray.size
}
//存储到临时缓冲区
bos.write(temp)
}
bos.close()
return String(bos.toByteArray())
}
/**
* 公钥解密
* @param input 密文
* @param publicKey 公钥
* @return 解密后字符串
*/
fun decryptBypublickey(input:String,publicKey: PublicKey): String {
val byteArray = Base64.decode(input)
//1、创建cipher对象
var cipher = Cipher.getInstance(transformation)
//2、初始化cipher对象
cipher.init(Cipher.DECRYPT_MODE,publicKey)
val bos = ByteArrayOutputStream()
var temp:ByteArray?=null
var offset=0 //当前偏移位置
//3、加密/解密
while (byteArray.size-offset > 0){
//每次最大加密长度256个字节
if (byteArray.size-offset >= DECRYPT_MAX_SIZE){
//剩余部分大于256
//加密完整256个字节
temp=cipher.doFinal(byteArray,offset, DECRYPT_MAX_SIZE)
//重新计算偏移
offset+= DECRYPT_MAX_SIZE
}else{
//加密最后一段
temp=cipher.doFinal(byteArray,offset, byteArray.size-offset)
offset=byteArray.size
}
//存储到临时缓冲区
bos.write(temp)
}
bos.close()
return String(bos.toByteArray())
}
}
fun main(args: Array<String>) {
//生成密钥对:公钥和私钥
val generator = KeyPairGenerator.getInstance("RSA")//秘钥对生成器
val keyPair = generator.genKeyPair()//生成密钥对
val privateKey = keyPair.private//私钥
val publicKey = keyPair.public//公钥
println("privateKey="+Base64.encode(privateKey.encoded))
println("publicKey="+Base64.encode(publicKey.encoded))
var input="2011年7月,JetBrains推出Kotlin项目,这是一个面向JVM的新语言 ,它已被开发一年之久。" +
"JetBrains负责人Dmitry Jemerov说,大多数语言没有他们正在寻找的特性,Scala除外。但是,他指" +
"出了Scala的编译时间慢这一明显缺陷。Kotlin的既定目标之一是像Java一样快速编译。 2012年2月," +
"JetBrains以Apache 2许可证开源此项目。"
var byprivatekey = RSAcrypt.encryptByprivatekey(input, privateKey)
println("RSA私钥加密:$byprivatekey")
var bypublickey = RSAcrypt.encryptBypublickey(input, publicKey)
println("RSA公钥加密:$bypublickey")
var decryptByprivatekey = RSAcrypt.decryptByPrivateKey(byprivatekey, privateKey)
println("RSA私钥解密:$decryptByprivatekey")
var decryptBypublickey = RSAcrypt.decryptBypublickey(bypublickey, publicKey)
println("RSA公钥解密:$decryptBypublickey")
}
}