汇编语言实现DES加解密的完整代码

admin 2023年2月12日13:54:32评论15 views字数 9640阅读32分8秒阅读模式
因为工作需要对大批量DES加密数据还原,在VS2010通过调用内置的DES功能很容易实现,另外调试了网上几个VB6.0的DES源程序,也顺利通过。总感觉DES加解密是通过大量比特位的变换实现的,用汇编语言应该更容易实现,可是网上目前没有发现用汇编语言实现DES的源程序。于是自己尝试着编写汇编代码,今天终于调试成功了,开源共享给大家,希望多提宝贵建议。
整个代码由两个子程序组成,一个KEY生成代码,一个是DES加解密代码。为了提高通用性,把DES的所有转换表数据都放在代码段中,数据读取使用相对寻址,通过堆栈传递参数,所以代码不存在重定位问题,通用性非常好。
使用中有什么不明白的地方可以给我留言。不多说了,源代码奉上:
;公开源码,转载请保持以上信息完整。;================================= .386.model flat, stdcalloption casemap :none .datastrKey db 13h,34h,57h,79h,9Bh,0BCh,0DFh,0F1h      ;64位KeySubKey dq 16 dup(0)                               ;16个48位子Key,每个子Key占用8字节空间lResult dd 0                                      ;保留(用于VB6.0内嵌汇编编程);DataIn db 01h,23h,45h,67h,89h,0ABh,0CDh,0EFh      ;64位输入数据(明文);DataIn db 85h,0E8h,13h,54h,0Fh,0Ah,0B4h,05h      ;64位输入数据(密文)DataOut db 8 dup(0)                               ;64位输出数据WorkMode db 0                                     ;工作模式 0:加密,非0:解密;WorkMode db 8 .codeSTART:        lea eax,lResult                                ;保留        push eax        lea eax,SubKey                                 ;子密钥数组首地址        push eax        lea eax,strKey                                 ;密钥地址        push eax        push 0                                         ;保留        call KEYPROC                 lea eax,lResult                                ;保留        push eax        lea eax,DataIn                                 ;64位输入数据地址        push eax        lea eax,DataOut                                ;64位输出数据地址        push eax        lea eax,SubKey                                 ;子密钥数组首地址        push eax        lea eax,WorkMode                               ;工作模式变量地址        push eax        push 0                                         ;保留        call DESPROC         ;说明:上述调用步骤是VB6.0调用类函数时的标准方法,本人用于VB6.0内嵌汇编编程,保留的参数忽略即可。                 ret;************************************;************************************;**                                **;**      计算16组子密钥代码        **;**                                **;************************************;************************************KEYPROC:        mov ebp,esp        pushad        call NEXT1                 ;  PC-1置换表:        db 57,49,41,33,25,17,09,01        db 58,50,42,34,26,18,10,02        db 59,51,43,35,27,19,11,03        db 60,52,44,36,63,55,47,39        db 31,23,15,07,62,54,46,38        db 30,22,14,06,61,53,45,37        db 29,21,13,05,28,20,12,04                 ;  PC-2置换表:        db 14,17,11,24,01,05,03,28        db 15,06,21,10,23,19,12,04        db 26,08,16,07,27,20,13,02        db 41,52,31,37,47,55,30,40        db 51,45,33,48,44,49,39,56        db 34,53,46,42,50,36,29,32                 db 16 dup(90h) NEXT1:                pop ebx                  ;EBX的值为PC-1的首地址                 ;取出64位strKey的首地址,交换高低位后放入EDX:EAX        mov ecx,[ebp+8]        mov dh,byte ptr[ecx]        mov dl,byte ptr[ecx+1]        shl edx,16        mov dh,byte ptr[ecx+2]        mov dl,byte ptr[ecx+3]        mov ah,byte ptr[ecx+4]        mov al,byte ptr[ecx+5]        shl eax,16        mov ah,byte ptr[ecx+6]        mov al,byte ptr[ecx+7]         ;=====================================================                 ;PC-1置换        xor esi,esi              ;EDI、ESI清零        xor edi,edi              ;转换后的结果放在:EDI:ESI        mov ch,1                 ;计数器置1CHG_PC1_1:                  ;由于没有第32位、64位的移位操作,无须特殊处理。(移动次数为0或寄存器长度的整数倍时,均为移动0次,对标志位无影响)        mov cl,byte ptr[ebx]        cmp cl,32                ;位数大于32,对EAX操作        ja PC1_A32_1        push edx                 ;否则对EDX操作        rol edx,cl        pop edx        jmp PC1_EDIPC1_A32_1:        push eax        rol eax,cl        pop eaxPC1_EDI:        rcl edi,1                ;前28位数据(高位)放在EDI        inc ebx        inc ch        cmp ch,28        jbe CHG_PC1_1         CHG_PC1_2:        mov cl,byte ptr[ebx]        cmp cl,32                ;位数大于32,对EAX操作        ja PC1_A32_2        push edx                 ;否则对EDX操作        rol edx,cl        pop edx        jmp PC1_ESIPC1_A32_2:        push eax        rol eax,cl        pop eaxPC1_ESI:        rcl esi,1                ;后28位数据(低位)放在ESI        inc ebx        inc ch        cmp ch,56        jbe CHG_PC1_2                mov edx,edi              ;转换后结果重新放入EDX:EAX,EBX的值为PC-2置换表首地址        mov eax,esi                 ;=====================================================                 ;16轮循环计算SubKey(1)-SubKey(16)        xor ecx,ecx              ;ECX计数器初值0,终值15FOR_ECX:        cmp ecx,0                ;判断循环轮数,0表示第1轮,依次类推        jz  SHL_1        cmp ecx,1        jz  SHL_1        cmp ecx,8        jz  SHL_1        cmp ecx,15        jz  SHL_1            ;第1、2、9、16轮左移1位,其它左移2位        shl edx,4            ;循环左移1位(除第1、2、9、16轮之外)           sar edx,4        rol edx,1        shl eax,4        sar eax,4        rol eax,1SHL_1:        shl edx,4            ;循环左移1位(所有16轮)        sar edx,4        rol edx,1        shl eax,4        sar eax,4        rol eax,1            ;完成Cn、Dn循环左移        push eax             ;保护高、低各28位的EDX:EAX,下一轮继续移位        push edx             ;保护EBX,每轮都要进行PC-2置换        push ebx        push ecx        shl edx,4            ;合并EDX:EAX:高28位:低28位 ——>高32位:低24位(EAX高24位,EAX低8位AL置0)        shl eax,4            ;EAX先左移4位,低4位补0        rol eax,4            ;再循环左移4位,将28位有效数据的高4位移到低4位        add dl,al            ;有效数据追加到EDX低4位        xor al,al            ;EAX低8位清零                  xor esi,esi        xor edi,edi        mov ch,1              ;PC-2置换,ch计数器初值1,终值48CHG_PC2_1:        mov cl,byte ptr[ebx]        cmp cl,32             ;位数大于32,对EAX操作        ja PC2_A32_1          ;否则对EDX操作        push edx        rol edx,cl        pop edx        jmp PC2_EDIPC2_A32_1:        push eax        rol eax,cl        pop eaxPC2_EDI:        rcl edi,1             ;前32位数据(高位)放在EDI        inc ebx        inc ch        cmp ch,32        jbe CHG_PC2_1 CHG_PC2_2:        mov cl,byte ptr[ebx]        cmp cl,32             ;位数大于32,对EAX操作        ja PC2_A32_2          ;否则对EDX操作        je PC2_E32        push edx        rol edx,cl        pop edx        jmp PC2_ESIPC2_E32:                        ;当移动次数是寄存器长度倍数时(32、64……),相当于不移动(次数为0),对标志位无影响        push edx              ;解决办法是:拆分成两次移动,两次移动总和为32        rol edx,1             ;例如:先移动1位,再移动31位        dec cl        rol edx,cl        pop edx        jmp PC2_ESIPC2_A32_2:        push eax        rol eax,cl        pop eaxPC2_ESI:        rcl esi,1            ;后16位数据(低位)放在ESI        inc ebx              ;SubKey放在EDI:ESI中,格式为:高32位:低16位(ESI高16位为有效数据,低16位置0)        inc ch        cmp ch,48        jbe CHG_PC2_2        shl esi,16         ;=====================================================         pop ecx               ;恢复16轮计数器        mov ebx,[ebp+12]      ;SubKey首地址        mov [ebx+8*ecx],esi   ;计算SubKey(n)地址,ESI放在低4字节        mov [ebx+8*ecx+4],edi ;EDI放在高4字节        pop ebx               ;恢复PC-2表首地址        pop edx               ;恢复Cn、Dn到EDX:EAX,进入下一轮移位        pop eax        inc ecx               ;计数器加1        cmp ecx,16            ;从0到15,循环16次        jnz FOR_ECX                 popad        ret 10h;************************************;************************************;**                                **;**       DES加密/解密代码         **;**                                **;************************************;************************************DESPROC:        mov ebp,esp        pushad        call NEXT2                 ;初始变换置换表 IP:        db 58,50,42,34,26,18,10,02        db 60,52,44,36,28,20,12,04        db 62,54,46,38,30,22,14,06        db 64,56,48,40,32,24,16,08        db 57,49,41,33,25,17,09,01        db 59,51,43,35,27,19,11,03        db 61,53,45,37,29,21,13,05        db 63,55,47,39,31,23,15,07                  ;扩展置换表 E:        db 32,01,02,03,04,05        db 04,05,06,07,08,09        db 08,09,10,11,12,13        db 12,13,14,15,16,17        db 16,17,18,19,20,21        db 20,21,22,23,24,25        db 24,25,26,27,28,29        db 28,29,30,31,32,01                 ;S盒1:        db 14,4,13,1,2,15,11,8,3,10,6,12,5,9,0,7        db 0,15,7,4,14,2,13,1,10,6,12,11,9,5,3,8        db 4,1,14,8,13,6,2,11,15,12,9,7,3,10,5,0        db 15,12,8,2,4,9,1,7,5,11,3,14,10,0,6,13                 ;S盒2:        db 15,1,8,14,6,11,3,4,9,7,2,13,12,0,5,10        db 3,13,4,7,15,2,8,14,12,0,1,10,6,9,11,5        db 0,14,7,11,10,4,13,1,5,8,12,6,9,3,2,15        db 13,8,10,1,3,15,4,2,11,6,7,12,0,5,14,9                 ;S盒3:        db 10,0,9,14,6,3,15,5,1,13,12,7,11,4,2,8        db 13,7,0,9,3,4,6,10,2,8,5,14,12,11,15,1        db 13,6,4,9,8,15,3,0,11,1,2,12,5,10,14,7        db 1,10,13,0,6,9,8,7,4,15,14,3,11,5,2,12                 ;S盒4:        db 7,13,14,3,0,6,9,10,1,2,8,5,11,12,4,15        db 13,8,11,5,6,15,0,3,4,7,2,12,1,10,14,9        db 10,6,9,0,12,11,7,13,15,1,3,14,5,2,8,4        db 3,15,0,6,10,1,13,8,9,4,5,11,12,7,2,14                         ;S盒5:        db 2,12,4,1,7,10,11,6,8,5,3,15,13,0,14,9        db 14,11,2,12,4,7,13,1,5,0,15,10,3,9,8,6        db 4,2,1,11,10,13,7,8,15,9,12,5,6,3,0,14        db 11,8,12,7,1,14,2,13,6,15,0,9,10,4,5,3                         ;S盒6:        db 12,1,10,15,9,2,6,8,0,13,3,4,14,7,5,11        db 10,15,4,2,7,12,9,5,6,1,13,14,0,11,3,8        db 9,14,15,5,2,8,12,3,7,0,4,10,1,13,11,6        db 4,3,2,12,9,5,15,10,11,14,1,7,6,0,8,13                         ;S盒7:        db 4,11,2,14,15,0,8,13,3,12,9,7,5,10,6,1        db 13,0,11,7,4,9,1,10,14,3,5,12,2,15,8,6        db 1,4,11,13,12,3,7,14,10,15,6,8,0,5,9,2        db 6,11,13,8,1,4,10,7,9,5,0,15,14,2,3,12                         ;S盒8:        db 13,2,8,4,6,15,11,1,10,9,3,14,5,0,12,7        db 1,15,13,8,10,3,7,4,12,5,6,11,0,14,9,2        db 7,11,4,1,9,12,14,2,0,6,10,13,15,3,5,8        db 2,1,14,7,4,10,8,13,15,12,9,0,3,5,6,11                         ;P盒置换表:        db 16,07,20,21,29,12,28,17,01,15,23,26,05,18,31,10        db 02,08,24,14,32,27,03,09,19,13,30,06,22,11,04,25                 ;逆置换表IP_1:        db 40,08,48,16,56,24,64,32,39,07,47,15,55,23,63,31        db 38,06,46,14,54,22,62,30,37,05,45,13,53,21,61,29        db 36,04,44,12,52,20,60,28,35,03,43,11,51,19,59,27        db 34,02,42,10,50,18,58,26,33,01,41,09,49,17,57,25                         db 16 dup(90h)         NEXT2:        pop ebx                  ;EBX的值为初始变换IP的首地址                 ;取出64位DataIn数据的首地址,交换高低位后放入EDX:EAX        mov ecx,[ebp+20]        mov dh,byte ptr[ecx]        mov dl,byte ptr[ecx+1]        shl edx,16        mov dh,byte ptr[ecx+2]        mov dl,byte ptr[ecx+3]        mov ah,byte ptr[ecx+4]        mov al,byte ptr[ecx+5]        shl eax,16        mov ah,byte ptr[ecx+6]        mov al,byte ptr[ecx+7]                 ;=====================================================                 ;初始IP变换        push edx               ;EDX:EAX做为入口参数入栈,利用堆栈做为临时变量        push eax        xor esi,esi            ;EDI:ESI清零,保存IP变换后的结果        xor edi,edi        xor eax,eax        mov ecx,32IP_L32:        mov al,byte ptr[ebx]        cmp al,32        ja IP_A32L        neg al        add al,32               ;AL=32-AL,将DES算法的位顺序转换成CPU默认的位顺序        bt [esp+4],eax        jmp IP_EDIIP_A32L:        neg al        add al,64               ;AL=64-AL,将DES算法的位顺序转换成CPU默认的位顺序        bt [esp],eaxIP_EDI:        rcl edi,1        inc ebx        loop IP_L32                         mov ecx,32IP_R32:        mov al,BYTE ptr[ebx]        cmp al,32        ja IP_A32R        neg al        add al,32        bt [esp+4],eax        jmp IP_ESIIP_A32R:        neg al        add al,64        bt [esp],eaxIP_ESI:        rcl esi,1        inc ebx        loop IP_R32                 add esp,8                 ;=====================================================                 ;开始16轮迭代运算        ;入口参数Ln、Rn为EDI:ESI        xor ecx,ecx             ;循环次数初值0 Func_16:                ;扩展置换E:        push ebx             ;保护扩展置换E首地址        push ecx        push edi               ;Ln入栈        push esi               ;Rn入栈        xor edi,edi            ;EDI、ESI清零,用于保存E置换后的48位值        xor esi,esi            ;格式为:EDI:ESI(高32位:高16位,ESI低16位置0)        xor eax,eax                 mov ecx,32E_32:        mov al,byte ptr[ebx]        neg al        add al,32        bt [esp],eax        rcl edi,1        inc ebx        loop E_32                 mov ecx,16E_16:        mov al,byte ptr[ebx]        neg al        add al,32        bt [esp],eax        rcl esi,1        inc ebx        loop E_16        shl esi,16                 ;=====================================================                 ;与子密钥进行XOR运算        mov ecx,[esp+8]       ;取出循环次数        mov eax,[ebp+8]       ;取出WorkMode地址        cmp BYTE ptr[eax],0           ;0:加密,非0:解密        jz ENCODE        neg ecx        add ecx,15            ;ECX=15-ECX,解密时子密钥顺序相反ENCODE:                mov eax,[ebp+12]      ;取出SubKey首地址        push [eax+ecx*8+4]    ;SubKey(n)高4字节入栈        push [eax+ecx*8]      ;SubKey(n)低4字节入栈XOR_SUBKEY:        xor edi,[esp+4]       ;与子密钥进行XOR运算        xor esi,[esp]         ;结果保存在:EDI:ESI(高32位:高16位,ESI低16位置0)        add esp,8                 mov eax,edi        shl eax,24        shr esi,8        add esi,eax          ;结果转换为:EDI:ESI(高24位:高24位,EDI、ESI低8位无意义)                          ;=====================================================                 ;S盒置换:        xor edx,edx          ;EDX清零,用于保存S盒转换后的结果        mov ecx,0            ;S盒计数S0_S7:        shl edx,4            ;EDX左移4位,准备追加下一组数据        cmp ecx,4            ;        jNE S_N4        mov edi,esi          ;转换后4组数据S_N4:        rol edi,6            ;高6位循环左移至低6位        mov eax,edi          ;保存在AL低6位        mov ah,al            ;再保存一份到AH        ror ah,1        sar ah,4        rol ah,1        and ah,3             ;计算AH,AH=S盒的行数        shr al,1        and al,0fh           ;计算AL,AL=S盒的列数        shl ah,4             ;AH=AH*16        add al,ah            ;AL=AH+AL        and eax,0FFh         ;EAX高24位清零        add dl,BYTE ptr[ebx+eax]    ;查找S盒数据,追加到EDX低4位        add ebx,64           ;下一个S盒首地址        inc ecx        cmp ecx,8        jb S0_S7                 ;=====================================================                 ;P盒置换:        xor esi,esi          ;ESI清零,用于保存P盒置换后的结果        mov ecx,32P_32:        mov al,byte ptr[ebx]        neg al        add al,32        bt edx,eax        rcl esi,1        inc ebx        loop P_32                         ;=====================================================                 xor esi,[esp+4]       ;P盒结果与L(n-1)异或,得到ESI=Rn        pop edi               ;Ln=R(n-1),保存到EDI=Ln        add esp,4             ;恢复堆栈        pop ecx               ;恢复16轮迭代计数器        pop ebx               ;恢复扩展置换E首地址        inc ecx        cmp ecx,16        jb Func_16        xchg edi,esi          ;交换L16和R16        add ebx,592           ;EBX指向逆置换表IP_1首地址                 ;=====================================================                 ;逆置换IP_1:        push edi               ;EDI:ESI做为入口参数入栈,利用堆栈做为临时变量        push esi        xor esi,esi            ;EDI:ESI清零,保存IP_1变换后的结果        xor edi,edi        xor eax,eax            ;实现代码与初始置换IP完全相同。        mov ecx,32IP_1_L32:        mov al,byte ptr[ebx]        cmp al,32        ja IP_1_A32L        neg al        add al,32               ;AL=32-AL,将DES算法的位顺序转换成CPU默认的位顺序        bt [esp+4],eax        jmp IP_1_EDIIP_1_A32L:        neg al        add al,64               ;AL=64-AL,将DES算法的位顺序转换成CPU默认的位顺序        bt [esp],eaxIP_1_EDI:        rcl edi,1        inc ebx        loop IP_1_L32                         mov ecx,32IP_1_R32:        mov al,BYTE ptr[ebx]        cmp al,32        ja IP_1_A32R        neg al        add al,32        bt [esp+4],eax        jmp IP_1_ESIIP_1_A32R:        neg al        add al,64        bt [esp],eaxIP_1_ESI:        rcl esi,1        inc ebx        loop IP_1_R32                 add esp,8         ;=====================================================        mov ecx,[ebp+16]        ;交换高低位,结果存放在DataOut变量中        mov eax,edi             ;后期的Intel CPU 有一个MOVBE指令,可以快速实现换位,但AMD的CPU不支持        mov [ecx+3],al        mov [ecx+2],ah        shr eax,16        mov [ecx+1],al        mov [ecx],ah        mov eax,esi        mov [ecx+7],al        mov [ecx+6],ah        shr eax,16        mov [ecx+5],al        mov [ecx+4],ah         popad        ret 18h                 end START

作者:我是太阳男神
链接:https://juejin.cn/post/7028580053520908318
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

原文始发于微信公众号(汇编语言):汇编语言实现DES加解密的完整代码

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年2月12日13:54:32
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   汇编语言实现DES加解密的完整代码https://cn-sec.com/archives/1549404.html

发表评论

匿名网友 填写信息