[原创][首发]汇编语言实现DES加解密的完整代码
本帖最后由 苏紫方璇 于 2021-10-22 11:31 编辑因为工作需要对大批量DES加密数据还原,在VS2010通过调用内置的DES功能很容易实现,另外调试了网上几个VB6.0的DES源程序,也顺利通过。总感觉DES加解密是通过大量比特位的变换实现的,用汇编语言应该更容易实现,可是网上目前没有发现用汇编语言实现DES的源程序。于是自己尝试着编写汇编代码,今天终于调试成功了,开源共享给大家,希望多提宝贵建议。
整个代码由两个子程序组成,一个KEY生成代码,一个是DES加解密代码。为了提高通用性,把DES的所有转换表数据都放在代码段中,数据读取使用相对寻址,通过堆栈传递参数,所以代码不存在重定位问题,通用性非常好。
使用中有什么不明白的地方可以给我留言。不多说了,源代码奉上:
;================================
;作者:longs75
;时间:2021年10月21日
;公开源码,转载请保持以上信息完整。
;=================================
.386
.model flat, stdcall
option casemap :none
.data
strKey db 13h,34h,57h,79h,9Bh,0BCh,0DFh,0F1h ;64位Key
SubKey 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
.code
START:
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,
mov dh,byte ptr
mov dl,byte ptr
shl edx,16
mov dh,byte ptr
mov dl,byte ptr
mov ah,byte ptr
mov al,byte ptr
shl eax,16
mov ah,byte ptr
mov al,byte ptr
;=====================================================
;PC-1置换
xor esi,esi ;EDI、ESI清零
xor edi,edi ;转换后的结果放在:EDI:ESI
mov ch,1 ;计数器置1
CHG_PC1_1: ;由于没有第32位、64位的移位操作,无须特殊处理。(移动次数为0或寄存器长度的整数倍时,均为移动0次,对标志位无影响)
mov cl,byte ptr
cmp cl,32 ;位数大于32,对EAX操作
ja PC1_A32_1
push edx ;否则对EDX操作
rol edx,cl
pop edx
jmp PC1_EDI
PC1_A32_1:
push eax
rol eax,cl
pop eax
PC1_EDI:
rcl edi,1 ;前28位数据(高位)放在EDI
inc ebx
inc ch
cmp ch,28
jbe CHG_PC1_1
CHG_PC1_2:
mov cl,byte ptr
cmp cl,32 ;位数大于32,对EAX操作
ja PC1_A32_2
push edx ;否则对EDX操作
rol edx,cl
pop edx
jmp PC1_ESI
PC1_A32_2:
push eax
rol eax,cl
pop eax
PC1_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,终值15
FOR_ECX:
cmp ecx,0 ;判断循环轮数,0表示第1轮,依次类推
jzSHL_1
cmp ecx,1
jzSHL_1
cmp ecx,8
jzSHL_1
cmp ecx,15
jzSHL_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,1
SHL_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,终值48
CHG_PC2_1:
mov cl,byte ptr
cmp cl,32 ;位数大于32,对EAX操作
ja PC2_A32_1 ;否则对EDX操作
push edx
rol edx,cl
pop edx
jmp PC2_EDI
PC2_A32_1:
push eax
rol eax,cl
pop eax
PC2_EDI:
rcl edi,1 ;前32位数据(高位)放在EDI
inc ebx
inc ch
cmp ch,32
jbe CHG_PC2_1
CHG_PC2_2:
mov cl,byte ptr
cmp cl,32 ;位数大于32,对EAX操作
ja PC2_A32_2 ;否则对EDX操作
je PC2_E32
push edx
rol edx,cl
pop edx
jmp PC2_ESI
PC2_E32: ;当移动次数是寄存器长度倍数时(32、64……),相当于不移动(次数为0),对标志位无影响
push edx ;解决办法是:拆分成两次移动,两次移动总和为32
rol edx,1 ;例如:先移动1位,再移动31位
dec cl
rol edx,cl
pop edx
jmp PC2_ESI
PC2_A32_2:
push eax
rol eax,cl
pop eax
PC2_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, ;SubKey首地址
mov ,esi ;计算SubKey(n)地址,ESI放在低4字节
mov ,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,
mov dh,byte ptr
mov dl,byte ptr
shl edx,16
mov dh,byte ptr
mov dl,byte ptr
mov ah,byte ptr
mov al,byte ptr
shl eax,16
mov ah,byte ptr
mov al,byte ptr
;=====================================================
;初始IP变换
push edx ;EDX:EAX做为入口参数入栈,利用堆栈做为临时变量
push eax
xor esi,esi ;EDI:ESI清零,保存IP变换后的结果
xor edi,edi
xor eax,eax
mov ecx,32
IP_L32:
mov al,byte ptr
cmp al,32
ja IP_A32L
neg al
add al,32 ;AL=32-AL,将DES算法的位顺序转换成CPU默认的位顺序
bt ,eax
jmp IP_EDI
IP_A32L:
neg al
add al,64 ;AL=64-AL,将DES算法的位顺序转换成CPU默认的位顺序
bt ,eax
IP_EDI:
rcl edi,1
inc ebx
loop IP_L32
mov ecx,32
IP_R32:
mov al,BYTE ptr
cmp al,32
ja IP_A32R
neg al
add al,32
bt ,eax
jmp IP_ESI
IP_A32R:
neg al
add al,64
bt ,eax
IP_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,32
E_32:
mov al,byte ptr
neg al
add al,32
bt ,eax
rcl edi,1
inc ebx
loop E_32
mov ecx,16
E_16:
mov al,byte ptr
neg al
add al,32
bt ,eax
rcl esi,1
inc ebx
loop E_16
shl esi,16
;=====================================================
;与子密钥进行XOR运算
mov ecx, ;取出循环次数
mov eax, ;取出WorkMode地址
cmp BYTE ptr,0 ;0:加密,非0:解密
jz ENCODE
neg ecx
add ecx,15 ;ECX=15-ECX,解密时子密钥顺序相反
ENCODE:
mov eax, ;取出SubKey首地址
push ;SubKey(n)高4字节入栈
push ;SubKey(n)低4字节入栈
XOR_SUBKEY:
xor edi, ;与子密钥进行XOR运算
xor esi, ;结果保存在: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 ;查找S盒数据,追加到EDX低4位
add ebx,64 ;下一个S盒首地址
inc ecx
cmp ecx,8
jb S0_S7
;=====================================================
;P盒置换:
xor esi,esi ;ESI清零,用于保存P盒置换后的结果
mov ecx,32
P_32:
mov al,byte ptr
neg al
add al,32
bt edx,eax
rcl esi,1
inc ebx
loop P_32
;=====================================================
xor esi, ;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,32
IP_1_L32:
mov al,byte ptr
cmp al,32
ja IP_1_A32L
neg al
add al,32 ;AL=32-AL,将DES算法的位顺序转换成CPU默认的位顺序
bt ,eax
jmp IP_1_EDI
IP_1_A32L:
neg al
add al,64 ;AL=64-AL,将DES算法的位顺序转换成CPU默认的位顺序
bt ,eax
IP_1_EDI:
rcl edi,1
inc ebx
loop IP_1_L32
mov ecx,32
IP_1_R32:
mov al,BYTE ptr
cmp al,32
ja IP_1_A32R
neg al
add al,32
bt ,eax
jmp IP_1_ESI
IP_1_A32R:
neg al
add al,64
bt ,eax
IP_1_ESI:
rcl esi,1
inc ebx
loop IP_1_R32
add esp,8
;=====================================================
mov ecx, ;交换高低位,结果存放在DataOut变量中
mov eax,edi ;后期的Intel CPU 有一个MOVBE指令,可以快速实现换位,但AMD的CPU不支持
mov ,al
mov ,ah
shr eax,16
mov ,al
mov ,ah
mov eax,esi
mov ,al
mov ,ah
shr eax,16
mov ,al
mov ,ah
popad
ret 18h
end START
longs75 发表于 2021-10-22 20:50
感谢提供信息,我到openssl的github页面看了下,果然找到了,可是打开看了下,基本看不懂,不明白它是用 ...
为了最大优化都支持是否开启汇编支持的,aes汇编都在这里,大部分是perl脚本,用来生成汇编算法的
https://github.com/openssl/openssl/blob/master/crypto/aes/asm/aes-x86_64.pl
作为兴趣玩一下就好,太投入造轮子就不要了,把时间拿来做其他的 感谢 苏紫方璇 版主加精置顶!
一点感受:通过编程实践才能提高水平。我在开始编写这个程序时,对汇编指令的理解也是一知半解,刚开始感觉难度很大,有些想放弃,随着边学边干,渐入佳境,然后一气呵成。
DES算法大量用到位操作,在编程过程中逐渐熟悉了逻辑移位、算术移位、循环移位、带进位循环移位这几组传统的位操作指令的特点和用法,同时也掌握了BT指令这个比较“新”的指令,甚至现在对BMI指令集这些更高端的位操作指令也产生了浓厚兴趣。KEYPROC 子程序完全依赖寄存器编程,没有使用堆栈变量,大量使用各种移位指令,通过CF标志实现位变换,没有使用BT指令(因为刚开始我还没接触到这个指令……),编程压力比较大,到编写DESPROC子程序的时候,由于使用了BT指令,并且运用堆栈做为临时变量,编程压力就小了很多,如果用64位汇编指令,我估计除了搞懂算法,就没什么编程压力了……
好高大上啊谢谢提供好好学习了 谢谢 提供好好学习了 本帖最后由 舒默哦 于 2021-10-22 17:13 编辑
openssl提供有汇编,2.26G文件,用DES加密大概需要27秒。 舒默哦 发表于 2021-10-22 17:10
openssl提供有汇编,2.26G文件,用DES加密大概需要27秒。
感谢提供信息,我到openssl的github页面看了下,果然找到了,可是打开看了下,基本看不懂,不明白它是用的什么格式的语法和编译器,甚至连几个置换表都没找到,惭愧,看来我还得加强学习,知识有些陈旧了{:1_893:} 不得不说,膜拜汇编大佬{:1_921:} max2012 发表于 2021-10-22 22:54
为了最大优化都支持是否开启汇编支持的,aes汇编都在这里,大部分是perl脚本,用来生成汇编算法的
https ...
明白了,本人非计算机专业,也就是玩玩而已,比专业人士差太远了;www 看到搞汇编的人,就是牛。感谢楼主无私共享。这个转化应该比其他高级语言效率高 。