数字证书的匙包分拆问题,DLL及原代码在里面,请看 ( 积分: 100 )

  • 主题发起人 主题发起人 QXCOMM
  • 开始时间 开始时间
Q

QXCOMM

Unregistered / Unconfirmed
GUEST, unregistred user!
//文件读写公共函数,用法较复杂<br>int _PubKey_IO(char *buf1,int *len1,char *buf2,int *len2,int Action)<br>/*<br>'Action=1:<br>'buf1指向公钥数据块、<br>'len1指向一个表示数据块长度的int变量;<br>'buf2指向文件名字串、<br>'len2无意义。<br>'操作结果:将buf1数据块内容以DER格式存盘。<br>'Action=3:<br>'buf1指向文件名字串、<br>'len1指向一个数值为0的int变量;<br>'buf2指向一个数据缓冲区、<br>'len2指向一个表示数据缓冲区最大长度的int变量;<br>'操作结果:将公钥文件读入并以PEM格式放入buf2缓冲区,len2为读入后的数据块有效长度。<br>'如果buf2空间不够大,len2指向的变量返回实际需要值。<br>'Action=P12:<br>'buf1指向一个数据缓冲区,区内存放读P12文件名字串、<br>'len1指向一个表示buf1数据缓冲区最大长度的int变量(不需要读取私钥时置0);<br>'buf2指向一个数据缓冲区,区内存放读P12文件的密码,如果该文件不需要密码,则将其第一个字节置0、<br>'len2指向一个表示buf2数据缓冲区最大长度的int变量;<br>'操作结果:将P12文件的公钥读入并以PEM格式放入buf2缓冲区,len2为读入后的数据块有效长度。<br>'如果buf2空间不够大,len2指向的变量返回实际需要值,<br>'将P12文件的私钥读入并以PEM格式放入buf1缓冲区,len1为读入后的数据块有效长度。<br>'如果buf2空间不够大,len2指向的变量返回实际需要值,<br>'如果密码无效,len1和len2指向的变量返回-1。<br>'操作成功:返回值&lt;&gt;0,失败:返回值=0。<br>'利用这个函数实现&quot;查看&quot;公钥、&quot;分拆匙包&quot;功能(先Action=5读出公私钥,然后分别存盘)<br>*/<br>================================================================================<br>var<br>buf1,buf2:Pchar;<br>len1,len2:longint;<br>ms1,ms2:TMemoryStream;<br>F1: file;<br>Size1,Size2: longint;<br><br>begin<br><br><br>//将匙包放入缓冲区buf1内<br>AssignFile(F1, Edit1.Text);<br>Reset(F1, 1);<br>Size1 := FileSize(F1);<br>GetMem(Buf1, Size1);<br>BlockRead(F1, Buf1^, Size1);<br>len1:=4096;<br><br><br>//将密码放入缓冲区buf2内<br>GetMem(Buf2,Length(edit2.Text ));<br>StrCopy(Buf2, PChar(edit2.Text));<br>len2:=4096;<br><br>_PubKey_IO(buf1,len1,buf2,len2,5);<br><br><br><br>//从缓冲区buf1内读出私钥<br>ms1:=TMemoryStream.Create;<br>ms1.Write(buf1^,len1);<br>ms1.SaveToFile('c:/yjyaaa.prk');<br>ms1.Free;<br><br>//从缓冲区buf2内读出公钥<br>_PubKey_IO(buf2,len2,Pchar(Edit3.text),len2,1);<br><br>ms2:=TMemoryStream.Create;<br>ms2.Write(buf2^,len2);<br>ms2.SaveToFile('c:/yjyaaa.cer');<br>ms2.Free;<br><br>end;<br><br><br>上面的代码是运行后分拆匙包,产生的公钥,和私钥的格式不正确,我怀疑是代码错误,请帮忙分析
 
//文件读写公共函数,用法较复杂<br>int _PubKey_IO(char *buf1,int *len1,char *buf2,int *len2,int Action)<br>/*<br>'Action=1:<br>'buf1指向公钥数据块、<br>'len1指向一个表示数据块长度的int变量;<br>'buf2指向文件名字串、<br>'len2无意义。<br>'操作结果:将buf1数据块内容以DER格式存盘。<br>'Action=3:<br>'buf1指向文件名字串、<br>'len1指向一个数值为0的int变量;<br>'buf2指向一个数据缓冲区、<br>'len2指向一个表示数据缓冲区最大长度的int变量;<br>'操作结果:将公钥文件读入并以PEM格式放入buf2缓冲区,len2为读入后的数据块有效长度。<br>'如果buf2空间不够大,len2指向的变量返回实际需要值。<br>'Action=P12:<br>'buf1指向一个数据缓冲区,区内存放读P12文件名字串、<br>'len1指向一个表示buf1数据缓冲区最大长度的int变量(不需要读取私钥时置0);<br>'buf2指向一个数据缓冲区,区内存放读P12文件的密码,如果该文件不需要密码,则将其第一个字节置0、<br>'len2指向一个表示buf2数据缓冲区最大长度的int变量;<br>'操作结果:将P12文件的公钥读入并以PEM格式放入buf2缓冲区,len2为读入后的数据块有效长度。<br>'如果buf2空间不够大,len2指向的变量返回实际需要值,<br>'将P12文件的私钥读入并以PEM格式放入buf1缓冲区,len1为读入后的数据块有效长度。<br>'如果buf2空间不够大,len2指向的变量返回实际需要值,<br>'如果密码无效,len1和len2指向的变量返回-1。<br>'操作成功:返回值&lt;&gt;0,失败:返回值=0。<br>'利用这个函数实现&quot;查看&quot;公钥、&quot;分拆匙包&quot;功能(先Action=5读出公私钥,然后分别存盘)<br>*/<br>================================================================================<br>var<br>buf1,buf2:Pchar;<br>len1,len2:longint;<br>ms1,ms2:TMemoryStream;<br>F1: file;<br>Size1,Size2: longint;<br><br>begin<br><br><br>//将匙包放入缓冲区buf1内<br>AssignFile(F1, Edit1.Text);<br>Reset(F1, 1);<br>Size1 := FileSize(F1);<br>GetMem(Buf1, Size1);<br>BlockRead(F1, Buf1^, Size1);<br>len1:=4096;<br><br><br>//将密码放入缓冲区buf2内<br>GetMem(Buf2,Length(edit2.Text ));<br>StrCopy(Buf2, PChar(edit2.Text));<br>len2:=4096;<br><br>_PubKey_IO(buf1,len1,buf2,len2,5);<br><br><br><br>//从缓冲区buf1内读出私钥<br>ms1:=TMemoryStream.Create;<br>ms1.Write(buf1^,len1);<br>ms1.SaveToFile('c:/yjyaaa.prk');<br>ms1.Free;<br><br>//从缓冲区buf2内读出公钥<br>_PubKey_IO(buf2,len2,Pchar(Edit3.text),len2,1);<br><br>ms2:=TMemoryStream.Create;<br>ms2.Write(buf2^,len2);<br>ms2.SaveToFile('c:/yjyaaa.cer');<br>ms2.Free;<br><br>end;<br><br><br>上面的代码是运行后分拆匙包,产生的公钥,和私钥的格式不正确,我怀疑是代码错误,请帮忙分析
 
分析什么呢,你这里哪有什么关于格式的语句呢,谁知道你要什么格式<br>除了这个没有源代码的函数 _PubKey_IO(buf1,len1,buf2,len2,5);
 
我是让大家看看我写的代码对还是不对,我怀疑我的代码有问题
 
我来试图解释一下存在的问题吧。按照你对该函数的注释和你的调用程序看来,你的这个函数在设计上存在一个很大的问题:既然buf1是用来向函数传递要分拆的那个“匙包”数据的,那么就不应该再通过这个缓冲区来返回分拆出来的私匙。因为对于一个数据处理函数来说,不应该将处理结果通过原来用于存放待处理数据的缓冲区来返回的,应该用另外一个专门的缓冲区来返回。这个设计上的缺陷将导致函数的调用者无所适从,因为他们在开始调用前,为缓冲区buf1分配存储空间的时候将不知道到底是应该以待处理数据量的大小还是返回数据量的大小来分配空间。这样的函数设计风格是十分的不好的。
 
SparkV<br><br>那个问题是一个问题,但是有人用这个函数写出了工具<br>那说明这个DLL还是能解决问题的<br>帮忙看看我写的代码,是否有不正确的地方,帮忙指正
 
好、好,就算这个问题无伤大雅,你也可以忍受吧。但至少--既然你的程序里面要调用的是它的(Action=5)功能,那么你的注释里面就应该把Action=5时,各个参数和返回值的含义给出来吧?要不然我怎么知道你哪里出的问题。你空给了一大堆的注释,偏偏你要调用的那个功能的注释没有,这是怎么搞的。[:(!]
 
SparkV,所有的书面资料就是下面这些,这是DLL的全部资料,我这里还有个DLL文件,请帮忙看看,谢谢<br>============================================================<br>//返回错误信息指针<br>void *_Dll_Err(int errp)<br>/*每当下述函数调用失败,可以紧接着调用此函数得到指向出错信息字串的指针,如无错误发生或者重复调用,则指向“未定义的错误类型”字串。errp置0。*/<br><br>//文件读写公共函数,用法较复杂<br>int _PubKey_IO(char *buf1,int *len1,char *buf2,int *len2,int Action)<br>/*<br>'Action=DER:<br>'buf1指向公钥数据块、<br>'len1指向一个表示数据块长度的int变量;<br>'buf2指向文件名字串、<br>'len2无意义。<br>'操作结果:将buf1数据块内容以DER格式存盘。<br>'Action=PEM:<br>'buf1指向文件名字串、<br>'len1指向一个数值为0的int变量;<br>'buf2指向一个数据缓冲区、<br>'len2指向一个表示数据缓冲区最大长度的int变量;<br>'操作结果:将公钥文件读入并以PEM格式放入buf2缓冲区,len2为读入后的数据块有效长度。<br>'如果buf2空间不够大,len2指向的变量返回实际需要值。<br>'Action=P12:<br>'buf1指向一个数据缓冲区,区内存放读P12文件名字串、<br>'len1指向一个表示buf1数据缓冲区最大长度的int变量(不需要读取私钥时置0);<br>'buf2指向一个数据缓冲区,区内存放读P12文件的密码,如果该文件不需要密码,则将其第一个字节置0、<br>'len2指向一个表示buf2数据缓冲区最大长度的int变量;<br>'操作结果:将P12文件的公钥读入并以PEM格式放入buf2缓冲区,len2为读入后的数据块有效长度。<br>'如果buf2空间不够大,len2指向的变量返回实际需要值,<br>'将P12文件的私钥读入并以PEM格式放入buf1缓冲区,len1为读入后的数据块有效长度。<br>'如果buf2空间不够大,len2指向的变量返回实际需要值,<br>'如果密码无效,len1和len2指向的变量返回-1。<br>'操作成功:返回值&lt;&gt;0,失败:返回值=0。<br>'利用这个函数实现&quot;查看&quot;公钥、&quot;分拆匙包&quot;功能(先Action=P12读出公私钥,然后分别存盘)<br>*/<br><br>//检验公钥、私钥文件或数据快是否配对<br>int _IsPair(<br> &nbsp; &nbsp;char *cert /*公钥*/,<br> &nbsp; &nbsp;int certlen /*公钥长度:0则cert为磁盘文件名,否则为内存数据块*/,<br> &nbsp; &nbsp;char *key /*私钥*/,<br> &nbsp; &nbsp;int keylen /*私钥长度:0则key为磁盘文件名,否则为内存数据块*/)<br>//'操作成功:返回值&lt;&gt;0,失败:返回值=0。<br><br>//将密钥对组成p12包<br>int _P12Pack(<br> &nbsp; &nbsp;char * strP12 /*pfx包文件名*/,<br> &nbsp; &nbsp;char * strPwd /*保护密码*/,<br> &nbsp; &nbsp;char * NiceName /*好记的名称*/,<br> &nbsp; &nbsp;char * strCert /*公钥*/,<br> &nbsp; &nbsp;int plen /*公钥长度,0则strCert为磁盘文件名,否则为内存数据块*/,<br> &nbsp; &nbsp;char * strkey /*私钥*/,<br> &nbsp; &nbsp;int klen /*私钥长度,0则strkey为磁盘文件名,否则为内存数据块*/)<br>//'操作成功:返回值&lt;&gt;0,失败:返回值=0。<br><br><br>//修改/验证p12包密码<br>int _ChangePW(<br> &nbsp; &nbsp;char * strP12 /*原文件名*/,<br> &nbsp; &nbsp;char * strPwd /*原密码*/,<br> &nbsp; &nbsp;char * strPwd2 /*新密码*/,<br> &nbsp; &nbsp;char * NiceName /*好记的名字*/,<br> &nbsp; &nbsp;char * strOutP12 /*新文件名*/)<br>//'(strOutP12==NULL)||(*strOutP12==0)为验证密码,密码正确则返回值=2,不正确返回值=0。<br>//'其余情况为修改密码,成功则返回值=1,不成功返回值=0。 <br><br>//将私钥转换为微软pvk格式<br>int _Prk2Pvk(<br> char *keyfile /*私钥*/,<br> int keylen /*私钥长度,0则keyfile为磁盘文件名,否则为内存数据块*/,<br> char *pvkfile /*pvk文件名*/)<br>//'操作成功:返回值&lt;&gt;0,失败:返回值=0。<br><br>//常数<br>#define DER &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1 //FORMAT_ASN1<br>#define PEM &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3 &nbsp; /*定义格式*/<br>#define P12 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 5
 
晕倒,原来那个P12就是5啊!怎么不早说?!这样挤一点出来一点的哪时候才解决得了问题?[:D]<br>================================================================================<br>var<br>i,buf1,buf2:Pchar;<br>len1,len2:longint;<br>ms1,ms2:TMemoryStream;<br>F1: file;<br>Size1,Size2: longint;<br><br>begin<br><br><br>// 修改点一:根据你的注释里面的描述。当调用Aciton=5功能时,buf1里面放的应该是P12<br>// 文件名,而不是文件的数据内容。所以你没有必要自己“将匙包放入缓冲区buf1内”。<br>GetMem(Buf1, 4096);<br>// 因为我前面说过,你要调用的那个函数存在设计上的缺陷。使得我没有办法用常规的<br>// 手段来探测返回数据量的大小,所以这里我是一开始就分配给了两个缓冲区最大的容量<br><br>// 按照你原来代码的意思,Edit1里面输入的应该是数据文件的文件名吧?<br>// 由于前面分配缓冲区空间时,用的是最大容量,所以下面将数据文件文件名放入缓冲区时,我没有用字符串复制函数,而是自己写代码来复制:<br>for i:=1 to Length(Edit1.Text) do<br> &nbsp;buf1[i-1]:=Edit1.Text;<br>buf1[Length(Edit1.Text)]:=#0;<br>len1:=4096;<br><br><br>//将密码放入缓冲区buf2内<br>GetMem(Buf2,4096);<br>for i:=1 to Length(Edit2.Text)) do<br> &nbsp;buf2[i-1]:=Edit2.Text;<br>buf2[Length(Edit2.Text)]:=#0;<br>len2:=4096;<br><br>_PubKey_IO(buf1,@len1,buf2,@len2,5); &nbsp;<br>// 修改点二:改传值调用为传址调用。如果不这么改的话,len1和len2可能不能返回读入的数据块的有效长度。<br><br><br>//从缓冲区buf1内读出私钥<br>ms1:=TMemoryStream.Create;<br>ms1.Write(buf1^,len1);<br>ms1.SaveToFile('c:/yjyaaa.prk');<br>ms1.Free;<br><br>//从缓冲区buf2内读出公钥<br>_PubKey_IO(buf2,len2,Pchar(Edit3.text),len2,1);<br><br>ms2:=TMemoryStream.Create;<br>ms2.Write(buf2^,len2);<br>ms2.SaveToFile('c:/yjyaaa.cer');<br>ms2.Free;<br><br>end;
 
SparkV<br>你修改的这段代码编译不通过,<br>一、i的变量类型不对吧,我修改为i:integer;<br>二、_PubKey_IO(buf1,@len1,buf2,@len2,5); 编译不通过<br>问题显示为:<br>Build<br> &nbsp;[Warning] Unit1.pas(37): Unsafe type 'PChar'<br> &nbsp;[Warning] Unit1.pas(37): Unsafe type 'PChar'<br> &nbsp;[Warning] Unit1.pas(55): Unsafe type 'PChar'<br> &nbsp;[Warning] Unit1.pas(67): Unsafe type 'buf1: PAnsiChar'<br> &nbsp;[Warning] Unit1.pas(68): Unsafe type 'buf1: PAnsiChar'<br> &nbsp;[Warning] Unit1.pas(74): Unsafe code 'GetMem'<br> &nbsp;[Warning] Unit1.pas(74): Unsafe type 'buf2: PAnsiChar'<br> &nbsp;[Warning] Unit1.pas(76): Unsafe type 'buf2: PAnsiChar'<br> &nbsp;[Warning] Unit1.pas(77): Unsafe type 'buf2: PAnsiChar'<br> &nbsp;[Warning] Unit1.pas(80): Unsafe type 'buf1: PAnsiChar'<br> &nbsp;[Warning] Unit1.pas(80): Unsafe code '@ operator'<br> &nbsp;[Error] Unit1.pas(80): Incompatible types: 'Integer' and 'Pointer'<br> &nbsp;[Error] Unit1.pas(80): Incompatible types: 'Integer' and 'Pointer'<br> &nbsp;[Warning] Unit1.pas(86): Unsafe type 'buf1: PAnsiChar'<br> &nbsp;[Warning] Unit1.pas(92): Unsafe type 'buf2: PAnsiChar'<br> &nbsp;[Fatal Error] Project1.dpr(5): Could not compile used unit 'Unit1.pas'<br><br>我也晕了,是什么问题?要不我把哪个DLL,发给你,帮忙调试一下,告诉我的E_mail吧
 
啊,不好意思,忘了告诉你。你给出的那个函数原型是C++形式的:<br>int _PubKey_IO(char *buf1,int *len1,char *buf2,int *len2,int Action)<br>里面那两个len1和len2被定义为int*,也就是“指向整型的指针”。所以你在改成Delphi的形式的原型的时候,不能把len1和len2定义为Integer,而应该定义为相应的PInteger:<br>_PubKey_IO(buf1:PChar;len1:PInteger;buf2:PChar;len2:PInteger;Action:Integer):Integer;<br>这样子写才对。<br>然后下面的调用代码不变。
 
对于楼主提问的能力我很失望,从上一个类似的帖子开始就很失望
 
bjyplbx,<br>我看你还是闭嘴的比较好,你说你来这里是什么意思嘛?我都糊涂了,既然你不能解决问题,就请你不要发言,何必呢,你不说话没有人把你当成哑巴卖了啊!!!<br>我真佩服你了,正经事不干,到这里斗嘴,希望在我的贴子里不要再看到你<br>象SparkV,我是对他很佩服的五体投地的,而对你我是用鄙视的眼光看你,你是能说不能做的人。
 
咦?楼主还没试出来吗?
 
SparkV:<br>我没有你说的要一点挤一点出来的意思啊,我恨不能把我的所有资料都给你,哈哈<br>现在可以了,非常感谢啊,该天请你吃饭
 
问题解决了就好,哈哈~
 
SparkV, <br>如何动态调用哪个p12.dll,并如何使用_PubKey_IO()函数,麻烦你给个提示吧,谢谢
 
基本上,就是这样吧:<br>==================================<br>unit Unit1;<br><br>interface<br><br>uses<br> &nbsp;Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,<br> &nbsp;Dialogs, StdCtrls;<br><br>type<br> &nbsp;TForm1 = class(TForm)<br> &nbsp; &nbsp;Button1: TButton;<br> &nbsp; &nbsp;procedure Button1Click(Sender: TObject);<br> &nbsp;private<br> &nbsp; &nbsp;{ Private declarations }<br> &nbsp;public<br> &nbsp; &nbsp;{ Public declarations }<br> &nbsp;end;<br><br> &nbsp;T_PubKey_IO=function (buf1:PChar;len1:PInteger;buf2:PChar;len2:PInteger;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Action:Integer):Integer; stdcall;<br><br><br>var<br> &nbsp;Form1: TForm1;<br><br>implementation<br><br>{$R *.dfm}<br><br>procedure TForm1.Button1Click(Sender: TObject);<br>var<br> &nbsp;_PubKey_IO:T_PubKey_IO;<br> &nbsp;Handle:THandle;<br>begin<br> &nbsp;Handle:=LoadLibrary('p12.dll');<br> &nbsp;if Handle&lt;&gt;0 then<br> &nbsp;begin<br> &nbsp; &nbsp;@_PubKey_IO:=GetProcAddress(Handle,'_PubKey_IO');<br> &nbsp; &nbsp;if @_PubKey_IO&lt;&gt;nil then<br> &nbsp; &nbsp;begin<br> &nbsp; &nbsp; &nbsp;... // 这里就是你调用函数来实现需要的功能的代码了,跟原来<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// 静态调用的时候写的是一样的。<br> &nbsp; &nbsp;end;<br> &nbsp; &nbsp;FreeLibrary(Handle)<br> &nbsp;end<br>end;<br><br>end.
 
后退
顶部