cyberfan's blog

正其谊不谋其利,明其道不计其功

  IT博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  15 随笔 :: 489 文章 :: 44 评论 :: 0 Trackbacks
大家知道,为防止非授权人随意运行软件,可以在该软件中设置密码而达到保护软件不被随意运行的目的。如果直接在软件中设置密码,至少存在两点不足:1、密码容易被PCTOOLS之类的工具软件窥视到;2、给普通用户修改密码带来困难。为此,笔者用VB5.0制作口令登录ACTIVEX控件 PASSWORD.OCX,该控件将口令加密后以文件的形式保存,工具软件无法看到密码,而用户修改口令却很方便。笔者认为虽然自编的口令登录控件在加密算法方面比较简单,但因其不象专业加密软件那样广泛应用,不至于引起众多的解密者挖空心思对其解密,反而更安全。当你用兼容ACTIVEX控件的语言编写应用软件时,只需将PASSWORD.OCX控件加入你的软件之中,就可使应用软件具有口令登录的功能。
该控件将口令加密后以文件的形式储存在WINDOWS目录下。加密方法为:产生随机数与每个口令字符的ASCII码异或,再乘以该随机数后储存.并将随机数和口令长度加密后保存。该控件的具体制作过程如下:
1、设计控件外观。运行VB,选择新建ACTIVEX控件,制作如图1所示的登录窗体,把工程名称改为PASSWORD。



2、设置控件属性、方法。在VB菜单的外接程序里找到ACTIVEX控件向导,按照向导提示逐步完成。具体过程为:在选定界面成员窗体步骤中选中TIMER事件,在创建自定义界面成员步骤中定义OPENPASWD方法及GETLOGONINFO属性(获取登录成功与否的信息)、GETCOUNTFT属性(获取输入口令次数的信息)和PRESS事件。在设置映射步骤中将TIMER事件映射到控件TIMER1,成员TIMER之中。在设置属性步骤中,将GETCOUNTFT及GETLOGONINFO属性数据类型设置为BOOLEAN,缺省值为0 。至此,ACTIVEX控件向导设置完成。
3、在控件中添加模块MODULE1,并在代码中加入如下申明:
DECLARE FUNCTION GETWINDOWSDIRECTORY LIB "KERNEL32" ALIAS "GETWINDOWSDIRECTORYA" _
(BYVAL LPBUFFER AS STRING, BYVAL NSIZE AS LONG) AS LONG '获取WINDOWS目录
4、编写控件代码,完成口令登录、口令修改功能,其代码如程序1所示。
5、编译PASSWORD.OCX控件。
口令登录控件编译完成之后,可以把它加入工具箱中,供应用程序使用。当我们把应用软件提供给用户时,可以通过安装程序把初始口令装在WINDOWS目录下,安装程序的创建可参考有关书籍。
为了演示该控件,先将初始口令为123的口令文件TST.DAT拷贝到WINDOWS目录下,在VB中建立标准的EXE工程,将PASSWORD.OCX 控件添加到工具箱中,制作如图2所示的窗体,编写如程序2所示代码,编译后运行,输入123便进入登录成功的FORM2窗体中,如果输入三次口令均不对则程序终止。在实际应用中FORM2窗体就应该是我们应用软件在口令登录成功后下一步需要作的内容。



本控件程序在WINDOWS ME、WINDOWS98,VB5.0环境下,调试运行通过。
TST.DAT的内容为:"DON'T MODIFY THESE DATA",191165,438555,126258860,126292595,126281350,3733101,3699366, 3665631,3631896,3598161,3564426,3530691,3496956,

程序1 (口令控件代码)
DIM PSW AS STRING
DIM PASOK AS BOOLEAN
DIM PASNEW AS STRING
DIM PASFIRST AS STRING
DIM PASNUM AS BOOLEAN
DIM LENG AS LONG
DIM PASOLD AS STRING
DIM FLAG AS STRING
DIM FIRST AS INTEGER
DIM LP AS LONG
DIM LPP AS LONG
DIM GETINFO AS BOOLEAN
DIM GETCOUNT AS BOOLEAN
DIM WINDIR AS STRING
DIM WINDIRLEN AS LONG
DIM WINDIRS AS STRING
PUBLIC EVENT PRESS()
'EVENT DECLARATIONS:
EVENT TIMER() 'MAPPINGINFO=TIMER1,TIMER1,-1,TIMER
PRIVATE SUB COMMAND1_CLICK() '如果口令正确就登录
STATIC LOOPNUM AS INTEGER
LOOPNUM = LOOPNUM + 1
IF LOOPNUM > 2 THEN GETCOUNT = FALSE '判断输入口令次数是否超过3次
PSW = "NO"
PASOLD = TEXT1.TEXT

CALL OPENPASWD

IF LENG <> LEN(TEXT1.TEXT) THEN PSW = "NO" '判断输入口令是否与原口令长度相等
IF STRCOMP(PSW, "NO") = 0 THEN
LABEL2.CAPTION = "口令错,请重新输入!"
TEXT1.TEXT = ""
TEXT1.SETFOCUS
ELSE:
GETINFO = TRUE '口令正确

END IF
RAISEEVENT PRESS
END SUB
PUBLIC SUB OPENPASWD() '打开口令文件
T = 0
ON ERROR RESUME NEXT ' 将错误处理的方式改为"继续下一行"。
OPEN WINDIRS & "\TST.DAT" FOR INPUT AS #1 '读取口令密文
IF ERR.NUMBER <> 0 THEN
P = MSGBOX("口令已被破坏无法运行", 16, "退出应用软件")
ERR.CLEAR
GETCOUNT = FALSE
END IF
INPUT #1, INFO, NUM, LENG
NUM = NUM / 17
LENG = (LENG / NUM) / 13 '解密口令长度及口令
DO WHILE T <= LENG - 1
T = T + 1
INPUT #1, CHR1
LP = CHR1 / NUM
LPP = LP XOR NUM
PASS = CHR(LPP)
IF STRCOMP(PASS, RIGHT(LEFT(PASOLD, T), 1)) <> 0 THEN
PSW = "NO"
ELSE: PSW = "YES"
END IF
LOOP
CLOSE
END SUB

PRIVATE SUB COMMAND2_CLICK() '如果输入正确的原口令就更改口令
INFO = "DON'T MODIFY THESE DATA"
IF PSW = "YES" THEN
PASNUM = TRUE
PASNEW = TEXT2.TEXT
IF STRCOMP(PASFIRST, PASNEW) = 0 THEN PASOK = TRUE

IF PASOK = TRUE THEN
T = 0
OPEN WINDIRS & "\TST.DAT" FOR OUTPUT AS #1 '将口令文件创建在WINDOWS目录下
SAV = PASNEW
RANDOMIZE
NUM = INT(10000 * RND(20)) + 1 + INT(RND(60) * 10000) '随机数
KK = LEN(SAV)
WRITE #1, INFO, NUM * 17, KK * NUM * 13, '将随机数及变换后的口令长度写入文件
DO WHILE T <= KK - 1 '加密口令
T = T + 1
CHRQ = LEFT(SAV, T)
CHR1 = RIGHT(CHRQ, 1)
LP = ASC(CHR1) XOR NUM
LPP = LP * NUM
WRITE #1, LPP,
LOOP
IF KK < 10 THEN '如果口令长度少于10个字符,继续写入字符,防止解密者猜测口令长度
LL = 10 - KK
DO WHILE LL >= 0
WRITE #1, NUM * KK * (LL + 100) + 123456,
LL = LL - 1
LOOP
END IF
CLOSE

LABEL2.FORECOLOR = QBCOLOR(3)
LABEL2.CAPTION = "口令更改成功!"
TIMER1.ENABLED = TRUE
END IF

IF PASNUM = TRUE AND PASOK = FALSE THEN '允许有三次确认新口令的机会
LABEL2.FORECOLOR = QBCOLOR(13)
LABEL2.CAPTION = "请再输入一次新口令!"
FIRST = FIRST + 1
IF FIRST = 1 THEN PASFIRST = PASNEW
IF FIRST > 3 THEN GETCOUNT = FALSE
TEXT2.TEXT = ""
TEXT2.SETFOCUS
END IF

ELSE:
STATIC LOOPNUM AS INTEGER '有三次机会输入原口令
LOOPNUM = LOOPNUM + 1
IF LOOPNUM > 2 THEN GETCOUNT = FALSE
PASOLD = TEXT2.TEXT
CALL OPENPASWD
IF LENG <> LEN(PASOLD) THEN PSW = "NO"
IF STRCOMP(PSW, "NO") = 0 THEN
LABEL2.FORECOLOR = QBCOLOR(12)
LABEL2.CAPTION = "口令错,请重新输入!"
TEXT2.TEXT = ""
TEXT2.SETFOCUS
END IF

IF STRCOMP(PSW, "YES") = 0 THEN
LABEL2.FORECOLOR = QBCOLOR(4)
LABEL2.CAPTION = "请输入新口令!"
TEXT2.TEXT = ""
TEXT2.SETFOCUS
PASNUM = TRUE
END IF
END IF
RAISEEVENT PRESS
END SUB

PRIVATE SUB OPTION1_CLICK() '更改口令
TEXT2.SETFOCUS
LABEL2.CAPTION = "请输入原口令!"
RAISEEVENT PRESS
END SUB

PRIVATE SUB TIMER1_TIMER() '延时2秒关闭登录窗口
GETCOUNT = FALSE
RAISEEVENT TIMER
END SUB
PUBLIC PROPERTY GET GETLOGONINFO() AS BOOLEAN
GETLOGONINFO = GETINFO
END PROPERTY

PRIVATE SUB USERCONTROL_INITIALIZE()
WINDIR = STRING(255, 0)
WINDIRLEN = GETWINDOWSDIRECTORY(WINDIR, 255)
WINDIRS = LEFT(WINDIR, WINDIRLEN)
PSW = "NO"
TIMER1.INTERVAL = 2000
LOOPNUM = 0
TIMER1.ENABLED = FALSE
PASNUM = FALSE
PASOK = FALSE
FIRST = 0
GETINFO = FALSE
GETCOUNT = TRUE
END SUB

PUBLIC PROPERTY GET GETCOUNTFT() AS BOOLEAN
GETCOUNTFT = GETCOUNT
END PROPERTY

程序2:(演示程序)
PRIVATE SUB USERCONTROL11_PRESS()
IF USERCONTROL11.GETLOGONINFO = TRUE THEN
UNLOAD FORM1
FORM2.SHOW
END IF
IF USERCONTROL11.GETCOUNTFT = FALSE THEN
UNLOAD FORM1
END IF
END SUB

PRIVATE SUB USERCONTROL11_TIMER()
IF USERCONTROL11.GETCOUNTFT = FALSE THEN

UNLOAD FORM1
END IF
END SUB
posted on 2005-08-12 14:44 cyberfan 阅读(199) 评论(0)  编辑 收藏 引用 所属分类: vb
只有注册用户登录后才能发表评论。