Cipherサイファー関数

本ページには広告が含まれています。

Cipherモジュールは、暗号化・復号する関数をまとめたモジュールです。シーザー暗号・ROT13・ヴィジュネル暗号・XOR暗号の4種類が使えます。

構文
  1. UString = Cipher.Caesar.encode( str, num )
  2. UString = Cipher.Caesar.decode( str, num )
  3. UString = Cipher.ROT13.encode( str )
  4. UString = Cipher.ROT13.encode( str )
  5. UString = Cipher.Vigenere.encode( str, key )
  6. UString = Cipher.Vigenere.decode( str, key )
  7. UString = Cipher.XOR.encode( str, key )
  8. UString = Cipher.XOR.decode( str, key )
引数
str 必須
暗号化または復号する文字列
num 必須
シーザー暗号で文字をシフトさせる数
key 必須
戻り値
暗号化または復号した文字列

プログラム

UWSC
//////////////////////////////////////////////////
// 【引数】
//   str : 暗号化または復号する文字列 
//   num : シーザー暗号で文字をシフトさせる数 
//   key : 鍵 
// 【戻り値】
//   暗号化または復号した文字列 
//////////////////////////////////////////////////
MODULE Cipher
	FUNCTION Caesar.encode(str, num = 3)
		DIM res = ""
		FOR n = 1 TO LENGTH(str)
			DIM s = COPY(str, n, 1)
			DIM ofs = ""
			DIM normalizedNumber = IIF(num >= 0, num MOD 26, INT(ABS(num / 26) + 1) * 26 + num)
			SELECT TRUE
				CASE ASC(s) >= ASC("A") AND ASC(s) <= ASC("Z")
					ofs = (ASC(s) - ASC("A") + normalizedNumber) MOD 26
					res = res + CHR(ofs + ASC("A"))
				CASE ASC(s) >= ASC("a") AND ASC(s) <= ASC("z")
					ofs = (ASC(s) - ASC("a") + normalizedNumber) MOD 26
					res = res + CHR(ofs + ASC("a"))
				DEFAULT
					res = res + s
			SELEND
		NEXT
		RESULT = res
	FEND
	FUNCTION Caesar.decode(str, num = 3)
		DIM res = ""
		FOR n = 1 TO LENGTH(str)
			DIM s = COPY(str, n, 1)
			DIM ofs = ""
			DIM normalizedNumber = IIF(num >= 0, num MOD 26, INT(ABS(num / 26) + 1) * 26 + num)
			SELECT TRUE
				CASE ASC(s) >= ASC("A") AND ASC(s) <= ASC("Z")
					ofs = (ASC(s) - ASC("A") - normalizedNumber + 26) MOD 26
					res = res + CHR(ofs + ASC("A"))
				CASE ASC(s) >= ASC("a") AND ASC(s) <= ASC("z")
					ofs = (ASC(s) - ASC("a") - normalizedNumber + 26) MOD 26
					res = res + CHR(ofs + ASC("a"))
				DEFAULT
					res = res + s
			SELEND
		NEXT
		RESULT = res
	FEND
	FUNCTION ROT13.encode(str)
		RESULT = Cipher.Caesar.encode(str, 13)
	FEND	
	FUNCTION ROT13.decode(str)
		RESULT = Cipher.ROT13.encode(str)
	FEND
	FUNCTION Vigenere.encode(str, key)
		str = STRCONV(str, SC_LOWERCASE)
		key = STRCONV(key, SC_LOWERCASE)
		DIM res = ""
		DIM ofs = ""
		FOR n = 1 TO LENGTH(str)
			DIM s = COPY(str, n, 1)
			SELECT TRUE
				CASE ASC(s) >= ASC("a") AND ASC(s) <= ASC("z")
					DIM num = (n - 1) MOD LENGTH(key) + 1
					ofs = ((ASC(s) - ASC("a")) + (ASC(COPY(key, num, 1)) - ASC("a")) + 26) MOD 26
					res = res + CHR(ofs + ASC("a"))
				DEFAULT
					res = res + s
			SELEND
		NEXT
		RESULT = res
	FEND
	FUNCTION Vigenere.decode(str, key)
		str = STRCONV(str, SC_LOWERCASE)
		key = STRCONV(key, SC_LOWERCASE)
		DIM res = ""
		DIM ofs = ""
		FOR n = 1 TO LENGTH(str)
			DIM s = COPY(str, n, 1)
			SELECT TRUE
				CASE ASC(s) >= ASC("a") AND ASC(s) <= ASC("z")
					DIM num = (n - 1) MOD LENGTH(key) + 1
					ofs = ((ASC(s) - ASC("a")) - (ASC(COPY(key, num, 1)) - ASC("a")) + 26) MOD 26
					res = res + CHR(ofs + ASC("a"))
				DEFAULT
					res = res + s
			SELEND
		NEXT
		RESULT = res
	FEND
	FUNCTION XOR.encode(str, key)
		DIM res = ""
		FOR n = 1 TO LENGTH(str)
			DIM num = (n - 1) MOD LENGTH(key) + 1
			DIM a = ASC(COPY(str, n, 1))
			DIM b = ASC(COPY(key, num, 1))
			res = res + "" + REPLACE(FORMAT(VARTYPE(decToBin(a XOR b), VAR_INTEGER), 8), " ", "0")
		NEXT
		RESULT = res
	FEND
	FUNCTION XOR.decode(str, key)
		DIM res = ""
		FOR n = 1 TO LENGTH(str) / 8
			DIM num = (n - 1) MOD LENGTH(key) + 1
 			DIM a = binToDec(COPY(str, n * 8 - 7, 8))
			DIM b = ASC(COPY(key, num, 1))
			res = res + CHR(a XOR b)
		NEXT
		RESULT = res
	FEND
ENDMODULE

//////////////////////////////////////////////////
// 【引数】
//   bin : 2進数 
//   signFlg : 符号付きならばTrue 
// 【戻り値】
//   10進数に変換した値 
//////////////////////////////////////////////////
FUNCTION binToDec(bin, signFlg = TRUE)
	DIM dec = 0
	DIM decimalFlg = IIF(POS(".", bin), TRUE, FALSE)
	IFB COPY(bin, 1, 1) = "1" AND signFlg THEN
		DIM msb = IIF(decimalFlg, POS(".", bin) - 1, LENGTH(bin))
		DIM lsb = IIF(decimalFlg, POS(".", bin) - LENGTH(bin), 0)
		DIM dec2 = POWER(2, msb) - 1
		FOR i = -1 TO lsb STEP -1
			dec2 = dec2 + POWER(2, i)
		NEXT
		DIM a = binToDec(bin, FALSE)
		DIM b = dec2
		dec = -1 * (bitXor(a, b) + POWER(2, lsb))
	ELSE
		IFB decimalFlg THEN
			DIM integer = COPY(bin, 1, POS(".", bin) - 1)
			DIM decimal = COPY(bin, POS(".", bin) + 1)
			FOR i = 1 TO LENGTH(decimal)
				dec = dec + COPY(decimal, i, 1) * POWER(2, -1 * i)
			NEXT
		ELSE
			integer = bin
		ENDIF
		FOR i = 1 TO LENGTH(integer)
			dec = dec + COPY(integer, i, 1) * POWER(2, LENGTH(integer) - i)
		NEXT
	ENDIF
	RESULT = dec
FEND

//////////////////////////////////////////////////
// 【引数】
//   arg1 : 数値1(10進数) 
//   arg2 : 数値2(10進数) 
// 【戻り値】
//   2つの数値のビット毎の排他的論理和 
//////////////////////////////////////////////////
FUNCTION bitXor(arg1, arg2)
	DIM args[1] = arg1, arg2
	DIM bins[1]
	DIM decimals[1]
	DIM integers[1]
	DIM keta[1]
	IFB ABS(arg1) <> arg1 OR ABS(arg2) <> arg2 THEN
		RESULT = ERR_VALUE
		EXIT
	ENDIF
	FOR i = 0 TO 1
		bins[i] = decToBin(args[i])
		decimals[i] = 0
		IFB POS(".", bins[i]) <> 0 THEN
			integers[i] = COPY(bins[i], 1, POS(".", bins[i]) - 1)
			decimals[i] = COPY(bins[i], POS(".", bins[i]) + 1)
		ELSE
			integers[i] = bins[i]
		ENDIF
	NEXT
	keta[0] = IIF(LENGTH(integers[0]) > LENGTH(integers[1]), LENGTH(integers[0]), LENGTH(integers[1]))
	integers[0] = strPad(integers[0], keta[0], "0", LEFT)
	integers[1] = strPad(integers[1], keta[0], "0", LEFT)
	keta[1] = IIF(LENGTH(decimals[0]) > LENGTH(decimals[1]), LENGTH(decimals[0]), LENGTH(decimals[1]))
	decimals[0] = strPad(decimals[0], keta[1], "0", RIGHT)
	decimals[1] = strPad(decimals[1], keta[1], "0", RIGHT)
	DIM bin = ""
	FOR i = 1 TO keta[0]
		bin = bin + (VAL(COPY(integers[0], i, 1)) XOR VAL(COPY(integers[1], i, 1)))
	NEXT
	bin = bin + "."
	FOR i = 1 TO keta[1]
		bin = bin + (VAL(COPY(decimals[0], i, 1)) XOR VAL(COPY(decimals[1], i, 1)))
	NEXT
	RESULT = binToDec(bin)
FEND

//////////////////////////////////////////////////
// 【引数】
//   dec : 10進数 
//   signFlg : 符号付きならばTrueを指定 
//   digits : 変換した2進数の桁数合わせを自動で行うかを示すブール値、もしくは桁数を表す数値(8,16,24,32,64のいずれか)を指定 
//   recursive : 再帰処理の深さ。処理する際に必要なだけで指定する必要はありません。 
// 【戻り値】
//   2進数に変換した値 
//////////////////////////////////////////////////
FUNCTION decToBin(dec, signFlg = TRUE, digits = FALSE, recursive = 1)
	IFB dec < 0 AND signFlg = FALSE THEN
		RESULT = ERR_VALUE
		EXIT
	ENDIF
	IFB VARTYPE(digits) <> VAR_BOOLEAN AND digits < CEIL(LOGN(2, ABS(dec))) + IIF(dec < 0, 1, 0) THEN
		RESULT = ERR_VALUE
		EXIT
	ENDIF
	DIM bin = ""
	DIM decimalFlg = IIF(POS(".", dec) <> 0, TRUE, FALSE)
	DIM negativeFlg = IIF(dec < 0, TRUE, FALSE)
	dec = ABS(dec)
	DIM integer = IIF(decimalFlg, COPY(dec, 1, POS(".", dec) - 1), dec)
	DIM offset = POWER(10, LENGTH(dec) - POS(".", dec))
	DIM decimal = IIF(decimalFlg, COPY(dec, POS(".", dec) + 1) / offset, 0)
	REPEAT
		bin = (integer MOD 2) + bin
		integer = INT(integer / 2)
	UNTIL integer = 0
	IFB decimalFlg THEN
		bin = bin + "."
		DIM loop = 0
		REPEAT
			loop = loop + 1
			decimal = decimal * 2
			bin = bin + IIF(decimal >= 1, "1", "0")
			IF decimal > 1 THEN decimal = decimal - 1
		UNTIL decimal = 1 OR loop >= 64
		WHILE loop MOD 4 <> 0
			loop = loop + 1
			bin = bin + "0"
		WEND
	ENDIF
	IFB VARTYPE(digits) = VAR_BOOLEAN THEN
		bin = strPad(bin, CEIL(LENGTH(REPLACE(bin, ".", "")) / 8) * 8, "0", LEFT)
	ELSE
		bin = strPad(bin, digits, "0", LEFT)
	ENDIF
	IFB negativeFlg THEN
		DIM msb = IIF(decimalFlg, POS(".", bin) - 1, LENGTH(bin))
		DIM lsb = IIF(decimalFlg , POS(".", bin) - LENGTH(bin), 0)
		DIM a = binToDec(bin, FALSE)
		DIM b = POWER(2, msb) - 1
		FOR i = -1 TO lsb STEP -1
			b = b + POWER(2, i)
		NEXT
  		dec = bitXor(a, b) + POWER(2, lsb)
 		bin = decToBin(dec, signFlg, digits, recursive + 1)
	ENDIF
	IFB recursive = 1 THEN
		DIM bit = COPY(bin, 1, 1)
 		DIM len = LENGTH(REPLACE(bin, ".", ""))
		IF negativeFlg AND (bit = "0" OR len MOD 2 <> 0) THEN bin = strRepeat("1", IIF(len MOD 2 <> 0, 4, 8)) + bin
		IF !negativeFlg AND signFlg AND (bit = "1" OR len MOD 8 <> 0) THEN bin = strRepeat("0", IIF(len MOD 8 <> 0, 4, 8)) + bin
	ENDIF
	RESULT = bin
FEND

//////////////////////////////////////////////////
// 【引数】
//   expr : 評価する式 
//   truepart : 評価した式がTrueのときに返す値 
//   falsepart : 評価した式がFalseのときに返す値 
// 【戻り値】
//   truepart : 評価した式がTrueのとき、falsepart : 評価した式がFalseのとき 
//////////////////////////////////////////////////
FUNCTION IIF(expr, truepart, falsepart)
	IFB EVAL(expr) THEN
		RESULT = truepart
	ELSE
		RESULT = falsepart
	ENDIF
FEND

//////////////////////////////////////////////////
// 【引数】
//   num : 符号を求める数値 
// 【戻り値】
//   1 : 正の数、0 : ゼロ、-1 : 負の数、ERR_VALUE : それ以外 
//////////////////////////////////////////////////
FUNCTION sign(num)
	SELECT TRUE
		CASE !CHKNUM(num)
			RESULT = ERR_VALUE
		CASE num > 0
			RESULT = 1
		CASE num = 0
			RESULT = 0
		CASE num < 0
			RESULT = -1
	SELEND
FEND

//////////////////////////////////////////////////
// 【引数】
//   input : 入力文字列 
//   length : 埋めたあとの長さ 
//   str : 埋める文字 
//   type : 埋める方向 
// 【戻り値】
//   指定文字で埋めた文字列 
//////////////////////////////////////////////////
FUNCTION strPad(input, length, str = " ", type = RIGHT)
	DIM s = ""
	SELECT type
		CASE LEFT
			FOR i = 1 TO CEIL((length - LENGTH(input)) / LENGTH(str))
				s = s + str
			NEXT
			input = COPY(s, 1, length - LENGTH(input)) + input
		CASE RIGHT
			FOR i = 1 TO CEIL((length - LENGTH(input)) / LENGTH(str))
				s = s + str
			NEXT
			input = input + COPY(s, 1, length - LENGTH(input))
	SELEND
	RESULT = input
FEND

//////////////////////////////////////////////////
// 【引数】
//   inputs : 繰り返す文字列 
//   multiplier : inputsを繰り返す回数 
// 【戻り値】
//   inputsをmultiplier回を繰り返した文字列を返します 
//////////////////////////////////////////////////
FUNCTION strRepeat(inputs, multiplier)
	DIM res = ""
	FOR n = 1 TO multiplier
		res = res + inputs
	NEXT
	RESULT = res
FEND

解説

  1. 2-20行目
    UWSC
    	FUNCTION Caesar.encode(str, num = 3)
    		DIM res = ""
    		FOR n = 1 TO LENGTH(str)
    			DIM s = COPY(str, n, 1)
    			DIM ofs = ""
    			DIM normalizedNumber = IIF(num >= 0, num MOD 26, INT(ABS(num / 26) + 1) * 26 + num)
    			SELECT TRUE
    				CASE ASC(s) >= ASC("A") AND ASC(s) <= ASC("Z")
    					ofs = (ASC(s) - ASC("A") + normalizedNumber) MOD 26
    					res = res + CHR(ofs + ASC("A"))
    				CASE ASC(s) >= ASC("a") AND ASC(s) <= ASC("z")
    					ofs = (ASC(s) - ASC("a") + normalizedNumber) MOD 26
    					res = res + CHR(ofs + ASC("a"))
    				DEFAULT
    					res = res + s
    			SELEND
    		NEXT
    		RESULT = res
    	FEND
    Cipher.Caesar.encode
    シーザー暗号でエンコードします。シフトする文字数のデフォルトは3文字です。

    エンコードした結果を代入する変数resを宣言。変数normalizedNumberにシフトさせる数を0~25の範囲に正規化した数値を代入。

    ASC(s) >= ASC("A") AND ASC(s)
    ASC(s) >= ASC("a") AND ASC(s)
    アルファベット以外の文字
    そのまま代入
  2. 21-39行目
    UWSC
    	FUNCTION Caesar.decode(str, num = 3)
    		DIM res = ""
    		FOR n = 1 TO LENGTH(str)
    			DIM s = COPY(str, n, 1)
    			DIM ofs = ""
    			DIM normalizedNumber = IIF(num >= 0, num MOD 26, INT(ABS(num / 26) + 1) * 26 + num)
    			SELECT TRUE
    				CASE ASC(s) >= ASC("A") AND ASC(s) <= ASC("Z")
    					ofs = (ASC(s) - ASC("A") - normalizedNumber + 26) MOD 26
    					res = res + CHR(ofs + ASC("A"))
    				CASE ASC(s) >= ASC("a") AND ASC(s) <= ASC("z")
    					ofs = (ASC(s) - ASC("a") - normalizedNumber + 26) MOD 26
    					res = res + CHR(ofs + ASC("a"))
    				DEFAULT
    					res = res + s
    			SELEND
    		NEXT
    		RESULT = res
    	FEND
    Cipher.Caesar.decode
    シーザー暗号でデコードします。

    変数sにデコードする文字列から1文字を代入。

    変数normalizedNumberにシフトさせる数を0~25の範囲に正規化した数値を代入。

    ASC(s) >= ASC("A") AND ASC(s)
    マイナスにならないように「+26」する。

    AのASCIIコードにシフトする数を加算してから文字に戻す。

    ASC(s) >= ASC("a") AND ASC(s)
    マイナスにならないように「+26」する。

    AのASCIIコードにシフトする数を加算してから文字に戻す。

    アルファベット以外の文字
    そのまま代入
  3. 40-42行目
    UWSC
    	FUNCTION ROT13.encode(str)
    		RESULT = Cipher.Caesar.encode(str, 13)
    	FEND
    Cipher.ROT13.encode
    ROT13でエンコードします。

    シーザー暗号で13文字シフトします。

  4. 43-45行目
    UWSC
    	FUNCTION ROT13.decode(str)
    		RESULT = Cipher.ROT13.encode(str)
    	FEND
    Cipher.ROT13.decode
    ROT13でデコードします。
    暗号化を2回行うと元に戻るので、再度ROT13でエンコード。
  5. 46-63行目
    UWSC
    	FUNCTION Vigenere.encode(str, key)
    		str = STRCONV(str, SC_LOWERCASE)
    		key = STRCONV(key, SC_LOWERCASE)
    		DIM res = ""
    		DIM ofs = ""
    		FOR n = 1 TO LENGTH(str)
    			DIM s = COPY(str, n, 1)
    			SELECT TRUE
    				CASE ASC(s) >= ASC("a") AND ASC(s) <= ASC("z")
    					DIM num = (n - 1) MOD LENGTH(key) + 1
    					ofs = ((ASC(s) - ASC("a")) + (ASC(COPY(key, num, 1)) - ASC("a")) + 26) MOD 26
    					res = res + CHR(ofs + ASC("a"))
    				DEFAULT
    					res = res + s
    			SELEND
    		NEXT
    		RESULT = res
    	FEND
    Cipher.Vigenere.encode
    ヴィジュネル暗号でエンコードします。
  6. 64-81行目
    UWSC
    	FUNCTION Vigenere.decode(str, key)
    		str = STRCONV(str, SC_LOWERCASE)
    		key = STRCONV(key, SC_LOWERCASE)
    		DIM res = ""
    		DIM ofs = ""
    		FOR n = 1 TO LENGTH(str)
    			DIM s = COPY(str, n, 1)
    			SELECT TRUE
    				CASE ASC(s) >= ASC("a") AND ASC(s) <= ASC("z")
    					DIM num = (n - 1) MOD LENGTH(key) + 1
    					ofs = ((ASC(s) - ASC("a")) - (ASC(COPY(key, num, 1)) - ASC("a")) + 26) MOD 26
    					res = res + CHR(ofs + ASC("a"))
    				DEFAULT
    					res = res + s
    			SELEND
    		NEXT
    		RESULT = res
    	FEND
    Cipher.Vigenere.decode
    ヴィジュネル暗号でデコードします。
  7. 82-91行目
    UWSC
    	FUNCTION XOR.encode(str, key)
    		DIM res = ""
    		FOR n = 1 TO LENGTH(str)
    			DIM num = (n - 1) MOD LENGTH(key) + 1
    			DIM a = ASC(COPY(str, n, 1))
    			DIM b = ASC(COPY(key, num, 1))
    			res = res + "" + REPLACE(FORMAT(VARTYPE(decToBin(a XOR b), VAR_INTEGER), 8), " ", "0")
    		NEXT
    		RESULT = res
    	FEND
    Cipher.XOR.encode
    XOR暗号でエンコードします。
  8. 92-101行目
    UWSC
    	FUNCTION XOR.decode(str, key)
    		DIM res = ""
    		FOR n = 1 TO LENGTH(str) / 8
    			DIM num = (n - 1) MOD LENGTH(key) + 1
     			DIM a = binToDec(COPY(str, n * 8 - 7, 8))
    			DIM b = ASC(COPY(key, num, 1))
    			res = res + CHR(a XOR b)
    		NEXT
    		RESULT = res
    	FEND
    Cipher.XOR.decode
    XOR暗号でデコードします。

プログラム実行例

シーザー暗号

UWSC
DIM str = "info@example.com"
DIM Caesar = Cipher.Caesar.encode(str)
PRINT "暗号化︰" + Caesar
PRINT "復号︰" + Cipher.Caesar.decode(Caesar)

//////////////////////////////////////////////////
// 【引数】
//   bin : 2進数 
//   signFlg : 符号付きならばTrue 
// 【戻り値】
//   10進数に変換した値 
//////////////////////////////////////////////////
FUNCTION binToDec(bin, signFlg = TRUE)
	DIM dec = 0
	DIM decimalFlg = IIF(POS(".", bin), TRUE, FALSE)
	IFB COPY(bin, 1, 1) = "1" AND signFlg THEN
		DIM msb = IIF(decimalFlg, POS(".", bin) - 1, LENGTH(bin))
		DIM lsb = IIF(decimalFlg, POS(".", bin) - LENGTH(bin), 0)
		DIM dec2 = POWER(2, msb) - 1
		FOR i = -1 TO lsb STEP -1
			dec2 = dec2 + POWER(2, i)
		NEXT
		DIM a = binToDec(bin, FALSE)
		DIM b = dec2
		dec = -1 * (bitXor(a, b) + POWER(2, lsb))
	ELSE
		IFB decimalFlg THEN
			DIM integer = COPY(bin, 1, POS(".", bin) - 1)
			DIM decimal = COPY(bin, POS(".", bin) + 1)
			FOR i = 1 TO LENGTH(decimal)
				dec = dec + COPY(decimal, i, 1) * POWER(2, -1 * i)
			NEXT
		ELSE
			integer = bin
		ENDIF
		FOR i = 1 TO LENGTH(integer)
			dec = dec + COPY(integer, i, 1) * POWER(2, LENGTH(integer) - i)
		NEXT
	ENDIF
	RESULT = dec
FEND

//////////////////////////////////////////////////
// 【引数】
//   arg1 : 数値1(10進数) 
//   arg2 : 数値2(10進数) 
// 【戻り値】
//   2つの数値のビット毎の排他的論理和 
//////////////////////////////////////////////////
FUNCTION bitXor(arg1, arg2)
	DIM args[1] = arg1, arg2
	DIM bins[1]
	DIM decimals[1]
	DIM integers[1]
	DIM keta[1]
	IFB ABS(arg1) <> arg1 OR ABS(arg2) <> arg2 THEN
		RESULT = ERR_VALUE
		EXIT
	ENDIF
	FOR i = 0 TO 1
		bins[i] = decToBin(args[i])
		decimals[i] = 0
		IFB POS(".", bins[i]) <> 0 THEN
			integers[i] = COPY(bins[i], 1, POS(".", bins[i]) - 1)
			decimals[i] = COPY(bins[i], POS(".", bins[i]) + 1)
		ELSE
			integers[i] = bins[i]
		ENDIF
	NEXT
	keta[0] = IIF(LENGTH(integers[0]) > LENGTH(integers[1]), LENGTH(integers[0]), LENGTH(integers[1]))
	integers[0] = strPad(integers[0], keta[0], "0", LEFT)
	integers[1] = strPad(integers[1], keta[0], "0", LEFT)
	keta[1] = IIF(LENGTH(decimals[0]) > LENGTH(decimals[1]), LENGTH(decimals[0]), LENGTH(decimals[1]))
	decimals[0] = strPad(decimals[0], keta[1], "0", RIGHT)
	decimals[1] = strPad(decimals[1], keta[1], "0", RIGHT)
	DIM bin = ""
	FOR i = 1 TO keta[0]
		bin = bin + (VAL(COPY(integers[0], i, 1)) XOR VAL(COPY(integers[1], i, 1)))
	NEXT
	bin = bin + "."
	FOR i = 1 TO keta[1]
		bin = bin + (VAL(COPY(decimals[0], i, 1)) XOR VAL(COPY(decimals[1], i, 1)))
	NEXT
	RESULT = binToDec(bin)
FEND

//////////////////////////////////////////////////
// 【引数】
//   str : 暗号化または復号する文字列 
//   num : シーザー暗号で文字をシフトさせる数 
//   key : 鍵 
// 【戻り値】
//   暗号化または復号した文字列 
//////////////////////////////////////////////////
MODULE Cipher
	FUNCTION Caesar.encode(str, num = 3)
		DIM res = ""
		FOR n = 1 TO LENGTH(str)
			DIM s = COPY(str, n, 1)
			DIM ofs = ""
			DIM normalizedNumber = IIF(num >= 0, num MOD 26, INT(ABS(num / 26) + 1) * 26 + num)
			SELECT TRUE
				CASE ASC(s) >= ASC("A") AND ASC(s) <= ASC("Z")
					ofs = (ASC(s) - ASC("A") + normalizedNumber) MOD 26
					res = res + CHR(ofs + ASC("A"))
				CASE ASC(s) >= ASC("a") AND ASC(s) <= ASC("z")
					ofs = (ASC(s) - ASC("a") + normalizedNumber) MOD 26
					res = res + CHR(ofs + ASC("a"))
				DEFAULT
					res = res + s
			SELEND
		NEXT
		RESULT = res
	FEND
	FUNCTION Caesar.decode(str, num = 3)
		DIM res = ""
		FOR n = 1 TO LENGTH(str)
			DIM s = COPY(str, n, 1)
			DIM ofs = ""
			DIM normalizedNumber = IIF(num >= 0, num MOD 26, INT(ABS(num / 26) + 1) * 26 + num)
			SELECT TRUE
				CASE ASC(s) >= ASC("A") AND ASC(s) <= ASC("Z")
					ofs = (ASC(s) - ASC("A") - normalizedNumber + 26) MOD 26
					res = res + CHR(ofs + ASC("A"))
				CASE ASC(s) >= ASC("a") AND ASC(s) <= ASC("z")
					ofs = (ASC(s) - ASC("a") - normalizedNumber + 26) MOD 26
					res = res + CHR(ofs + ASC("a"))
				DEFAULT
					res = res + s
			SELEND
		NEXT
		RESULT = res
	FEND
	FUNCTION ROT13.encode(str)
		RESULT = Cipher.Caesar.encode(str, 13)
	FEND	
	FUNCTION ROT13.decode(str)
		RESULT = Cipher.ROT13.encode(str)
	FEND
	FUNCTION Vigenere.encode(str, key)
		str = STRCONV(str, SC_LOWERCASE)
		key = STRCONV(key, SC_LOWERCASE)
		DIM res = ""
		DIM ofs = ""
		FOR n = 1 TO LENGTH(str)
			DIM s = COPY(str, n, 1)
			SELECT TRUE
				CASE ASC(s) >= ASC("a") AND ASC(s) <= ASC("z")
					DIM num = (n - 1) MOD LENGTH(key) + 1
					ofs = ((ASC(s) - ASC("a")) + (ASC(COPY(key, num, 1)) - ASC("a")) + 26) MOD 26
					res = res + CHR(ofs + ASC("a"))
				DEFAULT
					res = res + s
			SELEND
		NEXT
		RESULT = res
	FEND
	FUNCTION Vigenere.decode(str, key)
		str = STRCONV(str, SC_LOWERCASE)
		key = STRCONV(key, SC_LOWERCASE)
		DIM res = ""
		DIM ofs = ""
		FOR n = 1 TO LENGTH(str)
			DIM s = COPY(str, n, 1)
			SELECT TRUE
				CASE ASC(s) >= ASC("a") AND ASC(s) <= ASC("z")
					DIM num = (n - 1) MOD LENGTH(key) + 1
					ofs = ((ASC(s) - ASC("a")) - (ASC(COPY(key, num, 1)) - ASC("a")) + 26) MOD 26
					res = res + CHR(ofs + ASC("a"))
				DEFAULT
					res = res + s
			SELEND
		NEXT
		RESULT = res
	FEND
	FUNCTION XOR.encode(str, key)
		DIM res = ""
		FOR n = 1 TO LENGTH(str)
			DIM num = (n - 1) MOD LENGTH(key) + 1
			DIM a = ASC(COPY(str, n, 1))
			DIM b = ASC(COPY(key, num, 1))
			res = res + "" + REPLACE(FORMAT(VARTYPE(decToBin(a XOR b), VAR_INTEGER), 8), " ", "0")
		NEXT
		RESULT = res
	FEND
	FUNCTION XOR.decode(str, key)
		DIM res = ""
		FOR n = 1 TO LENGTH(str) / 8
			DIM num = (n - 1) MOD LENGTH(key) + 1
 			DIM a = binToDec(COPY(str, n * 8 - 7, 8))
			DIM b = ASC(COPY(key, num, 1))
			res = res + CHR(a XOR b)
		NEXT
		RESULT = res
	FEND
ENDMODULE

//////////////////////////////////////////////////
// 【引数】
//   dec : 10進数 
//   signFlg : 符号付きならばTrueを指定 
//   digits : 変換した2進数の桁数合わせを自動で行うかを示すブール値、もしくは桁数を表す数値(8,16,24,32,64のいずれか)を指定 
//   recursive : 再帰処理の深さ。処理する際に必要なだけで指定する必要はありません。 
// 【戻り値】
//   2進数に変換した値 
//////////////////////////////////////////////////
FUNCTION decToBin(dec, signFlg = TRUE, digits = FALSE, recursive = 1)
	IFB dec < 0 AND signFlg = FALSE THEN
		RESULT = ERR_VALUE
		EXIT
	ENDIF
	IFB VARTYPE(digits) <> VAR_BOOLEAN AND digits < CEIL(LOGN(2, ABS(dec))) + IIF(dec < 0, 1, 0) THEN
		RESULT = ERR_VALUE
		EXIT
	ENDIF
	DIM bin = ""
	DIM decimalFlg = IIF(POS(".", dec) <> 0, TRUE, FALSE)
	DIM negativeFlg = IIF(dec < 0, TRUE, FALSE)
	dec = ABS(dec)
	DIM integer = IIF(decimalFlg, COPY(dec, 1, POS(".", dec) - 1), dec)
	DIM offset = POWER(10, LENGTH(dec) - POS(".", dec))
	DIM decimal = IIF(decimalFlg, COPY(dec, POS(".", dec) + 1) / offset, 0)
	REPEAT
		bin = (integer MOD 2) + bin
		integer = INT(integer / 2)
	UNTIL integer = 0
	IFB decimalFlg THEN
		bin = bin + "."
		DIM loop = 0
		REPEAT
			loop = loop + 1
			decimal = decimal * 2
			bin = bin + IIF(decimal >= 1, "1", "0")
			IF decimal > 1 THEN decimal = decimal - 1
		UNTIL decimal = 1 OR loop >= 64
		WHILE loop MOD 4 <> 0
			loop = loop + 1
			bin = bin + "0"
		WEND
	ENDIF
	IFB VARTYPE(digits) = VAR_BOOLEAN THEN
		bin = strPad(bin, CEIL(LENGTH(REPLACE(bin, ".", "")) / 8) * 8, "0", LEFT)
	ELSE
		bin = strPad(bin, digits, "0", LEFT)
	ENDIF
	IFB negativeFlg THEN
		DIM msb = IIF(decimalFlg, POS(".", bin) - 1, LENGTH(bin))
		DIM lsb = IIF(decimalFlg , POS(".", bin) - LENGTH(bin), 0)
		DIM a = binToDec(bin, FALSE)
		DIM b = POWER(2, msb) - 1
		FOR i = -1 TO lsb STEP -1
			b = b + POWER(2, i)
		NEXT
  		dec = bitXor(a, b) + POWER(2, lsb)
 		bin = decToBin(dec, signFlg, digits, recursive + 1)
	ENDIF
	IFB recursive = 1 THEN
		DIM bit = COPY(bin, 1, 1)
 		DIM len = LENGTH(REPLACE(bin, ".", ""))
		IF negativeFlg AND (bit = "0" OR len MOD 2 <> 0) THEN bin = strRepeat("1", IIF(len MOD 2 <> 0, 4, 8)) + bin
		IF !negativeFlg AND signFlg AND (bit = "1" OR len MOD 8 <> 0) THEN bin = strRepeat("0", IIF(len MOD 8 <> 0, 4, 8)) + bin
	ENDIF
	RESULT = bin
FEND

//////////////////////////////////////////////////
// 【引数】
//   expr : 評価する式 
//   truepart : 評価した式がTrueのときに返す値 
//   falsepart : 評価した式がFalseのときに返す値 
// 【戻り値】
//   truepart : 評価した式がTrueのとき、falsepart : 評価した式がFalseのとき 
//////////////////////////////////////////////////
FUNCTION IIF(expr, truepart, falsepart)
	IFB EVAL(expr) THEN
		RESULT = truepart
	ELSE
		RESULT = falsepart
	ENDIF
FEND

//////////////////////////////////////////////////
// 【引数】
//   num : 符号を求める数値 
// 【戻り値】
//   1 : 正の数、0 : ゼロ、-1 : 負の数、ERR_VALUE : それ以外 
//////////////////////////////////////////////////
FUNCTION sign(num)
	SELECT TRUE
		CASE !CHKNUM(num)
			RESULT = ERR_VALUE
		CASE num > 0
			RESULT = 1
		CASE num = 0
			RESULT = 0
		CASE num < 0
			RESULT = -1
	SELEND
FEND

//////////////////////////////////////////////////
// 【引数】
//   input : 入力文字列 
//   length : 埋めたあとの長さ 
//   str : 埋める文字 
//   type : 埋める方向 
// 【戻り値】
//   指定文字で埋めた文字列 
//////////////////////////////////////////////////
FUNCTION strPad(input, length, str = " ", type = RIGHT)
	DIM s = ""
	SELECT type
		CASE LEFT
			FOR i = 1 TO CEIL((length - LENGTH(input)) / LENGTH(str))
				s = s + str
			NEXT
			input = COPY(s, 1, length - LENGTH(input)) + input
		CASE RIGHT
			FOR i = 1 TO CEIL((length - LENGTH(input)) / LENGTH(str))
				s = s + str
			NEXT
			input = input + COPY(s, 1, length - LENGTH(input))
	SELEND
	RESULT = input
FEND

//////////////////////////////////////////////////
// 【引数】
//   inputs : 繰り返す文字列 
//   multiplier : inputsを繰り返す回数 
// 【戻り値】
//   inputsをmultiplier回を繰り返した文字列を返します 
//////////////////////////////////////////////////
FUNCTION strRepeat(inputs, multiplier)
	DIM res = ""
	FOR n = 1 TO multiplier
		res = res + inputs
	NEXT
	RESULT = res
FEND
結果
CSV
暗号化︰   lqir@hadpsoh.frp
復号︰     info@example.com
使用関数
解説

シーザー暗号

シーザー暗号は単一換字式暗号の一種で、平文の各文字を3字分シフトして作る暗号のことです。例えばADBEに置換します。文字のシフト数は固定だが、3である必要はありません。

シフト数が26の倍数の場合、平文と同じになります。

シフトする数がすべての文字で同じなので、アルファベットで構成された文は26通りすべて総当りすることで簡単に破られます。

\[E_{n}(x)=(x+n) \quad \rm{mod} \quad 26\] \[D_{n}(x)=(x-n) \quad \rm{mod} \quad 26\]

シーザー暗号の解析

シーザー暗号で暗号化されていることがわかっている場合、26パターンしかないので総当たりをすることで解読することができます。

以下のプログラムで全パターンを出力することができ、その結果の中から暗号化する前の文字列を見つけることができます。

UWSC
DIM str = "シーザー暗号で暗号化した文字列"

FOR i = 1 TO 26
	PRINT i + "<#TAB>" + Cipher.Caesar.decode(str, i)
NEXT

例えばWklv lv d shq.という文字列を解析したい場合は、以下のプログラムで全パターンを出力します。出力された結果の中から、出力された平文を順に調べていくと3番目のThis is a pen.が元の文だということがわかります。

UWSC
DIM str = "Wklv lv d shq."

FOR i = 1 TO 26
	PRINT i + "<#TAB>" + Cipher.Caesar.decode(str, i)
NEXT
結果
復号シフト取得される平文
1Vjku ku c rgp.
2Uijt jt b qfo.
3This is a pen.
4Sghr hr z odm.
5Rfgq gq y ncl.
6Qefp fp x mbk.
7Pdeo eo w laj.
8Ocdn dn v kzi.
9Nbcm cm u jyh.
10Mabl bl t ixg.
11Lzak ak s hwf.
12Kyzj zj r gve.
13Jxyi yi q fud.
14Iwxh xh p etc.
15Hvwg wg o dsb.
16Guvf vf n cra.
17Ftue ue m bqz.
18Estd td l apy.
19Drsc sc k zox.
20Cqrb rb j ynw.
21Bpqa qa i xmv.
22Aopz pz h wlu.
23Znoy oy g vkt.
24Ymnx nx f ujs.
25Xlmw mw e tir.
26Wklv lv d shq.

ROT13

ROT13は単一換字式暗号(シーザー暗号)の一種で、平文の各文字を13字分シフトして作る暗号のことです。例えばANBOに置換します。ROTate by 13 placesの略。暗号化と復号が同じ処理でとても単純なのもこの暗号の特徴。アルファベットが26文字であるのに対し、暗号化は13文字シフトするので2回処理をすると元の文に戻ります。

\[{\rm{ROT}}_{13}({\rm{ROT}}_{13}(x))={\rm{ROT}}_{26}(x)=x\]
UWSC
DIM str = "This is a pen."

PRINT Cipher.ROT13.encode(str)
結果
プレーンテキスト
Guvf vf n cra.

ROT13の解析

ROT13はアルファベットを13文字シフトしただけなので、もう一度ROT13で暗号化(13文字後ろにシフト)するか復号(13文字前にシフト)することで解析することができます。

UWSC
DIM str = "Guvf vf n cra."

PRINT Cipher.ROT13.encode(str)
PRINT Cipher.ROT13.decode(str)
結果
プレーンテキスト
This is a pen.
This is a pen.

ヴィジュネル暗号

アルファベットを0~25(a~z)の数値としてみれば、次の式が成り立ちます。ただし、\(P_{i}\)は平文の\(i\)文字目、\(K_{i}\)は鍵の\(i\)文字目、\(C_{i}\)は暗号文の\(i\)文字目です。

以下が、ヴィジュネル暗号は多表式の換字式暗号です。

\[C_{i}=(P_{i}+K_{i}) \quad \rm{mod} \quad 26\] \[P_{i}=(C_{i}-K_{i}) \quad \rm{mod} \quad 26\] .png

XOR暗号

XOR暗号とは、平文をバイナリデータと考えて、2進数の鍵とXORをとって暗号化する手法のことです。

XOR(排他的論理和)には、以下の特徴があります。

  • 与えられた2つの入力のうち片方が真・片方が偽のとき真を出力し、両方とも真もしくは偽のときは偽を出力する。
  • ビットごとの排他的論理和は特定ビットの反転操作なので、2回繰り返せばもとに戻る。

関連記事

MODULE化
QuotedPrintable関数 (自作関数)
Quoted-printableのエンコード・デコードを行います。
Base64関数 (自作関数)
Base64のエンコード・デコードを行います。
Morse関数 (自作関数)
モールス信号の符号化・復号を行います。