kotlin版本RSA非對稱加密解密與分段加密解密

基于kotlin語言的RSA非對稱加密解密與分段加密解密

RSA非對稱加密

RSA非對稱加密的具體算法與來源我就不寫了,感興趣的可以自己找度娘或者維基百科
前面我的兩篇文章講了DES和AES對稱加密,我們可以看出他們加密和解密時都使用的是同一個密鑰,那么:
非對稱加密就是加密和解密使用不同的密鑰:
我們將它稱為密鑰對,密鑰對包含公鑰私鑰兩個,如果使用公鑰加密則要使用私鑰解密,反之使用私鑰加密則要用公鑰解密,我們將相對應(yīng)的公鑰私鑰稱為密鑰對。
密鑰對由系統(tǒng)生成
使用時兩個組織或者個人通過交換公鑰解密

缺點

RSA非對稱加密速度慢,如果文件較大加密時間會較長而且需要使用分段加密

首先生成密鑰對

注意自己生成的密鑰對的位數(shù),這個涉及到你加密解密時的最大位數(shù),我生成的是2048bits的,所以每次最大加密字節(jié)為245,每次最大解密字節(jié)為256

    //如何生成密鑰對:2048bit
    val generator = KeyPairGenerator.getInstance("RSA")//密鑰生成器
    val keyPair = generator.genKeyPair()//生成密鑰對
    val publicKey = keyPair.public//公鑰
    val privateKey = keyPair.private//私鑰

    println("publicKey="+Base64.getEncoder().encodeToString(publicKey.encoded))
    println("privateKey="+Base64.getEncoder().encodeToString(privateKey.encoded))

注意打印的寫法,如果直接打印你看到的是三個參數(shù),這樣會打印出你的公鑰和私鑰方便我們保存,否則每次都會生成新的密鑰對。

保存密鑰對

首先我們將第一次生成的公鑰和私鑰打印出來,然后保存

val publicKeyString = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAivLe1hpft8xOgdEyYTllA04dj+0ILZXTSkugcBKdChr15mk7KchD4D2RkBGUl5SL17oPVBYstLJnEbf1oBmHnkb7xm8A0VDoJJKHwgFLiS7QlLSr+Lta3fePopswuExgt3JFcRlv84RVqz0W5H2p2kiR063+Cw06BwY8496M/M8h5EoZoNkCKEmQPR3fP2Y0bpeZhVyTwLIKyhtjgMA68qSVJeiDYADbADNK/plZG5FDUspa27Rhlm4HYR5gFJKyIUmylE1EmMj67hJ+hHhP8qbK60S21IIwPhiRLISMrLkV3IqVGQk/hiW0VOUlYaPZ6ylwCQEwuKZS7cbHIDI5jwIDAQAB"
val privateKeyString = "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCK8t7WGl+3zE6B0TJhOWUDTh2P7QgtldNKS6BwEp0KGvXmaTspyEPgPZGQEZSXlIvXug9UFiy0smcRt/WgGYeeRvvGbwDRUOgkkofCAUuJLtCUtKv4u1rd94+imzC4TGC3ckVxGW/zhFWrPRbkfanaSJHTrf4LDToHBjzj3oz8zyHkShmg2QIoSZA9Hd8/ZjRul5mFXJPAsgrKG2OAwDrypJUl6INgANsAM0r+mVkbkUNSylrbtGGWbgdhHmAUkrIhSbKUTUSYyPruEn6EeE/ypsrrRLbUgjA+GJEshIysuRXcipUZCT+GJbRU5SVho9nrKXAJATC4plLtxscgMjmPAgMBAAECggEAX8E35/yM8jEN+VCdk3rmLfzrSoBjHmceERlFG3b4WjpyM7NZXlXw0NwdMFetOzjXlndWkPAnJu+7L+7Ciu6NE3p/kCR3P8it8mY4wG38DDIC9Df+O4+B823jwn+Id7nK/SD20hZhnEQadcPHvvcK0q8oL+S8KgmXb7fQxohcSOu4lk2z6POuIXTlBIMYEJI7ASb1A4XNyM8ScOROLp3RYEZUTU/b4/MuA/sEiYN1+yeK6NhK0mut621gyu1joLQBivHOw+lV6+fHS6j8hMeWKXFYEXIOvTXNhUu3XSQLt95V9NF8XwyzA1iX1Tn/+a6YGuma+nIHpWYkM7u9hnZeAQKBgQD1/cBsdbjHj9gUOQAdIz1MJQ2gA8FWdrlE6ZEpQWg8IvgAK1Lpc3/FfO74QqREsFYpDZPKFtfSOhrM3vJq5RK5fInfZmSG3ZopVvRUKwT8w65fslCQxQmgqG+V6Tk7b74x1UuJi2pYi9EgS+pGQNbJh+bzNYt5qERk2Q43maVsTwKBgQCQmimTdwmEDJ/4+zSEwktCXsuITxkLR8SEIDZvA3Ed87P+I03Vqwe0aM099nnmjzREML54CkWaC26dvwNzDcPAJgi1bDa5waKRit9ze3WTV47G8PpQjbu/eZWAcFNzuWW85k5Afc/F/Q2peS2J7NHzhD03fe6MyD/09n+NxGzOwQKBgDSA6KU9qybNCO2oDOIrN1YdQn84zfdKd9jBkX4gu8K6I/zFQnkZcdgRBmBuuOkASiORBk5H+eChDj9UBqHSKuD0N+k6zZILkm/oY1XjqLjae0lpodCEfb2QteBlWxXYj9vLDshYvWYQ0Z33FhXQmQeCvkSC1TYuOAreWS582NX5AoGARYtPGZPzaKWlvloaTQsgpN/wZTMdaVZvxde0NjniijQtybjy8yMZRoPsybMjt2YCDhWfVR4jkU2UOpumLgxdq6jfIVnVDAt7gyHWC7VBu8YtbbJxwJIZzKHN7AKZsBtnOa1Nzyhy59anXm1gIGhcJRDhXDHdq6mXUNnISMdCSUECgYAvWqSPlTocztnl1cxAkbmrB96Y4/mKCbN63/8RfaaF+HTOLONhshN5E3H7YJVVP83uif9/y+Ey7g7dWqn7D+dZGv6FHM3+T1npmYtTQZ4U9QUPN/KGPItnYbQhcqiqjRKYCqLU26qipaq8Mb6oqcwaKCm7uE7BywGYS8yYrQKwoQ=="

然后我們將字符串轉(zhuǎn)為密鑰對對象

//字符串轉(zhuǎn)成密鑰對對象
    val keyFactory = KeyFactory.getInstance("RSA")
    val privateKey = keyFactory.generatePrivate(PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKeyString)))
    val publicKey = keyFactory.generatePublic(X509EncodedKeySpec(Base64.getDecoder().decode(publicKeyString)))

后面我們就可以使用生成的密鑰對

加密

首先我們將創(chuàng)建cipher需要的內(nèi)容定義好

val transformation = "RSA"

私鑰加密

    /**
     * 私鑰加密
     * @param input 原文
     * @param privateKey 私鑰
     */
    fun encryptByPrivateKey(input:String,privateKey:PrivateKey): String {

        //****非對稱加密****
        //創(chuàng)建cipher對象
        val cipher = Cipher.getInstance(transformation)
        //初始化cipher
        cipher.init(Cipher.ENCRYPT_MODE,privateKey)
        //加密
        val encrypt = cipher.doFinal(input.toByteArray())

        return String(Base64.getEncoder().encode(encrypt))

    }

公鑰加密

    /**
     * 公鑰加密
     * @param input 原文
     * @param publicKey 公鑰
     */
    fun encryptByPublicKey(input:String,publicKey:PublicKey): String {

        //****非對稱加密****
        //創(chuàng)建cipher對象
        val cipher = Cipher.getInstance(transformation)
        //初始化cipher
        cipher.init(Cipher.ENCRYPT_MODE,publicKey)
        //加密
        val encrypt = cipher.doFinal(input.toByteArray())

        return String(Base64.getEncoder().encode(encrypt))

    }

然后我們在main函數(shù)中調(diào)用,并打印結(jié)果

    val desInput = "測試"
    //私鑰加密
    val byPrivateKey = RSACrypt.encryptByPrivateKey(desInput, privateKey)
    println("RSA私鑰加密結(jié)果:"+byPrivateKey)
    //公鑰加密
    val byPublicKey = RSACrypt.encryptByPublicKey(desInput, publicKey)
    println("RSA公鑰加密結(jié)果:"+byPublicKey)

接下來我們進(jìn)行解密

解密

當(dāng)我們進(jìn)行解密時會發(fā)現(xiàn)報錯,錯誤如下

Exception in thread "main" javax.crypto.IllegalBlockSizeException: Data must not be longer than 256 bytes
    at com.sun.crypto.provider.RSACipher.doFinal(RSACipher.java:346)
    at com.sun.crypto.provider.RSACipher.engineDoFinal(RSACipher.java:391)
    at javax.crypto.Cipher.doFinal(Cipher.java:2168)
    at RSACrypt.decryptByPrivateKey(RSACrypt.kt:51)
    at RSACryptKt.main(RSACrypt.kt:306)

通過錯誤提示我們可以知道,解密數(shù)據(jù)不能超過256字節(jié)。但是我們加密后的秘文超過了256字節(jié),那么我們應(yīng)該怎么解決呢:
方式為分段解密,那我們我們可以試試如果加密的字段過長的話也會報錯,這里我就不打印了,想嘗試的可以自己試試。
加密時如果超過245字節(jié)就會報錯,解決方法同樣是使用分段加密。

分段加密

分段加密和分擔(dān)解密的思路其實很簡單就是將我們輸入的字節(jié)進(jìn)行分段,然后進(jìn)行加密解密。很簡單的思路所以我就不詳細(xì)解釋了,在代碼中都有注釋。
首先我們將加密的最大字節(jié)數(shù)與解密的最大字節(jié)數(shù)設(shè)為常量

    //注意自己生成的密鑰對的bits長度
    val ENCRYPT_MAX_SIZE = 245//加密每次最大加密字節(jié)
    val DECRYPT_MAX_SIZE = 256//解密每次最大加密字節(jié)

私鑰分段加密

    /**
     * 私鑰分段加密
     * @param input 原文
     * @param privateKey 私鑰
     */
    fun segmentEncryptByPrivateKey(input:String,privateKey:PrivateKey): String {

        //創(chuàng)建cipher對象
        val cipher = Cipher.getInstance(transformation)
        //初始化cipher
        cipher.init(Cipher.ENCRYPT_MODE,privateKey)

        //****非對稱加密****
        val byteArray = input.toByteArray()

        //分段加密
        var temp:ByteArray? = null
        var offset = 0 //當(dāng)前偏移的位置

        val outputStream = ByteArrayOutputStream()

        //拆分input
        while (byteArray.size - offset > 0){
            //每次最大加密245個字節(jié)
            if (byteArray.size - offset >= ENCRYPT_MAX_SIZE){
                //剩余部分大于245
                //加密完整245
                temp = cipher.doFinal(byteArray,offset, ENCRYPT_MAX_SIZE)
                //重新計算偏移位置
                offset += ENCRYPT_MAX_SIZE
            }else{
                //加密最后一塊
                temp = cipher.doFinal(byteArray,offset, byteArray.size - offset)
                //重新計算偏移位置
                offset = byteArray.size
            }
            //存儲到臨時的緩沖區(qū)
            outputStream.write(temp)
        }
        outputStream.close()

        return String(Base64.getEncoder().encode(outputStream.toByteArray()))

    }

公鑰分段加密

    /**
     * 公鑰分段加密
     * @param input 原文
     * @param publicKey 公鑰
     */
    fun segmentEncryptByPublicKey(input:String,publicKey:PublicKey): String {

        //創(chuàng)建cipher對象
        val cipher = Cipher.getInstance(transformation)
        //初始化cipher
        cipher.init(Cipher.ENCRYPT_MODE,publicKey)
        //加密
//        val encrypt = cipher.doFinal(input.toByteArray())

        //****非對稱加密****
        val byteArray = input.toByteArray()

        var temp:ByteArray? = null
        var offset = 0 //當(dāng)前偏移的位置

        val outputStream = ByteArrayOutputStream()

        //拆分input
        while (byteArray.size - offset > 0){
            //每次最大加密117個字節(jié)
            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
            }
            //存儲到臨時的緩沖區(qū)
            outputStream.write(temp)
        }
        outputStream.close()

        return String(Base64.getEncoder().encode(outputStream.toByteArray()))

    }

這樣我們可以打印結(jié)果查看

    val input = "RSA加密測試RSA加密測試RSA加密測試RSA加密測試RSA加密測試RSA加密測試RSA加密測試RSA加密測試RSA加密測試RSA加密測試RSA加密測試"
    // 超過245個字節(jié)需要使用分段加密
    //私鑰分段加密
    val encryptByPrivateKey = RSACrypt.segmentEncryptByPrivateKey(input, privateKey)
    println("RSA私鑰分段加密結(jié)果:"+encryptByPrivateKey)
    //公鑰分段加密
    val encryptByPublicKey = RSACrypt.segmentEncryptByPublicKey(input, publicKey)
    println("RSA公鑰分段加密結(jié)果:"+encryptByPublicKey)

分段解密

分段解密的原理一樣,我們需要將加密后的秘文分段,然后解密

私鑰分段解密

    /**
     * 私鑰分段解密
     * @param input 秘文
     * @param privateKey 私鑰
     */
    fun segmentDecryptByPrivateKey(input:String,privateKey:PrivateKey): String {

        //創(chuàng)建cipher對象
        val cipher = Cipher.getInstance(transformation)
        //初始化cipher
        cipher.init(Cipher.DECRYPT_MODE,privateKey)

        //****非對稱加密****
        val byteArray = Base64.getDecoder().decode(input)

        //分段解密
        var temp:ByteArray? = null
        var offset = 0 //當(dāng)前偏移的位置

        val outputStream = ByteArrayOutputStream()

        //拆分input
        while (byteArray.size - offset > 0){
            //每次最大解密256個字節(jié)
            if (byteArray.size - offset >= DECRYPT_MAX_SIZE){

                temp = cipher.doFinal(byteArray,offset, DECRYPT_MAX_SIZE)
                //重新計算偏移位置
                offset += DECRYPT_MAX_SIZE
            }else{
                //加密最后一塊
                temp = cipher.doFinal(byteArray,offset, byteArray.size - offset)
                //重新計算偏移位置
                offset = byteArray.size
            }
            //存儲到臨時的緩沖區(qū)
            outputStream.write(temp)
        }
        outputStream.close()

        return String(outputStream.toByteArray())

    }

公鑰分段解密

    /**
     * 公鑰分段解密
     * @param input 秘文
     * @param privateKey 公鑰
     */
    fun segmentDecryptByPublicKey(input:String,publicKey: PublicKey): String {

        //創(chuàng)建cipher對象
        val cipher = Cipher.getInstance(transformation)
        //初始化cipher
        cipher.init(Cipher.DECRYPT_MODE,publicKey)

        //****非對稱加密****
        val byteArray = Base64.getDecoder().decode(input)

        //分段解密
        var temp:ByteArray? = null
        var offset = 0 //當(dāng)前偏移的位置

        val outputStream = ByteArrayOutputStream()

        //拆分input
        while (byteArray.size - offset > 0){
            //每次最大解密256個字節(jié)
            if (byteArray.size - offset >= DECRYPT_MAX_SIZE){

                temp = cipher.doFinal(byteArray,offset, DECRYPT_MAX_SIZE)
                //重新計算偏移位置
                offset += DECRYPT_MAX_SIZE
            }else{
                //加密最后一塊
                temp = cipher.doFinal(byteArray,offset, byteArray.size - offset)
                //重新計算偏移位置
                offset = byteArray.size
            }
            //存儲到臨時的緩沖區(qū)
            outputStream.write(temp)
        }
        outputStream.close()

        return String(outputStream.toByteArray())

    }

然后我們進(jìn)行結(jié)果打印,需要注意:
使用私鑰解密的是用公鑰加密的秘文
使用公鑰解密的是用私鑰加密的秘文

    //分段解密
    //私鑰分段解密:input應(yīng)該為使用公鑰加密后的秘文
    val decryptByPrivateKey = RSACrypt.segmentDecryptByPrivateKey(encryptByPublicKey, privateKey)
    println("RSA私鑰分段解密結(jié)果:"+decryptByPrivateKey)
    //公鑰分段解密:input應(yīng)該為使用私鑰加密后的秘文
    val decryptByPublicKey = RSACrypt.segmentDecryptByPublicKey(encryptByPrivateKey, publicKey)
    println("RSA公鑰分段解密結(jié)果:"+decryptByPublicKey)

以上就是RSA非對稱加密解密的全部內(nèi)容
RSA加密主要用于數(shù)字簽名,SSL證書等用途
如果文中有錯誤的地方,歡迎評論指出
謝謝觀看

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容