OSDN Git Service

・スレタイの特定ワードを非表示にする機能に「©bbspink.com」も追加
[gikonavigoeson/gikonavi.git] / Encrypt / UCryptAuto.pas
1 unit UCryptAuto;
2 (* 2002 Twiddle *)
3
4 interface
5 uses
6   Classes,
7   SysUtils,
8   Windows;
9
10 type
11   HCRYPTPROV = Longword;
12   HCRYPTKEY  = Longword;
13   HCRYPTHASH = Longword;
14   ALG_ID     = Cardinal;
15
16   THogeCryptAuto = class(TObject)
17   protected
18     FErrorCode: cardinal;
19     FErrorStr: string;
20     FCryptAlg: ALG_ID;
21     FBlockSize: cardinal;
22     FHashAlg:  ALG_ID;
23     FBufSize: cardinal;
24     FMaxBlobSize: cardinal;
25   public
26     constructor Create;
27     destructor Destroy; override;
28     function Encrypt(inputStream: TStream;      // (in) plain text
29                      const password: string;    // (in) password
30                      outputStream: TStream)     // (out) encrypted text
31         : boolean;
32     function Decrypt(inputStream: TStream;      // (in) ecrrypted text
33                      const password: string;    // (in) password
34                      outputStream: TStream)     // (out) plain text
35         : boolean;
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;
43   end;
44
45
46
47 const
48   PROV_RSA_FULL      =     1;
49   PROV_RSA_SIG       =     2;
50   PROV_DSS           =     3;
51   PROV_FORTEZZA      =     4;
52   PROV_MS_EXCHANGE   =     5;
53   PROV_SSL           =     6;
54   PROV_RSA_SCHANNEL  =    12;
55   PROV_DSS_DH        =    13;
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;
61
62   SIMPLEBLOB         =    $1;
63   PUBLICKEYBLOB      =    $6;
64   PRIVATEKEYBLOB     =    $7;
65   PLAINTEXTKEYBLOB   =    $8;
66
67   AT_KEYEXCHANGE     =     1;
68   AT_SIGNATURE       =     2;
69
70   CRYPT_USERDATA     =     1;
71
72   //Algorithm classes
73   ALG_CLASS_ANY          = (0);
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);
79
80   // Algorithm types
81   ALG_TYPE_ANY           = (0);
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);
88
89   // Generic sub-ids
90   ALG_SID_ANY            = 0;
91
92   // Some RSA sub-ids
93   ALG_SID_RSA_ANY        = 0;
94   ALG_SID_RSA_PKCS       = 1;
95   ALG_SID_RSA_MSATWORK   = 2;
96   ALG_SID_RSA_ENTRUST    = 3;
97   ALG_SID_RSA_PGP        = 4;
98
99   // Some DSS sub-ids
100   ALG_SID_DSS_ANY        = 0;
101   ALG_SID_DSS_PKCS       = 1;
102   ALG_SID_DSS_DMS        = 2;
103
104   // Block cipher sub ids
105   // DES sub_ids
106   ALG_SID_DES            =  1;
107   ALG_SID_3DES           =  3;
108   ALG_SID_DESX           =  4;
109   ALG_SID_IDEA           =  5;
110   ALG_SID_CAST           =  6;
111   ALG_SID_SAFERSK64      =  7;
112   ALG_SID_SAFERSK128     =  8;
113   ALG_SID_3DES_112       =  9;
114   ALG_SID_CYLINK_MEK     = 12;
115   ALG_SID_RC5            = 13;
116
117   // Fortezza sub-ids
118   ALG_SID_SKIPJACK       = 10;
119   ALG_SID_TEK            = 11;
120
121   // KP_MODE
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
127
128   // RC2 sub-ids
129   ALG_SID_RC2            = 2;
130
131   // Stream cipher sub-ids
132   ALG_SID_RC4            = 1;
133   ALG_SID_SEAL           = 2;
134
135   // Diffie-Hellman sub-ids
136   ALG_SID_DH_SANDF       = 1;
137   ALG_SID_DH_EPHEM       = 2;
138   ALG_SID_AGREED_KEY_ANY = 3;
139   ALG_SID_KEA            = 4;
140
141   // Hash sub ids
142   ALG_SID_MD2            = 1;
143   ALG_SID_MD4            = 2;
144   ALG_SID_MD5            = 3;
145   ALG_SID_SHA            = 4;
146   ALG_SID_SHA1           = 4;
147   ALG_SID_MAC            = 5;
148   ALG_SID_RIPEMD         = 6;
149   ALG_SID_RIPEMD160      = 7;
150   ALG_SID_SSL3SHAMD5     = 8;
151   ALG_SID_HMAC           = 9;
152
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;
161
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);
196
197   // dwFlags definitions for CryptAcquireContext
198   CRYPT_VERIFYCONTEXT  = $F0000000;
199   CRYPT_NEWKEYSET      = $00000008;
200   CRYPT_DELETEKEYSET   = $00000010;
201   CRYPT_MACHINE_KEYSET = $00000020;
202
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;
217
218
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';
226
227 function CryptReleaseContext(
228         hProv: HCRYPTPROV;      // in
229         dwFlags: Longword       // in
230 ) : LongBool; stdcall; external 'advapi32.dll';
231
232 function CryptGetUserKey(
233         hProv: HCRYPTPROV;      // in
234         dwKeySpec: Longword;    // in
235         var hUserKey: HCRYPTKEY // out
236 ) : LongBool; stdcall; external 'advapi32.dll';
237
238 function CryptGenKey(
239         hProv: HCRYPTPROV;      // in
240         Algid: ALG_ID;          // in
241         dwFlags: Longword;      // in
242         var hKey: HCRYPTKEY     // out
243 ) : LongBool; stdcall; external 'advapi32.dll';
244
245
246 function CryptDestroyKey(
247         hKey: HCRYPTKEY         // in
248 ) : LongBool; stdcall; external 'advapi32.dll';
249
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';
258
259 function CryptCreateHash(
260         hProv: HCRYPTPROV;      // in
261         Algid: ALG_ID;          // in
262         hKey: HCRYPTKEY;        // in
263         dwFlags: Longword;      // in
264         var hHash: HCRYPTHASH   // out
265 ) : LongBool; stdcall; external 'advapi32.dll';
266
267 function CryptDestroyHash(
268         hHash: HCRYPTHASH       // in
269 ) : LongBool; stdcall; external 'advapi32.dll';
270
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';
277
278 function CryptDeriveKey(
279         hProv: HCRYPTPROV;      // in
280         Algid: ALG_ID;          // in
281         hBaseData: HCRYPTHASH;  // in
282         dwFlags: Longword;      // in
283         var hKey: HCRYPTKEY     // in/out
284 ) : LongBool; stdcall; external 'advapi32.dll';
285
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';
294
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';
304
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';
313
314
315
316 implementation
317 {$B-} (* short circuit *)
318
319 constructor THogeCryptAuto.Create;
320 begin
321   FCryptAlg  := CALG_RC2;
322   FBlockSize := 8;
323   FHashAlg   := CALG_MD5;
324   FBufSize   := 1024;       (* MUST be multiple of FBlockSize *)
325   FErrorCode := 0;
326   FErrorStr  := '';
327   FMaxBlobSize := 1024 * 1024;
328 end;
329
330 destructor THogeCryptAuto.Destroy;
331 begin
332 end;
333
334 function THogeCryptAuto.Encrypt(inputStream: TStream; const password: string;
335                                 outputStream: TStream): boolean;
336 var
337   hProv: HCRYPTPROV;
338   hKey: HCRYPTKEY;
339   hXKey: HCRYPTKEY;
340   hHash: HCRYPTHASH;
341   dwLen: Longword;
342   pBlob: Pointer;
343   pBuffer: Pointer;
344   dwSize: cardinal;
345   Final: boolean;
346 begin
347   FErrorCode := 0;
348   FErrorStr  := '';
349   result := false;
350   if FBufSize <= 0 then
351     exit;
352   hProv := 0;
353   hKey := 0;
354   hXKey := 0;
355   hHash := 0;
356   pBlob := nil;
357   pBuffer := nil;
358   try
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
364     begin
365       if not CryptGenKey(hProv, FCryptAlg, CRYPT_EXPORTABLE, hKey) then
366         raise Exception.Create('CryptGenKey');
367       if (not CryptGetUserKey(hProv, AT_KEYEXCHANGE, hXKey)) then
368       begin
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');
373       end;
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);
380       hXKey := 0;
381       outputStream.WriteBuffer(dwLen, SizeOf(dwLen));
382       outputStream.WriteBuffer(pBlob^, dwLen);
383     end
384     else begin
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);
392       hHash := 0;
393     end;
394     dwLen := FBufSize + FBlockSize;
395     GetMem(pBuffer, dwLen);
396     repeat
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);
403     until Final;
404     result := true;
405   except
406     on e: Exception do
407     begin
408       FErrorCode := Windows.GetLastError;
409       FErrorStr := e.Message;
410     end;
411   end;
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);
418 end;
419
420 function THogeCryptAuto.Decrypt(inputStream: TStream; const password: string;
421                                 outputStream: TStream): boolean;
422 var
423   hProv: HCRYPTPROV;
424   hKey: HCRYPTKEY;
425   hXKey: HCRYPTKEY;
426   hHash: HCRYPTHASH;
427   dwLen: Longword;
428   pBlob: Pointer;
429   pBuffer: Pointer;
430   dwSize: cardinal;
431   Final: boolean;
432 begin
433   FErrorCode := 0;
434   FErrorStr  := '';
435   result := false;
436   if FBufSize <= 0 then
437     exit;
438   hProv := 0;
439   hKey := 0;
440   hXKey := 0;
441   hHash := 0;
442   pBlob := nil;
443   pBuffer := nil;
444   try
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
450     begin
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');
462     end
463     else begin
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);
471       hHash := 0;
472     end;
473     dwLen := FBufSize + FBlockSize;
474     GetMem(pBuffer, dwLen);
475     repeat
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);
481     until Final;
482     result := true;
483   except
484     on e: Exception do
485     begin
486       FErrorCode := Windows.GetLastError;
487       FErrorStr := e.Message;
488     end;
489   end;
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);
496 end;
497
498 end.