You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

将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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 03:35:12