Snippets
Created by
Алексей Корепанов
last modified
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 | unit uCryptoDecode;
interface
uses
System.SysUtils;
function SBDecryptData(const AData: PByte; const ADataSize: Cardinal; const APassword: PByte; const APasswordSize: Cardinal): TBytes; overload;
function SBDecryptData(const AData, APassword: TBytes): TBytes; overload;
function SBDecryptData(const AData, APassword: String): String; overload;
implementation
uses
System.Classes,
JwaWinCrypt,
JwaWinType,
Winapi.Windows;
type
TObjectValue<T: record> = record
private
FBuffer: TBytes;
FStruct: ^T;
function GetValue: T; inline;
public
procedure Read(const AStructType: PAnsiChar; const AData: PByte; const ADataSize: Cardinal;
const AEncodingType: Cardinal = PKCS_7_ASN_ENCODING or X509_ASN_ENCODING; const AFlags: Cardinal = CRYPT_DECODE_NOCOPY_FLAG or CRYPT_DECODE_SHARE_OID_STRING_FLAG);
property Value: T read GetValue;
property Buffer: TBytes read FBuffer;
end;
function Win32Check(RetVal: BOOL): BOOL; inline;
begin
{$WARN SYMBOL_PLATFORM OFF}
Result := System.SysUtils.Win32Check(RetVal);
{$WARN SYMBOL_PLATFORM ON}
end;
function DecryptCipher(const ACipher, ASalt, APassword, AIV: PByte;
const ACipherLength, ASaltLength, APasswordLength: Cardinal; const AHashAlg, AEncAlg: ALG_ID): TBytes;
var
LProv: HCRYPTPROV;
LHash: HCRYPTHASH;
LDeriveKey: HCRYPTKEY;
LBufferSize: Cardinal;
begin
Win32Check(CryptAcquireContext(LProv, nil, nil, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT));
try
Win32Check(CryptCreateHash(LProv, AHashAlg, 0, 0, LHash));
try
Win32Check(CryptHashData(LHash, APassword, APasswordLength, 0));
Win32Check(CryptHashData(LHash, ASalt, ASaltLength, 0));
Win32Check(CryptDeriveKey(LProv, AEncAlg, LHash, CRYPT_EXPORTABLE or CRYPT_NO_SALT, LDeriveKey));
finally
Win32Check(CryptDestroyHash(LHash));
end;
try
Win32Check(CryptSetKeyParam(LDeriveKey, KP_IV, AIV, 0));
LBufferSize := ACipherLength;
Win32Check(CryptDecrypt(LDeriveKey, 0, True, 0, ACipher, LBufferSize));
SetLength(Result, LBufferSize);
CopyMemory(@Result[0], ACipher, LBufferSize);
finally
Win32Check(CryptDestroyKey(LDeriveKey));
end;
finally
Win32Check(CryptReleaseContext(LProv, 0));
end;
end;
function SBDecryptData(const AData: PByte; const ADataSize: Cardinal; const APassword: PByte; const APasswordSize: Cardinal): TBytes;
var
LContentInfo: TObjectValue<CRYPT_CONTENT_INFO>;
LContentInfoSequence: TObjectValue<CRYPT_CONTENT_INFO_SEQUENCE_OF_ANY>;
LSequence: PCRYPT_DER_BLOB;
LCapicomVersion: TObjectValue<Integer>;
LAlgId: TObjectValue<Integer>;
LKeyLength: TObjectValue<Integer>;
LIV: TObjectValue<CRYPT_DATA_BLOB>;
LSalt: TObjectValue<CRYPT_DATA_BLOB>;
LCipher: TObjectValue<CRYPT_DATA_BLOB>;
begin
LContentInfo.Read(PKCS_CONTENT_INFO, AData, ADataSize);
LContentInfoSequence.Read(PKCS_CONTENT_INFO_SEQUENCE_OF_ANY, LContentInfo.Value.Content.pbData, LContentInfo.Value.Content.cbData);
LSequence := LContentInfoSequence.Value.rgValue;
LCapicomVersion.Read(X509_INTEGER, LSequence.pbData, LSequence.cbData);
Inc(LSequence);
LAlgId.Read(X509_INTEGER, LSequence.pbData, LSequence.cbData);
Inc(LSequence);
LKeyLength.Read(X509_INTEGER, LSequence.pbData, LSequence.cbData);
Inc(LSequence);
LIV.Read(X509_OCTET_STRING, LSequence.pbData, LSequence.cbData);
Inc(LSequence);
LSalt.Read(X509_OCTET_STRING, LSequence.pbData, LSequence.cbData);
Inc(LSequence);
LCipher.Read(X509_OCTET_STRING, LSequence.pbData, LSequence.cbData);
Result := DecryptCipher(LCipher.Value.pbData, LSalt.Value.pbData, APassword, LIV.Value.pbData,
LCipher.Value.cbData, LSalt.Value.cbData, APasswordSize, CALG_SHA, LAlgId.Value);
end;
function SBDecryptData(const AData: TBytes; const APassword: TBytes): TBytes;
begin
Result := SBDecryptData(@AData[0], Length(AData), @APassword[0], Length(APassword));
end;
function CryptStringToBinary(pszString: LPCTSTR; cchString: DWORD;
dwFlags: DWORD; ppBinary: PBYTE; var ppcbBinary: DWORD;
ppdwSkip: PDWORD; ppdwFlags: PDWORD): BOOL; stdcall; external 'crypt32.dll' name 'CryptStringToBinaryW';
function SBDecryptData(const AData, APassword: String): String; overload;
var
LData: TBytes;
LDataSize: Cardinal;
begin
Win32Check(CryptStringToBinary(PWideChar(AData), Length(AData) + 1, CRYPT_STRING_BASE64, nil, LDataSize, nil, nil));
SetLength(LData, LDataSize);
Win32Check(CryptStringToBinary(PWideChar(AData), Length(AData) + 1, CRYPT_STRING_BASE64, @LData[0], LDataSize, nil, nil));
with TEncoding.Unicode do
Result := GetString(SBDecryptData(LData, GetBytes(APassword)));
end;
{ TObjectValue<T> }
function TObjectValue<T>.GetValue: T;
begin
Result := FStruct^;
end;
procedure TObjectValue<T>.Read(const AStructType: PAnsiChar; const AData: PByte; const ADataSize, AEncodingType,
AFlags: Cardinal);
var
LBufferSize: DWORD;
begin
Win32Check(CryptDecodeObject(AEncodingType, AStructType, AData, ADataSize, AFlags, nil, LBufferSize));
SetLength(FBuffer, LBufferSize);
Win32Check(CryptDecodeObject(AEncodingType, AStructType, AData, ADataSize, AFlags, @FBuffer[0], LBufferSize));
FStruct := @FBuffer[0];
end;
end.
|
Comments (0)
You can clone a snippet to your computer for local editing. Learn more.