在 Java 中实现 IllegalBlockSizeException 的解决方案?
Implementing solution to IllegalBlockSizeException in Java?
我正在尝试修复我的代码。在我的代码中,我试图生成一个我已经完成的 16 位密钥。其次,生成一条随机消息,这也已完成。加密和解密我收到错误的数据。最后有一个蛮力算法来解密我稍后会尝试做的消息。因此,对于我的加密,代码对其进行加密但不对随机生成的字符串进行加密。我遇到了一堆错误。
我的代码:
import java.util.Random;
import java.security.Security;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
public class Assignment1Demo {
private static String msg;
private static String msgE;
private static String msgD;
private static int key;
public static void main(String[] args){
//TODO: You can only call methods in main method
key = generateKey();
msg = generateMsg();
msgE = encryption(key,msg);
bruteForce(msgE);
}
private static int generateKey() {
//TODO: implement step a (randomly generate 16-bit key)
//16 bit digit means 2^16 -1 in decimal
Random rand = new Random();
return rand.nextInt((int) (Math.pow(2, 16)-1));
}
private static String generateMsg() {
//TODO: implement step b (randonly generate a string with an even number of characters)
String chractersU="ABCDEFGHIJKLMNOPQRSTUVWXYZ";
String chractersL=chractersU.toLowerCase();
String space=" ";
String alphanum=chractersU+space+chractersL;
String random="";
int length=alphanum.length();
Random rand=new Random();
char[] text=new char[length];
for(int i=0;i<length;i++) {
text[i]=alphanum.charAt(rand.nextInt(alphanum.length()));
}
for(int i=0;i<text.length/2;i++) {
if(text.length%2!=0) {
random += text[i];
}}
return random;
}
private static String encryption (int key, String msg) {
//TODO: implement step c (encrypt the message)
String strData="";
String strKey=Integer.toString(key);
try {
SecretKeySpec skeyspec=new SecretKeySpec(strKey.getBytes(),"Blowfish");
Cipher cipher=Cipher.getInstance("Blowfish");
cipher.init(Cipher.ENCRYPT_MODE, skeyspec);
byte[] encrypted=cipher.doFinal(msg.getBytes());
strData=new String(encrypted);
} catch (Exception e) {
e.printStackTrace();
}
return strData;
}
private static void decryption(int key, String msgE) {
//TODO: implement step d (decryption)
String strKey = Integer.toString(key);
String strData="";
try {
SecretKeySpec skeyspec=new SecretKeySpec(strKey.getBytes(),"Blowfish");
Cipher cipher=Cipher.getInstance("Blowfish");
cipher.init(Cipher.DECRYPT_MODE, skeyspec);
byte[] decrypted=cipher.doFinal(msgE.getBytes());
strData=new String(decrypted);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(strData);
}
private static void bruteForce(String msgE) {
//TODO: implement bruteForce algorithm, you may need the above decryption(key,msgE) method
boolean isEnglisString = msgE.matches("[a-zA-Z]+");
if(isEnglisString)
System.out.println("Yes encrypted message is Randomly English generated message " + msgE);
else
System.out.println("encrypted message is Not Randomly english generated message "+msgE);
decryption(key, msgE);
isEnglisString = msgD.matches("[a-zA-Z]+");
if(isEnglisString)
System.out.println("Yes decrypted message is Randomly english generated message "+ msgD);
else
System.out.println("decrypted message is not Randomly english generated message "+ msgD);
}}
错误:
javax.crypto.IllegalBlockSizeException: Input length must be multiple of 8 when decrypting with padded cipher
at java.base/com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:936)
at java.base/com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:847)
at java.base/com.sun.crypto.provider.BlowfishCipher.engineDoFinal(BlowfishCipher.java:319)
at java.base/javax.crypto.Cipher.doFinal(Cipher.java:2189)
at Assignment1Demo.decryption(Assignment1Demo.java:110)
at Assignment1Demo.bruteForce(Assignment1Demo.java:132)
at Assignment1Demo.main(Assignment1Demo.java:30)
Exception in thread "main" java.lang.NullPointerException
at Assignment1Demo.bruteForce(Assignment1Demo.java:133)
at Assignment1Demo.main(Assignment1Demo.java:30)
您的字符串是随机生成的,但是当块大小与密码预期的不匹配时,您需要应用可接受的填充算法,以便输入的大小与算法保持一致。这适用于所有分组密码。
这个例子是一个简单的密码计,而不是可以使用类似算法的东西
"AES/CBC/PKCS5Padding"
"RC2/CBC/PKCS5Padding"
“DESede/CBC/PKCS5Padding
(PKCS#5 填充是为 8 字节块大小定义的)
@Override
public SimpleMeter testEncryption(File baseInput, String algorithm, String provider) throws NoSuchProviderException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException {
Cipher cipherEncryption;
SimpleMeter meter = new SimpleMeter();
SecureRandom randGenerator = new SecureRandom();
KeyGenerator generator;
generator = KeyGenerator.getInstance(algorithm.split("/")[0], provider);
generator.init(randGenerator);
SecretKey key = generator.generateKey();
cipherEncryption = Cipher.getInstance(algorithm, provider);
cipherEncryption.init(Cipher.ENCRYPT_MODE, key);
try (BufferedInputStream input = new BufferedInputStream(new FileInputStream(baseInput))) {
CipherInputStream encryptionStream = new CipherInputStream(input, cipherEncryption);
meter.start();
while (encryptionStream.read() > -1);
encryptionStream.close();//End all encryption and decryption operation
meter.stop();
} catch (Exception ex) {
ex.printStackTrace();
meter = null;
}
return meter;
}
另一个没有流的例子:
cipher = Cipher.getInstance("Blowfish/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] decrypted = cipher.doFinal(encryptedString.getBytes(CHARSET_ISO_8859_1));
decryptedString = new String(decrypted, CHARSET_ISO_8859_1);
确实没有必要,但是如果你想用base64,你可以找Apache:
http://commons.apache.org/proper/commons-codec/
使用您的代码的示例
1) 欧洲央行模式
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.util.Random;
public class Assignment1Demo {
private static String msg;
private static byte[] msgE;
private static String msgD;
private static int key;
public static void main( String[] args ) {
//TODO: You can only call methods in main method
key = generateKey( );
msg = generateMsg( );
msgE = encryption( key, msg );
bruteForce( msgE );
}
private static int generateKey( ) {
//TODO: implement step a (randomly generate 16-bit key)
//16 bit digit means 2^16 -1 in decimal
Random rand = new Random( );
return rand.nextInt( ( int ) ( Math.pow( 2, 16 ) - 1 ) );
}
private static String generateMsg( ) {
//TODO: implement step b (randonly generate a string with an even number of characters)
String chractersU = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
String chractersL = chractersU.toLowerCase( );
String space = " ";
String alphanum = chractersU + space + chractersL;
String random = "";
int length = alphanum.length( );
Random rand = new Random( );
char[] text = new char[ length ];
for ( int i = 0; i < length; i++ ) {
text[ i ] = alphanum.charAt( rand.nextInt( alphanum.length( ) ) );
}
for ( int i = 0; i < text.length / 2; i++ ) {
if ( text.length % 2 != 0 ) {
random += text[ i ];
}
}
return random;
}
private static byte[] encryption( int key, String msg ) {
//TODO: implement step c (encrypt the message)
byte[] encrypted =new byte[]{};
String strKey = Integer.toString( key );
try {
SecretKeySpec skeyspec = new SecretKeySpec( strKey.getBytes( ), "Blowfish" );
Cipher cipher = Cipher.getInstance("Blowfish/ECB/PKCS5Padding");
cipher.init( Cipher.ENCRYPT_MODE, skeyspec );
encrypted = cipher.doFinal( msg.getBytes( ) );
}
catch ( Exception e ) {
e.printStackTrace( );
}
return encrypted;
}
private static void bruteForce( byte[] msgE ) {
//TODO: implement bruteForce algorithm, you may need the above decryption(key,msgE) method
decryption( key, msgE );
}
private static void decryption( int key, byte[] msgE ) {
//TODO: implement step d (decryption)
String strKey = Integer.toString( key );
String strData = "";
try {
SecretKeySpec skeyspec = new SecretKeySpec( strKey.getBytes( ), "Blowfish" );
Cipher cipher = Cipher.getInstance("Blowfish/ECB/PKCS5Padding");
cipher.init( Cipher.DECRYPT_MODE, skeyspec );
byte[] decrypted = cipher.doFinal( msgE);
strData = new String( decrypted );
}
catch ( Exception e ) {
e.printStackTrace( );
}
System.out.println( strData );
}
}
示例 2) 使用 CBC 模式的代码
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.security.AlgorithmParameters;
import java.util.Random;
public class Assignment1Demo {
private static String msg;
private static byte[] msgE;
private static String msgD;
private static int key;
private static byte[] encodedParams;
public static void main( String[] args ) {
//TODO: You can only call methods in main method
key = generateKey( );
msg = generateMsg( );
msgE = encryption( key, msg );
bruteForce( msgE );
}
private static int generateKey( ) {
//TODO: implement step a (randomly generate 16-bit key)
//16 bit digit means 2^16 -1 in decimal
Random rand = new Random( );
return rand.nextInt( ( int ) ( Math.pow( 2, 16 ) - 1 ) );
}
private static String generateMsg( ) {
//TODO: implement step b (randonly generate a string with an even number of characters)
String chractersU = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
String chractersL = chractersU.toLowerCase( );
String space = " ";
String alphanum = chractersU + space + chractersL;
String random = "";
int length = alphanum.length( );
Random rand = new Random( );
char[] text = new char[ length ];
for ( int i = 0; i < length; i++ ) {
text[ i ] = alphanum.charAt( rand.nextInt( alphanum.length( ) ) );
}
for ( int i = 0; i < text.length / 2; i++ ) {
if ( text.length % 2 != 0 ) {
random += text[ i ];
}
}
return random;
}
private static byte[] encryption( int key, String msg ) {
//TODO: implement step c (encrypt the message)
byte[] encrypted =new byte[]{};
String strKey = Integer.toString( key );
try {
SecretKeySpec skeyspec = new SecretKeySpec( strKey.getBytes( ), "Blowfish" );
Cipher cipher = Cipher.getInstance("Blowfish/CBC/PKCS5Padding");
cipher.init( Cipher.ENCRYPT_MODE, skeyspec );
encrypted = cipher.doFinal( msg.getBytes( ) );
encodedParams = cipher.getParameters().getEncoded();
}
catch ( Exception e ) {
e.printStackTrace( );
}
return encrypted;
}
private static void bruteForce( byte[] msgE ) {
//TODO: implement bruteForce algorithm, you may need the above decryption(key,msgE) method
decryption( key, msgE );
}
private static void decryption( int key, byte[] msgE ) {
//TODO: implement step d (decryption)
String strKey = Integer.toString( key );
String strData = "";
try {
SecretKeySpec skeyspec = new SecretKeySpec( strKey.getBytes( ), "Blowfish" );
Cipher cipher = Cipher.getInstance("Blowfish/CBC/PKCS5Padding");
AlgorithmParameters params = AlgorithmParameters.getInstance("Blowfish");
params.init(encodedParams);
cipher.init( Cipher.DECRYPT_MODE, skeyspec, params );
byte[] decrypted = cipher.doFinal( msgE);
strData = new String( decrypted );
}
catch ( Exception e ) {
e.printStackTrace( );
}
System.out.println( strData );
}
}
简而言之,您正在使用加密的二进制数据并假设它是有效文本,但一般来说它不会。
您可以使用 UTF-8 编码将字符串编码为 byte[],但并非所有可能的 byte[] 编码都是有效的字符串。加密数据时,可以使用任何可能的字节,但不能总是使用标准字符编码将其转换为字符串。这可能会导致数据长度发生变化,这就是为什么它不再像数据编码时那样是 8 的倍数。
将数据编码为可打印字符串的一种简单方法是使用 Base64 编码。
在encryption
中使用
strData = DatatypeConverter.printBase64Binary(encrypted);
并在 decryption
中使用
byte[] decrypted=cipher.doFinal(DatatypeConverter.parseBase64Binary(msgE));
这样您将始终尝试解密您编写的二进制数据。
另一种选择是不尝试将二进制数据存储在字符串中,而只使用原始 byte[]
EDIT 你能试试这个吗,使用 byte[]
而不是 String
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
public class A {
public static void main(String... args) {
String text = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
for (int i = 0; i < text.length(); i++) {
byte[] encrypt = encryption(1, text.substring(0, i));
String hello = decryption(1, encrypt);
System.out.println(hello);
}
}
private static byte[] encryption(int key, String msg) {
String strKey = Integer.toString(key);
try {
SecretKeySpec skeyspec = new SecretKeySpec(strKey.getBytes(), "Blowfish");
Cipher cipher = Cipher.getInstance("Blowfish");
cipher.init(Cipher.ENCRYPT_MODE, skeyspec);
return cipher.doFinal(msg.getBytes(StandardCharsets.UTF_8));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private static String decryption(int key, byte[] msgE) {
String strKey = Integer.toString(key);
try {
SecretKeySpec skeyspec = new SecretKeySpec(strKey.getBytes(), "Blowfish");
Cipher cipher = Cipher.getInstance("Blowfish");
cipher.init(Cipher.DECRYPT_MODE, skeyspec);
byte[] decrypted = cipher.doFinal(msgE);
return new String(decrypted, StandardCharsets.UTF_8);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
我正在尝试修复我的代码。在我的代码中,我试图生成一个我已经完成的 16 位密钥。其次,生成一条随机消息,这也已完成。加密和解密我收到错误的数据。最后有一个蛮力算法来解密我稍后会尝试做的消息。因此,对于我的加密,代码对其进行加密但不对随机生成的字符串进行加密。我遇到了一堆错误。
我的代码:
import java.util.Random;
import java.security.Security;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
public class Assignment1Demo {
private static String msg;
private static String msgE;
private static String msgD;
private static int key;
public static void main(String[] args){
//TODO: You can only call methods in main method
key = generateKey();
msg = generateMsg();
msgE = encryption(key,msg);
bruteForce(msgE);
}
private static int generateKey() {
//TODO: implement step a (randomly generate 16-bit key)
//16 bit digit means 2^16 -1 in decimal
Random rand = new Random();
return rand.nextInt((int) (Math.pow(2, 16)-1));
}
private static String generateMsg() {
//TODO: implement step b (randonly generate a string with an even number of characters)
String chractersU="ABCDEFGHIJKLMNOPQRSTUVWXYZ";
String chractersL=chractersU.toLowerCase();
String space=" ";
String alphanum=chractersU+space+chractersL;
String random="";
int length=alphanum.length();
Random rand=new Random();
char[] text=new char[length];
for(int i=0;i<length;i++) {
text[i]=alphanum.charAt(rand.nextInt(alphanum.length()));
}
for(int i=0;i<text.length/2;i++) {
if(text.length%2!=0) {
random += text[i];
}}
return random;
}
private static String encryption (int key, String msg) {
//TODO: implement step c (encrypt the message)
String strData="";
String strKey=Integer.toString(key);
try {
SecretKeySpec skeyspec=new SecretKeySpec(strKey.getBytes(),"Blowfish");
Cipher cipher=Cipher.getInstance("Blowfish");
cipher.init(Cipher.ENCRYPT_MODE, skeyspec);
byte[] encrypted=cipher.doFinal(msg.getBytes());
strData=new String(encrypted);
} catch (Exception e) {
e.printStackTrace();
}
return strData;
}
private static void decryption(int key, String msgE) {
//TODO: implement step d (decryption)
String strKey = Integer.toString(key);
String strData="";
try {
SecretKeySpec skeyspec=new SecretKeySpec(strKey.getBytes(),"Blowfish");
Cipher cipher=Cipher.getInstance("Blowfish");
cipher.init(Cipher.DECRYPT_MODE, skeyspec);
byte[] decrypted=cipher.doFinal(msgE.getBytes());
strData=new String(decrypted);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(strData);
}
private static void bruteForce(String msgE) {
//TODO: implement bruteForce algorithm, you may need the above decryption(key,msgE) method
boolean isEnglisString = msgE.matches("[a-zA-Z]+");
if(isEnglisString)
System.out.println("Yes encrypted message is Randomly English generated message " + msgE);
else
System.out.println("encrypted message is Not Randomly english generated message "+msgE);
decryption(key, msgE);
isEnglisString = msgD.matches("[a-zA-Z]+");
if(isEnglisString)
System.out.println("Yes decrypted message is Randomly english generated message "+ msgD);
else
System.out.println("decrypted message is not Randomly english generated message "+ msgD);
}}
错误:
javax.crypto.IllegalBlockSizeException: Input length must be multiple of 8 when decrypting with padded cipher
at java.base/com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:936)
at java.base/com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:847)
at java.base/com.sun.crypto.provider.BlowfishCipher.engineDoFinal(BlowfishCipher.java:319)
at java.base/javax.crypto.Cipher.doFinal(Cipher.java:2189)
at Assignment1Demo.decryption(Assignment1Demo.java:110)
at Assignment1Demo.bruteForce(Assignment1Demo.java:132)
at Assignment1Demo.main(Assignment1Demo.java:30)
Exception in thread "main" java.lang.NullPointerException
at Assignment1Demo.bruteForce(Assignment1Demo.java:133)
at Assignment1Demo.main(Assignment1Demo.java:30)
您的字符串是随机生成的,但是当块大小与密码预期的不匹配时,您需要应用可接受的填充算法,以便输入的大小与算法保持一致。这适用于所有分组密码。
这个例子是一个简单的密码计,而不是可以使用类似算法的东西 "AES/CBC/PKCS5Padding" "RC2/CBC/PKCS5Padding" “DESede/CBC/PKCS5Padding (PKCS#5 填充是为 8 字节块大小定义的)
@Override
public SimpleMeter testEncryption(File baseInput, String algorithm, String provider) throws NoSuchProviderException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException {
Cipher cipherEncryption;
SimpleMeter meter = new SimpleMeter();
SecureRandom randGenerator = new SecureRandom();
KeyGenerator generator;
generator = KeyGenerator.getInstance(algorithm.split("/")[0], provider);
generator.init(randGenerator);
SecretKey key = generator.generateKey();
cipherEncryption = Cipher.getInstance(algorithm, provider);
cipherEncryption.init(Cipher.ENCRYPT_MODE, key);
try (BufferedInputStream input = new BufferedInputStream(new FileInputStream(baseInput))) {
CipherInputStream encryptionStream = new CipherInputStream(input, cipherEncryption);
meter.start();
while (encryptionStream.read() > -1);
encryptionStream.close();//End all encryption and decryption operation
meter.stop();
} catch (Exception ex) {
ex.printStackTrace();
meter = null;
}
return meter;
}
另一个没有流的例子:
cipher = Cipher.getInstance("Blowfish/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] decrypted = cipher.doFinal(encryptedString.getBytes(CHARSET_ISO_8859_1));
decryptedString = new String(decrypted, CHARSET_ISO_8859_1);
确实没有必要,但是如果你想用base64,你可以找Apache: http://commons.apache.org/proper/commons-codec/
使用您的代码的示例
1) 欧洲央行模式
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.util.Random;
public class Assignment1Demo {
private static String msg;
private static byte[] msgE;
private static String msgD;
private static int key;
public static void main( String[] args ) {
//TODO: You can only call methods in main method
key = generateKey( );
msg = generateMsg( );
msgE = encryption( key, msg );
bruteForce( msgE );
}
private static int generateKey( ) {
//TODO: implement step a (randomly generate 16-bit key)
//16 bit digit means 2^16 -1 in decimal
Random rand = new Random( );
return rand.nextInt( ( int ) ( Math.pow( 2, 16 ) - 1 ) );
}
private static String generateMsg( ) {
//TODO: implement step b (randonly generate a string with an even number of characters)
String chractersU = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
String chractersL = chractersU.toLowerCase( );
String space = " ";
String alphanum = chractersU + space + chractersL;
String random = "";
int length = alphanum.length( );
Random rand = new Random( );
char[] text = new char[ length ];
for ( int i = 0; i < length; i++ ) {
text[ i ] = alphanum.charAt( rand.nextInt( alphanum.length( ) ) );
}
for ( int i = 0; i < text.length / 2; i++ ) {
if ( text.length % 2 != 0 ) {
random += text[ i ];
}
}
return random;
}
private static byte[] encryption( int key, String msg ) {
//TODO: implement step c (encrypt the message)
byte[] encrypted =new byte[]{};
String strKey = Integer.toString( key );
try {
SecretKeySpec skeyspec = new SecretKeySpec( strKey.getBytes( ), "Blowfish" );
Cipher cipher = Cipher.getInstance("Blowfish/ECB/PKCS5Padding");
cipher.init( Cipher.ENCRYPT_MODE, skeyspec );
encrypted = cipher.doFinal( msg.getBytes( ) );
}
catch ( Exception e ) {
e.printStackTrace( );
}
return encrypted;
}
private static void bruteForce( byte[] msgE ) {
//TODO: implement bruteForce algorithm, you may need the above decryption(key,msgE) method
decryption( key, msgE );
}
private static void decryption( int key, byte[] msgE ) {
//TODO: implement step d (decryption)
String strKey = Integer.toString( key );
String strData = "";
try {
SecretKeySpec skeyspec = new SecretKeySpec( strKey.getBytes( ), "Blowfish" );
Cipher cipher = Cipher.getInstance("Blowfish/ECB/PKCS5Padding");
cipher.init( Cipher.DECRYPT_MODE, skeyspec );
byte[] decrypted = cipher.doFinal( msgE);
strData = new String( decrypted );
}
catch ( Exception e ) {
e.printStackTrace( );
}
System.out.println( strData );
}
}
示例 2) 使用 CBC 模式的代码
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.security.AlgorithmParameters;
import java.util.Random;
public class Assignment1Demo {
private static String msg;
private static byte[] msgE;
private static String msgD;
private static int key;
private static byte[] encodedParams;
public static void main( String[] args ) {
//TODO: You can only call methods in main method
key = generateKey( );
msg = generateMsg( );
msgE = encryption( key, msg );
bruteForce( msgE );
}
private static int generateKey( ) {
//TODO: implement step a (randomly generate 16-bit key)
//16 bit digit means 2^16 -1 in decimal
Random rand = new Random( );
return rand.nextInt( ( int ) ( Math.pow( 2, 16 ) - 1 ) );
}
private static String generateMsg( ) {
//TODO: implement step b (randonly generate a string with an even number of characters)
String chractersU = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
String chractersL = chractersU.toLowerCase( );
String space = " ";
String alphanum = chractersU + space + chractersL;
String random = "";
int length = alphanum.length( );
Random rand = new Random( );
char[] text = new char[ length ];
for ( int i = 0; i < length; i++ ) {
text[ i ] = alphanum.charAt( rand.nextInt( alphanum.length( ) ) );
}
for ( int i = 0; i < text.length / 2; i++ ) {
if ( text.length % 2 != 0 ) {
random += text[ i ];
}
}
return random;
}
private static byte[] encryption( int key, String msg ) {
//TODO: implement step c (encrypt the message)
byte[] encrypted =new byte[]{};
String strKey = Integer.toString( key );
try {
SecretKeySpec skeyspec = new SecretKeySpec( strKey.getBytes( ), "Blowfish" );
Cipher cipher = Cipher.getInstance("Blowfish/CBC/PKCS5Padding");
cipher.init( Cipher.ENCRYPT_MODE, skeyspec );
encrypted = cipher.doFinal( msg.getBytes( ) );
encodedParams = cipher.getParameters().getEncoded();
}
catch ( Exception e ) {
e.printStackTrace( );
}
return encrypted;
}
private static void bruteForce( byte[] msgE ) {
//TODO: implement bruteForce algorithm, you may need the above decryption(key,msgE) method
decryption( key, msgE );
}
private static void decryption( int key, byte[] msgE ) {
//TODO: implement step d (decryption)
String strKey = Integer.toString( key );
String strData = "";
try {
SecretKeySpec skeyspec = new SecretKeySpec( strKey.getBytes( ), "Blowfish" );
Cipher cipher = Cipher.getInstance("Blowfish/CBC/PKCS5Padding");
AlgorithmParameters params = AlgorithmParameters.getInstance("Blowfish");
params.init(encodedParams);
cipher.init( Cipher.DECRYPT_MODE, skeyspec, params );
byte[] decrypted = cipher.doFinal( msgE);
strData = new String( decrypted );
}
catch ( Exception e ) {
e.printStackTrace( );
}
System.out.println( strData );
}
}
简而言之,您正在使用加密的二进制数据并假设它是有效文本,但一般来说它不会。
您可以使用 UTF-8 编码将字符串编码为 byte[],但并非所有可能的 byte[] 编码都是有效的字符串。加密数据时,可以使用任何可能的字节,但不能总是使用标准字符编码将其转换为字符串。这可能会导致数据长度发生变化,这就是为什么它不再像数据编码时那样是 8 的倍数。
将数据编码为可打印字符串的一种简单方法是使用 Base64 编码。
在encryption
中使用
strData = DatatypeConverter.printBase64Binary(encrypted);
并在 decryption
中使用
byte[] decrypted=cipher.doFinal(DatatypeConverter.parseBase64Binary(msgE));
这样您将始终尝试解密您编写的二进制数据。
另一种选择是不尝试将二进制数据存储在字符串中,而只使用原始 byte[]
EDIT 你能试试这个吗,使用 byte[]
而不是 String
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
public class A {
public static void main(String... args) {
String text = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
for (int i = 0; i < text.length(); i++) {
byte[] encrypt = encryption(1, text.substring(0, i));
String hello = decryption(1, encrypt);
System.out.println(hello);
}
}
private static byte[] encryption(int key, String msg) {
String strKey = Integer.toString(key);
try {
SecretKeySpec skeyspec = new SecretKeySpec(strKey.getBytes(), "Blowfish");
Cipher cipher = Cipher.getInstance("Blowfish");
cipher.init(Cipher.ENCRYPT_MODE, skeyspec);
return cipher.doFinal(msg.getBytes(StandardCharsets.UTF_8));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private static String decryption(int key, byte[] msgE) {
String strKey = Integer.toString(key);
try {
SecretKeySpec skeyspec = new SecretKeySpec(strKey.getBytes(), "Blowfish");
Cipher cipher = Cipher.getInstance("Blowfish");
cipher.init(Cipher.DECRYPT_MODE, skeyspec);
byte[] decrypted = cipher.doFinal(msgE);
return new String(decrypted, StandardCharsets.UTF_8);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}