Java实现Blowfish/CBC可变加密及与在线工具兼容问题
I see exactly what's going on here—your code is almost there, but two key pieces are missing to match the website's behavior: random IV handling, and proper packaging of the IV with the ciphertext. Let's walk through this step by step:
1. Why Your Encryption Results Are Not Random
Blowfish in CBC mode produces identical ciphertexts when you use the same plaintext, key, and initialization vector (IV). Your code hardcodes a fixed IV ("12345678"), so every encryption run spits out the same result. To get different ciphertexts each time (while still being able to decrypt back to the original plaintext), you need to generate a random 8-byte IV for every encryption (Blowfish uses an 8-byte block size).
2. How codebeautify.org Handles Encryption
The site follows this standard secure workflow for CBC mode:
- Generates a random 8-byte IV for each encryption
- Encrypts the plaintext using Blowfish-CBC-PKCS5Padding with that random IV
- Concatenates the IV bytes + encrypted ciphertext bytes into a single byte array
- Encodes this combined array with Base64 to produce the final displayed ciphertext
- For decryption: Decodes the Base64 string, splits off the first 8 bytes as the IV, then uses that IV to decrypt the remaining bytes
Your error decrypting the site's ciphertext happens because you're using your fixed IV instead of extracting the random IV embedded in the site's ciphertext.
3. Updated Code to Match the Site's Behavior
Here's the revised Crypto class that implements the correct logic:
Encryption Method (Random IV + IV+Ciphertext Packaging)
import javax.crypto.Cipher; import javax.crypto.SecretKeySpec; import javax.crypto.spec.IvParameterSpec; import javax.xml.bind.DatatypeConverter; import java.security.SecureRandom; public class Crypto { private static final int BLOWFISH_BLOCK_SIZE = 8; // Blowfish uses 8-byte blocks private static final String CIPHER_CONFIG = "Blowfish/CBC/PKCS5Padding"; public static String enc(String content, String key) { String encryptedResult = ""; try { // Generate a random 8-byte IV byte[] iv = new byte[BLOWFISH_BLOCK_SIZE]; new SecureRandom().nextBytes(iv); // Initialize cipher with random IV SecretKeySpec keySpec = new SecretKeySpec(key.getBytes("UTF-8"), "Blowfish"); Cipher cipher = Cipher.getInstance(CIPHER_CONFIG); cipher.init(Cipher.ENCRYPT_MODE, keySpec, new IvParameterSpec(iv)); // Encrypt the plaintext byte[] ciphertext = cipher.doFinal(content.getBytes("UTF-8")); // Combine IV and ciphertext into one byte array byte[] ivPlusCiphertext = new byte[iv.length + ciphertext.length]; System.arraycopy(iv, 0, ivPlusCiphertext, 0, iv.length); System.arraycopy(ciphertext, 0, ivPlusCiphertext, iv.length, ciphertext.length); // Encode to Base64 for final output encryptedResult = DatatypeConverter.printBase64Binary(ivPlusCiphertext); System.out.println("-- Encrypted -----------"); System.out.println("-- Result: " + encryptedResult); } catch (Exception ex) { ex.printStackTrace(); } return encryptedResult; }
Decryption Method (Extract IV from Ciphertext)
public static String dec(String content, String key) { String decryptedResult = ""; try { // Decode the Base64 string to get IV + ciphertext bytes byte[] ivPlusCiphertext = DatatypeConverter.parseBase64Binary(content); // Split into IV (first 8 bytes) and ciphertext (remaining bytes) byte[] iv = new byte[BLOWFISH_BLOCK_SIZE]; byte[] ciphertext = new byte[ivPlusCiphertext.length - BLOWFISH_BLOCK_SIZE]; System.arraycopy(ivPlusCiphertext, 0, iv, 0, iv.length); System.arraycopy(ivPlusCiphertext, iv.length, ciphertext, 0, ciphertext.length); // Initialize cipher with extracted IV SecretKeySpec keySpec = new SecretKeySpec(key.getBytes("UTF-8"), "Blowfish"); Cipher cipher = Cipher.getInstance(CIPHER_CONFIG); cipher.init(Cipher.DECRYPT_MODE, keySpec, new IvParameterSpec(iv)); // Decrypt and convert to plaintext byte[] plaintextBytes = cipher.doFinal(ciphertext); decryptedResult = new String(plaintextBytes, "UTF-8"); System.out.println("-- Decrypted -----------"); System.out.println("-- Result: " + decryptedResult); } catch (Exception ex) { ex.printStackTrace(); } return decryptedResult; } }
Test the Code
public class Main { public static void main(String[] args) { // Test encryption: two runs produce different ciphertexts String ciphertext1 = Crypto.enc("Hello", "key123"); String ciphertext2 = Crypto.enc("Hello", "key123"); System.out.println("\nTwo different encryption results:"); System.out.println(ciphertext1); System.out.println(ciphertext2); // Test decryption: both ciphertexts decrypt to "Hello" Crypto.dec(ciphertext1, "key123"); Crypto.dec(ciphertext2, "key123"); // Now decrypt the ciphertext from codebeautify.org successfully Crypto.dec("08GCpwyZc+qGNuxSvXAD2A==", "key123"); } }
4. Confirming the Encoding Type
codebeautify.org uses Base64 encoding for the final output. The reason you didn't get matching results before is that your code only encoded the ciphertext, not the combined IV + ciphertext array. With the updated code, you'll produce Base64 strings in the exact same format as the site.
内容的提问来源于stack exchange,提问作者Chor Wai Chun

