基于kotlin语言的RSA非对称加密解密与分段加密解密
RSA非对称加密
RSA非对称加密的具体算法与来源我就不写了,感兴趣的可以自己找度娘或者维基百科
前面我的两篇文章讲了DES和AES对称加密,我们可以看出他们加密和解密时都使用的是同一个密钥,那么:
非对称加密就是加密和解密使用不同的密钥:
我们将它称为密钥对,密钥对包含公钥私钥两个,如果使用公钥加密则要使用私钥解密,反之使用私钥加密则要用公钥解密,我们将相对应的公钥私钥称为密钥对。
密钥对由系统生成
使用时两个组织或者个人通过交换公钥解密
缺点
RSA非对称加密速度慢,如果文件较大加密时间会较长而且需要使用分段加密
首先生成密钥对
注意自己生成的密钥对的位数,这个涉及到你加密解密时的最大位数,我生成的是2048bits的,所以每次最大加密字节为245,每次最大解密字节为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))
注意打印的写法,如果直接打印你看到的是三个参数,这样会打印出你的公钥和私钥方便我们保存,否则每次都会生成新的密钥对。
保存密钥对
首先我们将第一次生成的公钥和私钥打印出来,然后保存
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=="
然后我们将字符串转为密钥对对象
//字符串转成密钥对对象
val keyFactory = KeyFactory.getInstance("RSA")
val privateKey = keyFactory.generatePrivate(PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKeyString)))
val publicKey = keyFactory.generatePublic(X509EncodedKeySpec(Base64.getDecoder().decode(publicKeyString)))
后面我们就可以使用生成的密钥对
加密
首先我们将创建cipher需要的内容定义好
val transformation = "RSA"
私钥加密
/**
* 私钥加密
* @param input 原文
* @param privateKey 私钥
*/
fun encryptByPrivateKey(input:String,privateKey:PrivateKey): String {
//****非对称加密****
//创建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 {
//****非对称加密****
//创建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函数中调用,并打印结果
val desInput = "测试"
//私钥加密
val byPrivateKey = RSACrypt.encryptByPrivateKey(desInput, privateKey)
println("RSA私钥加密结果:"+byPrivateKey)
//公钥加密
val byPublicKey = RSACrypt.encryptByPublicKey(desInput, publicKey)
println("RSA公钥加密结果:"+byPublicKey)
接下来我们进行解密
解密
当我们进行解密时会发现报错,错误如下
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)
通过错误提示我们可以知道,解密数据不能超过256字节。但是我们加密后的秘文超过了256字节,那么我们应该怎么解决呢:
方式为分段解密,那我们我们可以试试如果加密的字段过长的话也会报错,这里我就不打印了,想尝试的可以自己试试。
加密时如果超过245字节就会报错,解决方法同样是使用分段加密。
分段加密
分段加密和分担解密的思路其实很简单就是将我们输入的字节进行分段,然后进行加密解密。很简单的思路所以我就不详细解释了,在代码中都有注释。
首先我们将加密的最大字节数与解密的最大字节数设为常量
//注意自己生成的密钥对的bits长度
val ENCRYPT_MAX_SIZE = 245//加密每次最大加密字节
val DECRYPT_MAX_SIZE = 256//解密每次最大加密字节
私钥分段加密
/**
* 私钥分段加密
* @param input 原文
* @param privateKey 私钥
*/
fun segmentEncryptByPrivateKey(input:String,privateKey:PrivateKey): String {
//创建cipher对象
val cipher = Cipher.getInstance(transformation)
//初始化cipher
cipher.init(Cipher.ENCRYPT_MODE,privateKey)
//****非对称加密****
val byteArray = input.toByteArray()
//分段加密
var temp:ByteArray? = null
var offset = 0 //当前偏移的位置
val outputStream = ByteArrayOutputStream()
//拆分input
while (byteArray.size - offset > 0){
//每次最大加密245个字节
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
}
//存储到临时的缓冲区
outputStream.write(temp)
}
outputStream.close()
return String(Base64.getEncoder().encode(outputStream.toByteArray()))
}
公钥分段加密
/**
* 公钥分段加密
* @param input 原文
* @param publicKey 公钥
*/
fun segmentEncryptByPublicKey(input:String,publicKey:PublicKey): String {
//创建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 //当前偏移的位置
val outputStream = ByteArrayOutputStream()
//拆分input
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
}
//存储到临时的缓冲区
outputStream.write(temp)
}
outputStream.close()
return String(Base64.getEncoder().encode(outputStream.toByteArray()))
}
这样我们可以打印结果查看
val input = "RSA加密测试RSA加密测试RSA加密测试RSA加密测试RSA加密测试RSA加密测试RSA加密测试RSA加密测试RSA加密测试RSA加密测试RSA加密测试"
// 超过245个字节需要使用分段加密
//私钥分段加密
val encryptByPrivateKey = RSACrypt.segmentEncryptByPrivateKey(input, privateKey)
println("RSA私钥分段加密结果:"+encryptByPrivateKey)
//公钥分段加密
val encryptByPublicKey = RSACrypt.segmentEncryptByPublicKey(input, publicKey)
println("RSA公钥分段加密结果:"+encryptByPublicKey)
分段解密
分段解密的原理一样,我们需要将加密后的秘文分段,然后解密
私钥分段解密
/**
* 私钥分段解密
* @param input 秘文
* @param privateKey 私钥
*/
fun segmentDecryptByPrivateKey(input:String,privateKey:PrivateKey): String {
//创建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 //当前偏移的位置
val outputStream = ByteArrayOutputStream()
//拆分input
while (byteArray.size - offset > 0){
//每次最大解密256个字节
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
}
//存储到临时的缓冲区
outputStream.write(temp)
}
outputStream.close()
return String(outputStream.toByteArray())
}
公钥分段解密
/**
* 公钥分段解密
* @param input 秘文
* @param privateKey 公钥
*/
fun segmentDecryptByPublicKey(input:String,publicKey: PublicKey): String {
//创建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 //当前偏移的位置
val outputStream = ByteArrayOutputStream()
//拆分input
while (byteArray.size - offset > 0){
//每次最大解密256个字节
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
}
//存储到临时的缓冲区
outputStream.write(temp)
}
outputStream.close()
return String(outputStream.toByteArray())
}
然后我们进行结果打印,需要注意:
使用私钥解密的是用公钥加密的秘文
使用公钥解密的是用私钥加密的秘文
//分段解密
//私钥分段解密:input应该为使用公钥加密后的秘文
val decryptByPrivateKey = RSACrypt.segmentDecryptByPrivateKey(encryptByPublicKey, privateKey)
println("RSA私钥分段解密结果:"+decryptByPrivateKey)
//公钥分段解密:input应该为使用私钥加密后的秘文
val decryptByPublicKey = RSACrypt.segmentDecryptByPublicKey(encryptByPrivateKey, publicKey)
println("RSA公钥分段解密结果:"+decryptByPublicKey)
以上就是RSA非对称加密解密的全部内容
RSA加密主要用于数字签名,SSL证书等用途
如果文中有错误的地方,欢迎评论指出
谢谢观看