kotlin学习系列2_加密算法

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、加密算法的工作模式和填充模式

工作模式 & 填充模式
算法工作模式填充模式
AESCBCNoPadding (128)
AESCBCPKCS5Padding (128)
AESECBNoPadding (128)
AESECBPKCS5Padding (128)
DESCBCNoPadding (56)
DESCBCPKCS5Padding(56)
DESECBNoPadding(56)
DESECBPKCS5Padding (56)
DESedeCBCNoPadding (168)
DESedeCBCPKCS5Padding (168)
DESedeECBNoPadding (168)
DESedeECBPKCS5Padding (168)
RSAECBPKCS1Padding ( 1024,2048 )
RSAECBOAEPWithSHA-1AndMGF1Padding ( 1024,2048 )
RSAECBOAEPWithSHA-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. 秘钥对:公钥和私钥,必须由系统生成
  2. 公钥加密,私钥解密;私钥加密,公钥解密
  3. 公钥需要互换:解密方与加密方
  4. 缺点:加密速度慢
    两种方式
    方式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")
   }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hlpinghcg

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值