delphi 应用CryptoAPI,加密解密的源(200分)

  • 主题发起人 主题发起人 fkekennan
  • 开始时间 开始时间
F

fkekennan

Unregistered / Unconfirmed
GUEST, unregistred user!
delphi 应用CryptoAPI算法,加密解密的源码
要求:一个窗体,2个输入框,2个按钮
1按钮,把1输入框内容加密,内容显示在2框
2按钮,把1输入框内容解密,内容显示在2框
因为是朋友急用,我带这个还不熟,所以麻烦懂的朋友帮忙
目前只有290分,可以全部给掉,
如果不够,可以开朋友号送分,
混分的不要回,谢谢合作。
符合可联系QQ:69898567,或mailto: yuanyd_hrb@126.com
 
怎么就没人帮我解决呢?害我自己用了个别的算法,哎
 
问题: 请教CryptoApi用Delphi的实现 ( 积分: 200 )
分类: Windows API

来自: pwxwabcd, 时间: 2003-06-02 16:58:00, ID: 1917895
请教CryptoApi用Delphi的实现
1.公钥,私钥生成
2.加密
3.验证
4.证书

来自: thx1180, 时间: 2003-06-04 22:09:00, ID: 1925546
{---------------------------------------------------------
Copyright (c) 1996-97 Massimo Maria Ghisalberti
CopyRight (c) 1996-97 MAx!
CopyRight (c) 1996-97 Objects Built for you! (O.B.you!)
Internet EMail: roentgen@mbox.vol.it

translate from: wincrypt.h
date: mm/gg/yy
version: 2beta.

note: use at own risk.
If you use this code, please mention O.B.you!
somewhere in your program


----------------------------------------------------------
IMPORTANT : USE ONLY IF YOU HAVE WINDOWS NT 4.X OR WINDOWS
95 OSR2 OR/AND INTERNET EXPLORER 3.X.
----------------------------------------------------------}

unit wincrypt;

interface

uses
Windows;

const CryptDll = 'advapi32';

{---------------------------------------------------------------------------

Microsoft Windows
Copyright (C) Microsoft Corporation, 1992 - 1996.

File: wincrypt.h
Contents: Cryptographic API Prototypes and Definitions
----------------------------------------------------------------------------}


{Algorithm IDs and Flags }

{ALG_ID crackers }
function GET_ALG_CLASS(x:integer) :integer;
function GET_ALG_TYPE(x:integer) :integer;
function GET_ALG_SID(x:integer) :integer;

{Algorithm classes }
Const
ALG_CLASS_ANY = 0;
ALG_CLASS_SIGNATURE = (1 shl 13);
ALG_CLASS_MSG_ENCRYPT = (2 shl 13);
ALG_CLASS_DATA_ENCRYPT = (3 shl 13);
ALG_CLASS_HASH = (4 shl 13);
ALG_CLASS_KEY_EXCHANGE = (5 shl 13);
{Algorithm types }
ALG_TYPE_ANY = 0;
ALG_TYPE_DSS = (1 shl 9);
ALG_TYPE_RSA = (2 shl 9);
ALG_TYPE_BLOCK = (3 shl 9);
ALG_TYPE_STREAM = (4 shl 9);
{Generic sub-ids }
ALG_SID_ANY = 0;
{Some RSA sub-ids }
ALG_SID_RSA_ANY = 0;
ALG_SID_RSA_PKCS = 1;
ALG_SID_RSA_MSATWORK = 2;
ALG_SID_RSA_ENTRUST = 3;
ALG_SID_RSA_PGP = 4;
{Some DSS sub-ids}
ALG_SID_DSS_ANY = 0;
ALG_SID_DSS_PKCS = 1;
ALG_SID_DSS_DMS = 2;
{Block cipher sub ids DES sub_ids }
ALG_SID_DES = 1;
ALG_SID_3DES = 3;
ALG_SID_DESX = 4;
ALG_SID_IDEA = 5;
ALG_SID_CAST = 6;
ALG_SID_SAFERSK64 = 7;
ALD_SID_SAFERSK128 = 8;
{KP_MODE }
CRYPT_MODE_CBCI = 6; {ANSI CBC Interleaved}
CRYPT_MODE_CFBP = 7; {ANSI CFB Pipelined}
CRYPT_MODE_OFBP = 8; {ANSI OFB Pipelined}
CRYPT_MODE_CBCOFM = 9; {ANSI CBC + OF Masking}
CRYPT_MODE_CBCOFMI = 10; {ANSI CBC + OFM Interleaved}
{RC2 sub-ids }
ALG_SID_RC2 = 2;
{Stream cipher sub-ids }
ALG_SID_RC4 = 1;
ALG_SID_SEAL = 2;
{Hash sub ids }
ALG_SID_MD2 = 1;
ALG_SID_MD4 = 2;
ALG_SID_MD5 = 3;
ALG_SID_SHA = 4;
ALG_SID_MAC = 5;
ALG_SID_RIPEMD = 6;
ALG_SID_RIPEMD160 = 7;
ALG_SID_SSL3SHAMD5 = 8;
{Our silly example sub-id }
ALG_SID_EXAMPLE = 80;

{$IFNDEF ALGIDDEF}
{$DEFINE ALGIDDEF}
Type ALG_ID = Cardinal;
{$ENDIF}

{algorithm identifier definitions }
Const
CALG_MD2 = (ALG_CLASS_HASH or ALG_TYPE_ANY or ALG_SID_MD2);
CALG_MD4 = (ALG_CLASS_HASH or ALG_TYPE_ANY or ALG_SID_MD4);
CALG_MD5 = (ALG_CLASS_HASH or ALG_TYPE_ANY or ALG_SID_MD5);
CALG_SHA = (ALG_CLASS_HASH or ALG_TYPE_ANY or ALG_SID_SHA);
CALG_MAC = (ALG_CLASS_HASH or ALG_TYPE_ANY or ALG_SID_MAC);
CALG_RSA_SIGN = (ALG_CLASS_SIGNATURE or ALG_TYPE_RSA or ALG_SID_RSA_ANY);
CALG_DSS_SIGN = (ALG_CLASS_SIGNATURE or ALG_TYPE_DSS or ALG_SID_DSS_ANY);
CALG_RSA_KEYX = (ALG_CLASS_KEY_EXCHANGE or ALG_TYPE_RSA or ALG_SID_RSA_ANY);
CALG_DES = (ALG_CLASS_DATA_ENCRYPT or ALG_TYPE_BLOCK or ALG_SID_DES);
CALG_RC2 = (ALG_CLASS_DATA_ENCRYPT or ALG_TYPE_BLOCK or ALG_SID_RC2);
CALG_RC4 = (ALG_CLASS_DATA_ENCRYPT or ALG_TYPE_STREAM or ALG_SID_RC4);
CALG_SEAL = (ALG_CLASS_DATA_ENCRYPT or ALG_TYPE_STREAM or ALG_SID_SEAL);

type VTableProvStruc = record
Version: LongInt;
FuncVerifyImage: TFarProc;
FuncReturnhWnd: TFarProc;
end;
PVTableProvStruc = ^VTableProvStruc;


const
{dwFlags definitions for CryptAquireContext }
CRYPT_VERIFYCONTEXT = $F0000000;
CRYPT_NEWKEYSET

来自: pwxwabcd, 时间: 2003-06-05 7:46:00, ID: 1925904
请提供详细的例子

来自: thx1180, 时间: 2003-06-05 16:31:00, ID: 1928125
http://homepages.borland.com/efg2lab/Library/Delphi/MathFunctions/BerndLehmannCrypto.zip

来自: pwxwabcd, 时间: 2003-06-06 8:42:00, ID: 1929492
楼上的朋友提供的例子不能正常执行,不过还是谢谢。

来自: thx1180, 时间: 2003-06-06 13:58:00, ID: 1930530
你自己到这里找找吧:
http://homepages.borland.com/efg2lab/Library/Delphi/MathFunctions/Cryptography.htm

来自: pwxwabcd, 时间: 2003-06-11 8:23:00, ID: 1941510
楼上的朋友提供的连接地址只有头文件,没有delphi实际的例子.

来自: thx1180, 时间: 2003-06-11 13:51:00, ID: 1942747
怎么没有啊,这个是全的:
ftp://delphi-jedi.org/api/CryptoAPI1.zip

来自: itren, 时间: 2003-06-11 17:31:00, ID: 1943842
Enjoy This Samples hehe!
http://delphi.ur-solution.com/delphi_download/upload/29919_CryptSample.zip

来自: pwxwabcd, 时间: 2003-06-16 8:45:00, ID: 1954627
证书如何生成,如何在不通过文件导入导出获得私钥。

来自: pwxwabcd, 时间: 2003-07-17 15:43:00, ID: 2037303
谢谢

得分大富翁: thx1180
 
问题: 关于微软CryptoAPI用PKI加解密的问题 ( 积分: 200 )
分类: Windows API

来自: devil-li, 时间: 2002-05-25 14:27:00, ID: 1123455
我用微软CryptoAPI用PKI加解密,产生两个问题:
1。用公钥加密的数据,公钥也可以解密。
2。只能够加密大约53个字符的数据,超过长度CryptEncrypt会出错。CryptEncrypt到底能不能实现PKI加密呀?
请教大家是什么原因。下面是我的源代码:

procedure TForm1.Button1Click(Sender: TObject);
begin
Str1 := Memo1.Text;
Str2 := PvtSignature.Encrypt(Str1, LoadPublicKey);//加密
Memo2.Text := Str2;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
Str1 := PvtSignature.Decrypt(Str2, LoadPrivateKey);//解密
Memo1.Text := Str1;
end;

procedure TForm1.Button3Click(Sender: TObject);
var
KeyPair: TKeyPair;
begin
KeyPair := PvtSignature.GetGenKey(PVT_KEYEXCHANGE);//产生随机密钥对
SavePrivateKey(KeyPair.PrivateKey);
SavePublicKey(KeyPair.PublicKey);
end;

function TPvtSignature.Decrypt(Data, Key: string): string;
var
hProv: HCRYPTPROV;
hKey: HCRYPTKEY;
Buffer, temp: string;
Index: Integer;
dwCount: DWORD;
Endof: Boolean;
BufferLen: DWORD;

procedure Init;
begin
hProv := 0;
hKey := 0;
end;
procedure Clear;
begin
if Boolean(hKey) then
CryptDestroyKey(hKey);
if Boolean(hProv) then
CryptReleaseContext(hProv, 0);
end;
begin
Init;
if not CryptAcquireContext(@hProv, nil, nil, PROV_RSA_FULL, 0) then
begin
Clear;
raise Exception.Create('Error during CryptAcquireContext');
end;

if not CryptImportKey(hProv, PByte(PChar(Key)), Length(Key), 0, 0, @hKey) then
begin
Clear;
raise Exception.Create('Error during CryptImportKey');
end;

Index := 1;
Result := '';
BufferLen := BlockLen + 8;
repeat
Buffer := Copy(Data, Index, BlockLen);
dwCount := Length(Buffer);
Inc(Index, dwCount);
Endof := Index > Length(Data);
SetLength(Buffer, BufferLen);
if not CryptDecrypt(hKey, 0, Endof, 0, PByte(PChar(Buffer)), @dwCount) then
begin
Clear;
raise Exception.Create('Error during CryptDecrypt');
end;
SetLength(temp, dwCount);
Move(PChar(Buffer)^, Pointer(temp)^, dwCount);
Result := Result + temp;
until Endof;
Clear;
end;


function TPvtSignature.Encrypt(Data, Key: string): string;
var
hProv: HCRYPTPROV;
hKey: HCRYPTKEY;
Buffer, temp: string;
Index: Integer;
dwCount: DWORD;
Endof: Boolean;
BufferLen: DWORD;

procedure Init;
begin
hProv := 0;
hKey := 0;
Endof := False;
end;
procedure Clear;
begin
if Boolean(hKey) then
CryptDestroyKey(hKey);
if Boolean(hProv) then
CryptReleaseContext(hProv, 0);
end;
begin
Init;
if not CryptAcquireContext(@hProv, nil, nil, PROV_RSA_FULL, 0) then
begin
Clear;
raise Exception.Create('Error during CryptAcquireContext');
end;

if not CryptImportKey(hProv, PByte(PChar(Key)), Length(Key), 0, 0, @hKey) then
begin
Clear;
raise Exception.Create('Error during CryptImportKey');
end;

Index := 1;
Result := '';
BufferLen := BlockLen + 8;
repeat
Buffer := Copy(Data, Index, BlockLen);
dwCount := Length(Buffer);
Inc(Index, dwCount);
Endof := Index > Length(Data);
SetLength(Buffer, BufferLen);
if not CryptEncrypt(hKey, 0, Endof, 0, PByte(PChar(Buffer)), @dwCount, BufferLen) then
begin
Clear;
raise Exception.Create('Error during CryptEncrypt');
end;
SetLength(temp, dwCount);
Move(PChar(Buffer)^, Pointer(temp)^, dwCount);
Result := Result + temp;
until Endof;
Clear;
end;

function TPvtSignature.GetGenKey(KeyType: TKeyPairType): TKeyPair;
var
hProv: HCRYPTPROV;
hKey: HCRYPTKEY;
pbPublicKeyBlob: PByte;
pbPrivateKeyBlob: PByte;
dwPublicBlobLen: DWORD;
dwPrivateBlobLen: DWORD;
VKeyType: Cardinal;

procedure Init;
begin
hProv := 0;
hKey := 0;
pbPublicKeyBlob := nil;
pbPrivateKeyBlob := nil;
dwPublicBlobLen := 0;
dwPrivateBlobLen := 0;
end;

procedure Clear;
begin
if dwPrivateBlobLen <> 0 then
begin
FillChar(pbPrivateKeyBlob^, dwPrivateBlobLen, 0);
FreeMem(pbPrivateKeyBlob);


来自: bingjian, 时间: 2002-05-25 19:23:00, ID: 1123936
以下是我找的一组C语言的代码,自己看看,
---- 下面以两个文件加密与解密的C程序片断为例,演示一下CryptoAPI的强大功能。这两个程序均为Win32控制台应用,程序省略了出错处理,实际运行时请加入。

---- ①文件加密

#include < windows.h >
#include < stdio.h >
#include < stdlib.h >
#include < wincrypt.h >

//确定使用RC2块编码或是RC4流式编码
#ifdef USE_BLOCK_CIPHER
#define ENCRYPT_ALGORITHMCALG_RC2
#define ENCRYPT_BLOCK_SIZE8
#else
#define ENCRYPT_ALGORITHMCALG_RC4
#define ENCRYPT_BLOCK_SIZE1
#endif

void CAPIDecryptFile(PCHAR szSource,
PCHAR szDestination, PCHAR szPassword);

void _cdecl main(int argc, char *argv[])
{
PCHAR szSource= NULL;
PCHAR szDestination = NULL;
PCHAR szPassword= NULL;

// 验证参数个数
if(argc != 3 && argc != 4) {
printf("USAGE: decrypt < source file >
< dest file > [ < password > ]/n");
exit(1);
}

//读取参数.
szSource = argv[1];
szDestination = argv[2];
if(argc == 4) {
szPassword = argv[3];
}
CAPIDecryptFile(szSource, szDestination, szPassword);
}

/*szSource为要加密的文件名称,szDestination
为加密过的文件名称,szPassword为加密口令*/
void CAPIEncryptFile(PCHAR szSource, PCHAR
szDestination, PCHAR szPassword)
{
FILE *hSource = NULL;
FILE *hDestination = NULL;
INT eof = 0;
HCRYPTPROV hProv = 0;
HCRYPTKEY hKey = 0;
HCRYPTKEY hXchgKey = 0;
HCRYPTHASH hHash = 0;
PBYTE pbKeyBlob = NULL;
DWORD dwKeyBlobLen;
PBYTE pbBuffer = NULL;
DWORD dwBlockLen;
DWORD dwBufferLen;
DWORD dwCount;

hSource = fopen(szSource,"rb"));// 打开源文件.
hDestination = fopen(szDestination,"wb") ;
//.打开目标文件
// 连接缺省的CSP
CryptAcquireContext(&hProv, NULL, NULL,
PROV_RSA_FULL, 0));
if(szPassword == NULL) {
//口令为空,使用随机产生的会话密钥加密
// 产生随机会话密钥.
CryptGenKey(hProv, ENCRYPT_ALGORITHM,
CRYPT_EXPORTABLE, &hKey)
// 取得密钥交换对的公共密钥
CryptGetUserKey(hProv, AT_KEYEXCHANGE, &hXchgKey);
// 计算隐码长度并分配缓冲区
CryptExportKey(hKey, hXchgKey, SIMPLEBLOB, 0,
NULL, &dwKeyBlobLen);
pbKeyBlob = malloc(dwKeyBlobLen)) == NULL) ;
// 将会话密钥输出至隐码
CryptExportKey(hKey, hXchgKey, SIMPLEBLOB,
0, pbKeyBlob, &dwKeyBlobLen));
// 释放密钥交换对的句柄
CryptDestroyKey(hXchgKey);
hXchgKey = 0;
// 将隐码长度写入目标文件
fwrite(&dwKeyBlobLen, sizeof(DWORD), 1, hDestination);
//将隐码长度写入目标文件
fwrite(pbKeyBlob, 1, dwKeyBlobLen, hDestination);
} else {
//口令不为空, 使用从口令派生出的密钥加密文件
CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash);
// 建立散列表
CryptHashData(hHash, szPassword, strlen(szPassword), 0);
//散列口令
// 从散列表中派生密钥
CryptDeriveKey(hProv, ENCRYPT_ALGORITHM, hHash, 0, &hKey);
// 删除散列表
CryptDestroyHash(hHash);
hHash = 0;
}

//计算一次加密的数据字节数,必须为ENCRYPT_BLOCK_SIZE的整数倍
dwBlockLen = 1000 - 1000 % ENCRYPT_BLOCK_SIZE;
//如果使用块编码,则需要额外空间
if(ENCRYPT_BLOCK_SIZE > 1) {
dwBufferLen = dwBlockLen + ENCRYPT_BLOCK_SIZE;
} else {
dwBufferLen = dwBlockLen;
}
//分配缓冲区
pbBuffer = malloc(dwBufferLen);
//加密源文件并写入目标文件
do {
// 从源文件中读出dwBlockLen个字节
dwCount = fread(pbBuffer, 1, dwBlockLen, hSource);
eof = feof(hSource);
//加密数据
CryptEncrypt(hKey, 0, eof, 0, pbBuffer,
&dwCount, dwBufferLen);
// 将加密过的数据写入目标文件
fwrite(pbBuffer, 1, dwCount, hDestination);
} while(!feof(hSource));
printf("OK/n");
……//关闭文件、释放内存
}

②文件解密

void CAPIDecryptFile(PCHAR szSource, PCHAR
szDestination, PCHAR szPassword)
{
……//变量声明、文件操作同文件加密程序

CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0);
if(szPassword == NULL) {
// 口令为空,使用存储在加密文件中的会话密钥解密
// 读隐码的长度并分配内存
fread(&dwKeyBlobLen, sizeof(DWORD), 1, hSource);
pbKeyBlob = malloc(dwKeyBlobLen)) == NULL);
// 从源文件中读隐码.
fread(pbKeyBlob, 1, dwKeyBlobLen, hSource);
// 将隐码输入CSP
CryptImportKey(hProv, pbKeyBlob,
dwKeyBlobLen, 0, 0, &hKey);
} else {
// 口令不为空, 使用从口令派生出的密钥解密文件
CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash);
CryptHashData(hHash, sz

来自: devil-li, 时间: 2002-05-25 19:47:00, ID: 1123963
你的这段代码采用的对称密钥加密。MSDN上都有这段代码。
但是我要采用的是公开密钥加密(用公钥加密,私钥解密)。
请问如何实现。

来自: devil-li, 时间: 2002-05-25 19:53:00, ID: 1123974
我的算法是:
调用CryptGenKey产生随机公/私密钥对;(对应Button3Click)
调用Encrypt对数据用公钥加密。(对应Button1Click)
调用Decrypt对数据用私钥解密。(对应Button2Click)

来自: devil-li, 时间: 2002-05-29 20:17:00, ID: 1131585
我自己搞定了。
1。
CryptoAPI对公开密钥加密算法的支持需要Windows 2000 或以上版本。
Provider 需要MS_ENHANCED_PROV。
调用CryptAcquireContext(@hProv, nil, MS_ENHANCED_PROV, PROV_RSA_FULL, 0)
就支持公开密钥加密算法了。
2。好像是有这样的限制,只好用循环搞定了。

能不能收回积分呀?

来自: flanker, 时间: 2003-06-06 9:34:00, ID: 1929701
to devil-li:

我正在研究 PKI的算法,我要实现 3DES对称加密和RSA非对称加密

能不能把你修改过可用的代码发一份给我,flanker@fj163.com

非常感谢,要分的话我就给分!

关于pki 我们可以讨论一下

来自: WorldCreater, 时间: 2003-06-06 10:51:00, ID: 1930024
导入这些函数的头文件delphi7里有吗?
你自个导入的?

来自: devil_li, 时间: 2003-06-07 9:21:00, ID: 1932481
flanker:你的email有问题,发不过去
WorldCreater:头文件Delphi没有,但是网上很多地方有下载

来自: pwxwabcd, 时间: 2003-06-09 16:02:00, ID: 1937151
devil_li,请给我发一个pwxwabcd@371.com

来自: pwxwabcd, 时间: 2003-06-11 8:33:00, ID: 1941530
请提供CryptoAPI的详细例子

来自: devil_li, 时间: 2003-06-11 10:06:00, ID: 1941884
既然大家需要,我就给大家帖几段吧:
//加密
class function TPvtCAPICrypto.Encrypt(const Data, Key: string): string;
var
hProv: HCRYPTPROV;
hKey: HCRYPTKEY;
Buffer, temp: string;
Index: Integer;
dwCount: DWORD;
Endof: Boolean;
BufferLen: DWORD;


procedure Init;
begin
hProv := 0;
hKey := 0;
Endof := False;
end;
procedure Clear;
begin
if Boolean(hKey) then
CryptDestroyKey(hKey);
if Boolean(hProv) then
CryptReleaseContext(hProv, 0);
end;
function Encrypt53(Data53: string): string;
begin
Init;

CryptAcquireContextEx(hProv);

if not CryptImportKey(hProv, PByte(PChar(Key)), Length(Key), 0, 0, @hKey) then
begin
Clear;
raise Exception.Create('Error during CryptImportKey');
end;

Index := 1;
Result := '';
BufferLen := BlockLen + 8;
repeat
Buffer := Copy(Data53, Index, BlockLen);
dwCount := Length(Buffer);
Inc(Index, dwCount);
Endof := Index > Length(Data53);
SetLength(Buffer, BufferLen);
if not CryptEncrypt(hKey, 0, Endof, 0, PByte(PChar(Buffer)), @dwCount, BufferLen) then
begin
Clear;
raise Exception.Create('Error during CryptEncrypt');
end;
SetLength(temp, dwCount);
Move(PChar(Buffer)^, Pointer(temp)^, dwCount);
Result := Result + temp;
until Endof;
Clear;
end;
var
I: Integer;
SegStr: string;
begin
Result := '';
if Ord(Key[1]) = 1 then //对称密钥加密
Result := Encrypt53(Data)
else // 公开密钥加密
begin
for I := 0 to Length(Data) div EncryptLen + 1 do
begin
SegStr := Copy(Data, I * EncryptLen + 1, EncryptLen);
SegStr := Encrypt53(SegStr);
Result := Result + Chr(Length(SegStr)) + SegStr;
end;
end;
end;


//解密
class function TPvtCAPICrypto.Decrypt(const Data, Key: string): string;
var
hProv: HCRYPTPROV;
hKey: HCRYPTKEY;
Buffer, temp: string;
Index: Integer;
dwCount: DWORD;
Endof: Boolean;
BufferLen: DWORD;

procedure Init;
begin
hProv := 0;
hKey := 0;
end;
procedure Clear;
begin
if Boolean(hKey) then
CryptDestroyKey(hKey);
if Boolean(hProv) then
CryptReleaseContext(hProv, 0);
end;
function Decrypt53(Data53: string): string;
begin
Init;

CryptAcquireContextEx(hProv);

if not CryptImportKey(hProv, PByte(PChar(Key)), Length(Key), 0, 0, @hKey) then
begin
Clear;
raise Exception.Create('Error during CryptImportKey');
end;

Index := 1;
Result := '';
BufferLen := BlockLen + 8;
repeat
Buffer := Copy(Data53, Index, BlockLen);
dwCount := Length(Buffer);
Inc(Index, dwCount);
Endof := Index > Length(Data53);
SetLength(Buffer, BufferLen);
if not CryptDecrypt(hKey, 0, Endof, 0, PByte(PChar(Buffer)), @dwCount) then
begin
Clear;
raise Exception.Create('Error during CryptDecrypt');
end;
SetLength(temp, dwCount);
Move(PChar(Buffer)^, Pointer(temp)^, dwCount);
Result := Result + temp;
until Endof;
Clear;
end;
var
SegPos, SegLen: Integer;
SegStr: string;
begin
Result := '';
if Ord(Key[1]) = 1 then //对称密钥解密
Result := Decrypt53(Data)
else // 公开密钥解密
begin
SegPos := 1;
while SegPos < Length(Data) do
begin
SegLen := Ord(Data[SegPos]);
SegStr := Copy(Data, SegPos + 1, SegLen);
Result := Result + Decrypt53(SegStr);
Inc(SegPos, SegLen + 1);
end;
end;
end;

来自: devil_li, 时间: 2003-06-11 10:11:00, ID: 1941908
至于头文件,由于太大了,2.0有7800多行,就不贴了,大家自己去网上下载

来自: Anubis99, 时间: 2003-06-11 10:25:00, ID: 1941986
微软CryptoAPI好像对密钥的长度和加密对象都有长度限制的,你最好查一下Windows SDK,那里面有非常详细的介绍。

来自: pwxwabcd, 时间: 2003-06-11 10:46:00, ID: 1942058
请问devil_li,程序中BlockLen怎样取值.

来自: pwxwabcd, 时间: 2003-06-17 17:02:00, ID: 1959729
我试了,用win2000也会出现公钥加密公钥也能解密的情况。

来自: jimiking, 时间: 2003-07-19 10:03:00, ID: 2041811
to devil_li : 我刚刚开始学用CryptoAPI,如果仅仅实现对文件的加密的话不论是对称或者是不对称,在delphi 中如何调用CryptEncryp 和CryptDecrypt 呢,是否就是你所说的在网上下载的头文件Wcrypt2.pas?能否把它导入到delphi6中成为一个单元,是用new component 加入吗?在你的程序中TPvtSignature是否是你自己定义的类,
我在一个考试系统中对客户端的考生成绩文件进行加密,但是操作系统是98 是否就不能实现非对称的加密
另外你的程序能否让我参考一下 谢谢 jimiking@163.com

最后一段程序是自己写的吗 Decrypt53是什么意思



来自: devil-li, 时间: 2003-07-21 15:07:00, ID: 2046819
pwxwabcd:BlockLen我取的1000
我又试了一下,果然用win2000也会出现公钥加密公钥也能解密的情况。明明以前可以的。。郁闷,盼望高手解答。
jimiking:Wcrypt2.pas应该是这个单元了。只需要把它加到工程里面就行了。TPvtSignature是我自己定义的类,98好像是不能实现非对称加密。Decrypt53是一次加密53个字节。源于我提的问题:只能够加密大约53个字符的数据,超过长度CryptEncrypt会出错。至今还未解决此问题,因此自己循环解决。

来自: jimiking, 时间: 2003-07-23 17:59:00, ID: 2053784
能否解释一下为什么 if Ord(Key[1]) = 1 则是 对称密钥解密

另外EncryptLen 的取值和意义是什么 ?~如果我借用你的程序实现对称加密 就不需要调用GetGenKey 了吧?· 这时我应该如何获得加密和解密返回的string 呢

来自: dreamstill, 时间: 2003-07-23 18:17:00, ID: 2053844
很有难度

来自: devil-li, 时间: 2003-07-24 10:25:00, ID: 2055147
1。能否解释一下为什么 if Ord(Key[1]) = 1 则是 对称密钥解密:
》》对称密钥加密的密钥第一个字节是1(密钥不是任意的字符串,是要满足一定格式的,要得到满足条件的字符串,参见我以下的过程)
2。另外EncryptLen 的取值和意义是什么 ?
》》EncryptLen = 53; //公私钥加密的最大字节长度
3.如果我借用你的程序实现对称加密 就不需要调用GetGenKey 了吧?
》》你加密总是需要一个密钥的,但是在我的函数里面
class function TPvtCAPICrypto.Encrypt(const Data, Key: string): string;
中的key不是任意格式的字符串都可以的,如果想从一个普通字符串得到加密所需要的key,可以调用我的这个过程:
class function TPvtCAPICrypto.MakeKeyFromStr(const AStr: string): string;
var
hProv: HCRYPTPROV;
hHash: HCRYPTHASH;
hKey, hXchgKey: HCRYPTKEY;
pbKeyBlob: PByte;
dwBlobLen: DWORD;

procedure Init;
begin
hProv := 0;
hHash := 0;
hKey := 0;
pbKeyBlob := nil;
dwBlobLen := 0;
end;

procedure Clear;
begin
if (dwBlobLen <> 0) and (pbKeyBlob <> nil) then
begin
FillChar(pbKeyBlob^, dwBlobLen, 0);
FreeMem(pbKeyBlob);
FillChar(dwBlobLen, Sizeof(dwBlobLen), 0);
end;
if Boolean(hKey) then
CryptDestroyKey(hKey);
if Boolean(hHash) then
CryptDestroyHash(hHash);
if Boolean(hProv) then
CryptReleaseContext(hProv, 0);
end;
begin
Init;

CryptAcquireContextEx(hProv);

if not CryptCreateHash(hProv, CALG_MD5, 0, 0, @hHash) then //创建哈西对象
begin
Clear;
raise Exception.Create('CryptCreateHash Failed!');
end;

if not CryptHashData(hHash, PByte(PChar(AStr)), Length(AStr), 0) then //创建字符串的哈西值
begin
Clear;
raise Exception.Create('CryptHashData Failed!');
end;

if not CryptDeriveKey(hProv, CALG_RC4, hHash, CRYPT_EXPORTABLE, @hKey) then //从hash对象中分离密钥
begin
Clear;
raise Exception.Create('CryptDeriveKey Failed!');
end;

//==============================导出密钥======================================
if not CryptGetUserKey(hProv, AT_KEYEXCHANGE, @hXchgKey) then
begin
Clear;
raise Exception.Create('CryptGetUserKey Failed!');
end;

if not CryptExportKey(hKey, hXchgKey, SIMPLEBLOB, 0, nil,
@dwBlobLen) then //得到从密钥盒中导出私有密钥所需空间大小
begin
Clear;
raise Exception.Create('CryptExportKey Failed!');
end;
try
GetMem(pbKeyBlob, dwBlobLen);
except
on EOutOfMemory do
begin
Clear;
raise Exception.Create('OutOfMemory!');
end;
end;
if not CryptExportKey(hKey, hXchgKey, SIMPLEBLOB, 0, pbKeyBlob,
@dwBlobLen) then //从密钥盒中导出私有密钥
begin
Clear;
raise Exception.Create('CryptExportKey Failed!');
end;

SetLength(Result, dwBlobLen);
Move(pbKeyBlob^, Pointer(Result)^, dwBlobLen);
Clear;
end;

4.这时我应该如何获得加密和解密返回的string 呢
》》class function TPvtCAPICrypto.Encrypt(const Data, Key: string): string;
》》class function TPvtCAPICrypto.Decrypt(const Data, Key: string): string;
》》的返回值就是加密和解密返回的string

来自: jimiking, 时间: 2003-07-24 11:22:00, ID: 2055432
下面是我对crpytoapi加密方法的理解,不知道是否正确。在你的加密解密函数中的key参数只是一个口令,而不是实际完成加密的密匙。如果我想实现对称加密的话,使用CryptDeriveKey 函数即可,返回的是指向密匙的句柄。

下面是我对你的函数的修改,实现了对称加密,好像觉得调用Ecrypt时对key 并没有限制
甚至为空也可以,可能把为空的情况夜作为一个字符串处理,我们可以一起讨论一下
不需要在MakeKeyFromStr过程中使用导出密匙CryptGetUserKey,CryptExportKey
修改如下:
Function TForm1.Encrypt(const Data,Key :string):string;
var
hProv : HCRYPTPROV; //指向csp提供者的句柄
hKey : HCRYPTKEY ; //指向密匙的句柄
hHash :HCRYPTHASH; //指向散列表的句柄,用于创建散列表
Buffer,Temp :string;
Index : integer;
dwCount :DWORD;
Endof : Boolean;
BufferLen :DWORD;

procedure Init ;
begin
hProv:=0;
hKey :=0;
hHash:=0;
Endof:=False;
end;

procedure clear;
begin
if boolean(hKey) then
CryptDestroyKey(hKey); //先销毁指向key的句柄
if boolean(hHash) then
CryptDestroyHash(hHash); //销毁指向散列的句柄
if boolean(hProv) then
CryptReleaseContext(hProv,0); //销毁指向提供者的句柄
end;
Function Encrypt53(Data53 :string):string;
begin
Init;
if not CryptAcquireContext(@hProv, nil, nil,PROV_RSA_FULL, 0) then //连接缺省的csp

begin
windows.MessageBox(0,'Erro during CryptAcquireContext','error..',MB_OK);
clear;
exit;
end;

//Key 为加密口令,用口令派生出的密匙加密

//建立散列表
if not CryptCreateHash(hProv,CALG_MD5,0,0,@hHash) then

begin
clear;
raise Exception.Create('Error during CryptCreateHash');
end;

//散列口令
if not CryptHashData(hHash,PBYTE(Pchar(Key)),Length(Key),0) then //PBYTE(pchar(Key))

begin
windows.MessageBox(0,'Error during CryptHashData','Error..,',MB_OK);
clear;
exit;
end;

//从散列口令中派生出密匙
if not CryptDeriveKey(hProv,CALG_RC2 ,hHash,0,@hKey) then
begin
windows.MessageBox(0,'Erroe during CryptDeriveKey','Error..',MB_OK);
clear;
exit;
end;

CryptDestroyHash(hHash);
hHash := 0;

Index:=1;
Result:='';
BufferLen:=BlockLen+8; //使用块编码,则需要额外空间
repeat
Buffer:=Copy(Data53,Index,BlockLen); //为Buffer赋值
dwCount:=Length(Buffer); //buffer的长度
Inc(Index,dwCount); //Index:=Index+dwCount
Endof:=Index>Length(Data53); //Index是否大于需要加密的数据的长度
SetLength(Buffer,BufferLen); // 为buffer分配长度空间 bufferlen
if not CryptEncrypt(hKey,0,Endof,0,PByte(PChar(Buffer)),@dwCount,BufferLen) then
begin
clear;
Raise Exception.Create('Error during CryptEncrypt');
end;
SetLength(temp,dwCount); //为temp 分配长度空间dwCount
Move(PChar(Buffer)^,Pointer(temp)^,dwCount); //??
Result:=Result+temp;
until Endof;
Clear;
end;
var
i: integer;
SegStr :string;
begin
Result:='';
if ord(Key[1])=1 then
Result:=Encrypt53(Data)
else
begin
for i:=0 to Length(Data) div EncryptLen + 1 do
begin
SegStr:=Copy(Data,i*EncryptLen + 1,EncryptLen );
SegStr:=Encrypt53(SegStr);
Result:=Result+Chr(Length(SegStr))+ SegStr;
end;
end;
end;

对解密过程做相应的改动即可。

来自: jimiking, 时间: 2003-07-24 12:01:00, ID: 2055454
1.密钥不是任意的字符串,是要满足一定格式的,要得到满足条件的字符串,参见我以下的过程)
>>我的key取的是类似与‘11111111111’的数字字符串,那请问字符串要满足的格式是什么
2。在我的程序里 EncryptLen取的是1
3。1。能否解释一下为什么 if Ord(Key[1]) = 1 则是 对称密钥解密:
》》对称密钥加密的密钥第一个字节是1
》》》我还是不是很理解,key[1]是字符串key的第一个字符,ord是获得字符的ascii 码,是否
是说对称加密中密匙的第一个字节ascii码必须是一。
4。按照你的理解 key参数即为加密的密匙,但是我认为key是口令 ,密匙是根据key由CryptDeriveKey
和CryptGenKey 得到 不知道是不是正确?应该怎样理解,如果你比较清楚的话,能否将原理解释一下

另外是否可以留下你的邮箱进行联系 jimiking@163.com

来自: devil-li, 时间: 2003-07-25 10:16:00, ID: 2058517
1。直接用纯文本字符串是无法加密的:因为需要一个密钥句柄hkey。因此要用纯文本加密必需要将纯文本变成key结构。我之所以用MakeKeyFromStr是考虑了公开密钥加密的情况:公开密钥加密是不可能由你自己指定纯文本字符串的密钥的。如果你只需要对称密钥加密,就用你的方法也可以:CryptDeriveKey以后直接用hkey而不用导出。我只不过是CryptDeriveKey然后导出,Encrypt再导入。结果都是一样的。
2。密钥不是任意的字符串。我指的密钥不是纯文本的密钥,而是hkey的密钥。(就是CryptDeriveKey之后的结果)对称密钥加密的密钥第一个字节是1,这里的密钥也是指的hkey指向的密钥。
3。按照你的理解 key参数即为加密的密匙,但是我认为key是口令 ,密匙是根据key由CryptDeriveKey和CryptGenKey 得到 不知道是不是正确?
》》在我的函数中,key参数即为加密的密匙。key就是从CryptDeriveKey和CryptGenKey得到的,因此你的理解和我的意思是一样的。
4。我的纯文本的密钥加密的过程:1.有一个纯文本[red]密码[/red],通过MakeKeyFromStr得到密码对应的密钥(key)。调用Encrypt,key参数就是MakeKeyFromStr的结果。在Encrypt里面会调用CryptImportKey导入key而得到hkey。然后加密。
5。我的EMail:blacwet@163.com

来自: jimiking, 时间: 2003-08-02 9:22:00, ID: 2078287
你好 : 我的对称加密在2000 下可以通过,为什么到98下 总是连接不到CSP

现在我参照你的代码改为对称加密后,在2000环境下可以通过,但是在98下时候,总是连接不到CSP,

Function Encrypt53(Data53 :string):string;
begin
Init;
if not CryptAcquireContext(@hProv, nil, nil,PROV_RSA_FULL, 0) then //连接缺省的csp

begin
windows.MessageBox(0,'Erro during CryptAcquireContext','error..',MB_OK);
clear;
exit;
end;

CryptAcquireContext(@hProv, nil, nil,PROV_RSA_FULL, 0)执行会有错误,请你指教。我做的对称加密在2000下通过,到98下调试的时候需要注意些什么问题呢 谢谢



来自: devil-li, 时间: 2003-08-05 9:34:00, ID: 2084386
因为你的98没有container。
你可以这样写:
class procedure TPvtCAPICrypto.CryptAcquireContextEx(var hProv: HCRYPTPROV);
begin
if not CryptAcquireContext(@hProv, nil, nil, PROV_RSA_FULL, 0) then
if not CryptAcquireContext(@hProv, 'PvtContainer', nil,
PROV_RSA_FULL, CRYPT_NEWKEYSET) then
raise Exception.Create('Error during CryptAcquireContext');
end;

其中'PvtContainer'这个名字是随便起的。

来自: jimiking, 时间: 2003-08-05 15:25:00, ID: 2085785
那之后的调用方法还一样么 PvtContainer参数在后面怎么引用

我后来改为 CryptAcquireContext(@hProv, nil, nil,
PROV_RSA_FULL, CRYPT_NEWKEYSET) 也不行的

来自: devil-li, 时间: 2003-08-05 18:06:00, ID: 2086502
'PvtContainer'这个是Container的名字,一定要指定的。随便什么名字都可以。
以后访问直接用
if not CryptAcquireContext(@hProv, nil, nil, PROV_RSA_FULL, 0) then
所以直接像我那样封装就行了,使用时直接调用CryptAcquireContextEx

来自: jimiking, 时间: 2003-08-06 9:46:00, ID: 2087511
下面是我进行调试时候发现的一些问题,和你讨论一下:
1。不能有两个相同的container 名字。如
if not CryptAcquireContext(@hProv, 'wer', nil,PROV_RSA_FULL,CRYPT_NEWKEYSET)then 在第一次执行时,跳出Exception处理。当第二次执行时就会执行Exception。
(这是只有这一句的情况)
2.如果有上一句代码的话就必须要有
if not CryptAcquireContext(@hProv, nil, nil, PROV_RSA_FULL, 0) then

即像你上面所写:
if not CryptAcquireContext(@hProv, nil, nil, PROV_RSA_FULL, 0) then //(1)
if not CryptAcquireContext(@hProv, 'PvtContainer', nil,
PROV_RSA_FULL, CRYPT_NEWKEYSET) then //(2)
raise Exception.Create('Error during CryptAcquireContext');
end;
当第一次执行时,执行的是(2),而再一次调用Encrypt53时,执行到(1)的时,就执行完毕,这时候CryptAcquireContext(@hProv, nil, nil, PROV_RSA_FULL, 0) 中的第二个参数应理解为缺省值,即是我们刚刚创建的container 的名字'PvtContainer'

不知道我的理解是否正确 谢谢



来自: jimiking, 时间: 2003-08-07 9:10:00, ID: 2090378
另外 创建的这个container的名字,有没有存在生命期的问题,即我运行了第一句代码后

是不是在系统里永远的建立了这个container,或者机器重启后 就销毁,再进行建立

来自: devil-li, 时间: 2003-08-08 9:56:00, ID: 2093651
应该是不重装系统就永远存在

来自: jnbutian, 时间: 2003-12-10 11:37:00, ID: 2344923
to devil-li
请把你的程序给我发一份吧,我现在也在做这样一个东西.非常感谢.
jnbutian@sohu.com

来自: devil-li, 时间: 2003-12-11 10:30:00, ID: 2346993
对不起,这个是商业程序,不能发给你。通过上面的讨论,所有的关键源代码都有了。你自己研究一下吧

来自: zhongtian中天, 时间: 2004-10-11 22:24:10, ID: 2844076
to devil-li:
我想问一下,我用cryptoapi作一个两个机器加解密的东西,我现在有两个得安公司的cpu智能卡,我想请问这个大哥我应该怎么用机器a的公钥加密后(a的私钥存在卡中),传给机器b密文,让机器b解密啊??


来自: zhongtian中天, 时间: 2004-10-11 22:35:31, ID: 2844087
我的email是:xiaoxiaokonglong@lianluo.com

来自: wdyisbest, 时间: 2004-10-28 17:21:52, ID: 2870016
to devil_li
请问 Wcrypt2.pas 在哪里可以下载?能给我个地址吗?谢啦!

问题讨论没有结束 ...
 
http://homepages.borland.com/jedi/cms/modules/apilib/viewcat.php?op=&cid=4&PHPSESSID=cbe1d586d3a0fa1c2183c16fa16b0572

给你一个CryptoAPI.PAS,1.0.2.0的下载地址,里面不但有单元,而且带例子。
繁体中文教程。
没有怎么看。。。。让我现作,我也是抄写。。。。。。。。。。。。。。。
 
就在最底下。。。
繁体中文说明:
http://delphi.ktop.com.tw/download/upload/29414_CryptoAPI.pdf
http://down3.tomore.com/down/datanew/2004011112260923687.zip
 
帮顶..................
 
谢谢各位,我先用别的算法解决,回头我自己研究了下,也搞定,
仍然感谢大家的帮忙,结帖,散分
 
后退
顶部