[Java] Base64 디코딩 중 Illegal base64 character a 에러 해결

작성: 2023.12.02

수정: 2023.12.02

읽는시간: 00 분

Development/Daily Error

반응형

문제

Java에서 Base64 디코딩을 시도하는 과정에서 java.lang.IllegalArgumentException: Illegal base64 character a 오류가 발생했다. 이 오류는 Base64 문자열에 유효하지 않은 문자가 포함되어 있음을 나타내는 건데, charater a 라는 에러메시지때문에 괜히 헤맸기 때문에 이 글을 남긴다.

Base64 인코딩은 일반적으로 A-Z, a-z, 0-9, +, / 문자와, 끝에 '=' 패딩 문자를 사용한다. 범위 밖의 문자가 포함되어 있으면 유효하지 않은 Base64 문자열이 되어 예외가 발생하는데, character a 라는 메시지때문에 원인을 찾기가 쉽지 않았다.

원인

일단 결론적으로 원인은 base64 문자열을 복사하는 과정에서 의도치 않은 줄바꿈 문자가 발생했기 때문이었다.

동일한 에러 상황을 재현해보자.

package com.tistory.shanepark.string.encoding;

import java.util.Base64;

public class Base64Error {

    public static void main(String[] args) {
        String base64 = "SGVsbG8sIFdvcmxkIQ\n==";

        byte[] decodedBytes = Base64.getDecoder().decode(base64.getBytes());
        System.out.println(new String(decodedBytes));
    }

}

위의 코드를 실행하면 정확히 같은 내용의 에러가 발생한다.

image-20231202104147626 pm

Exception in thread "main" java.lang.IllegalArgumentException: Illegal base64 character a

해결

공백문자를 제거 하는 코드를 추가해준다. \\s+는 하나 이상의 연속된 공백 문자를 의미한다.

해당 코드로 스페이스(' '), 탭('\t'), 줄바꿈('\n'), 캐리지 리턴('\r'), 폼 피드('\f') 등의 포함 문제를 모두 해결할 수 있다.

package com.tistory.shanepark.string.encoding;

import java.util.Base64;

public class Base64Error {

    public static void main(String[] args) {
        String base64 = "SGVsbG8sIFdvcmxkIQ\n==";
        base64 = base64.replaceAll("\\s+", ""); // 모든 공백 문자 제거

        byte[] decodedBytes = Base64.getDecoder().decode(base64.getBytes());
        System.out.println(new String(decodedBytes));
    }

}

실행 결과 문제 없이 디코딩 해낸다.

image-20231202105314679 pm

에러메시지 분석

왜 하필 base64 character a 라는 에러메시지였을까? 에러가 발생한 Base64 라이브러리를 살펴보자.

image-20231202105856071 pm

에러가 발생한 부분이다. 'a' 라고 보여진건 실제 알파벳 a 가 아닌16진수였다.

16진수 a는 십진수로 10 을 의미한다. 그러면 아스키코드 테이블에서 10을 찾아보자.

image-20231202110434428 pm

https://en.wikipedia.org/wiki/ASCII

아스키코드에서 10은 LF(Line Feed) 를 의미한다. 드디어 에러메시지의 미스테리가 풀렸다.

그렇다면 Base64 라이브러리의 에러 메시지에서는 굳이 저걸 왜 16진수로 변환해서 헷갈리게 만들었을까?

이번에는 반대로 생각해보자. 만약 에러메시지에 a 가 아닌 \n이 직접 출력되었다면 문제를 알아내기가 더 쉬웠을까? 줄바꿈 문자가 그대로 출력되면서 결국 아무 문자도 볼 수 없었을것이다. LF 외의 다른 많은 아스키 비표시 문자도 마찬가지다.

이제 실제 문자가 아닌 아스키 번호를 보여주는 편이 낫다는건 납득이 된다. 다만 0xa 처럼 16진수라는걸 명확하게 표시해줬으면 좀 낫지 않았을까 하는 아쉬움이 남는다.

반응형