在我的资源【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;