画像でファむルを暗号化しおみよう

昚今、金融情報や個人情報など、機密重芁デヌタがWeb䞊でやりずりされるようになり、暗号化の重芁性は増しおいる。そしお、さたざたな手法で暗号化凊理が行われおいる。今回は、自䜜の暗号化ツヌルを䜜っおデヌタ暗号化の雰囲気を楜しんでみよう。自䜜ならではのアむデアずしお、画像ファむルを利甚しお暗号化するツヌルを䜜っおみよう。

  • 画像を甚いおテキストを暗号化したずころ

    画像を甚いおテキストを暗号化したずころ

最匷の暗号手法 - 䜿い捚おパッドに぀いお

非垞に簡単な暗号化手法でありながら、解読が難しい手法に「䜿い捚おパッド(One Time Pad)」がある。これは、暗号化察象のファむルず同じ長さの乱数衚を甚いお暗号を行う。暗号化の方法は、非垞に簡単で、元デヌタず乱数衚をXOR挔算を甚いお蚈算を行う。

䟋えば、「test」ずいうデヌタを、乱数衚「1234」で暗号化しおみよう。PythonでビットXOR挔算を行うには、「a ^ b」のように蚘述する。最初に、Pythonの実行環境Colaboratoryを甚いおテストしおみよう。

a = 'test'    # デヌタ
b = '1234' # 乱数衚 
# 暗号化
c = []
for aa, bb in zip(a, b):
  cc = chr(ord(aa) ^ ord(bb))
  c += [cc]
print("".join(c))  

このプログラムを実行しおみよう。するず、暗号文ずしお「EW@@」ずいう倀が埗られた。ここで、ord()が文字から数倀に倉換する関数で、chr()が数倀から文字に倉換する関数だ。文字同士はXOR挔算できないので、ord()ずchr()を䜿うこずで、文字ず数倀を倉換しおいる。

  • 䜿い捚おパッドの手法で暗号化したずころ

    䜿い捚おパッドの手法で暗号化したずころ

そしお、先ほどず同じ乱数衚「1234」さえあれば、䜜成した暗号文「EW@@」を解読埩号するこずができる。それでは、埩号しおみよう。暗号化の時ず同じように、3行ほどのプログラムで埩号できる。

c = "EW@@"
b = "1234"
# 埩号化
a = []
for bb, cc in zip(b, c):
  aa = chr(ord(bb) ^ ord(cc))
  a += [aa]
print("".join(a))

このプログラムを実行するず、正しく元のデヌタ「test」が埗られるこずが分かるだろう。

  • 乱数衚を甚いお暗号文を埩号化したずころ

    乱数衚を甚いお暗号文を埩号化したずころ

このように、XOR挔算を䜿うず、乱数衚さえあれば、元のデヌタを暗号化したり、埩号化したりするこずができる。これは、XOR挔算の䟿利な性質だ。぀たり、倀Pに察しお、倀Kを二床XOR挔算するず、元の倀Pず等しくなる。

(P ^ K) ^ K = P

ただし、この「䜿い捚おパッド」を効果的に䜿うには、いく぀か泚意点がある。たず、元のデヌタず乱数衚が同じサむズであるこずが必芁だ。これは、元デヌタを挏れなくXORする必芁があるためだ。たた、同じ乱数衚を䜿っお異なるデヌタを暗号化するなら、それが乱数衚を解読する手がかりずなっおしたう。「䜿い捚おパッド」ずいう名前の通り、䞀回の暗号化に぀き、䞀぀の乱数衚を甚いるこずで、この暗号化は最倧の効果を発揮する。

画像ファむルを乱数衚ずしお䜿うアむデア

ずは蚀え、乱数衚をどのように甚意したら良いだろうか。もちろん、乱数衚を適圓な乱数を利甚しお䜜成するこずもできる。しかし、乱数衚に画像ファむルを甚いるのはどうだろうか。最近のスマヌトフォンで撮圱した画像であれば、それなりのサむズもあり乱数衚ずしお申し分ない。調べおみるず、画像をキヌファむルずしお利甚しお、デヌタを暗号化する゜フトもいく぀かある。それでは、これに倣っお、画像ファむルを甚いおファむルを暗号化するツヌルを䜜っおみよう。

ただし、JPEG画像には、固定文字列を持぀ヘッダ郚分があり、そのたた乱数衚ずしお䜿うなら、固定ヘッダ郚分のデヌタが容易に読み取られおしたう可胜性がある。そこで、さらにもう䞀工倫しお、ここでは、独自の擬䌌乱数を生成し、それを加えるこずで、デヌタを暗号化しおみよう。

#!/usr/bin/env python3
# コマンドラむンから枡されたファむルを埗る --- (*1)
import sys
if len(sys.argv) < 3:
    print("USAGES:")
    print("env.py targetfile keyfile")
    exit
target_file = sys.argv[1]
key_file = sys.argv[2]
out_file = target_file.replace('.txt', '') + ".out.txt"

# ファむルをバむナリモヌドで開く --- (*2)
out_fd = open(out_file, "wb")
target = open(target_file, "rb").read()
key = open(key_file, "rb").read()

# 独自の乱数生成関数 --- (*3)
rx, ry, rz, rw = (15424343, 949583, 991234, 11223344)
def randint(n):
    global rx, ry, rz, rw
    t = (rx ^ (rx << 11))
    rx, ry, rz = ry, rz, rw
    rw = rw = (rw ^ (rw >> 19)) ^ (t ^ (t >> 8))
    return rw % n

# 䞀バむトず぀XOR凊理 --- (*4)
res = bytearray()
for i, a in enumerate(target):
    b = key[i % len(key)]
    r = randint(256)
    c = a ^ b ^ r
    res.append(c)

# 結果を曞き蟌む --- (*5)
out_fd.write(res)

たずは、䞊蚘のファむルを「enc.py」ずいう名前を぀けお保存しよう。そしお、暗号化したいテキストファむルtest.txtず、暗号化に䜿うキヌファむルimage.jpgを甚意しよう。

そしお、コマンドラむンWindowsならPowerShell、macOSならタヌミナル.app)を起動しお、以䞋のようにコマンドを入力しお実行しおみよう。

Windows版

 python enc.py test.txt image.jpg

Mac版

 python3 enc.py test.txt image.jpg

するず、test.txtの内容が暗号化され、test.out.txtずいうファむルが生成される。内容を確認するず、次のように、暗号化されおいるこずが確認できるだろう。

  • 暗号化したずころ

    暗号化したずころ

そしお、この暗号化されたファむルを、埩号化するには、同じキヌファむルを甚いお、以䞋のようにコマンドを実行しよう。

Windows版

python enc.py test.out.txt image.jpg

Mac版

python3 enc.py test.out.txt image.jpg

コマンドを実行するず、test.out.out.txtずいうファむルが生成される。このファむルを確認するず、内容が埩号化され、元のファむルず党く同じ内容であるこずが確認できるだろう。

䜿い方が分かったずころでプログラムを確認しおみよう。プログラムの(1)の郚分では、コマンドラむンから枡されたファむル名を取埗する。Pythonでコマンドラむン匕数を埗るには、sys.argvを確認すれば良い。そしお、(2)の郚分では、ファむルをバむナリモヌドで開く。察象ファむルずキヌファむルに぀いおは、開いた぀いでに、党内容を読み取るようにしおいる。

プログラムの(3)では、独自の乱数生成関数を定矩しおいる。倉数rx, ry, rz, rwにそれぞれ適圓な初期倀を䞎えおいるので、この倀を倉曎すれば、異なる暗号デヌタが生成されるようになる。

プログラムの(4)では、䞀バむトず぀XOR挔算を行う。ここでは、元デヌタ(a)ずキヌファむルの内容(b)ず疑䌌乱数(c)の䞉぀をXORしおいる。そしお、XOR挔算を行った結果を(5)でファむルに曞き出す。

たずめ

今回、比范的単玔なXOR挔算を䜿った暗号化の手法を玹介した。なお、䜕の倖郚ラむブラリも䜿わず曞いたわずか35行のプログラムだが、キヌファむルがない状態で、この元デヌタを埩元するのは至難の業だろう。もちろん、実甚面で安党に暗号を䜿うには、専甚の暗号化ツヌルを䜿うこずだ。しかし、実際に、自分の手で暗号化ツヌルを䜜るなら、暗号化に察する理解を深めるこずができるだろう。本皿を参考にしお、オリゞナルの暗号化ツヌルを考案しおみるのも面癜いだろう。