解密mIRC FiSH插件加密消息时遇Blowfish ECB块对齐错误求助
Let's break down your problem and fix that error step by step. First, the core issue here is that Blowfish in ECB mode requires input data to be exactly a multiple of its block size (8 bytes). The error you're seeing means the data you're passing to the decryption function doesn't meet this requirement—and it's probably tied to a mix-up in how FiSH actually handles encryption, or missing padding logic.
First, Clarify the Real FiSH Encryption Flow
From what I know of the mIRC FiSH plugin, its standard encryption workflow is not "Base64 first, then Blowfish". It's actually the opposite:
- Take the plaintext and apply PKCS#5/PKCS#7 padding (since Blowfish uses 8-byte blocks, these two padding methods work identically here) to make the plaintext length a multiple of 8 bytes.
- Encrypt the padded plaintext with Blowfish in ECB mode.
- Base64-encode the encrypted bytes to get the final, shareable ciphertext.
If you were following the wrong order (Base64 first, then encrypt), that's likely why your decryption is failing—because the Base64-encoded plaintext might not be an 8-byte multiple, and without padding, the encryption step would have broken things before you even got to decryption.
Solution 1: Decrypting Standard FiSH Ciphertexts
Here's the correct Python code to decrypt messages encrypted with the standard FiSH workflow:
from Crypto.Cipher import Blowfish from Crypto.Util.Padding import unpad import base64 def decrypt_fish(ciphertext_b64, key): # Step 1: Decode the Base64 ciphertext to get raw encrypted bytes ciphertext = base64.b64decode(ciphertext_b64) # Sanity check: Ensure we have a valid block size multiple if len(ciphertext) % Blowfish.block_size != 0: raise ValueError("Ciphertext is corrupted or not properly formatted (block size mismatch)") # Step 2: Initialize Blowfish ECB cipher cipher = Blowfish.new(key.encode('utf-8'), Blowfish.MODE_ECB) # Step 3: Decrypt and remove padding to get the original plaintext padded_plaintext = cipher.decrypt(ciphertext) plaintext = unpad(padded_plaintext, Blowfish.block_size) return plaintext.decode('utf-8') # Example usage (replace with your actual ciphertext and key) secret_key = "your_fish_secret_key" fish_ciphertext = "your_base64_encoded_ciphertext" try: decrypted = decrypt_fish(fish_ciphertext, secret_key) print(f"Decrypted message: {decrypted}") except Exception as e: print(f"Decryption failed: {str(e)}")
Solution 2: If You Did Use "Base64 First, Then Blowfish"
If you intentionally reversed the workflow (for some custom use case), you need to make sure you added padding before encryption—and reverse those steps properly during decryption. Here's how that would work:
Encryption Code (for your custom workflow)
from Crypto.Cipher import Blowfish from Crypto.Util.Padding import pad import base64 def encrypt_custom(plaintext, key): # Step 1: Base64-encode the plaintext plaintext_b64 = base64.b64encode(plaintext.encode('utf-8')) # Step 2: Pad the Base64 bytes to an 8-byte multiple padded_data = pad(plaintext_b64, Blowfish.block_size) # Step 3: Encrypt with Blowfish ECB cipher = Blowfish.new(key.encode('utf-8'), Blowfish.MODE_ECB) encrypted_bytes = cipher.encrypt(padded_data) # Step 4: Base64-encode the encrypted bytes for storage/sharing return base64.b64encode(encrypted_bytes).decode('utf-8') # Test with your sample plaintext test_plaintext = "Probando un mensaje cifrado" custom_key = "your_custom_key" custom_ciphertext = encrypt_custom(test_plaintext, custom_key) print(f"Custom encrypted ciphertext: {custom_ciphertext}")
Corresponding Decryption Code
from Crypto.Cipher import Blowfish from Crypto.Util.Padding import unpad import base64 def decrypt_custom(ciphertext_b64, key): # Step 1: Decode the Base64 ciphertext to get encrypted bytes ciphertext = base64.b64decode(ciphertext_b64) if len(ciphertext) % Blowfish.block_size != 0: raise ValueError("Ciphertext length doesn't match Blowfish block size") # Step 2: Decrypt the bytes cipher = Blowfish.new(key.encode('utf-8'), Blowfish.MODE_ECB) padded_b64_bytes = cipher.decrypt(ciphertext) # Step 3: Remove padding to get the original Base64-encoded plaintext plaintext_b64 = unpad(padded_b64_bytes, Blowfish.block_size) # Step 4: Base64-decode to get the final plaintext return base64.b64decode(plaintext_b64).decode('utf-8') # Test decryption try: decrypted_msg = decrypt_custom(custom_ciphertext, custom_key) print(f"Decrypted custom message: {decrypted_msg}") except Exception as e: print(f"Custom decryption failed: {str(e)}")
Key Takeaways
- Always remember: Blowfish ECB requires input data to be a multiple of 8 bytes. Padding fixes this during encryption, and unpadding reverses it during decryption.
- Double-check the FiSH workflow—most users stick to the standard "pad → encrypt → Base64" order, so that's the first thing to verify if you're hitting block size errors.
- Ensure your ciphertext isn't truncated or corrupted—even a single missing byte will break the block alignment.
内容的提问来源于stack exchange,提问作者bausshal bausshal

