Quick.Crypto.pas 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. { ***************************************************************************
  2. Copyright (c) 2016-2017 Kike Pérez
  3. Unit : Quick.Crypto
  4. Description : Cryptography utils
  5. Author : Kike Pérez
  6. Version : 1.19
  7. Created : 15/10/2017
  8. Modified : 08/11/2017
  9. This file is part of QuickLib: https://github.com/exilon/QuickLib
  10. ***************************************************************************
  11. Licensed under the Apache License, Version 2.0 (the "License");
  12. you may not use this file except in compliance with the License.
  13. You may obtain a copy of the License at
  14. http://www.apache.org/licenses/LICENSE-2.0
  15. Unless required by applicable law or agreed to in writing, software
  16. distributed under the License is distributed on an "AS IS" BASIS,
  17. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  18. See the License for the specific language governing permissions and
  19. limitations under the License.
  20. *************************************************************************** }
  21. unit Quick.Crypto;
  22. interface
  23. function AES128_Encrypt(const Value, Password: string): string;
  24. function AES128_Decrypt(const Value, Password: string): string;
  25. implementation
  26. uses
  27. SysUtils, Windows, IdCoderMIME, IdGlobal;
  28. //-------------------------------------------------------------------------------------------------------------------------
  29. // Base64 Encode/Decode
  30. //-------------------------------------------------------------------------------------------------------------------------
  31. function Base64_Encode(Value: TBytes): string;
  32. var
  33. Encoder: TIdEncoderMIME;
  34. begin
  35. Encoder := TIdEncoderMIME.Create(nil);
  36. try
  37. Result := Encoder.EncodeBytes(TIdBytes(Value));
  38. finally
  39. Encoder.Free;
  40. end;
  41. end;
  42. function Base64_Decode(Value: string): TBytes;
  43. var
  44. Encoder: TIdDecoderMIME;
  45. begin
  46. Encoder := TIdDecoderMIME.Create(nil);
  47. try
  48. Result := TBytes(Encoder.DecodeBytes(Value));
  49. finally
  50. Encoder.Free;
  51. end;
  52. end;
  53. //-------------------------------------------------------------------------------------------------------------------------
  54. // WinCrypt.h
  55. //-------------------------------------------------------------------------------------------------------------------------
  56. type
  57. HCRYPTPROV = Cardinal;
  58. HCRYPTKEY = Cardinal;
  59. ALG_ID = Cardinal;
  60. HCRYPTHASH = Cardinal;
  61. const
  62. _lib_ADVAPI32 = 'ADVAPI32.dll';
  63. CALG_SHA_256 = 32780;
  64. CALG_AES_128 = 26126;
  65. CRYPT_NEWKEYSET = $00000008;
  66. PROV_RSA_AES = 24;
  67. KP_MODE = 4;
  68. CRYPT_MODE_CBC = 1;
  69. function CryptAcquireContext(var Prov: HCRYPTPROV; Container: PChar; Provider: PChar; ProvType: LongWord; Flags: LongWord): LongBool; stdcall; external _lib_ADVAPI32 name 'CryptAcquireContextW';
  70. function CryptDeriveKey(Prov: HCRYPTPROV; Algid: ALG_ID; BaseData: HCRYPTHASH; Flags: LongWord; var Key: HCRYPTKEY): LongBool; stdcall; external _lib_ADVAPI32 name 'CryptDeriveKey';
  71. function CryptSetKeyParam(hKey: HCRYPTKEY; dwParam: LongInt; pbData: PBYTE; dwFlags: LongInt): LongBool stdcall; stdcall; external _lib_ADVAPI32 name 'CryptSetKeyParam';
  72. function CryptEncrypt(Key: HCRYPTKEY; Hash: HCRYPTHASH; Final: LongBool; Flags: LongWord; pbData: PBYTE; var Len: LongInt; BufLen: LongInt): LongBool;stdcall;external _lib_ADVAPI32 name 'CryptEncrypt';
  73. function CryptDecrypt(Key: HCRYPTKEY; Hash: HCRYPTHASH; Final: LongBool; Flags: LongWord; pbData: PBYTE; var Len: LongInt): LongBool; stdcall; external _lib_ADVAPI32 name 'CryptDecrypt';
  74. function CryptCreateHash(Prov: HCRYPTPROV; Algid: ALG_ID; Key: HCRYPTKEY; Flags: LongWord; var Hash: HCRYPTHASH): LongBool; stdcall; external _lib_ADVAPI32 name 'CryptCreateHash';
  75. function CryptHashData(Hash: HCRYPTHASH; Data: PChar; DataLen: LongWord; Flags: LongWord): LongBool; stdcall; external _lib_ADVAPI32 name 'CryptHashData';
  76. function CryptReleaseContext(hProv: HCRYPTPROV; dwFlags: LongWord): LongBool; stdcall; external _lib_ADVAPI32 name 'CryptReleaseContext';
  77. function CryptDestroyHash(hHash: HCRYPTHASH): LongBool; stdcall; external _lib_ADVAPI32 name 'CryptDestroyHash';
  78. function CryptDestroyKey(hKey: HCRYPTKEY): LongBool; stdcall; external _lib_ADVAPI32 name 'CryptDestroyKey';
  79. //-------------------------------------------------------------------------------------------------------------------------
  80. {$WARN SYMBOL_PLATFORM OFF}
  81. function __CryptAcquireContext(ProviderType: Integer): HCRYPTPROV;
  82. begin
  83. if (not CryptAcquireContext(Result, nil, nil, ProviderType, 0)) then
  84. begin
  85. if HRESULT(GetLastError) = NTE_BAD_KEYSET then
  86. Win32Check(CryptAcquireContext(Result, nil, nil, ProviderType, CRYPT_NEWKEYSET))
  87. else
  88. RaiseLastOSError;
  89. end;
  90. end;
  91. function __AES128_DeriveKeyFromPassword(m_hProv: HCRYPTPROV; Password: string): HCRYPTKEY;
  92. var
  93. hHash: HCRYPTHASH;
  94. Mode: DWORD;
  95. begin
  96. Win32Check(CryptCreateHash(m_hProv, CALG_SHA_256, 0, 0, hHash));
  97. try
  98. Win32Check(CryptHashData(hHash, PChar(Password), Length(Password) * SizeOf(Char), 0));
  99. Win32Check(CryptDeriveKey(m_hProv, CALG_AES_128, hHash, 0, Result));
  100. // Wine uses a different default mode of CRYPT_MODE_EBC
  101. Mode := CRYPT_MODE_CBC;
  102. Win32Check(CryptSetKeyParam(Result, KP_MODE, Pointer(@Mode), 0));
  103. finally
  104. CryptDestroyHash(hHash);
  105. end;
  106. end;
  107. function AES128_Encrypt(const Value, Password: string): string;
  108. var
  109. hCProv: HCRYPTPROV;
  110. hKey: HCRYPTKEY;
  111. lul_datalen: Integer;
  112. lul_buflen: Integer;
  113. Buffer: TBytes;
  114. begin
  115. Assert(Password <> '');
  116. if (Value = '') then
  117. Result := ''
  118. else begin
  119. hCProv := __CryptAcquireContext(PROV_RSA_AES);
  120. try
  121. hKey := __AES128_DeriveKeyFromPassword(hCProv, Password);
  122. try
  123. // allocate buffer space
  124. lul_datalen := Length(Value) * SizeOf(Char);
  125. Buffer := TEncoding.Unicode.GetBytes(Value + ' ');
  126. lul_buflen := Length(Buffer);
  127. // encrypt to buffer
  128. Win32Check(CryptEncrypt(hKey, 0, True, 0, @Buffer[0], lul_datalen, lul_buflen));
  129. SetLength(Buffer, lul_datalen);
  130. // base 64 result
  131. Result := Base64_Encode(Buffer);
  132. finally
  133. CryptDestroyKey(hKey);
  134. end;
  135. finally
  136. CryptReleaseContext(hCProv, 0);
  137. end;
  138. end;
  139. end;
  140. function AES128_Decrypt(const Value, Password: string): string;
  141. var
  142. hCProv: HCRYPTPROV;
  143. hKey: HCRYPTKEY;
  144. lul_datalen: Integer;
  145. Buffer: TBytes;
  146. begin
  147. Assert(Password <> '');
  148. if Value = '' then
  149. Result := ''
  150. else begin
  151. hCProv := __CryptAcquireContext(PROV_RSA_AES);
  152. try
  153. hKey := __AES128_DeriveKeyFromPassword(hCProv, Password);
  154. try
  155. // decode base64
  156. Buffer := Base64_Decode(Value);
  157. // allocate buffer space
  158. lul_datalen := Length(Buffer);
  159. // decrypt buffer to to string
  160. Win32Check(CryptDecrypt(hKey, 0, True, 0, @Buffer[0], lul_datalen));
  161. Result := TEncoding.Unicode.GetString(Buffer, 0, lul_datalen);
  162. finally
  163. CryptDestroyKey(hKey);
  164. end;
  165. finally
  166. CryptReleaseContext(hCProv, 0);
  167. end;
  168. end;
  169. end;
  170. end.