今天在在通过管道将上一个命令的输出传递给下一个命令时, 发现最终得到的数据怎么都不对, 经过一整天的debug, 终于发现问题出在了第二个命令的缓冲区上
一开始脑子抽了, 觉得是openwrt平台的zstd有问题, 甚至用go重新写了一个zstd工具
背景
- tar打包目录为
A.tar
- zstd压缩
A.tar
为A.tar.zst
- kscrypt加密
A.tar.zst
为A.tar.zst.enc
(kscrypt是自己编写的加密程序)
完整命令如下
1# 打包压缩加密
2tar -cf - -C "$SYNC_PATH" . | zstd -c | kscrypt -key "$PASSWORD" -out "A.tar.zst.enc"
3# 测试
4kscrypt -d -key "$PASSWORD" -in "A.tar.zst.enc" | zstd -d -c | tar -tf - > /dev/null
5# 解密解压解包
6kscrypt -d -key "$PASSWORD" -in "A.tar.zst.enc" | zstd -d -c | tar -xvf -
经过多次测试, 发现在OpenWrt系统下 kscrypt
加密后的数据怎么都对不上, 解密总是失败
问题代码
虽然配置了缓冲区大小, 但是每次input.Read
得到的数据大小并不固定, 导致每次加密的数据块大小不一致. 而在解密时没有读取到正确的数据块大小, 导致解密失败
1buffer := make([]byte, bufferSize)
2for {
3 n, readErr := input.Read(buffer)
4 if n > 0 {
5 encrypted := aesGCM.Seal(nil, nonce, buffer[:n], nil) // 加密
6 _, writeErr := output.Write(encrypted) // 写入加密数据
7 if writeErr != nil {
8 return fmt.Errorf("写入加密数据失败: %v", writeErr)
9 }
10 }
11 if errors.Is(readErr, io.EOF) {
12 break
13 }
14 if readErr != nil {
15 return fmt.Errorf("读取输入数据失败: %v", readErr)
16 }
17}
改正代码
增加了缓冲区, 当缓冲区数据达到指定的块大小后, 再执行加密或解密, 保证数据块大小一致
1tmp := make([]byte, maxEncryptionBlockSize)
2buffer := bytes.NewBuffer(nil)
3for {
4 n, readErr := input.Read(tmp)
5 if n > 0 {
6 _, err = buffer.Write(tmp[:n])
7 if err != nil {
8 return err
9 }
10 for buffer.Len() >= maxEncryptionBlockSize {
11 incrementNonce(nonce)
12 data := buffer.Next(maxEncryptionBlockSize)
13 encrypted := aesGCM.Seal(nil, nonce, data, nil)
14 if _, err := output.Write(encrypted); err != nil {
15 return err
16 }
17 }
18 }
19 if readErr == io.EOF {
20 if buffer.Len() > 0 {
21 incrementNonce(nonce)
22 data := buffer.Bytes()
23 encrypted := aesGCM.Seal(nil, nonce, data, nil)
24 if _, err := output.Write(encrypted); err != nil {
25 return err
26 }
27 }
28 break
29 }
30 if readErr != nil {
31 return readErr
32 }
33}
除另有声明外,本博客文章均采用 知识共享 (Creative Commons) 署名 4.0 国际许可协议 进行许可。转载请注明原作者与文章出处。