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
結果
暗号化 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)
    復号した文字列を出力します。

シーザー暗号

シーザー暗号は単一換字式暗号の一種で、平文の各文字を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回繰り返せばもとに戻る。