張東瀛
原載 自動化科技 1996 年 12 月 p.62-67(上) 自動化科技 1997 年 1 月 p.54-59(下)
REM ******************************************
REM * CHarades.BAS Version 2.0 *
REM * 01-22-1986 *
REM * By Tony Chang *
REM * 06-22-1996 *
REM * Writing in Quick BASIC 4.5 *
REM * Tony Knowledge Engineering Lab *
REM ******************************************
以上為版權宣告及程式設計相關資訊
'EXIT Reminder 暫回DOS作業系統的檢知器。程式內因設有暫回DOS的功能
因此利用&H4E位址來偵測是否已執行本程式。使用者按Esc時,將&H4E內函值設
定為5,表示電腦已執行本程式
COLOR 15, 1: DEF SEG = &H30: MS% = PEEK(&H4E): DEF SEG
IF MS% = 5 THEN
CLS : BEEP: PRINT
PRINT "CHarades 2.0 already installed, type EXIT to return": END
END IF
程式開始執行時先檢查&H4E是否等於5,是的話,則提醒使用者打EXIT回本程式
若否,則繼續下一步,定義變數
A1$ = CHR$(68): A3$ = CHR$(97): A4$ = CHR$(109): A5$ = CHR$(101)
A2$ = CHR$(114)
這些變數用來定義密碼所需的字母,如果直接使用字串定義,很容易用PCTools
等工具程式看出,所以先用字母的ASCII值來定義變數,再加以組合成密碼
此一變數為音樂響鈴,可用PLAY指令發聲
FATE1$ = "MB T180 O2 P2 P8 L8 GGG L2 E-"
利用剛才定義的變數設定密碼PK1$,至於PK2$可作為備用鑰匙或第二個密碼,
必要時也可再增加幾個KEY CODE,甚至建立密碼庫存放這些密碼
I = 1: KEY OFF: CLS : LOCATE , , 0, 14
PK1$ = A1$ + A2$ + A5$ + A3$ + A4$ + A5$ + A2$
PK2$ = PK1$ '本例只用一個密碼
從第line 14到line 18為密碼檢核常式,I值設定讓使用者可輸入三次,超過
三次未輸入正確密碼則結束程式。非法使用者有時會先找出密碼為幾位數,再進
行測試。此處使用DO ... LOOP 的目的即是讓非法使用者無法查覺密碼位數,以
增加篩檢困難度。
14 PRINT : PRINT : PRINT : ' PLAY FATE1$
IF I <= 3 THEN
I$ = LTRIM$(STR$(I))
ANS$ = "": LOCATE 8, 10, 1: PRINT "Password"
DO: SANS$ = INPUT$(1): ANS$ = ANS$ + SANS$
LOOP UNTIL ASC(SANS$) = 13
I = I + 1: PRINT : ANS$ = LEFT$(ANS$, 7)
IF I > 3 THEN
GOTO 16
ELSE
GOTO 18
END IF
END IF
CLS : LOCATE 10, 12: PRINT "Incorrect password, permission denied."
LOCATE 22, 7
PRINT "* * * By Tony Chang, Tainan, Taiwan, August 18, 1986 * * *"
PRINT : END
16 IF NOT (ANS$ = PK1$ OR ANS$ = PK2$) THEN GOTO 14
18 IF NOT (ANS$ = PK1$ OR ANS$ = PK2$) THEN
LOCATE 10, 10: PRINT "Incorrect password, try again please."
SOUND 700, 1: GOTO 14
以上的密碼檢核常式,原先是以MBASIC寫成,後來改用QBASIC編譯成OBJECT
CODE 就可在不同的程式呼叫。
50 CLS
A6$ = CHR$(110): A12$ = CHR$(111): A15$ = CHR$(121): A16$ = CHR$(84)
LOCATE 1, 1:
PRINT "CHarades 1.0 Copyright " + A16$ + A12$ + A6$ + A15$ + " Lab 1992"
IF A16$ <> "T" OR A6$ <> "n" OR A12$ <> "o" OR A15$ <> "y" THEN 50
以上是防止版權宣告遭他人篡改的措施
其次是設計以方向鍵操作的功能選單,使用者可以選擇「加密」「解密」「結束」
等功能,選項以紅底黃字顯示,項目少時,用方向鍵比較便捷,選單多時才用滑鼠操作
CLEAR : DIM M$(4): ECG$ = "MF L16O2ECG>CEG>CL32O2CDEFGAB>CDEFGAB>C"
M$(1) = " 1: Charades "
M$(2) = " 2: Reduction "
M$(3) = " 3: Exit to DOS "
FOR Y = 1 TO 3: LOCATE 2 * Y + 6, 30: PRINT M$(Y): NEXT Y
LOCATE , , 0
Y = 1: MVE = NO: X = 1: Q$ = ""
WHILE Q$ <> CHR$(13)
LOCATE 2 * Y + 6, 30: COLOR 14, 4: PRINT M$(Y): COLOR 15, 1
Q$ = INKEY$: WHILE Q$ = "": Q$ = INKEY$: WEND
IF LEN(Q$) = 2 AND ASC(RIGHT$(Q$, 1)) = 72 THEN
MVE = YES: X = Y - 1:
IF X = 0 THEN
X = 3
END IF
END IF
IF LEN(Q$) = 2 AND ASC(RIGHT$(Q$, 1)) = 80 THEN
MVE = YES: X = Y + 1:
IF X = 4 THEN
X = 1
END IF
END IF
'Call DOS shell
這一段是利用SHELL指令設計暫回DOS功能,有時候忘記檔案放在那個目錄,或是臨時想
到DOS作業,便可按Esc跳出。&H4E用來存放程式辨識值
IF ASC(RIGHT$(Q$, 1)) = 27 THEN
CLS : DEF SEG = &H30: H4E% = PEEK(&H4E): POKE &H4E, 5: SHELL
DEF SEG = &H30: POKE &H4E, H4E%: DEF SEG : GOTO 50
END IF
IF Q$ >= "1" AND Q$ <= "3" THEN X = VAL(Q$): MVE = YES
IF MVE = YES THEN LOCATE 2 * Y + 6, 30: PRINT M$(Y): Y = X: MVE = NO
WEND
A$ = STRING$(1, " ")'定字串長度
IF Y = 1 THEN 110
IF Y = 2 THEN 370
IF Y = 3 THEN PLAY ECG$: CLS
END
這一段是加密常式,先輸入要進行加密和加密後的檔名
110 CLS : BEEP
LOCATE 7, 20: PRINT "ASCII (Binary) file -> Charade file"
LOCATE 9, 20: INPUT "Source file name "; SFN1$: IF SFN1$ = "" THEN 110
LOCATE 11, 20: INPUT "Charade file name "; CFN1$: IF CFN1$ = "" THEN 110
再用 SUB 600 讓使用者選擇 1-99999 五位數作密碼,CD%是密碼值除以256後的餘數
GOSUB 600
打開檔案,將ASCII碼逐一讀入,經過編碼運算後存入新檔
OPEN SFN1$ FOR BINARY AS #1
OPEN CFN1$ FOR BINARY AS #2
L = LOF(1)
FOR I = 1 TO L
GET #1, I, A$
H% = ASC(A$)
AC% = H% + CD%: IF AC% > 255 THEN AC% = AC% - 256
將ASCII值和密碼餘數值相加,若大於255則減去256
IF AC% >= 249 THEN 260 '超過249則商大於10,無法存個位數
A% = INT((AC%) / 25) '計算商
C% = AC% - A% * 25 '計算餘數
IF C% = 7 OR C% = 18 THEN
LOCATE 15, 30: PRINT "Proceeding : "; I '顯示進行加密的進度
END IF
AC% = C% * 10 + A% '以餘數當十位數,以商當個位數,計算新數值
260 PUT #2, I, AC% '將演算結果存進加密檔
NEXT I
LOCATE 15, 30
BEEP: LOCATE 20, 20: INPUT ; "Hit RETURN to continue.", ANS2$: GOTO 50
這一段是解密常式,將加密演算法反向操作,把ASCII數值還原,再存入解密檔
370 CLS : BEEP: LOCATE 7, 20: PRINT "Charade file -> ASCII (Binary) file"
LOCATE 9, 20: INPUT "Charade file name "; CFN2$: IF CFN2$ = "" THEN 370
LOCATE 11, 20: INPUT "Target file name "; TFN2$: IF TFN2$ = "" THEN 370
GOSUB 600
OPEN CFN2$ FOR BINARY AS #1
OPEN TFN2$ FOR BINARY AS #2
L = LOF(1) - 1
FOR I = 1 TO L
GET #1, I, A$
AC% = ASC(A$)
IF AC% >= 249 THEN 500
C% = INT(AC% / 10): D% = AC% - C% * 10 'C% 為十位數, D%為個位數
AC% = D% * 25 + C% 'D%為原來的商,C%為原來的餘數
IF D% = 2 OR D% = 7 THEN LOCATE 15, 30: PRINT "Proceeding : "; I
500 H% = AC% - CD%: IF H% < 0 THEN H% = H% + 256
B$ = CHR$(H%)
PUT #2, I, B$
NEXT I
LOCATE 15, 30: PRINT "Proceeding : "; I 顯示進行解密的進度
BEEP: LOCATE 20, 20: INPUT ; "Hit RETURN to continue.", ANS2$: GOTO 50
END
SUB 600 用以計算密碼的餘數值,由於ASCII值為0-255,故除以256再取餘數值,
密碼設計為五位數只是障眼法,目的是取一個隨機的ASCII值來運算
600 BEEP: LOCATE 13, 20: PRINT "Code Number (XXXXX) : ": CD$ = INPUT$(5)
CD& = VAL(CD$): IF CD& > 99999 OR CD& < 1 THEN PLAY ECG$: GOTO 600
CD% = CD& - (INT(CD& / 256)) * 256
RETURN
這種加密方式由於一次處理一個BYTE,速度較慢,而且密碼為定值,被解開的機率較大。
50 CLS : A6$ = CHR$(110): A12$ = CHR$(111): A15$ = CHR$(121): A16$ = CHR$(84)
LOCATE 1, 1
PRINT "CHarades 2.0 Copyright " + A16$ + A12$ + A6$ + A15$ + " Lab 1992"
IF A16$ <> "T" OR A6$ <> "n" OR A12$ <> "o" OR A15$ <> "y" THEN 50
CLEAR : DIM M$(4): ECG$ = "MF L16O2ECG>CEG>CL32O2CDEFGAB>CDEFGAB>C"
M$(1) = " 1: Charades "
M$(2) = " 2: Reduction "
M$(3) = " 3: Exit to DOS "
FOR Y = 1 TO 3: LOCATE 2 * Y + 6, 30: PRINT M$(Y): NEXT Y
LOCATE , , 0
Y = 1: MVE = NO: X = 1: Q$ = ""
WHILE Q$ <> CHR$(13)
LOCATE 2 * Y + 6, 30: COLOR 14, 4: PRINT M$(Y): COLOR 15, 1
Q$ = INKEY$: WHILE Q$ = "": Q$ = INKEY$: WEND
IF LEN(Q$) = 2 AND ASC(RIGHT$(Q$, 1)) = 72 THEN
MVE = YES: X = Y - 1:
IF X = 0 THEN
X = 3
END IF
END IF
IF LEN(Q$) = 2 AND ASC(RIGHT$(Q$, 1)) = 80 THEN
MVE = YES: X = Y + 1:
IF X = 4 THEN
X = 1
END IF
END IF
'Call DOS shell
IF ASC(RIGHT$(Q$, 1)) = 27 THEN
CLS : DEF SEG = &H30: H4E% = PEEK(&H4E): POKE &H4E, 5: SHELL
DEF SEG = &H30: POKE &H4E,
END IF
IF Q$ >= "1" AND Q$ <= "3" THEN X = VAL(Q$): MVE = YES
IF Q$ >= "1" AND Q$ <= "3" THEN X = VAL(Q$): MVE = YES
IF Q$ >= "1" AND Q$ <= "3" THEN X = VAL(Q$): MVE = YES
IF MVE = YES THEN LOCATE 2 * Y + 6, 30: PRINT M$(Y): Y = X: MVE = NO
WEND
IF Y = 1 THEN 110
IF Y = 2 THEN 370
IF Y = 3 THEN PLAY ECG$: CLS : END
以上程式說明,請參考規則式加密法部份
加密常式: 輸入相關檔名,打開檔案,視檔案相對長度決定一次讀入字串和陣列大小
110 CLS
LOCATE 7, 20: PRINT "Input file name for Charades Process"
LOCATE 9, 20: INPUT "Source file: ", SFN1$: IF SFN1$ = "" THEN 110
LOCATE 11, 20: INPUT "Signature file: ", CFN1$: IF CFN1$ = "" THEN 110
LOCATE 13, 20: INPUT "Charades file: ", TFN1$: IF TFN1$ = "" THEN 110
OPEN SFN1$ FOR BINARY AS #1
OPEN CFN1$ FOR BINARY AS #2
OPEN TFN1$ FOR BINARY AS #3
L1 = LOF(1)
L2 = LOF(2)
若檔名輸入有誤,則重新輸入
IF L1=0 OR L2=0 THEN
BEEP: LOCATE 20,20
INPUT ; "File Error! Hit RETURN to continue.", ANS2$
GOTO 110
END IF
IF L1 > L2 THEN IL = L2 ELSE IL = L1
以來源檔及簽名檔中較小的檔案長度作為字串陣列設定值IL
IF IL > 20480 THEN IL = 20480 'IL最大值為20K BYTE
設定動態定長字串陣列
'$DYNAMIC
DIM RD$(2)
定義字串變數長度
RD$(1) = SPACE$(IL)
RD$(2) = SPACE$(IL)
若來源檔大於一次處理長度則分段進行加密,否則一次完成
IF L1 > IL THEN GOSUB RECHA ELSE GOSUB NONRECHA
ERASE RD$ '將動態陣列移除
CLOSE : BEEP:
LOCATE 20, 20: INPUT ; "Hit RETURN to continue.", ANS2$: GOTO 50
一次完成加密常式
NONRECHA:
GET #1, , RD$(1)
GET #2, , RD$(2)
FOR I = 1 TO IL
DSOR$ = MID$(RD$(1), I, 1)
DCHA$ = MID$(RD$(2), I, 1)
SOR% = ASC(DSOR$)
CHA% = ASC(DCHA$)
TAG% = SOR% + CHA%: IF TAG% > 255 THEN TAG% = TAG% - 256
必要時可在此處加上其他演算法變碼
DSOR$ = CHR$(TAG%)
PUT #3, , DSOR$
NEXT I
RETURN
分次完成加密常式
RECHA:
LAST = 0
JT = INT(L1 / IL) + 1
FOR J = 1 TO JT
GET #1, , RD$(1)
GET #2, 1, RD$(2)
FOR I = 1 TO IL
DSOR$ = MID$(RD$(1), I, 1)
DCHA$ = MID$(RD$(2), I, 1)
SOR% = ASC(DSOR$)
CHA% = ASC(DCHA$)
TAG% = SOR% + CHA%: IF TAG% > 255 THEN TAG% = TAG% - 256
必要時可在此處加上其他演算法變碼
LAST = IL * (J - 1) + I
DSOR$ = CHR$(TAG%)
PUT #3, LAST, DSOR$
IF LAST = L1 THEN EXIT FOR
NEXT I
LOCATE 15, 30: PRINT "Proceeding : "; LAST
NEXT J
RETURN
解密常式: 輸入相關檔名,打開檔案,視檔案相對長度決定一次讀入字串和陣列大小
370 CLS
LOCATE 7, 20: PRINT "Input file name for Reduction Process"
LOCATE 9, 20: INPUT "Charades file: ", SFN1$: IF SFN1$ = "" THEN 370
LOCATE 11, 20: INPUT "Signature file: ", CFN1$: IF CFN1$ = "" THEN 370
LOCATE 13, 20: INPUT "Reduction file: ", TFN1$: IF TFN1$ = "" THEN 370
OPEN SFN1$ FOR BINARY AS #1
OPEN CFN1$ FOR BINARY AS #2
OPEN TFN1$ FOR BINARY AS #3
L1 = LOF(1)
L2 = LOF(2)
若檔名輸入有誤,則重新輸入
IF L1=0 OR L2=0 THEN
BEEP: LOCATE 20,20
INPUT ; "File Error! Hit RETURN to continue.", ANS2$
GOTO 370
END IF
IF L1 > L2 THEN IL = L2 ELSE IL = L1
IF IL > 20480 THEN IL = 20480
DIM RD$(2)
RD$(1) = SPACE$(IL)
RD$(2) = SPACE$(IL)
IF L1 > IL THEN GOSUB REDUC ELSE GOSUB NONREDUC
CLOSE : BEEP:
LOCATE 20, 20: INPUT ; "Hit RETURN to continue.", ANS2$: GOTO 50
一次完成解密常式
NONREDUC:
GET #1, , RD$(1)
GET #2, , RD$(2)
FOR I = 1 TO IL
DSOR$ = MID$(RD$(1), I, 1)
DCHA$ = MID$(RD$(2), I, 1)
SOR% = ASC(DSOR$)
CHA% = ASC(DCHA$)
TAG% = SOR% - CHA%: IF TAG% < 0 THEN TAG% = TAG% + 256
DSOR$ = CHR$(TAG%)
PUT #3, , DSOR$
NEXT I
RETURN
分次完成解密常式
REDUC:
LAST = 0
JT = INT(L1 / IL) + 1
FOR J = 1 TO JT
GET #1, , RD$(1)
GET #2, 1, RD$(2)
FOR I = 1 TO IL
DSOR$ = MID$(RD$(1), I, 1)
DCHA$ = MID$(RD$(2), I, 1)
SOR% = ASC(DSOR$)
CHA% = ASC(DCHA$)
TAG% = SOR% - CHA%: IF TAG% < 0 THEN TAG% = TAG% + 256
LAST = IL * (J - 1) + I
DSOR$ = CHR$(TAG%)
PUT #3, LAST, DSOR$
IF LAST = L1 THEN EXIT FOR
NEXT I
LOCATE 15, 30: PRINT "Proceeding : "; LAST
NEXT J
RETURN
This website is sponsored
by VIKON Corp.
Copyright July 1996.
All rights reserved.
Last update : 10-20-99
有什麼建議嗎 ? 來信請寄:
vikontony@gmail.com