t-hom’s diary

主にVBAネタを扱っているブログ…とも言えなくなってきたこの頃。

VBA ビット演算で文字列を暗号化(XOR暗号)

前回ビット演算を紹介した。

thom.hateblo.jp

ビット演算にはANDとORのほかにも色々あり、そのうちのひとつがXOR(排他的論理輪:はいたてきろんりわ)である。

これは、与えられた2つのビットのうち、どちらか片方が1でもう片方が0のときに、1になる。

全ケース書き出すと、以下のようになる。
1 Xor 1 = 0
1 Xor 0 = 1
0 Xor 1 = 1
0 Xor 0 = 0

このXOR演算には、あるビット列Aに対し、別のビット列BをXor演算させると暗号化され、もう一度ビット列BをXorさせると元のビット列Aにもどる性質がある。
文書ではよく分らないと思うのでやってみよう。

ビット列A 11110000
ビット列B 01010101
Xor結果 10100101

Xor結果を仮に、ビット列Cとしておこう。
ビット列C:10100101

ビット列Cから、元のビット列Aは推測できない。

しかし、ビット列Cにもう一度ビット列BをXORしてやると、ビット列Aにもどる。

ビット列C 10100101
ビット列B 01010101
Xor結果 11110000

この性質を利用した暗号化が、XOR暗号である。
平文にパスワードをXorすると暗号文が得られる。
暗号文にもう一度パスワードをXorすると復号化できるという原理だ。


VBAで再現したのがこちら

Sub XOR暗号サンプル()
    '■平文とパスワードを準備
    平文 = "これは平文です。"
    パスワード = "pass"
    
    '■パスワードを平文の長さに切りそろえ
    Do While Len(平文) > Len(パスワード)
        パスワード = パスワード & パスワード
    Loop
    パスワード = Left(パスワード, Len(平文))
    
    '■暗号文を出力
    暗号文 = ""
    For i = 1 To Len(平文)
        暗号文 = 暗号文 & CStr(Asc(Mid(平文, i, 1)) Xor Asc(Mid(パスワード, i, 1))) & " "
    Next
    Debug.Print "暗号文は:" & 暗号文
    
    '■復号化された平文を出力
    暗号配列 = Split(暗号文, " ")
    復号文 = ""
    For j = LBound(暗号配列) To UBound(暗号配列) - 1
        復号文 = 復号文 & Chr(CLng(暗号配列(j)) Xor Asc(Mid(パスワード, j + 1, 1)))
    Next j
    Debug.Print 復号文
End Sub

※解説用なので変数は宣言せずに使用しています。実際に利用される場合は変数宣言してください。

まず、平文とパスワードの長さを揃えておく。
パスワード長が平文の長さに達するまで足し合わせて、それからLeftで切り揃えている。

それから、平文とパスワードから一文字ずつ取り出し、Asc関数で文字コードに変えてからXorしていく。
それをスペース区切りで足し合わせたものを暗号文とし、解読の前にはスペースでSplitして暗号配列としておく。

そして暗号配列とパスワードから一文字ずつ取り出しながら、Xorして平文の文字コードを得て、Chr関数で文字に戻していく。
最後に、つなぎ合わせた復号文を表示させて完了。

以前に紹介したシーザー暗号は、それ単体で解読されてしまう危険をはらんでいるが、XOR暗号はパスワードがバレない限り、シーザー暗号よりは安全である。
thom.hateblo.jp

ただし、パスワードを推測する方法は存在するのでこちらも簡易暗号程度に考えておこう。

関連記事

ビット演算の応用で、2つの画像の差分を取り出すマクロを紹介しています。
thom.hateblo.jp

当ブログは、amazon.co.jpを宣伝しリンクすることによってサイトが紹介料を獲得できる手段を提供することを目的に設定されたアフィリエイト宣伝プログラムである、 Amazonアソシエイト・プログラムの参加者です。