Base64 decoding encountered java.lang.IllegalArgumentException: Illegal base64 character d


Preface

When the file was encrypted and stored in the database through Base64 and the corresponding file was read, when decrypting through the Base64 decryption method, an error occurred that should not have occurred. The process of solving the problem is recorded here. and summary


Tip: The following is the text of this article. The following cases are for reference.

1. Problem description

Insert image description here
When decrypting here, it was reported that d is an illegal character in Base64. However, no such problem was reported when testing encryption and decryption before. Therefore, I think the cause of the problem must not be because d is an illegal character .


2. Solution

The solution is relatively simple. Just replace the method of calling Base64 decryption getDecoder()and getMimeDecoder()the problem is solved.
Insert image description here

Running screenshot:
Insert image description here


3. Cause of the problem

After solving the problem, I went back to see why such a problem occurred. I just changed the decoding method in the project to use the MIME-type base64 encoding scheme and there was no decoding error problem. The original Base64 decoding method was just Using the basic base64 encoding scheme, what is the difference between the two? After consulting the information, I found the following differences between the two encoding methods:
Reference: Novice Tutorial_Java8 Base64

  1. Basic way : the output is mapped to a set of characters A-Za-z0-9+/,Coding does not add any line markers, the output decoding only supports A-Za-z0-9+/.
  2. MIME mode : Output is mapped to a MIME-friendly format. Each line of output should not exceed 76 characters,and use '\r' followed by '\n' as split. The encoded output ends up with no line splitting.

After seeing the difference between the two methods, I seemed to realize the problem, and then tested it in IntelliJ IDEA: the
Base64 used during the test was the Base64 tool class that comes with JDK1.8

During testing, first define a String type object, and then use two encoding methods for encryption:
first execute the following code:

import java.nio.charset.StandardCharsets;
import java.util.Base64;

/**
 * @author Dream_飞翔
 * @date 2021/11/12
 * @time 22:27
 * @email [email protected]
 */
public class TestBase64 {
    
    

    public static void main(String[] args) {
    
    
        String str01 = "这是一个测试两种编码方式的字符串";

        // 声明Base64基本方式编码对象
        Base64.Encoder encoderBase = Base64.getEncoder();
        // 声明Base64的MIME编码方式对象
        Base64.Encoder encoderMIME = Base64.getMimeEncoder();

        // 将同一字符以基本方式和MIME方式进行编码
        String encodeBase = encoderBase.encodeToString(str01.getBytes(StandardCharsets.UTF_8));
        String encodeMIME = encoderMIME.encodeToString(str01.getBytes(StandardCharsets.UTF_8));

        // 以UTF-8的格式编码字符串
        System.out.println("基本编码方式:\n" + encodeBase);
        System.out.println("MIME编码方式:\n" + encodeMIME);
    }
}

Here, the test string is encoded using two encoding methods to check whether the content output on the console is the same. The
running results: shorten the length of the test string and test again
Insert image description here
.
Insert image description here

For the encoding results, when the encrypted character length is less than 76 bits, the output results are exactly the same. Test whether the two encryption methods are OK.mutual decryption

Test code :

public class TestBase64 {
    
    

    public static void main(String[] args) {
    
    
        String str01 = "这是一个测试两种编码方式的字符串";

        // 声明Base64基本方式编码对象
        Base64.Encoder encoderBase = Base64.getEncoder();
        // 声明Base64的MIME编码方式对象
        Base64.Encoder encoderMIME = Base64.getMimeEncoder();

        // 将同一字符以基本方式和MIME方式进行编码
        String encodeBase = encoderBase.encodeToString(str01.getBytes(StandardCharsets.UTF_8));
        String encodeMIME = encoderMIME.encodeToString(str01.getBytes(StandardCharsets.UTF_8));

        // 以UTF-8的格式编码字符串
        System.out.println("基本编码方式:\n" + encodeBase);
        System.out.println("MIME编码方式:\n" + encodeMIME);

        // 进行解码
        Base64.Decoder decoderBase = Base64.getDecoder();
        Base64.Decoder decoderMIME = Base64.getMimeDecoder();

        // 将解密后的结果在控制台输出
        System.out.println("基本编码方式加密后的内容使用MIME编码方式的解密结果:\n" + new String(decoderMIME.decode(encodeBase)));
        System.out.println("MIME编码方式加密后的内容使用基本编码方式的解密结果:\n" + new String(decoderBase.decode(encodeMIME)));
    }
}

Insert image description here
Observing the running results, we can find that when the encrypted character length is less than 76 bits , the two encoding methods can decrypt each other's encrypted content.

Then testWhen the encrypted character length is greater than 76 bits, can the two encryption methods still decrypt each other?

Execute the following code to generate a long text on the console , and then copy it into a string (I am lazy and don’t want to type data by hand)

for (int i = 0;i < 200;i++) {
    
    
	System.out.print("测试");
}

Test code :

import java.nio.charset.StandardCharsets;
import java.util.Base64;

/**
 * @author Dream_飞翔
 * @date 2021/11/12
 * @time 00:27
 * @email [email protected]
 */
public class TestBase64 {
    
    

    public static void main(String[] args) {
    
    
        String str01 = "测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试";

        // 声明Base64基本方式编码对象
        Base64.Encoder encoderBase = Base64.getEncoder();
        // 声明Base64的MIME编码方式对象
        Base64.Encoder encoderMIME = Base64.getMimeEncoder();

        // 将同一字符以基本方式和MIME方式进行编码
        String encodeBase = encoderBase.encodeToString(str01.getBytes(StandardCharsets.UTF_8));
        String encodeMIME = encoderMIME.encodeToString(str01.getBytes(StandardCharsets.UTF_8));

        // 以UTF-8的格式编码字符串
        System.out.println("基本编码方式:\n" + encodeBase);
        System.out.println("MIME编码方式:\n" + encodeMIME);

        // 进行解码
        Base64.Decoder decoderBase = Base64.getDecoder();
        Base64.Decoder decoderMIME = Base64.getMimeDecoder();

        // 将解密后的结果在控制台输出
        System.out.println("基本编码方式加密后的内容使用MIME编码方式的解密结果:\n" + new String(decoderMIME.decode(encodeBase)));
        System.out.println("MIME编码方式加密后的内容使用基本编码方式的解密结果:\n" + new String(decoderBase.decode(encodeMIME)));
    }
}

Running results :
Insert image description here
It is not difficult to understand after comparing this. When using the basic encoding method of Base64 for decryption, it is impossible to decrypt the content containing line breaks in the encrypted characters , but the MIME encoding method can ignore whether the characters to be decrypted have line breaks. As for whether the MIME encoding method is what it says, let's test it now.

final verificationWhether the respective encrypted content can be decrypted using their respective encoding methods

Insert image description here


Summarize

After testing and discovering the difference between the two encoding methods for encryption and decryption, another problem arises. When I encrypt the file content, I use the basic encoding method to encrypt, but when I use the basic encryption method to decrypt, it cannot be decrypted.
Insert image description here
Here is the result after the file is encrypted and overwritten, but the basic encoding method does not work when decrypting. Later I found the real reason: the problem is that when I decrypt the file, I need to read the file content into the StringBuilder first . This is the final content we are going to decode with Base64 . When I read it, I added a flag variable to see how many lines the read content was. I discovered the truth of the matter.
Insert image description here
Now I look back at why the basic encoding method is not The problem of not being able to decode the content encoded in the basic way is that the content we decoded with Base64 actually has two lines, but we can only see one line. Therefore, we can also find that the MIME encrypted characters can only have a maximum of 76 characters in a line. However, it is also possible to decrypt a line of encrypted characters longer than 76 characters. At the same time, the Base64 basic encryption method in JDK8 cannot decode data containing line breaks in the encrypted characters, even if the second line has no data, there can only be one line of encrypted characters .

There are many things that I just grit my teeth and get through because I don’t want to trouble others. There were also many unspeakable difficulties that I overcame. When I was frustrated at a low point, I felt like I couldn't cheer myself up, but I didn't get over it in the end. You see, we are all stronger than we think. If you treat every day of your life as if it were your last, your life will be more exciting!
Insert image description here

Guess you like

Origin blog.csdn.net/qq_48455576/article/details/121295709