用 Python 进行 Blowfish 加解密


=Start=

缘由:

简单整理一下 Blowfish 密码算法的相关知识,方便后面有需要的时候参考。

正文:

参考解答:

Blowfish 密码算法介绍

Blowfish是一个对称密钥分组密码算法,由 Bruce Schneier 于1993年设计。Blowfish算法由于分组长度太小已被认为不安全,Schneier更建议在现代应用中使用 Twofish 密码。或者使用 AES 算法进行加解密。

Schneier设计的Blowfish算法用途广泛,意在替代老旧的DES及避免其他算法的问题与限制。Blowfish刚刚研发出的时候,大部分其他加密算法是专利所有的或属于商业(政府)机密,所以发展起来非常受限制。Schneier则声明Blowfish的使用没有任何限制,任何国家任何人任何时候都可以随意使用Blowfish算法。

Blowfish的填充模式

块(分组)密码只能对固定长度的数据块进行处理,而消息的长度通常是可变的,因此不同的工作模式对应的填充模式不同,当您选择NONE不填充时,则要保证加密文本长度为8的倍数,否则出现解密/加密异常。

  • 填充区别:在ECB、CBC工作模式下最后一块要在加密前进行填充,其它不用选择填充模式;
  • 填充模式:Blowfish支持的填充模式为PKCS5、PKCS7和NONE。其中PKCS7标准是主流加密算法都遵循的数据填充算法。Blowfish标准规定的区块长度为固定值64Bit,推荐PKCS7。
Blowfish密钥KEY和初始化向量IV

初始化向量IV可以有效提升安全性,但是在实际的使用场景中,它不能像密钥KEY那样直接保存在配置文件或固定写死在代码中,一般正确的处理方式为:在加密端将IV设置为一个8位的随机值,然后和加密文本一起返给解密端即可。

  • 区块长度:Blowfish标准规定区块长度只有一个值,固定为64Bit,对应的字节为8位;
  • 密钥KEY:密钥长度区间为32-448,对应4-56位,该字段不能公开传输,用于加密和解密;
  • 初始化向量IV:该字段可以公开,用于将加密随机化。同样的明文被多次加密也会产生不同的密文,避免了较慢的重新产生密钥的过程,初始化向量与密钥相比有不同的安全性需求,因此IV通常无须保密。然而在大多数情况中,不应当在使用同一密钥的情况下两次使用同一个IV,一般初始化向量IV为8位的随机值。
Blowfish 的主要特点
  • Block Cipher: Blowfish is a block cipher encryption algorithm that operates on 64-bit blocks of plaintext at a time. Blowfish 是一种分块密码加密算法,每次对 64 位的明文块进行操作。
  • Symmetric Key Encryption: Blowfish uses a symmetric key encryption system, meaning that the same key is used for both encryption and decryption. Blowfish 使用对称密钥加密系统,这意味着加密和解密都使用相同的密钥。
  • Variable Key Size: Blowfish allows for variable key sizes of up to 448 bits, making it more secure compared to other encryption algorithms. Blowfish 允许高达 448 位的可变密钥大小,与其他加密算法相比更加安全。
  • Feistel Cipher: Blowfish uses the Feistel Cipher structure, which splits the plaintext into two halves and then iteratively encrypts each half using a series of mathematical operations. Blowfish 使用 Feistel 密码结构,它将明文分成两半,然后通过一系列数学运算对每一半进行迭代加密。

用 Python 进行 Blowfish 加解密

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

def blowfish_str(encrypt_or_decrypt, msg, key):
    if encrypt_or_decrypt == "encrypt":
        bs = Blowfish.block_size
        key = bytes(key, encoding='utf-8')
        cipher = Blowfish.new(key, Blowfish.MODE_CBC)
        plaintext = msg.encode('utf-8')
        plen = bs - len(plaintext) % bs
        padding = [plen]*plen
        padding = pack('b'*plen, *padding)
        ciphertext = cipher.iv + cipher.encrypt(plaintext + padding) #加密返回的数据类型是 bytes 类型
        return ciphertext

    elif encrypt_or_decrypt == "decrypt":
        bs = Blowfish.block_size
        key = bytes(key, encoding='utf-8')
        ciphertext = base64.b64decode(msg) #和加密之后的操作有关
        iv = ciphertext[:bs]
        ciphertext = ciphertext[bs:]
        cipher = Blowfish.new(key, Blowfish.MODE_CBC, iv)
        plaintext = cipher.decrypt(ciphertext) #解密返回的数据是 bytes 类型
        last_byte = plaintext[-1]
        plaintext = plaintext[:- (last_byte if type(last_byte) is int else ord(last_byte))]
        return plaintext

def encrypt_decrypt_blowfish():
    key = 'password_here'

    with open('raw_data.txt') as fp:
        plaintext = fp.read()
    ciphertext = blowfish_str('encrypt', plaintext, key)
    with open('data_blowfish_encrypt.txt','w') as fp:
        fp.write(base64.b64encode(ciphertext).decode())

    with open('data_blowfish_encrypt.txt') as fp:
        encrypt_data = fp.read()
    decrypt_data = blowfish_str('decrypt', encrypt_data, key)
    # decrypt_data = blowfish_str('decrypt', base64.b64encode(ciphertext), key)
    with open('data_blowfish_decrypt.txt','w') as fp:
        fp.write(decrypt_data.decode())
#encrypt_decrypt_blowfish
from Crypto.Cipher import Blowfish
from Crypto import Random

def encrypt(key, plaintext):
    iv = Random.new().read(Blowfish.block_size)
    cipher = Blowfish.new(key, Blowfish.MODE_CBC, iv)
    padded_plaintext = _pad_string(plaintext)
    ciphertext = cipher.encrypt(padded_plaintext)
    return iv + ciphertext

def decrypt(key, ciphertext):
    iv = ciphertext[:Blowfish.block_size]
    cipher = Blowfish.new(key, Blowfish.MODE_CBC, iv)
    padded_plaintext = cipher.decrypt(ciphertext[Blowfish.block_size:])
    plaintext = _unpad_string(padded_plaintext)
    return plaintext

def _pad_string(s):
    padding_size = Blowfish.block_size - len(s) % Blowfish.block_size
    padding = chr(padding_size) * padding_size
    return s + padding

def _unpad_string(s):
    padding_size = ord(s[-1])
    return s[:-padding_size]

key = b'secret_key'
plaintext = 'This is a secret message.'
encrypted_data = encrypt(key, plaintext)
print('Encrypted data:', encrypted_data.hex())
decrypted_data = decrypt(key, encrypted_data)
print('Decrypted data:', decrypted_data)
参考链接:

Blowfish (cipher)
https://en.wikipedia.org/wiki/Blowfish_(cipher)

Understanding Blowfish Encryption Algorithm | 2023 #有代码,nice
https://cyberw1ng.medium.com/understanding-blowfish-encryption-algorithm-2023-24eb8f69f85b

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

Blowfish
https://pycryptodome.readthedocs.io/en/latest/src/cipher/blowfish.html
https://pycryptodome.readthedocs.io/en/latest/src/cipher/classic.html#cbc-mode

Blowfish 加密算法
https://leeyuxun.github.io/Blowfish%E5%8A%A0%E5%AF%86%E7%AE%97%E6%B3%95.html

Blowfish加密算法
https://try8.cn/tool/cipher/blowfish

A simple Python implementation for Blowfish Encryption Algorithm
https://github.com/ananya2407/Blowfish-Algorithm

=END=


发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注