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
戻値
暗号化または復号した文字列

プログラム

//////////////////////////////////////////////////
// 【引数】
//   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進数 
// 【戻値】
//   10進数に変換した値 
//////////////////////////////////////////////////
FUNCTION binToDec(bin)
	dec = 0
	FOR n = 1 TO LENGTH(bin)
		dec = dec + COPY(bin, n, 1) * POWER(2, LENGTH(bin) - n)
	NEXT
	RESULT = dec
FEND

//////////////////////////////////////////////////
// 【引数】
//   dec : 10進数 
// 【戻値】
//   2進数に変換した値 
//////////////////////////////////////////////////
FUNCTION decToBin(dec)
	bin = ""
	REPEAT
		bin = (dec MOD 2) + bin
		dec = INT(dec/2)
	UNTIL dec = 0
	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

解説

  1. 2-20行目
    	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("Z")(変数sの文字が大文字ならば)
    ASC(s) >= ASC("a") AND ASC(s) <= ASC("z")(変数sの文字が小文字ならば)
    アルファベット以外の文字
    そのまま代入
  2. 21-39行目
    	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) <= ASC("Z")
    マイナスにならないように「+26」する。

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

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

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

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

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

  4. 43-45行目
    	FUNCTION ROT13.decode(str)
    		RESULT = Cipher.ROT13.encode(str)
    	FEND
    
    Cipher.ROT13.decode
    ROT13でデコードします。
    暗号化を2回行うと元に戻るので、再度ROT13でエンコード。
  5. 46-63行目
    	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行目
    	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行目
    	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行目
    	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暗号でデコードします。

プログラム実行例

シーザー暗号

DIM str = "info@example.com"
DIM Caesar = Cipher.Caesar.encode(str)
PRINT "暗号化<#TAB>" + Caesar
PRINT "復号<#TAB>" + Cipher.Caesar.decode(Caesar)

//////////////////////////////////////////////////
// 【引数】
//   bin : 2進数 
// 【戻値】
//   10進数に変換した値 
//////////////////////////////////////////////////
FUNCTION binToDec(bin)
	dec = 0
	FOR n = 1 TO LENGTH(bin)
		dec = dec + COPY(bin, n, 1) * POWER(2, LENGTH(bin) - n)
	NEXT
	RESULT = dec
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進数 
// 【戻値】
//   2進数に変換した値 
//////////////////////////////////////////////////
FUNCTION decToBin(dec)
	bin = ""
	REPEAT
		bin = (dec MOD 2) + bin
		dec = INT(dec/2)
	UNTIL dec = 0
	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
  1. udf.Cipher(2,4)
結果
暗号化 lqir@hadpsoh.frp
復号 info@example.com
解説
  1. 1行目
    DIM str = "info@example.com"
    
    暗号化する文字列をstrに代入します。
  2. 2行目
    DIM Caesar = Cipher.Caesar.encode(str)
    
    シーザー暗号でエンコード(暗号化)します。
  3. 3行目
    PRINT "暗号化<#TAB>" + Caesar
    
    暗号化した文字列を出力します。
  4. 4行目
    PRINT "復号<#TAB>" + Cipher.Caesar.decode(Caesar)
    
    復号した文字列を出力します。
-PR-

シーザー暗号

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

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

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

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

ROT13

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

\[{\rm{ROT}}_{13}({\rm{ROT}}_{13}(x))={\rm{ROT}}_{26}(x)=x\]

ヴィジュネル暗号

アルファベットを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\]

XOR暗号

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

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

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