在我的资源【Delphi XE2+标准AES加解密算法(AES/EBC,CBC/PKCS5Padding-base64)】中,有朋友反应说aes加密以base64模式输出时,解密的时候报错。因为我的项目中使用的是十六进制,所以当时没有留意到这个情况。现将修复后的代码贴出,供有需要的朋友使用。
问题主要出现在JDAESExtend.pas解密函数(DecryptString)的base64解密段(以下代码在XE2,加密模式ECB+PKCS5Padding-base64模式下验证成功。)
在研究它加密的逻辑时可以看到,base64加密使用了EncdDecd.EncodeStream(DS,outDS):
outDS := TStringStream.Create('',TEncoding.UTF8);
try
DS.Position := 0;
EncdDecd.EncodeStream(DS,outDS);
Result := outDS.DataString;
finally
freeandnil(outDS);
end;
但base64解密时直接用了EncdDecd.DecodeString(Value)
if CipherType= ctHex then
str := HexToStr(Value)
else
str := EncdDecd.DecodeString(Value);
故我们可以尝试把解密的方式调整下,用base64的逆向解密。调整后的解密函数为:
function DecryptString(Value: AnsiString; Key: AnsiString; KeyBit: TKeyBit = kb128; algoMode: TalgoMode = amECB; padding: TPaddingType = PKCS5Padding; sInitVector: AnsiString = '0000000000000000';
CipherType: TCipherType = ctHex): AnsiString;
var
SS,DS: TMemoryStream;
DSBase64: TStringStream;
str: AnsiString;
byteContent: TBytes;
BytesValue: TBytes;
begin
Result := '';
DS := TMemoryStream.Create;
SS := TMemoryStream.Create;
if CipherType= ctHex then
begin
str := HexToStr(Value);
SetLength(byteContent, Length(str));
Move(str[1], byteContent[0], Length(str));
SS.WriteBuffer(byteContent[0], Length(byteContent));
end
else
begin
try
DSBase64 := TStringStream.Create(Value,TEncoding.UTF8);
DSBase64.Position := 0;
EncdDecd.DecodeStream(DSBase64,SS);
SS.Position := 0;
finally
freeandnil(DSBase64);
end;
end;
try
case KeyBit of
kb128:
begin
ZeroPadding(kb128);
Move(PAnsiChar(Key)^, AESKey128, Length(Key));
case algoMode of
amECB:
begin
DecryptAESStreamECB(SS, 0, AESKey128, DS);
end;
amCBC:
begin
// 不足16位用0补齐
FillChar(InitVector, SizeOf(InitVector), 0);
Move(PAnsiChar(sInitVector)^, InitVector, Length(sInitVector));
DecryptAESStreamCBC(SS, 0, AESKey128, InitVector, DS);
end;
end;
end;
kb192:
begin
ZeroPadding(kb192);
Move(PAnsiChar(Key)^, AESKey192, Length(Key));
case algoMode of
amECB:
begin
DecryptAESStreamECB(SS, 0, AESKey192, DS);
end;
amCBC:
begin
FillChar(InitVector, SizeOf(InitVector), 0);
Move(PAnsiChar(sInitVector)^, InitVector, Length(sInitVector));
DecryptAESStreamCBC(SS, 0, AESKey192, InitVector, DS);
end;
end;
end;
kb256:
begin
ZeroPadding(kb256);
Move(PAnsiChar(Key)^, AESKey256, Length(Key));
case algoMode of
amECB:
begin
DecryptAESStreamECB(SS, 0, AESKey256, DS);
end;
amCBC:
begin
FillChar(InitVector, SizeOf(InitVector), 0);
Move(PAnsiChar(sInitVector)^, InitVector, Length(sInitVector));
DecryptAESStreamCBC(SS, 0, AESKey256, InitVector, DS);
end;
end;
end;
end;
DS.Position := 0;
SetLength(BytesValue, DS.size);
DS.ReadBuffer(BytesValue[0], DS.size);
Result := PKCS5_DePadding(BytesValue);
finally
SS.Free;
DS.Free;
end;
end;