You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

解密mIRC FiSH插件加密消息时遇Blowfish ECB块对齐错误求助

Fixing "Data must be aligned to block boundary in ECB mode" when decrypting mIRC FiSH messages

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:

  1. 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.
  2. Encrypt the padded plaintext with Blowfish in ECB mode.
  3. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 06:41:30