为什么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.Base64

import 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.Base64

import 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

回到顶部