Quick.Crypto.pas 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  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. uses
  24. function AES128_Encrypt(Value, Password: string): string;
  25. function AES128_Decrypt(Value, Password: string): string;
  26. implementation
  27. uses
  28. SysUtils, Windows, IdCoderMIME, IdGlobal;
  29. //-------------------------------------------------------------------------------------------------------------------------
  30. // Base64 Encode/Decode
  31. //-------------------------------------------------------------------------------------------------------------------------
  32. function Base64_Encode(Value: TBytes): string;
  33. var
  34. Encoder: TIdEncoderMIME;
  35. begin
  36. Encoder := TIdEncoderMIME.Create(nil);
  37. try
  38. Result := Encoder.EncodeBytes(TIdBytes(Value));
  39. finally
  40. Encoder.Free;
  41. end;
  42. end;
  43. function Base64_Decode(Value: string): TBytes;
  44. var
  45. Encoder: TIdDecoderMIME;
  46. begin
  47. Encoder := TIdDecoderMIME.Create(nil);
  48. try
  49. Result := TBytes(Encoder.DecodeBytes(Value));
  50. finally
  51. Encoder.Free;
  52. end;
  53. end;
  54. //-------------------------------------------------------------------------------------------------------------------------
  55. // WinCrypt.h
  56. //-------------------------------------------------------------------------------------------------------------------------
  57. type
  58. HCRYPTPROV = Cardinal;
  59. HCRYPTKEY = Cardinal;
  60. ALG_ID = Cardinal;
  61. HCRYPTHASH = Cardinal;
  62. const
  63. _lib_ADVAPI32 = 'ADVAPI32.dll';
  64. CALG_SHA_256 = 32780;
  65. CALG_AES_128 = 26126;
  66. CRYPT_NEWKEYSET = $00000008;
  67. PROV_RSA_AES = 24;
  68. KP_MODE = 4;
  69. CRYPT_MODE_CBC = 1;
  70. function CryptAcquireContext(var Prov: HCRYPTPROV; Container: PChar; Provider: PChar; ProvType: LongWord; Flags: LongWord): LongBool; stdcall; external _lib_ADVAPI32 name 'CryptAcquireContextW';
  71. function CryptDeriveKey(Prov: HCRYPTPROV; Algid: ALG_ID; BaseData: HCRYPTHASH; Flags: LongWord; var Key: HCRYPTKEY): LongBool; stdcall; external _lib_ADVAPI32 name 'CryptDeriveKey';
  72. function CryptSetKeyParam(hKey: HCRYPTKEY; dwParam: LongInt; pbData: PBYTE; dwFlags: LongInt): LongBool stdcall; stdcall; external _lib_ADVAPI32 name 'CryptSetKeyParam';
  73. function CryptEncrypt(Key: HCRYPTKEY; Hash: HCRYPTHASH; Final: LongBool; Flags: LongWord; pbData: PBYTE; var Len: LongInt; BufLen: LongInt): LongBool;stdcall;external _lib_ADVAPI32 name 'CryptEncrypt';
  74. function CryptDecrypt(Key: HCRYPTKEY; Hash: HCRYPTHASH; Final: LongBool; Flags: LongWord; pbData: PBYTE; var Len: LongInt): LongBool; stdcall; external _lib_ADVAPI32 name 'CryptDecrypt';
  75. function CryptCreateHash(Prov: HCRYPTPROV; Algid: ALG_ID; Key: HCRYPTKEY; Flags: LongWord; var Hash: HCRYPTHASH): LongBool; stdcall; external _lib_ADVAPI32 name 'CryptCreateHash';
  76. function CryptHashData(Hash: HCRYPTHASH; Data: PChar; DataLen: LongWord; Flags: LongWord): LongBool; stdcall; external _lib_ADVAPI32 name 'CryptHashData';
  77. function CryptReleaseContext(hProv: HCRYPTPROV; dwFlags: LongWord): LongBool; stdcall; external _lib_ADVAPI32 name 'CryptReleaseContext';
  78. function CryptDestroyHash(hHash: HCRYPTHASH): LongBool; stdcall; external _lib_ADVAPI32 name 'CryptDestroyHash';
  79. function CryptDestroyKey(hKey: HCRYPTKEY): LongBool; stdcall; external _lib_ADVAPI32 name 'CryptDestroyKey';
  80. //-------------------------------------------------------------------------------------------------------------------------
  81. {$WARN SYMBOL_PLATFORM OFF}
  82. function __CryptAcquireContext(ProviderType: Integer): HCRYPTPROV;
  83. begin
  84. if (not CryptAcquireContext(Result, nil, nil, ProviderType, 0)) then
  85. begin
  86. if HRESULT(GetLastError) = NTE_BAD_KEYSET then
  87. Win32Check(CryptAcquireContext(Result, nil, nil, ProviderType, CRYPT_NEWKEYSET))
  88. else
  89. RaiseLastOSError;
  90. end;
  91. end;
  92. function __AES128_DeriveKeyFromPassword(m_hProv: HCRYPTPROV; Password: string): HCRYPTKEY;
  93. var
  94. hHash: HCRYPTHASH;
  95. Mode: DWORD;
  96. begin
  97. Win32Check(CryptCreateHash(m_hProv, CALG_SHA_256, 0, 0, hHash));
  98. try
  99. Win32Check(CryptHashData(hHash, PChar(Password), Length(Password) * SizeOf(Char), 0));
  100. Win32Check(CryptDeriveKey(m_hProv, CALG_AES_128, hHash, 0, Result));
  101. // Wine uses a different default mode of CRYPT_MODE_EBC
  102. Mode := CRYPT_MODE_CBC;
  103. Win32Check(CryptSetKeyParam(Result, KP_MODE, Pointer(@Mode), 0));
  104. finally
  105. CryptDestroyHash(hHash);
  106. end;
  107. end;
  108. function AES128_Encrypt(Value, Password: string): string;
  109. var
  110. hCProv: HCRYPTPROV;
  111. hKey: HCRYPTKEY;
  112. lul_datalen: Integer;
  113. lul_buflen: Integer;
  114. Buffer: TBytes;
  115. begin
  116. Assert(Password <> '');
  117. if (Value = '') then
  118. Result := ''
  119. else begin
  120. hCProv := __CryptAcquireContext(PROV_RSA_AES);
  121. try
  122. hKey := __AES128_DeriveKeyFromPassword(hCProv, Password);
  123. try
  124. // allocate buffer space
  125. lul_datalen := Length(Value) * SizeOf(Char);
  126. Buffer := TEncoding.Unicode.GetBytes(Value + ' ');
  127. lul_buflen := Length(Buffer);
  128. // encrypt to buffer
  129. Win32Check(CryptEncrypt(hKey, 0, True, 0, @Buffer[0], lul_datalen, lul_buflen));
  130. SetLength(Buffer, lul_datalen);
  131. // base 64 result
  132. Result := Base64_Encode(Buffer);
  133. finally
  134. CryptDestroyKey(hKey);
  135. end;
  136. finally
  137. CryptReleaseContext(hCProv, 0);
  138. end;
  139. end;
  140. end;
  141. function AES128_Decrypt(Value, Password: string): string;
  142. var
  143. hCProv: HCRYPTPROV;
  144. hKey: HCRYPTKEY;
  145. lul_datalen: Integer;
  146. Buffer: TBytes;
  147. begin
  148. Assert(Password <> '');
  149. if Value = '' then
  150. Result := ''
  151. else begin
  152. hCProv := __CryptAcquireContext(PROV_RSA_AES);
  153. try
  154. hKey := __AES128_DeriveKeyFromPassword(hCProv, Password);
  155. try
  156. // decode base64
  157. Buffer := Base64_Decode(Value);
  158. // allocate buffer space
  159. lul_datalen := Length(Buffer);
  160. // decrypt buffer to to string
  161. Win32Check(CryptDecrypt(hKey, 0, True, 0, @Buffer[0], lul_datalen));
  162. Result := TEncoding.Unicode.GetString(Buffer, 0, lul_datalen);
  163. finally
  164. CryptDestroyKey(hKey);
  165. end;
  166. finally
  167. CryptReleaseContext(hCProv, 0);
  168. end;
  169. end;
  170. end;
  171. end.