为什么hutool的AES工具类在循环内外表现不一致呢?
环境
- 语言:Kotlin 1.8
- 环境:Windows 11
- IDE:Idea 2023.1.3
- 框架:SpringBoot 3.1.1
- Hutool版本:cn.hutool.hutool-all:5.8.20
- KCP Java库:com.github.l42111996.kcp-base:1.6
期望
以KCP作为通讯协议,在客户端和服务端之间使用AES加密通讯数据,在客户端进行加密后的消息,能够在服务端正常解密。
代码(报错版)
客户端:
import cn.hutool.core.codec.Base64import cn.hutool.core.util.HexUtil
import cn.hutool.crypto.Mode
import cn.hutool.crypto.Padding
import cn.hutool.crypto.SecureUtil
import cn.hutool.crypto.asymmetric.KeyType
import cn.hutool.crypto.asymmetric.RSA
import cn.hutool.crypto.symmetric.AES
import cn.hutool.crypto.symmetric.SymmetricAlgorithm
import com.alibaba.fastjson2.JSON
import io.netty.buffer.ByteBuf
import io.netty.buffer.ByteBufAllocator
import kcp.ChannelConfig
import kcp.KcpClient
import kcp.KcpListener
import kcp.Ukcp
import org.slf4j.LoggerFactory
import threadPool.disruptor.DisruptorExecutorPool
import java.net.InetSocketAddress
import java.util.*
// 省略了KCP Listener的实现(表现正常)
fun main() {
val channelConfig = ChannelConfig()
// 普通模式,参考:https://github.com/skywind3000/kcp#%E5%8D%8F%E8%AE%AE%E9%85%8D%E7%BD%AE
channelConfig.nodelay(false, 40, 0, false)
channelConfig.setiMessageExecutorPool(DisruptorExecutorPool(Runtime.getRuntime().availableProcessors() / 2))
channelConfig.isCrc32Check = true
val kcpClient = KcpClient()
kcpClient.init(channelConfig)
val app = App()
val kcp = kcpClient.connect(InetSocketAddress("127.0.0.1", 9000), channelConfig, app)
val log = LoggerFactory.getLogger("main")
// =================================
// 问题出在下面这句AES的初始化
val aes = AES(Mode.ECB, Padding.ZeroPadding, app.aesKey)
// =================================
while (true) {
val scanner = Scanner(System.`in`)
val nextLine = scanner.nextLine()
val message = aes.encrypt(nextLine.toByteArray(Charsets.UTF_8))
log.info("解密测试:{}", aes.decrypt(message).toString(Charsets.UTF_8))
log.info("发送消息:{},长度:{},Hex:{}", message, message.size, HexUtil.encodeHexStr(message))
kcp?.write(ByteBufAllocator.DEFAULT.buffer().writeBytes(
message
))
}
}
运行上面的代码,会读取命令行输入,然后发送通过AES加密后的数据到服务器,服务器进行解密。
命令行输入:test
服务器输出:
这里解密后是一堆乱码,无法正常解密。
代码(正常版)
客户端:
import cn.hutool.core.codec.Base64import cn.hutool.core.util.HexUtil
import cn.hutool.crypto.Mode
import cn.hutool.crypto.Padding
import cn.hutool.crypto.SecureUtil
import cn.hutool.crypto.asymmetric.KeyType
import cn.hutool.crypto.asymmetric.RSA
import cn.hutool.crypto.symmetric.AES
import cn.hutool.crypto.symmetric.SymmetricAlgorithm
import com.alibaba.fastjson2.JSON
import io.netty.buffer.ByteBuf
import io.netty.buffer.ByteBufAllocator
import kcp.ChannelConfig
import kcp.KcpClient
import kcp.KcpListener
import kcp.Ukcp
import org.slf4j.LoggerFactory
import threadPool.disruptor.DisruptorExecutorPool
import java.net.InetSocketAddress
import java.util.*
// 省略了KCP Listener的实现(表现正常)
fun main() {
val channelConfig = ChannelConfig()
// 普通模式,参考:https://github.com/skywind3000/kcp#%E5%8D%8F%E8%AE%AE%E9%85%8D%E7%BD%AE
channelConfig.nodelay(false, 40, 0, false)
channelConfig.setiMessageExecutorPool(DisruptorExecutorPool(Runtime.getRuntime().availableProcessors() / 2))
channelConfig.isCrc32Check = true
val kcpClient = KcpClient()
kcpClient.init(channelConfig)
val app = App()
val kcp = kcpClient.connect(InetSocketAddress("127.0.0.1", 9000), channelConfig, app)
val log = LoggerFactory.getLogger("main")
while (true) {
val scanner = Scanner(System.`in`)
val nextLine = scanner.nextLine()
// =========================================
// 将AES初始化移到while循环内,就表现正常
val aes = AES(Mode.ECB, Padding.ZeroPadding, app.aesKey)
// =========================================
val message = aes.encrypt(nextLine.toByteArray(Charsets.UTF_8))
log.info("解密测试:{}", aes.decrypt(message).toString(Charsets.UTF_8))
log.info("发送消息:{},长度:{},Hex:{}", message, message.size, HexUtil.encodeHexStr(message))
kcp?.write(ByteBufAllocator.DEFAULT.buffer().writeBytes(
message
))
}
}
同样运行代码,命令行输入:test
服务器输出:
这里就可以正常解密了。
疑问
非常疑惑的一点在于,刚才的测试都是客户端刚启动,进入循环的第一次命令行读取时进行的,那么此时AES都是只被初始化了一次,对于第一次循环来说,执行的语句是一样的,那么为什么会有不同的结果——在循环外初始化会导致解密错误呢。
希望大佬解答!感谢!
补充
两个版本的代码,在客户端内部发送前的解密测试那里,都是可以正常解密的,但是错误版的代码将消息发送到服务器就会解密错误。
回答:
在服务器端,对每个接收到的数据块都建一个新的AES实例来解密。或者
在客户端和服务器端都使用一个持久的AES实例,但是要保证你用的是一个可以处理这种情况的加密模式和填充方式。比如,你可以用CBC模式和PKCS5Padding填充方式。
以上是 为什么hutool的AES工具类在循环内外表现不一致呢? 的全部内容, 来源链接: utcz.com/p/945294.html