PNG向けのLSB方式のsteganographyを書いた。
LSB方式とは
LSBとはleast significant bitの略で、末尾のビットのことである。LSB方式のsteganographyとはLSBを書き換えることで、あまり見た目に影響させずにデータを隠すものである。
コード
Python2、3両対応。RGBまたはRGBAなPNGにのみ対応。Pillowという画像処理ライブラリを使っている。
#!/usr/bin/env python # coding: UTF-8 import binascii from PIL import Image def stegano(source_path, message): ''' convert LSB steganography ''' img = Image.open(source_path) if img.mode in ('RGBA'): message_bit = str("{0:b}".format(int(binascii.hexlify(message.encode('UTF-8')), 16))) + '11111111111111110' old_data = img.getdata() new_data = [] counter = 0 for i, item in enumerate(old_data): # item is (r, g, b). int in tuple if counter < len(message_bit): if i % 2 == 0: new_red = int(str("{0:b}".format(item[0]))[:-1] + message_bit[counter], 2) item = (new_red, item[1], item[2]) counter += 1 elif i % 5 == 0: new_green = int(str("{0:b}".format(item[1]))[:-1] + message_bit[counter], 2) item = (item[0], new_green, item[2]) counter += 1 elif i % 11 == 0: pass else: new_blue = int(str("{0:b}".format(item[2]))[:-1] + message_bit[counter], 2) item = (item[0], item[1], new_blue) counter += 1 new_data.append(item) img.putdata(new_data) # change old_data to new_data img.save(source_path, "PNG") print('Completed!') else: print('failed') def unstegano(source_path): ''' extract str ''' img = Image.open(source_path) if img.mode in ('RGBA'): datas = img.getdata() binary = '' for i, item in enumerate(datas): # item is (r, g, b) if binary[-17:] != '11111111111111110': if i % 2 == 0: binary += str("{0:b}".format(item[0]))[-1] # red elif i % 5 == 0: binary += str("{0:b}".format(item[1]))[-1] # green elif i % 11 == 0: pass else: binary += str("{0:b}".format(item[2]))[-1] # blue else: break print(binascii.unhexlify(str("{0:x}".format(int(binary[:-17], 2)))).decode('UTF-8')) else: print('failed') if __name__ == '__main__': stegano('./test.png', 'kyapikyapisitai') unstegano('./test.png')
感想
bin()とかhex()を使うと先頭に0bや0xが、長くなると末尾にLがついてしまうが、.format()で変換することでつかなくなるという知見が得られた。あと、当たり前だけどデータ埋め込む際のアルゴリズムは、プログラムによって違うし、steganographyの検出は難しそうだなあと思った。また、LSB方式の他にBPCS方式という難しそうなのもあるので、それのコーディングにもチャレンジしたい。