基于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證書等用途
如果文中有錯誤的地方,歡迎評論指出
謝謝觀看