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

Java VoIP程序ByteBuffer解密异常:音频乱码问题求助

问题分析与修复方案

核心问题

  1. 加密逻辑完全错误
    你当前的加密代码里,每次循环都从原始数据重新读取(因为plainText.rewind()),而非基于上一次XOR的结果继续处理。说白了,不管你有多少个密钥,最终加密结果只等于原始数据 XOR 最后一个密钥,前面的密钥循环全白跑了,完全没起到作用。

  2. 解密端ByteBuffer索引彻底混乱

    • 读取完authKey后,cipherText的指针已经移到第2字节,但循环里调用cipherText.rewind()会把指针重置回0,导致后续循环把authKey的字节当成数据读取,直接破坏了解密流程。
    • 计算循环次数用block.length /4是错的,因为block包含2字节的authKey,实际数据长度是block.length -2,而且如果原数据长度不是4的倍数,还会丢失剩余字节。
  3. 数据长度兼容性缺失
    原代码只处理长度为4倍数的数据,VoIP音频数据大概率不是刚好4字节的整数倍,这会直接截断最后一部分数据,导致音频乱码。


修复后的加密代码

private byte[] encryptData(byte[] data) {
    // 分配空间:2字节校验位 + 原数据长度
    ByteBuffer unwrapEncrypt = ByteBuffer.allocate(2 + data.length);
    short authKey = 10;
    unwrapEncrypt.putShort(authKey);
    
    // 克隆原数据到临时缓冲区,用于累积XOR结果
    ByteBuffer tempBuffer = ByteBuffer.wrap(data.clone());
    
    // 依次用每个密钥做XOR,每次基于上一次的结果继续处理
    for (Integer key : keys) {
        tempBuffer.rewind();
        ByteBuffer tempResult = ByteBuffer.allocate(data.length);
        while (tempBuffer.hasRemaining()) {
            if (tempBuffer.remaining() >= 4) {
                int fourByte = tempBuffer.getInt();
                fourByte ^= key;
                tempResult.putInt(fourByte);
            } else {
                // 处理不足4字节的剩余数据,避免丢失
                byte[] remaining = new byte[tempBuffer.remaining()];
                tempBuffer.get(remaining);
                for (int i = 0; i < remaining.length; i++) {
                    remaining[i] ^= (byte) key.intValue();
                }
                tempResult.put(remaining);
            }
        }
        tempBuffer = tempResult;
    }
    
    // 把最终加密结果写入输出缓冲区
    tempBuffer.rewind();
    unwrapEncrypt.put(tempBuffer.array());
    return unwrapEncrypt.array();
}

修复后的解密代码

// 注意:unwrapDecrypt需要提前分配好大小为block.length -2的空间
ByteBuffer cipherText = ByteBuffer.wrap(block);
short authKey = cipherText.getShort();

if (authKey == 10) {
    // 跳过校验位,提取实际加密的数据部分
    byte[] encryptedData = new byte[block.length - 2];
    cipherText.get(encryptedData);
    
    ByteBuffer tempBuffer = ByteBuffer.wrap(encryptedData.clone());
    
    // 解密要反向遍历密钥列表(XOR可逆,逆操作就是反向再XOR一遍)
    for (int i = keys.size() - 1; i >= 0; i--) {
        Integer key = keys.get(i);
        tempBuffer.rewind();
        ByteBuffer tempResult = ByteBuffer.allocate(encryptedData.length);
        while (tempBuffer.hasRemaining()) {
            if (tempBuffer.remaining() >= 4) {
                int fourByte = tempBuffer.getInt();
                fourByte ^= key;
                tempResult.putInt(fourByte);
            } else {
                byte[] remaining = new byte[tempBuffer.remaining()];
                tempBuffer.get(remaining);
                for (int j = 0; j < remaining.length; j++) {
                    remaining[j] ^= (byte) key.intValue();
                }
                tempResult.put(remaining);
            }
        }
        tempBuffer = tempResult;
    }
    
    tempBuffer.rewind();
    unwrapDecrypt.put(tempBuffer.array());
    byte[] decryptedBlock = unwrapDecrypt.array();
    // 这里继续处理解密后的音频数据
}

关键修复说明

  • 加密逻辑改成累积XOR:每个密钥都基于上一次的加密结果继续处理,确保所有密钥都生效,同时保证解密时反向遍历密钥就能还原原始数据。
  • 解密端彻底修正了指针问题:读取校验位后直接提取数据部分,不再调用rewind()破坏指针位置,避免把校验位当成数据读取。
  • 兼容任意长度数据:新增了剩余字节处理逻辑,不管音频数据长度是不是4的倍数,都能完整加密解密,不会丢失数据。

内容的提问来源于stack exchange,提问作者sunny

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 22:13:19