暗号化 PyCrypto

2016/07/26

PyCrypto2.6, Python2.7

Blowfishアルゴリズムを使った暗号化して、元に戻す(復号化)スクリプト。
ブロック暗号とか呼ばれるものは、暗号化した文字列を16倍との倍数だとか決まったブロック数にしなきゃいけない。

# -*- coding: utf-8 -*-

from Crypto.Cipher import Blowfish
from Crypto import Random
from struct import pack

plaintext = 'hello world!!'
key = 'password'
print('source: '+plaintext)

bs = Blowfish.block_size
iv = Random.new().read(bs)
cipher = Blowfish.new(key, Blowfish.MODE_CBC, iv)

plen = bs - divmod(len(plaintext),bs)[1]
padding = [plen]*plen
padding = pack('b'*plen, *padding)
ciphertext = cipher.encrypt(plaintext + padding)
print('encrypt: '+ciphertext)

cipher = Blowfish.new(key, Blowfish.MODE_CBC, iv)
msg = cipher.decrypt(ciphertext)

last_byte = msg[-1]
msg = msg[:- (last_byte if type(last_byte) is int else ord(last_byte))]
print('decrypt: '+msg)

ivの部分が同じでないといけないので、これだと同一プログラムの中でしか、復号化できないので、ivを一緒に保存しとかなきゃいけない。
初期化ベクトルっていうらしい。

ということで、暗号化した分にくっつけてしまう。

# -*- coding: utf-8 -*-

from Crypto.Cipher import Blowfish
from Crypto import Random
from struct import pack

plaintext = 'hello world!!'
key = 'password'

def encrypt(plaintext,key):
    bs = Blowfish.block_size
    iv = Random.new().read(bs)
    cipher = Blowfish.new(key, Blowfish.MODE_CBC, iv)
    plen = bs - divmod(len(plaintext),bs)[1]
    padding = [plen]*plen
    padding = pack('b'*plen, *padding)
    ciphertext = cipher.encrypt(plaintext + padding)
    msg = iv + ciphertext
    return msg

def decrypt(msg,key):
    bs = Blowfish.block_size
    iv = msg[:bs]
    ciphertext = msg[bs:]
    cipher = Blowfish.new(key, Blowfish.MODE_CBC, iv)
    msg = cipher.decrypt(ciphertext)
    last_byte = msg[-1]
    msg = msg[:- (last_byte if type(last_byte) is int else ord(last_byte))]
    return msg

def main():
    print('source: '+plaintext)
    msg = encrypt(plaintext,key)
    print('encrypt: '+msg)
    msg = decrypt(msg,key)
    print('decrypt: '+msg)

main()


How to decrypt using Blowfish in Pycrypto?
http://stackoverflow.com/questions/35042164/how-to-decrypt-using-blowfish-in-pycrypto


ブロックサイズにするためにpaddingをなにやら難しいことをしているけど、base64エンコードしてもいい感じにブロックサイズに合わせることが出来るらしい。あと、文字化けも防げるので、保存しやすい。ただ、画像とかでやるとデータ量が膨らむのでよくないらしい。

# -*- coding: utf-8 -*-

from Crypto.Cipher import Blowfish
from Crypto import Random
from struct import pack

import base64

plaintext = 'hello'
key = 'password'
print('source: '+plaintext)

cipher = Blowfish.new(key, Blowfish.MODE_ECB)

plaintext = base64.b64encode(plaintext)
ciphertext = cipher.encrypt(plaintext)
ciphertext = base64.b64encode(ciphertext)
print('encrypt: '+ciphertext)

cipher = Blowfish.new(key, Blowfish.MODE_ECB)
ciphertext = base64.b64decode(ciphertext)
msg = cipher.decrypt(ciphertext)
msg = base64.b64decode(msg)
print('decrypt: '+msg)

ECBモードだと初期ベクトルは関係ないそうな(セキュリティ的には弱い)。