11 HCRYPTPROV = Longword;
13 HCRYPTHASH = Longword;
16 THogeCryptAuto = class(TObject)
24 FMaxBlobSize: cardinal;
27 destructor Destroy; override;
28 function Encrypt(inputStream: TStream; // (in) plain text
29 const password: string; // (in) password
30 outputStream: TStream) // (out) encrypted text
32 function Decrypt(inputStream: TStream; // (in) ecrrypted text
33 const password: string; // (in) password
34 outputStream: TStream) // (out) plain text
36 property ErrorCode: cardinal read FErrorCode;
37 property ErrorStr: string read FErrorStr;
38 property CryptAlg: ALG_ID read FCryptAlg write FCryptAlg;
39 property BlockSize: Cardinal read FBlockSize write FBlockSize;
40 property HashAlg: ALG_ID read FHashAlg write FHashAlg;
41 property BufSize: cardinal read FBufSize write FBufSize;
42 property MaxBlobSize: cardinal read FMaxBlobSize write FMaxBlobSize;
54 PROV_RSA_SCHANNEL = 12;
56 PROV_EC_ECDSA_SIG = 14;
57 PROV_EC_ECNRA_SIG = 15;
58 PROV_EC_ECDSA_FULL = 16;
59 PROV_EC_ECNRA_FULL = 17;
60 PROV_SPYRUS_LYNKS = 20;
65 PLAINTEXTKEYBLOB = $8;
74 ALG_CLASS_SIGNATURE = (1 shl 13);
75 ALG_CLASS_MSG_ENCRYPT = (2 shl 13);
76 ALG_CLASS_DATA_ENCRYPT = (3 shl 13);
77 ALG_CLASS_HASH = (4 shl 13);
78 ALG_CLASS_KEY_EXCHANGE = (5 shl 13);
82 ALG_TYPE_DSS = (1 shl 9);
83 ALG_TYPE_RSA = (2 shl 9);
84 ALG_TYPE_BLOCK = (3 shl 9);
85 ALG_TYPE_STREAM = (4 shl 9);
86 ALG_TYPE_DH = (5 shl 9);
87 ALG_TYPE_SECURECHANNEL = (6 shl 9);
95 ALG_SID_RSA_MSATWORK = 2;
96 ALG_SID_RSA_ENTRUST = 3;
101 ALG_SID_DSS_PKCS = 1;
104 // Block cipher sub ids
111 ALG_SID_SAFERSK64 = 7;
112 ALG_SID_SAFERSK128 = 8;
113 ALG_SID_3DES_112 = 9;
114 ALG_SID_CYLINK_MEK = 12;
118 ALG_SID_SKIPJACK = 10;
122 CRYPT_MODE_CBCI = 6; // ANSI CBC Interleaved
123 CRYPT_MODE_CFBP = 7; // ANSI CFB Pipelined
124 CRYPT_MODE_OFBP = 8; // ANSI OFB Pipelined
125 CRYPT_MODE_CBCOFM = 9; // ANSI CBC + OF Masking
126 CRYPT_MODE_CBCOFMI = 10; // ANSI CBC + OFM Interleaved
131 // Stream cipher sub-ids
135 // Diffie-Hellman sub-ids
136 ALG_SID_DH_SANDF = 1;
137 ALG_SID_DH_EPHEM = 2;
138 ALG_SID_AGREED_KEY_ANY = 3;
149 ALG_SID_RIPEMD160 = 7;
150 ALG_SID_SSL3SHAMD5 = 8;
153 // secure channel sub ids
154 ALG_SID_SSL3_MASTER = 1;
155 ALG_SID_SCHANNEL_MASTER_HASH = 2;
156 ALG_SID_SCHANNEL_MAC_KEY = 3;
157 ALG_SID_PCT1_MASTER = 4;
158 ALG_SID_SSL2_MASTER = 5;
159 ALG_SID_TLS1_MASTER = 6;
160 ALG_SID_SCHANNEL_ENC_KEY = 7;
162 // algorithm identifier definitions
163 CALG_MD2 = (ALG_CLASS_HASH or ALG_TYPE_ANY or ALG_SID_MD2);
164 CALG_MD4 = (ALG_CLASS_HASH or ALG_TYPE_ANY or ALG_SID_MD4);
165 CALG_MD5 = (ALG_CLASS_HASH or ALG_TYPE_ANY or ALG_SID_MD5);
166 CALG_SHA = (ALG_CLASS_HASH or ALG_TYPE_ANY or ALG_SID_SHA);
167 CALG_SHA1 = (ALG_CLASS_HASH or ALG_TYPE_ANY or ALG_SID_SHA1);
168 CALG_MAC = (ALG_CLASS_HASH or ALG_TYPE_ANY or ALG_SID_MAC);
169 CALG_RSA_SIGN = (ALG_CLASS_SIGNATURE or ALG_TYPE_RSA or ALG_SID_RSA_ANY);
170 CALG_DSS_SIGN = (ALG_CLASS_SIGNATURE or ALG_TYPE_DSS or ALG_SID_DSS_ANY);
171 CALG_RSA_KEYX = (ALG_CLASS_KEY_EXCHANGE or ALG_TYPE_RSA or ALG_SID_RSA_ANY);
172 CALG_DES = (ALG_CLASS_DATA_ENCRYPT or ALG_TYPE_BLOCK or ALG_SID_DES);
173 CALG_3DES_112 = (ALG_CLASS_DATA_ENCRYPT or ALG_TYPE_BLOCK or ALG_SID_3DES_112);
174 CALG_3DES = (ALG_CLASS_DATA_ENCRYPT or ALG_TYPE_BLOCK or ALG_SID_3DES);
175 CALG_RC2 = (ALG_CLASS_DATA_ENCRYPT or ALG_TYPE_BLOCK or ALG_SID_RC2);
176 CALG_RC4 = (ALG_CLASS_DATA_ENCRYPT or ALG_TYPE_STREAM or ALG_SID_RC4);
177 CALG_SEAL = (ALG_CLASS_DATA_ENCRYPT or ALG_TYPE_STREAM or ALG_SID_SEAL);
178 CALG_DH_SF = (ALG_CLASS_KEY_EXCHANGE or ALG_TYPE_DH or ALG_SID_DH_SANDF);
179 CALG_DH_EPHEM = (ALG_CLASS_KEY_EXCHANGE or ALG_TYPE_DH or ALG_SID_DH_EPHEM);
180 CALG_AGREEDKEY_ANY = (ALG_CLASS_KEY_EXCHANGE or ALG_TYPE_DH or ALG_SID_AGREED_KEY_ANY);
181 CALG_KEA_KEYX = (ALG_CLASS_KEY_EXCHANGE or ALG_TYPE_DH or ALG_SID_KEA);
182 CALG_HUGHES_MD5 = (ALG_CLASS_KEY_EXCHANGE or ALG_TYPE_ANY or ALG_SID_MD5);
183 CALG_SKIPJACK = (ALG_CLASS_DATA_ENCRYPT or ALG_TYPE_BLOCK or ALG_SID_SKIPJACK);
184 CALG_TEK = (ALG_CLASS_DATA_ENCRYPT or ALG_TYPE_BLOCK or ALG_SID_TEK);
185 CALG_CYLINK_MEK = (ALG_CLASS_DATA_ENCRYPT or ALG_TYPE_BLOCK or ALG_SID_CYLINK_MEK);
186 CALG_SSL3_SHAMD5 = (ALG_CLASS_HASH or ALG_TYPE_ANY or ALG_SID_SSL3SHAMD5);
187 CALG_SSL3_MASTER = (ALG_CLASS_MSG_ENCRYPT or ALG_TYPE_SECURECHANNEL or ALG_SID_SSL3_MASTER);
188 CALG_SCHANNEL_MASTER_HASH = (ALG_CLASS_MSG_ENCRYPT or ALG_TYPE_SECURECHANNEL or ALG_SID_SCHANNEL_MASTER_HASH);
189 CALG_SCHANNEL_MAC_KEY = (ALG_CLASS_MSG_ENCRYPT or ALG_TYPE_SECURECHANNEL or ALG_SID_SCHANNEL_MAC_KEY);
190 CALG_SCHANNEL_ENC_KEY = (ALG_CLASS_MSG_ENCRYPT or ALG_TYPE_SECURECHANNEL or ALG_SID_SCHANNEL_ENC_KEY);
191 CALG_PCT1_MASTER = (ALG_CLASS_MSG_ENCRYPT or ALG_TYPE_SECURECHANNEL or ALG_SID_PCT1_MASTER);
192 CALG_SSL2_MASTER = (ALG_CLASS_MSG_ENCRYPT or ALG_TYPE_SECURECHANNEL or ALG_SID_SSL2_MASTER);
193 CALG_TLS1_MASTER = (ALG_CLASS_MSG_ENCRYPT or ALG_TYPE_SECURECHANNEL or ALG_SID_TLS1_MASTER);
194 CALG_RC5 = (ALG_CLASS_DATA_ENCRYPT or ALG_TYPE_BLOCK or ALG_SID_RC5);
195 CALG_HMAC = (ALG_CLASS_HASH or ALG_TYPE_ANY or ALG_SID_HMAC);
197 // dwFlags definitions for CryptAcquireContext
198 CRYPT_VERIFYCONTEXT = $F0000000;
199 CRYPT_NEWKEYSET = $00000008;
200 CRYPT_DELETEKEYSET = $00000010;
201 CRYPT_MACHINE_KEYSET = $00000020;
203 // dwFlag definitions for CryptGenKey
204 CRYPT_EXPORTABLE = $00000001;
205 CRYPT_USER_PROTECTED = $00000002;
206 CRYPT_CREATE_SALT = $00000004;
207 CRYPT_UPDATE_KEY = $00000008;
208 CRYPT_NO_SALT = $00000010;
209 CRYPT_PREGEN = $00000040;
210 CRYPT_RECIPIENT = $00000010;
211 CRYPT_INITIATOR = $00000040;
212 CRYPT_ONLINE = $00000080;
213 CRYPT_SF = $00000100;
214 CRYPT_CREATE_IV = $00000200;
215 CRYPT_KEK = $00000400;
216 CRYPT_DATA_KEY = $00000800;
219 function CryptAcquireContext(
220 var hProv: HCRYPTPROV; // out
221 szContainer: PChar; // in
222 szProvider: PChar; // in
223 dwProvType: Longword; // in
224 dwFlags: Longword // in
225 ) : LongBool; stdcall; external 'advapi32.dll' name 'CryptAcquireContextA';
227 function CryptReleaseContext(
228 hProv: HCRYPTPROV; // in
229 dwFlags: Longword // in
230 ) : LongBool; stdcall; external 'advapi32.dll';
232 function CryptGetUserKey(
233 hProv: HCRYPTPROV; // in
234 dwKeySpec: Longword; // in
235 var hUserKey: HCRYPTKEY // out
236 ) : LongBool; stdcall; external 'advapi32.dll';
238 function CryptGenKey(
239 hProv: HCRYPTPROV; // in
241 dwFlags: Longword; // in
242 var hKey: HCRYPTKEY // out
243 ) : LongBool; stdcall; external 'advapi32.dll';
246 function CryptDestroyKey(
247 hKey: HCRYPTKEY // in
248 ) : LongBool; stdcall; external 'advapi32.dll';
250 function CryptExportKey(
251 hKey: HCRYPTKEY; // in
252 hExpKey: HCRYPTKEY; // in
253 dwBlobType: Longword; // in
254 dwFlags: Longword; // in
255 pbData: Pointer; // in
256 var cbDataLen: Longword // in/out
257 ) : LongBool; stdcall; external 'advapi32.dll';
259 function CryptCreateHash(
260 hProv: HCRYPTPROV; // in
262 hKey: HCRYPTKEY; // in
263 dwFlags: Longword; // in
264 var hHash: HCRYPTHASH // out
265 ) : LongBool; stdcall; external 'advapi32.dll';
267 function CryptDestroyHash(
268 hHash: HCRYPTHASH // in
269 ) : LongBool; stdcall; external 'advapi32.dll';
271 function CryptHashData(
272 hHash: HCRYPTHASH; // in
273 pbData: Pointer; // in
274 cbData: Longword; // in
275 dwFlags: Longword // in
276 ) : LongBool; stdcall; external 'advapi32.dll';
278 function CryptDeriveKey(
279 hProv: HCRYPTPROV; // in
281 hBaseData: HCRYPTHASH; // in
282 dwFlags: Longword; // in
283 var hKey: HCRYPTKEY // in/out
284 ) : LongBool; stdcall; external 'advapi32.dll';
286 function CryptImportKey(
287 hProv: HCRYPTPROV; // in
288 pbData: Pointer; // in
289 dwDataLen: Longword; // in
290 hPubKey: HCRYPTKEY; // in
291 dwFlags: Longword; // in
292 var hKey: HCRYPTKEY // out
293 ) : LongBool; stdcall; external 'advapi32.dll';
295 function CryptEncrypt(
296 hKey: HCRYPTPROV; // in
297 hHash: HCRYPTHASH; // in
298 Final: LongBool; // in
299 dwFlags: Longword; // in
300 pbData: Pointer; // in/out
301 var cbData: Longword; // in/out
302 cbBuffer: Longword // in
303 ) : LongBool; stdcall; external 'advapi32.dll';
305 function CryptDecrypt(
306 hKey: HCRYPTKEY; // in
307 hHash: HCRYPTHASH; // in
308 Final: LongBool; // in
309 dwFlags: Longword; // in
310 pbData: Pointer; // in/out
311 var pcbData: Longword // in/out
312 ) : LongBool; stdcall; external 'advapi32.dll';
317 {$B-} (* short circuit *)
319 constructor THogeCryptAuto.Create;
321 FCryptAlg := CALG_RC2;
323 FHashAlg := CALG_MD5;
324 FBufSize := 1024; (* MUST be multiple of FBlockSize *)
327 FMaxBlobSize := 1024 * 1024;
330 destructor THogeCryptAuto.Destroy;
334 function THogeCryptAuto.Encrypt(inputStream: TStream; const password: string;
335 outputStream: TStream): boolean;
350 if FBufSize <= 0 then
359 if (not CryptAcquireContext(hProv, nil, nil, PROV_RSA_FULL, 0)) and
360 (not CryptAcquireContext(hProv, nil, nil, PROV_RSA_FULL,
361 CRYPT_NEWKEYSET)) then
362 raise Exception.Create('CryptAcquireContext');
363 if length(password) <= 0 then
365 if not CryptGenKey(hProv, FCryptAlg, CRYPT_EXPORTABLE, hKey) then
366 raise Exception.Create('CryptGenKey');
367 if (not CryptGetUserKey(hProv, AT_KEYEXCHANGE, hXKey)) then
369 if GetLastError <> Longword(NTE_NO_KEY) then
370 raise Exception.Create('CryptGetUserKey');
371 if (not CryptGenKey(hProv, AT_KEYEXCHANGE, 0, hXKey)) then
372 raise Exception.Create('CryptGenKey 2');
374 if not CryptExportKey(hKey, hXKey, SIMPLEBLOB, 0, nil, dwLen) then
375 raise Exception.Create('CryptExportKey 1');
376 GetMem(pBlob, dwLen);
377 if not CryptExportKey(hKey, hXKey, SIMPLEBLOB, 0, pBlob, dwLen) then
378 raise Exception.Create('CryptExportKey 2');
379 CryptDestroyKey(hXKey);
381 outputStream.WriteBuffer(dwLen, SizeOf(dwLen));
382 outputStream.WriteBuffer(pBlob^, dwLen);
385 if not CryptCreateHash(hProv, FHashAlg, 0, 0, hHash) then
386 raise Exception.Create('CryptCreateHash');
387 if not CryptHashData(hHash, PChar(password), length(password), 0) then
388 raise Exception.Create('CryptHashData');
389 if not CryptDeriveKey(hProv, FCryptAlg, hHash, 0, hKey) then
390 raise Exception.Create('CryptDeriveKey');
391 CryptDestroyHash(hHash);
394 dwLen := FBufSize + FBlockSize;
395 GetMem(pBuffer, dwLen);
397 dwSize := inputStream.Read(pBuffer^, FBufSize);
398 Final := (inputStream.Size <= inputStream.Position);
399 if not CryptEncrypt(hKey, 0, Final, 0,
400 pBuffer, dwSize, dwLen) then
401 raise Exception.Create('CryptEncrypt');
402 outputStream.WriteBuffer(pBuffer^, dwSize);
408 FErrorCode := Windows.GetLastError;
409 FErrorStr := e.Message;
412 if pBuffer <> nil then Dispose(pBuffer);
413 if pBlob <> nil then Dispose(pBlob);
414 if hHash <> 0 then CryptDestroyHash(hHash);
415 if hXKey <> 0 then CryptDestroyKey(hXKey);
416 if hKey <> 0 then CryptDestroyKey(hKey);
417 if hProv <> 0 then CryptReleaseContext(hProv, 0);
420 function THogeCryptAuto.Decrypt(inputStream: TStream; const password: string;
421 outputStream: TStream): boolean;
436 if FBufSize <= 0 then
445 if (not CryptAcquireContext(hProv, nil, nil, PROV_RSA_FULL, 0)) and
446 (not CryptAcquireContext(hProv, nil, nil, PROV_RSA_FULL,
447 CRYPT_NEWKEYSET)) then
448 raise Exception.Create('CryptAcquireContext');
449 if length(password) <= 0 then
451 dwSize := inputStream.Read(dwLen, SizeOf(dwLen));
452 if dwSize <> SizeOf(dwLen) then
453 raise Exception.Create('invalid size');
454 if FMaxBlobSize < dwLen then
455 raise Exception.Create('too large');
456 GetMem(pBlob, dwLen);
457 dwSize := inputStream.Read(pBlob^, dwLen);
458 if dwSize <> dwLen then
459 raise Exception.Create('invalid size');
460 if not CryptImportKey(hProv, pBlob, dwSize, 0, 0, hKey) then
461 raise Exception.Create('CryptImportKey');
464 if not CryptCreateHash(hProv, FHashAlg, 0, 0, hHash) then
465 raise Exception.Create('CryptCreateHash');
466 if not CryptHashData(hHash, PChar(password), length(password), 0) then
467 raise Exception.Create('CryptHashData');
468 if not CryptDeriveKey(hProv, FCryptAlg, hHash, 0, hKey) then
469 raise Exception.Create('CryptDeriveKey');
470 CryptDestroyHash(hHash);
473 dwLen := FBufSize + FBlockSize;
474 GetMem(pBuffer, dwLen);
476 dwSize := inputStream.Read(pBuffer^, FBufSize);
477 Final := (inputStream.Size <= inputStream.Position);
478 if not CryptDecrypt(hKey, 0, Final, 0, pBuffer, dwSize) then
479 raise Exception.Create('CryptDecrypt');
480 outputStream.WriteBuffer(pBuffer^, dwSize);
486 FErrorCode := Windows.GetLastError;
487 FErrorStr := e.Message;
490 if pBuffer <> nil then Dispose(pBuffer);
491 if pBlob <> nil then Dispose(pBlob);
492 if hHash <> 0 then CryptDestroyHash(hHash);
493 if hXKey <> 0 then CryptDestroyKey(hXKey);
494 if hKey <> 0 then CryptDestroyKey(hKey);
495 if hProv <> 0 then CryptReleaseContext(hProv, 0);