摘要: 本文以MCS - 51 单片机为例介绍一种对片外E2PROM 里的程序进行软件加密和硬件解密的方法。这种方法不增加用户应用程序开销。

 由于固化在片外EPROM 里的单片机程序容易复制,所以,如不在技术上采取保护措施,则程序中所采用的处理方法易被他人分析仿制。对单片机程序进行加密是一种有效的保护措施,也是一项实用的技术。虽然本身带有EPROM 的单片机可做到程序保密,但由于价格和存储容量方面的原因,用户仍常常采用外接EPROM 的单片机来开发产品。

本文以MCS - 51 单片机为例介绍一种对片外E2PROM 里的程序进行软件加密和硬件解密的方法。这种方法不增加用户应用程序开销。

1  基本原理

我们知道,异或运算有这样的特点: A Ý B Ý B =A ,亦即当用变量B 对变量A 作偶数次异或运算后,其结果恢复为变量A。例如A = 32H , B = 5EH ,则AÝ B 的结果为6CH ,该结果再与变量B 作异或运算,即6CH Ý 5EH 就得到变量A 的值32H。因此,我们可以利用这一特点给单片机程序加密和解密。

51 系列单片机在对外部程序存储器ROM 和外部数据存储器RAM 操作时采用两套不同的指令,在对RAM 操作时用MOVX指令,并产生相应的读(RD) 和写(WR) 信号,而当对外部ROM 进行读操作时不用RD信号,而是有一条专给外部ROM 使用的“读”数控制信号(PSEN) 线。亦即外部RAM 和ROM 的控制信号是严格分开的。这就为利用异或运算给外部ROM里的程序进行加密后固化、解密后执行提供了条件。

这种方法的思路是:首先对欲固化到外部ROM里的目的代码(原代码) 进行第一次异或运算(加密) ,再把加密后的代码固化到ROM 里,程序运行时由硬件对从ROM 读出的加密代码进行第二次异或运算(解密) 变为原代码后送到数据总线。这样,外部ROM

里固化的是加密代码,即便该代码被复制也反汇编不出原程序。另外该程序的执行还需相应的解密电路支持。

图1 是可以在实际中应用的单片机解密电路。当CPU 对片外EPROM(U04) 进行“读”操作时,控制信号PSEN为低电平,这时U04 送出八位加密代码(RD0~RD7) 并和“密钥”经由U05 、U06 组成的异或运算电路作第二次异或运算(解密) 得到原代码,该代码经三

态缓冲器(U07) 由PSEN信号控制送入数据总线。由于电路中已将单片机的EA脚接地,故片外EPROM 的最低地址为0 。另外,与RD0~RD7 一起参与异或运算的另一个数据(“密钥”) 取自当前待解密代码在外部EPROM所在存储单元的低八位地址,并从高位到低位按A0 A2 A4 A6 A1 A3 A5 A7 的顺序组合成新的数据。例如,原地址分别为35H 和36H ,组合后的地址则分别为E2H 和6AH。采用这样的方法确定“密钥”,一是可使一页中的代码中“密钥”不重复,二是由于同页中的代码字节的“密钥”都不同,故很难找到加密规律,可增加破译难度。

2  操作过程

现以SICE 通用单片机仿真器为例说明制作加密程序并固化到片外EPROM 里的操作过程。设程序一是一个待固化到片外EPROM 里执行的用户应用程序。为简便起见,它对外部RAM 的前256 个单元赋于相应的低地址后转入死循环。因为仿真器的出借RAM 为从8000H 开始的24K空间,故应根据程序大小用伪指令把最低地址定位在8000H~DFFFH的24K空间里(如程序一中的ORG 8000H) ,否则,无法直接对该程序的目的码进行第一次异或运算。

程序二是对程序一的目的代码(存放于仿真RAM的8000H~804AH 中共4BH 个字节) 进行第一次异或加密运算的。要加密的总代码字节数由程序一经汇编后得知。该程序中“密钥”的计算应与硬件电路中送到解密电路的低八位地址线的连接关系相一致。

程序一:MAIN. ASM

ORG 8000H

SJMP MAIN

ORG 8003H

RETI

ORG 800BH

RETI

ORG 8013H

RETI

ORG 801BH

RETI

ORG 8023H

RETI

ORG 8030H

MAIN : CLR EA

CLR RS0

CLR RS1

MOV A , # 0

MOV DPTR , # 0

MOV B , # 0

ACALL SUBR

LOOP : NOP

SJMP LOOP

SUBR : MOVX @DPTR ,A

INC A

INC DPTR

DJNZ B ,SUBR

NOP

RET

END

程序二:XORM. ASM

XORM: MOV R0 , # 4BH ;置欲加密代码字节数

MOV DPTR , # 8000H ;置程序一首地址

LOP1 : MOVX A , @DPTR

PUSH ACC

MOV A ,DPL ;取代码单元的低地址

MOV B ,A

MOV C ,B. 0 ;组合新数据开始加密

MOV ACC. 7 ,C

MOV C ,B. 2

MOV ACC. 6 ,C

MOV C ,B. 4

MOV ACC. 5 ,C

MOV C ,B. 6

MOV ACC. 4 ,C

MOV C ,B. 1

MOV ACC. 3 ,C

MOV C ,B. 3

MOV ACC. 2 ,C

MOV C ,B. 5

MOV ACC. 1 ,C

MOV C ,B. 7

MOV ACC. 0 ,C

POP B

XRL A ,B ;“异或”产生加密代码

MOVX @DPTR ,A ;加密代码存入原单元

INC DPTR

DJNZ R0 ,LOP1

NOP

STOP : NOP

  首先把程序一调入仿真器汇编,目的是得到总的代码字节数。即键入如下内容(带下划线的为键入内容,否则为显示内容) 。

> ASM51 |

FD ASM251 V3. 0

Copyright 1989 Microcomputer Lab. Fudan University

No ERROR

Display List ? ( Y/ N) N |

Next adr :804B   ;记下程序一的末地址为804BH ,由此可知总代码字节数为4BH。再把程序二添加到程序一的末尾(RET 指令后,END 伪指令前) ,调入仿真器后再汇编。即:

> ASM51 |

FD ASM251 V3. 0

Copyright 1989 Microcomputer Lab. Fudan University

No ERROR

Display List ? ( Y/ N) N |

Next adr : 8081

> EXIT |   ;退到监控状态

3 MAP 3 | ;仿真RAM 出借(8000H~DFFFH)

3 DX 8000 | ;显示未加密代码(原代码)

8000 : 80 2E 5B 32 CD 90 07 98 A4 C0 5C 32 C9 94 03 9C

8010 : 80 E4 78 32 ED B0 27 B8 84 E5 6F 32 E9 B7 29 B8

8020 : 40 22 4F 32 72 4F 18 8F 52 CF 83 C3 12 92 F4 83

8030 : C2 AF C2 D3 C2 D4 74 00 90 00 00 75 F0 00 11 43

8040 : 00 80 FD F0 04 A3 D5 F0 FA 00 22 78 4B 90 80 00

8050 : E0 C0 E0 E5 82 F5 F0 A2 F0 92 E7 A2 F2 92 E6 A2

8060 : F4 92 E5 A2 F6 92 E4 A2 F1 92 E3 A2 F3 92 E2 A2

8070 : F5 92 E1 A2 F7 92 E0 D0 F0 65 F0 F0 A3 D8 D1 00

8080 : 00 00 00 00 00 A0 41 AC 44 50 48 8D 43 4A 4E 45

  这里应该注意的是如果在程序一中使用了长转移(LJMP) 或长调用(LCALL) 指令,就应列表显示或打印汇编结果,查找这些指令涉及的标号地址的高八位,并把高八位地址减去80H ,使其与外部EPROM 的地址相符。

3 GO XORM ,STOP |   ;执行程序二,对程序一的目的码进行异或加密运算

3 DX 8000 |       ;显示加密的代码,804BH以后的代码不变

8000 : 80 AE 53 BA 8D 50 4F 50 A0 44 50 BE 8D 50 4F 50

8010 : A0 44 50 9A 8D 50 4F 50 A0 41 43 9E 8D 53 45 54

8020 : 42 A0 45 B8 30 D8 53 45 54 49 8D 4D 54 54 BA4D

8030 : E0 0D E8 79 A0 36 1E EA B6 A6 2E DB 96 E6 7FAD

8040 : 10 10 E5 68 54 73 8D 28 EE 94 3E 78 4B 90 80 00

8050 : 0E C0 E0 E5 82 F5 F0 A2 F0 92 E7 A2 F2 92 E6 A2

8060 : F4 92 E5 A2 F6 92 E4 A2 F1 92 E3 A2 F3 92 E2 A2

8070 : F5 92 E1 A2 F7 92 E0 D0 F0 65 F0 F0 A3 D8 D1 00

8080 : 00 00 00 00 00 A0 41 AC 44 50 48 8D 43 4A 4E 45

3 MECK 0 ,3FFF |    ;检查待固化ROM

 OK

3 MEP 8000 ,804B ,0 ,5 |  ;将仿真RAM 中8000H~804BH 的加密代码

 OK          固化到外部ROM 的0 地址开始的单元里

3 MAP 0 |  ; 使用片外ROM ,取消仿真RAM 出借

3 EX 0 |   ; 执行片外ROM 里的程序

3 DX 0 |   ;显示外部RAM 从0 地址开始的单元内容可见程序执行无误(显示略)对于大的用户应用程序,其操作过程仍如上述,但需改变程序二的加密字节数,并注意不要把程序二的代码固化到EPROM 里,否则,加密方法会暴露。

3  讨论

由于单片机程序是固化在EPROM 里的,所以不能象个人计算机那样利用类似磁盘防复制等这一类的方法对单片机程序防复制(带保密位的单片机除外) ,而只能在程序本身和相应的硬件上做文章。

本文虽然以MCS - 51 单片机为例介绍了一种用异或运算对片外EPROM里的单片机程序进行软件加密和硬件解密的方法,但本方法也适用于其它外接E2PROM 的单片机,此法一直应用在笔者于1993 年研制成功并生产了20 余套的一种分布式数控测井系统中。

使用上面介绍的方法,如果解密电路做得隐蔽,使非设计者不知道加密方法,则要破译片外EPROM 里的程序具有一定的难度。实际使用中还可采用更为复杂的方法产生“密钥”, “密钥”周期还可进一步加长;在硬件上也应做得隐蔽,解密电路亦可用编程器件实现,以进一步增加破译难度。

Blowfish的单片机加密算法_Blowfish的单片机加密算法