使用 io.ReadFull 分块处理数据会导致文件损坏?

Processing data in chunks with io.ReadFull results in corrupted file?

我正在尝试下载和解密 HLS 流,方法是使用 io.ReadFull 分块处理数据以节省内存:

为简单起见,省略了不相关的代码部分。

func main() {
    f, _ := os.Create(out.ts)

    for _, v := range mediaPlaylist {
        resp, _ := http.Get(v.URI)
        for {
            r, err := decryptHLS(key, iv, resp.Body)
            if err != nil && err == io.EOF {
                break
            else if err != nil && err != io.ErrUnexpectedEOF {
                panic(err)
            }
            io.Copy(f, r)
        }
    }
}

func decryptHLS(key []byte, iv []byte, r io.Reader) (io.Reader, error) {
    block, _ := aes.NewCipher(key)

    buf := make([]byte, 8192)

    mode := cipher.NewCBCDecrypter(block, iv)

        n, err := io.ReadFull(r, buf)
        if err != nil && err != io.ErrUnexpectedEOF {
                return nil, err
        }

    mode.CryptBlocks(buf, buf)

    return bytes.NewReader(buf[:n]), err
}

起初这似乎是可行的,因为文件大小正确并且下载过程中没有错误, 但视频已损坏。不完全是因为文件仍被识别为视频,但图像和声音失真。

如果我将代码改为使用 ioutil.ReadAll,最终的视频文件将不再损坏:

func main() {
    f, _ := os.Create(out.ts)

    for _, v := range mediaPlaylist {
        resp, _ := http.Get(v.URI)
        segment, _ := ioutil.ReadAll(resp.Body)
        r, _ := decryptHLS(key, iv, &segment)
        io.Copy(f, r)
    }
}

func decryptHLS(key []byte, iv []byte, s *[]byte) io.Reader {
    block, _ := aes.NewCipher(key)

    mode := cipher.NewCBCDecrypter(block, iv)

    mode.CryptBlocks(*s, *s)

    return bytes.NewReader(*s)
}

知道为什么它在将整个段读入内存时能正常工作,而在使用 io.ReadFull 并分块处理时却不能正常工作吗?

在内部,CBCDecrypter 会复制您的 iv,因此后续块以初始 IV 开头,而不是被之前的解密变异的那个。

创建一次解密器,您应该能够re-using它逐块解密(假设块大小是此加密算法预期的块大小的倍数)。