我设计了一个存储数据块的系统,由多个客户端压缩和加密发送。
当尝试在特定计算机上获取存储的数据块(我需要解压缩和解密)时,在数据解压缩期间会引发 ZLib“数据错误”异常。很明显,该流尚未正确解密,因此输入流不是有效的 ZLib 流,从而导致此类问题。
经过一番研究,我发现对于同样存储的相同源数据块,这个有问题的块包含完全不同的数据,因此很明显加密或压缩算法存在问题。
然而,我不能轻易地重现问题的事实意味着,如果有错误,它远非显而易见。所以我在这里发布代码,希望有人会发现我没有看到的东西。
首先,数据块AStream
被压缩:
function CompressStream(AStream: TMemoryStream;
ACompressionLevel:
TCompressionLevel): Boolean;
var
LTempStream: TMemoryStream;
LCompressedStream: TCompressionStream;
begin
LTempStream := TMemoryStream.create;
try
try
AStream.Seek(0, soBeginning);
LCompressedStream := TCompressionStream.Create(ACompressionLevel, LTempStream);
try
try
LCompressedStream.CopyFrom(AStream, AStream.Size);
finally
LCompressedStream.free;
end;
finally
AStream.Clear;
AStream.CopyFrom(LTempStream, 0);
AStream.Seek(0, soBeginning);
Result := True;
end;
finally
LTempStream.free;
end;
except
Result := False;
end;
end;
然后,它被加密:
function EncryptStream(AStream: TMemoryStream; const AParameters: AnsiString): Boolean;
var
LModifiedStream: TMemoryStream;
LRijndaelCipher: TDCP_rijndael;
begin
try
LRijndaelCipher := TDCP_rijndael.Create(nil);
LModifiedStream := TMemoryStream.Create;
InitCipherWithKey(LRijndaelCipher, AParameters);
try
AStream.Seek(0, soBeginning);
LRijndaelCipher.EncryptStream(AStream, LModifiedStream, AStream.Size);
TMemoryStream(AStream).Clear;
AStream.CopyFrom(LModifiedStream, 0);
Result := True;
finally
LRijndaelCipher.Burn;
LRijndaelCipher.Free;
LModifiedStream.Free;
end;
except
Result := False;
end;
end;
...并存储在某个地方。
获取数据块时,首先对其进行解密:
function DecryptStream(AStream: TMemoryStream; const AParameters: AnsiString): Boolean;
var
LModifiedStream: TMemoryStream;
LRijndaelCipher: TDCP_rijndael;
begin
try
LRijndaelCipher := TDCP_rijndael.Create(nil);
LModifiedStream := TMemoryStream.Create;
InitCipherWithKey(LRijndaelCipher, AParameters);
try
AStream.Seek(0, soBeginning);
LRijndaelCipher.DecryptStream(AStream, LModifiedStream, AStream.Size);
TMemoryStream(AStream).Clear;
AStream.CopyFrom(LModifiedStream, 0);
Result := True;
finally
LRijndaelCipher.Burn;
LRijndaelCipher.Free;
LModifiedStream.Free;
end;
except
Result := False;
end;
end;
然后解压:
function DecompressStream(AStream: TMemoryStream): Boolean;
var
LTempStream: TMemoryStream;
LCompressedStream: TDecompressionStream;
begin
LTempStream := TMemoryStream.create;
try
try
AStream.Seek(0, soBeginning);
LCompressedStream := TDecompressionStream.Create(AStream);
try
try
LTempStream.CopyFrom(LCompressedStream, LCompressedStream.size);
finally
LCompressedStream.Free;
end;
finally
AStream.Clear;
AStream.CopyFrom(LTempStream, 0);
AStream.Seek(0, soBeginning);
Result := True;
end;
finally
LTempStream.free;
end;
except
Result := False;
end;
end;
使用该InitCipherWithKey()
方法初始化密码。它旨在将 MD5 哈希转换为包含在LMD5Hash
变量中的二进制表示(是的,数组长 64 个字节,但只有前 16 个字节将被密码使用,因为我Init()
使用 128 值调用(这意味着 128 -bit/16 字节密钥长度):
procedure InitCipherWithKey(ACipher: TDCP_cipher; const AKey: AnsiString);
var
LMD5Hash: array [0..63] of Byte;
S: AnsiString;
begin
//We use a 128 bit key
ZeroMemory(@LMD5Hash, SizeOf(LMD5Hash));
S := AKey;
HexToBin(PAnsiChar(S), LMD5Hash, Length(LMD5Hash) -1);
ACipher.Init(LMD5Hash[0], 128, nil);
ZeroMemory(@LMD5Hash, SizeOf(LMD5Hash));
end;
提前致谢。