基于kotlin語(yǔ)言的RSA非對(duì)稱(chēng)加密解密與分段加密解密
RSA非對(duì)稱(chēng)加密
RSA非對(duì)稱(chēng)加密的具體算法與來(lái)源我就不寫(xiě)了糊肤,感興趣的可以自己找度娘或者維基百科
前面我的兩篇文章講了DES和AES對(duì)稱(chēng)加密横侦,我們可以看出他們加密和解密時(shí)都使用的是同一個(gè)密鑰邮丰,那么:
非對(duì)稱(chēng)加密就是加密和解密使用不同的密鑰:
我們將它稱(chēng)為密鑰對(duì),密鑰對(duì)包含公鑰私鑰兩個(gè),如果使用公鑰加密則要使用私鑰解密,反之使用私鑰加密則要用公鑰解密耿眉,我們將相對(duì)應(yīng)的公鑰私鑰稱(chēng)為密鑰對(duì)。
密鑰對(duì)由系統(tǒng)生成
使用時(shí)兩個(gè)組織或者個(gè)人通過(guò)交換公鑰解密
缺點(diǎn)
RSA非對(duì)稱(chēng)加密速度慢鱼响,如果文件較大加密時(shí)間會(huì)較長(zhǎng)而且需要使用分段加密
首先生成密鑰對(duì)
注意自己生成的密鑰對(duì)的位數(shù)鸣剪,這個(gè)涉及到你加密解密時(shí)的最大位數(shù),我生成的是2048bits的热押,所以每次最大加密字節(jié)為245西傀,每次最大解密字節(jié)為256
//如何生成密鑰對(duì):2048bit
val generator = KeyPairGenerator.getInstance("RSA")//密鑰生成器
val keyPair = generator.genKeyPair()//生成密鑰對(duì)
val publicKey = keyPair.public//公鑰
val privateKey = keyPair.private//私鑰
println("publicKey="+Base64.getEncoder().encodeToString(publicKey.encoded))
println("privateKey="+Base64.getEncoder().encodeToString(privateKey.encoded))
注意打印的寫(xiě)法,如果直接打印你看到的是三個(gè)參數(shù)桶癣,這樣會(huì)打印出你的公鑰和私鑰方便我們保存拥褂,否則每次都會(huì)生成新的密鑰對(duì)。
保存密鑰對(duì)
首先我們將第一次生成的公鑰和私鑰打印出來(lái),然后保存
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)為密鑰對(duì)對(duì)象
//字符串轉(zhuǎn)成密鑰對(duì)對(duì)象
val keyFactory = KeyFactory.getInstance("RSA")
val privateKey = keyFactory.generatePrivate(PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKeyString)))
val publicKey = keyFactory.generatePublic(X509EncodedKeySpec(Base64.getDecoder().decode(publicKeyString)))
后面我們就可以使用生成的密鑰對(duì)
加密
首先我們將創(chuàng)建cipher需要的內(nèi)容定義好
val transformation = "RSA"
私鑰加密
/**
* 私鑰加密
* @param input 原文
* @param privateKey 私鑰
*/
fun encryptByPrivateKey(input:String,privateKey:PrivateKey): String {
//****非對(duì)稱(chēng)加密****
//創(chuàng)建cipher對(duì)象
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 {
//****非對(duì)稱(chēng)加密****
//創(chuàng)建cipher對(duì)象
val cipher = Cipher.getInstance(transformation)
//初始化cipher
cipher.init(Cipher.ENCRYPT_MODE,publicKey)
//加密
val encrypt = cipher.doFinal(input.toByteArray())
return String(Base64.getEncoder().encode(encrypt))
}
然后我們?cè)趍ain函數(shù)中調(diào)用牙寞,并打印結(jié)果
val desInput = "測(cè)試"
//私鑰加密
val byPrivateKey = RSACrypt.encryptByPrivateKey(desInput, privateKey)
println("RSA私鑰加密結(jié)果:"+byPrivateKey)
//公鑰加密
val byPublicKey = RSACrypt.encryptByPublicKey(desInput, publicKey)
println("RSA公鑰加密結(jié)果:"+byPublicKey)
接下來(lái)我們進(jìn)行解密
解密
當(dāng)我們進(jìn)行解密時(shí)會(huì)發(fā)現(xiàn)報(bào)錯(cuò)饺鹃,錯(cuò)誤如下
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)
通過(guò)錯(cuò)誤提示我們可以知道,解密數(shù)據(jù)不能超過(guò)256字節(jié)间雀。但是我們加密后的秘文超過(guò)了256字節(jié)悔详,那么我們應(yīng)該怎么解決呢:
方式為分段解密,那我們我們可以試試如果加密的字段過(guò)長(zhǎng)的話也會(huì)報(bào)錯(cuò)惹挟,這里我就不打印了茄螃,想嘗試的可以自己試試。
加密時(shí)如果超過(guò)245字節(jié)就會(huì)報(bào)錯(cuò)连锯,解決方法同樣是使用分段加密归苍。
分段加密
分段加密和分擔(dān)解密的思路其實(shí)很簡(jiǎn)單就是將我們輸入的字節(jié)進(jìn)行分段,然后進(jìn)行加密解密运怖。很簡(jiǎn)單的思路所以我就不詳細(xì)解釋了拼弃,在代碼中都有注釋。
首先我們將加密的最大字節(jié)數(shù)與解密的最大字節(jié)數(shù)設(shè)為常量
//注意自己生成的密鑰對(duì)的bits長(zhǎng)度
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對(duì)象
val cipher = Cipher.getInstance(transformation)
//初始化cipher
cipher.init(Cipher.ENCRYPT_MODE,privateKey)
//****非對(duì)稱(chēng)加密****
val byteArray = input.toByteArray()
//分段加密
var temp:ByteArray? = null
var offset = 0 //當(dāng)前偏移的位置
val outputStream = ByteArrayOutputStream()
//拆分input
while (byteArray.size - offset > 0){
//每次最大加密245個(gè)字節(jié)
if (byteArray.size - offset >= ENCRYPT_MAX_SIZE){
//剩余部分大于245
//加密完整245
temp = cipher.doFinal(byteArray,offset, ENCRYPT_MAX_SIZE)
//重新計(jì)算偏移位置
offset += ENCRYPT_MAX_SIZE
}else{
//加密最后一塊
temp = cipher.doFinal(byteArray,offset, byteArray.size - offset)
//重新計(jì)算偏移位置
offset = byteArray.size
}
//存儲(chǔ)到臨時(shí)的緩沖區(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對(duì)象
val cipher = Cipher.getInstance(transformation)
//初始化cipher
cipher.init(Cipher.ENCRYPT_MODE,publicKey)
//加密
// val encrypt = cipher.doFinal(input.toByteArray())
//****非對(duì)稱(chēng)加密****
val byteArray = input.toByteArray()
var temp:ByteArray? = null
var offset = 0 //當(dāng)前偏移的位置
val outputStream = ByteArrayOutputStream()
//拆分input
while (byteArray.size - offset > 0){
//每次最大加密117個(gè)字節(jié)
if (byteArray.size - offset >= ENCRYPT_MAX_SIZE){
//剩余部分大于117
//加密完整117
temp = cipher.doFinal(byteArray,offset, ENCRYPT_MAX_SIZE)
//重新計(jì)算偏移位置
offset += ENCRYPT_MAX_SIZE
}else{
//加密最后一塊
temp = cipher.doFinal(byteArray,offset, byteArray.size - offset)
//重新計(jì)算偏移位置
offset = byteArray.size
}
//存儲(chǔ)到臨時(shí)的緩沖區(qū)
outputStream.write(temp)
}
outputStream.close()
return String(Base64.getEncoder().encode(outputStream.toByteArray()))
}
這樣我們可以打印結(jié)果查看
val input = "RSA加密測(cè)試RSA加密測(cè)試RSA加密測(cè)試RSA加密測(cè)試RSA加密測(cè)試RSA加密測(cè)試RSA加密測(cè)試RSA加密測(cè)試RSA加密測(cè)試RSA加密測(cè)試RSA加密測(cè)試"
// 超過(guò)245個(gè)字節(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對(duì)象
val cipher = Cipher.getInstance(transformation)
//初始化cipher
cipher.init(Cipher.DECRYPT_MODE,privateKey)
//****非對(duì)稱(chēng)加密****
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個(gè)字節(jié)
if (byteArray.size - offset >= DECRYPT_MAX_SIZE){
temp = cipher.doFinal(byteArray,offset, DECRYPT_MAX_SIZE)
//重新計(jì)算偏移位置
offset += DECRYPT_MAX_SIZE
}else{
//加密最后一塊
temp = cipher.doFinal(byteArray,offset, byteArray.size - offset)
//重新計(jì)算偏移位置
offset = byteArray.size
}
//存儲(chǔ)到臨時(shí)的緩沖區(qū)
outputStream.write(temp)
}
outputStream.close()
return String(outputStream.toByteArray())
}
公鑰分段解密
/**
* 公鑰分段解密
* @param input 秘文
* @param privateKey 公鑰
*/
fun segmentDecryptByPublicKey(input:String,publicKey: PublicKey): String {
//創(chuàng)建cipher對(duì)象
val cipher = Cipher.getInstance(transformation)
//初始化cipher
cipher.init(Cipher.DECRYPT_MODE,publicKey)
//****非對(duì)稱(chēng)加密****
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個(gè)字節(jié)
if (byteArray.size - offset >= DECRYPT_MAX_SIZE){
temp = cipher.doFinal(byteArray,offset, DECRYPT_MAX_SIZE)
//重新計(jì)算偏移位置
offset += DECRYPT_MAX_SIZE
}else{
//加密最后一塊
temp = cipher.doFinal(byteArray,offset, byteArray.size - offset)
//重新計(jì)算偏移位置
offset = byteArray.size
}
//存儲(chǔ)到臨時(shí)的緩沖區(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非對(duì)稱(chēng)加密解密的全部?jī)?nèi)容
RSA加密主要用于數(shù)字簽名咏连,SSL證書(shū)等用途
如果文中有錯(cuò)誤的地方盯孙,歡迎評(píng)論指出
謝謝觀看