一个vc写的dll 实现3des功能,调三个函数,头文件如下
DECL des_3EEEinit(UCHAR *key, int len, DES_KS ks1, DES_KS ks2, DES_KS ks3);
DECL des_ecb3EEEencode(UCHAR *in64, UCHAR *out64, DES_KS ks1, DES_KS ks2, DES_KS ks3);
DECL des_ecb3EEEdecode(UCHAR *in64, UCHAR *out64, DES_KS ks1, DES_KS ks2, DES_KS ks3);
其中
typedef unsigned long DES_KS[16][2];在delphi中调用此dlltype
  kstype=array[1..16,1..2] of dword;    //对应unsigned long DES_KS[16][2];
Function des_3EEEinit (key:pchar;len : integer;var ks1,ks2,ks3:kstype) : Longword  ; cdecl ; external 'des3.dll' ;procedure TForm1.Button1Click(Sender: TObject);
var ks1,ks2,ks3:kstype;
    key:pchar;
begin
  key:= '123456789012345678901234';
  des_3EEEinit(key,224,ks1,ks2,ks3);
end;出内存错误  不知道是因为pchar对应UCHAR *key的问题,还是那个二维数组的问题,请高手指教
dll,头文件,demo在此下载http://euploading.cn/file/23057/des3-win32-zip.html如能提供delphi版的3des算法,能够解密该dll加密的文件也可

解决方案 »

  1.   

    http://www.delphifans.com/SoftView/SoftView_263.html 有DES下载
      

  2.   

    就是用的这个。解密结果不对
    按照EEE的加密方式
    我做了三次DecryStrHex,对不上
      

  3.   

    stdcall,.h文件里这样定义了:
    #if defined(WIN32) || defined(OS2)
    #define DECL int pascal
    #define UCHAR unsigned char
    #define SIZE_T size_t
    #define DES_PKS DES_KS *
    #endif /* WIN32 */pascal(其实应该写__pascal而好些)call就是stdcall
      

  4.   

    改成stdcall,也是报错,同样的内存错误
      

  5.   

    procedure TForm1.Button1Click(Sender: TObject); 
    var ks1,ks2,ks3:kstype; 
        key:array[0..255] of char; 
    begin 
      key:= '123456789012345678901234'; 
      des_3EEEinit(key,224,ks1,ks2,ks3); 
    end; 
    这样试试
      

  6.   


    难道跟delphi版本有关系?我是delphi7
      

  7.   

    跟版本没关系,调用约定是固定的,我用的也是d7
    参数传的没问题,虽然文件里说最大传的len是24,我试着传224也返回0,按照文档中的说明也算是正常初始化了。
    报错的原因是一开始cdecl调用约定,本来被调用方已经清理了栈,但cdecl的调用方又清理了一遍,栈指针被破坏了就出错了
      

  8.   

    我用 cdecl 出错,换成stdcall正常
      

  9.   

    目前,des_3EEEinit已经没问题了
    des_ecb3EEEencode(UCHAR *in64, UCHAR *out64, DES_KS ks1, DES_KS ks2, DES_KS ks3); 还是不行
    function des_ecb3EEEdecode(in64:pchar;var out64:pchar;ks1,ks2,ks3:kstype):Longword;stdcall;external 'DES3.dll';
    var ks1,ks2,ks3:kstype;
        key,out64:pchar;
        a:integer;
    begin
      key:= 'D352C02CADD98FA7C9A8E1F9';
      des_3EEEinit(key,24,ks1,ks2,ks3);
      a:=des_ecb3EEEdecode('A03E951B',out64,ks1,ks2,ks3);    //返回值=0,看似没问题
      showmessage(out64);              //取的时候出错。
      

  10.   

    type
      //unsigned long DES_KS[16][2]; 
      TDES_KS = array [0..16-1, 0..2-1] of LongWord;//DECL des_3EEEinit(UCHAR *key, int len, DES_KS ks1, DES_KS ks2, DES_KS ks3); 
    procedure des_3EEEinit(key: (*PByte*) PAnsiChar; len: Integer; const ks1,ks2,ks3); cdecl; external 'des3.dll' ;
    {//或者
    procedure des_3EEEinit(key: (*PByte*) PAnsiChar; len: Integer; ks1,ks2,ks3: TDES_KS); cdecl; external 'des3.dll' ;
    }
    //DECL des_ecb3EEEencode(UCHAR *in64, UCHAR *out64, DES_KS ks1, DES_KS ks2, DES_KS ks3); 
    procedure des_ecb3EEEencode(in64: (*PByte*) PAnsiChar; out64: (*PByte*) PAnsiChar; const ks1,ks2,ks3); cdecl; external 'des3.dll' ; 
    {//或者
    procedure des_ecb3EEEencode(in64: (*PByte*) PAnsiChar; out64: (*PByte*) PAnsiChar; const ks1,ks2,ks3: TDES_KS); cdecl; external 'des3.dll' ;
    }
    //DECL des_ecb3EEEdecode(UCHAR *in64, UCHAR *out64, DES_KS ks1, DES_KS ks2, DES_KS ks3); 
    procedure des_ecb3EEEdecode(in64: (*PByte*) PAnsiChar; out64: (*PByte*) PAnsiChar; const ks1,ks2,ks3); cdecl; external 'des3.dll' ; 
    {//或者
    procedure des_ecb3EEEdecode(in64: (*PByte*) PAnsiChar; out64: (*PByte*) PAnsiChar; const ks1,ks2,ks3: TDES_KS); cdecl; external 'des3.dll' ;
    }
    procedure TForm1.Button1Click(Sender: TObject); 
    var ks1,ks2,ks3:TDES_KS; 
        key:PAnsiChar; 
    begin 
      key:= '123456789012345678901234'; 
      des_3EEEinit(key,224,ks1,ks2,ks3); 
    end; 
    个人以为,这个Init实际上是把一个Key串初始化为三个DES_key_schedule,并通过参数分别返回给ks1,ks2,ks3,所以这里的三个参数不太可能是:
    DECL des_3EEEinit(UCHAR *key, int len, DES_KS ks1, DES_KS ks2, DES_KS ks3); 
    而应当是
    DECL des_3EEEinit(UCHAR *key, int len, DES_KS &ks1, DES_KS &ks2, DES_KS &ks3); 
    从而上面的代码应该改为:type
      //unsigned long DES_KS[16][2]; 
      TDES_KS = array [0..16-1, 0..2-1] of LongWord;//DECL des_3EEEinit(UCHAR *key, int len, DES_KS &ks1, DES_KS &ks2, DES_KS &ks3); 
    procedure des_3EEEinit(key: (*PByte*) PAnsiChar; len: Integer; var ks1,ks2,ks3); cdecl; external 'des3.dll' ;
    {或者
    procedure des_3EEEinit(key: (*PByte*) PAnsiChar; len: Integer; var ks1,ks2,ks3:TDES_KS); cdecl; external 'des3.dll' ;

    //DECL des_ecb3EEEencode(UCHAR *in64, UCHAR *out64, DES_KS ks1, DES_KS ks2, DES_KS ks3); 
    procedure des_ecb3EEEencode(in64: (*PByte*) PAnsiChar; out64: (*PByte*) PAnsiChar; const ks1,ks2,ks3); cdecl; external 'des3.dll' ;
    {//或者
    procedure des_ecb3EEEencode(in64: (*PByte*) PAnsiChar; out64: (*PByte*) PAnsiChar; const ks1,ks2,ks3: TDES_KS); cdecl; external 'des3.dll' ;

    //DECL des_ecb3EEEdecode(UCHAR *in64, UCHAR *out64, DES_KS ks1, DES_KS ks2, DES_KS ks3); 
    procedure des_ecb3EEEdecode(in64: (*PByte*) PAnsiChar; out64: (*PByte*) PAnsiChar; const ks1,ks2,ks3); cdecl; external 'des3.dll' ; 
    {//或者
    procedure des_ecb3EEEdecode(in64: (*PByte*) PAnsiChar; out64: (*PByte*) PAnsiChar; const ks1,ks2,ks3: TDES_KS); cdecl; external 'des3.dll' ;
    }
    procedure TForm1.Button1Click(Sender: TObject); 
    var ks1,ks2,ks3:TDES_KS; 
        key:PAnsiChar; 
    begin 
      key:= '123456789012345678901234'; 
      des_3EEEinit(key,224,ks1,ks2,ks3); 
    end; 
      

  11.   

    另外需要注意的是des_3EEEinit的第二个参数是key参数的字节数(如果没有估计错的话,这个可能需要的是24的倍数,不足时在后面用“填充值”补足,关键看DLL内部的实现)
    des_3EEEinit(key,224,ks1,ks2,ks3); 
      

  12.   

    18楼关于c的好几个说的都是错的。参数中“按引用传递( type& )”是c++的语法,连c99也不支持;而那段声明是在extern "C"中,说明那个头文件的本意是可以直接拿给C编译器用的。c的数组参数都会退化为指针(数组名不支持++ +=等运算,但非void*指针可以),像unsigned long [16][2]会退化成unsigned long *[2];另外这个参数本身也是指向一个16*2*sizeof(long)的连续空间的指针,已经完全可以实现你说的功能了。我虽然不懂c++,但至少清楚传参数的&和*是等价的这点,只不过编译器在处理的时候隐藏了细节(和delphi的var/out是一样的),传个unsigned long *[16][2]的话反倒是莫名其妙了。另外还有我前面已经说过的,因为是在WIN32平台上,根据预处理选项DECL被替换为int pascal,而在win32平台上stdcall采用了pascal调用约定,所以没有返回类值是错的,使用cdecl调用约定也是错的
      

  13.   

    1.不仅只是C++,几乎大部分的语言的数组参数传递都会以指针方式进行传递,Delphi也是。对于传出参数,显式声明为指针是合理的。有部分编译器默认的参数为const修饰,从而对于const DES_KS ks这样子的参数将会被检查为不允许修改。当然,这并不是我直接修改声明的原因。只是为了更为方便地转化为Delphi的描述才做的一个修改。对于支持“引用”参数的编译来说,定义为“引用”参数或是“指针”参数并没有太大的区别,只是调用者传递参数上面的代码写法上面的差异。相比之下则引用显得更为直观,至少使用者可以知道内存的分配者是调用者。
      

  14.   

    2.楼主并没有给出DECL的定义,没有必要去猜测,给出一个大致的定义(比如我用cdecl),这个并没有不合理,DECL并不是一个标准的定义。
      

  15.   

    你压根就没搞清楚我说的是什么,c语言的语法根本就不支持&的参数声明,c和c++是不是同一种语言,所以这个.h文件中不可能写成&的形式导出。这不是写法的差别,而是写成那样就不合语法
    在delphi中,不支持用固定数组作参数的语法,必须另声明类型才能传;而动态数组作参数的话,又不止传了一个首地址,还传了一个High()。c/cpp的编译器自动会把数组形式的参数退化成指针的形式([] -> *,这里不是C语言版,我就不多说了),而且也只传了一个首地址而已,两者之间差太多了,你说delphi“也是”就不知道该怎么讲了
      

  16.   

    兼容C编译器的代码并不能够单纯地说就是C语言的代码,对于C++编译器并没有C和C++代码的绝对区别,所以只要使用的是C++的编译器编译的C代码就可以并且应当认为那是C++代码,最终生成的代码都会或多或少存在C++的特性(如果有可能的话)。需要声明的是,由于网络受限,我并没有能够打开楼主提供的链接,我只是根据楼主贴出来的代码以及标题(delphi调用vc写的dll)来回复的。
      

  17.   

    这就问的有意思了,我问你,从哪里看出来的写cdecl呢?
      

  18.   

    windows平台dll导出函数表怎么是有common sense的,另外我倒是更好奇您为什么会认为vc编译出来的一定就是c++编译的呢?
      

  19.   

    这个我只是一个举例(在C++里面默认的就是cdecl)
      

  20.   

    procedure TForm1.Button1Click(Sender: TObject); 
    var ks1,ks2,ks3:kstype; 
        key:pchar; 
    begin 
      key:= '123456789012345678901234';
      GetMem(ks1, 1024); // 分配内存空间 
      GetMem(ks2, 1024);
      GetMem(ks3, 1024); 
     
      des_3EEEinit(key,224,ks1,ks2,ks3); 
      FreeMem(ks1); // 释放内存空间
      FreeMem(ks2);
      FreeMem(ks3);

    end; 楼主,请看红色代码部分,如果好用的话,记得给分噢,谢谢!
      

  21.   

    那为什么不举c#的unsafe呢?
    按照windows的约定,为避免歧义dll都是用c表达的,而且也方便翻译成各种语言。我还真没听过有哪门子正经用c++的dll写个c不认的声明,directx、gdi+都老老实实按c写的您要是认为我不用c++就谈不出结果,那大可以到newsmth.net的C版啊、C++版啊、programming版啊、msdn版之类的相关版面谈谈您的高见,那里的水平比csdn高多了,肯定能谈出结果来。不过那里即使c++用的很好的,也没几个自称懂c++的,可千万别以为他们真没你懂
      

  22.   

    我不是存心要跟谁去抬杠
    DECL des_3EEEinit(UCHAR *key, int len, DES_KS ks1, DES_KS ks2, DES_KS ks3); 
    按照直面的转换为delphi的声明
    function des_3EEEinit(key: PByte; len: Integer; ks1, ks2, ks3: DES_KS): Integer; winapi; 
    对于高版本的Delphi编译器(默认为传值),则等同于
    function des_3EEEinit(key: PByte; len: Integer; const ks1, ks2, ks3: DES_KS): Integer; winapi; 
    这对于使用者来讲,可能会认为ks1,ks2,ks3都为入参,则第一直觉将会是函数不会对这些参数做出修改,从而可能会传入一个const定义,或者原值需要复用的参数,则会存在一定的误导或者不明确性。C++之所以引入“引用”也是出于明确目的。DECL des_3EEEinit(UCHAR *key, int len, DES_KS ks1, DES_KS ks2, DES_KS ks3); 
    DECL des_3EEEinit(UCHAR *key, int len, DES_KS *ks1, DES_KS *ks2, DES_KS *ks3); 
    DECL des_3EEEinit(UCHAR *key, int len, DES_KS &ks1, DES_KS &ks2, DES_KS &ks3); 
    这三种定义对于C/C++使用者是等价的,相比最后的定义更为明确同时也更适合C/C++以外的使用者理解及声明转换。另外,实际上使用VC编译器编译出来的也不再是标准C当中的pascal Calling Convention,而是stdcall(或称WINAPI) Calling Convention。其它的问题就不再扯远了,刚下载了Source看了一下,给出一个Delphi当中相应的定义
    type
      DES_KS = array [0..16-1, 0..2-1] of LongWord;function des_3EEEinit(const key: PAnsiChar;const len: Integer;var ks1, ks2, ks3: DES_KS ): Integer; stdcall {WINAPI}; external 'des3.dll';
    function des_ecb3EEEencode(const in64: PAnsiChar; out64: PAnsiChar; const ks1, ks2, ks3: DES_KS): Integer; stdcall {WINAPI}; external 'des3.dll';
    function des_ecb3EEEdecode(const in64: PAnsiChar; out64: PAnsiChar; const ks1, ks2, ks3: DES_KS): Integer; stdcall {WINAPI}; external 'des3.dll'; 
      

  23.   

    不小心引发了一场争论  
    最大的问题是pchar和pbyte的问题
    用ollydbg查看堆栈指针,逐个比较ecb3EEEencode的参数,终于解决另外用delphi版的des算法也没问题了
    3des的eee算法,加密时,用三个8位的key,依次对数据加密
    但是delhpi版的des算法,key长度不够的话,没有用0填充,我的第一个key只有三位
    搞一个24位的byte数组,其余21位用0填充后解决总结一下这类问题,如果对语言不熟悉,多用调试工具仔细看堆栈,比猜测更重要