将XTEA解密实现从JS迁移至Go时遇结果不一致问题
问题:JavaScript XTEA解密转Go语言实现结果不匹配
我正尝试将以下JavaScript的XTEA解密实现改写为Go语言:
function decipherXTea(v, k) { const ROUNDS = 32; const DELTA = 0x9E3779B9; let y = v[0]; let z = v[1]; let sum = DELTA * ROUNDS; for (let round = 0; round < ROUNDS; round++) { z -= ((y << 4 ^ y >> 5) + y) ^ (sum + k[sum >> 11 & 3]); sum -= DELTA; y -= ((z << 4 ^ z >> 5) + z) ^ (sum + k[sum & 3]); } return [ y, z ]; }
但我的Go代码虽然初始y和z值与JS一致,经过运算轮次后,结果却完全不匹配。我的Go实现如下:
func decrypt(k [4]int64, block []byte) []byte { y := int64(int32(block[0])<<24 | int32(block[1])<<16 | int32(block[2])<<8 | int32(block[3])<<0) z := int64(int32(block[4])<<24 | int32(block[5])<<16 | int32(block[6])<<8 | int32(block[7])<<0) fmt.Printf("y: %d, z: %d\n", y, z) const ( rounds = 32 delta int64 = 0x9E3779B9 ) sum := delta * rounds for i := 0; i < rounds; i++ { z -= int64(int32(int64(int32(y)<<4^int32(y)>>5)+y) ^ int32(sum+k[int32(sum)>>11&3])) sum -= delta y -= int64((int32(z<<4^z>>5) + int32(z)) ^ int32(sum+k[int32(sum)&3])) } fmt.Printf("result: %d, %d\n", y, z) end := make([]byte, 8) end[0] = byte(y >> 24 & 255) end[1] = byte(y >> 16 & 255) end[2] = byte(y >> 8 & 255) end[3] = byte(y & 255) end[4] = byte(z >> 24 & 255) end[5] = byte(z >> 16 & 255) end[6] = byte(z >> 8 & 255) end[7] = byte(z & 255) return end }
问题原因及修复方案
问题核心在于整数类型的处理差异:JavaScript默认使用32位有符号整数运算,所有运算结果会自动截断为32位;而你的Go代码混用了int64和int32,破坏了原有的32位整数溢出逻辑,导致运算结果偏差。
修复步骤:
- 全程使用
int32类型处理所有运算,对齐JS的32位有符号整数行为 - 调整块数据解析逻辑,直接转为
int32而非先转int64 - 简化运算中的类型转换,避免不必要的强制转换
修复后的Go代码:
func decrypt(k [4]int32, block []byte) []byte { // 正确解析8字节块为两个32位有符号整数 y := int32(block[0])<<24 | int32(block[1])<<16 | int32(block[2])<<8 | int32(block[3]) z := int32(block[4])<<24 | int32(block[5])<<16 | int32(block[6])<<8 | int32(block[7]) const ( rounds = 32 delta int32 = 0x9E3779B9 ) sum := delta * rounds for i := 0; i < rounds; i++ { // 完全对齐JS运算逻辑,用int32保持溢出行为一致 z -= ((y << 4 ^ y >> 5) + y) ^ (sum + k[sum>>11&3]) sum -= delta y -= ((z << 4 ^ z >> 5) + z) ^ (sum + k[sum&3]) } // 将解密后的int32转换回8字节数组 end := make([]byte, 8) end[0] = byte(y >> 24) end[1] = byte(y >> 16) end[2] = byte(y >> 8) end[3] = byte(y) end[4] = byte(z >> 24) end[5] = byte(z >> 16) end[6] = byte(z >> 8) end[7] = byte(z) return end }
关键说明:
- 密钥参数
k的类型从[4]int64改为[4]int32,确保和JS密钥类型匹配 - 转换回字节数组时无需额外
&255,byte类型本身会自动截断为8位无符号值 - 保持
int32类型运算可精准模拟JS的32位整数溢出行为,这是结果匹配的核心
内容的提问来源于stack exchange,提问作者JustTalz
相关产品推荐
相关产品推荐

