Base64: java.lang.IllegalArgumentException: Illegal character
Asked Answered
I

6

58

I'm trying to send a confirmation email after user registration. I'm using the JavaMail library for this purpose and the Java 8 Base64 util class.

I'm encoding user emails in the following way:

byte[] encodedEmail = Base64.getUrlEncoder().encode(user.getEmail().getBytes(StandardCharsets.UTF_8));
Multipart multipart = new MimeMultipart();
InternetHeaders headers = new InternetHeaders();
headers.addHeader("Content-type", "text/html; charset=UTF-8");
String confirmLink = "Complete your registration by clicking on following"+ "\n<a href='" + confirmationURL + encodedEmail + "'>link</a>";
MimeBodyPart link = new MimeBodyPart(headers,
confirmLink.getBytes("UTF-8"));
multipart.addBodyPart(link);

where confirmationURL is:

private final static String confirmationURL = "http://localhost:8080/project/controller?command=confirmRegistration&ID=";

And then decoding this in ConfirmRegistrationCommand in such way:

    String encryptedEmail = request.getParameter("ID");

    String decodedEmail = new String(Base64.getUrlDecoder().decode(encryptedEmail), StandardCharsets.UTF_8);

    RepositoryFactory repositoryFactory = RepositoryFactory
            .getFactoryByName(FactoryType.MYSQL_REPOSITORY_FACTORY);
    UserRepository userRepository = repositoryFactory.getUserRepository();
    User user = userRepository.find(decodedEmail);

    if (user.getEmail().equals(decodedEmail)) {
        user.setActiveStatus(true);
        return Path.WELCOME_PAGE;
    } else {
        return Path.ERROR_PAGE;
    }

And when I'm trying to decode:

http://localhost:8080/project/controller?command=confirmRegistration&ID=[B@6499375d

I'm getting java.lang.IllegalArgumentException: Illegal base64 character 5b.

I tried to use basic Encode/Decoder (not URL ones) with no success.

SOLVED:

The problem was the next - in the line:

 String confirmLink = "Complete your registration by clicking on following"+ "\n<a href='" + confirmationURL + encodedEmail + "'>link</a>";

I'm calling toString on an array of bytes, so I should do the following:

String encodedEmail = new String(Base64.getEncoder().encode(
                user.getEmail().getBytes(StandardCharsets.UTF_8)));

Thanks to Jon Skeet and ByteHamster.

Ivonne answered 18/2, 2015 at 12:47 Comment(5)
Out of curiosity, why .getBytes(StandardCharsets.UTF_8) and .getBytes("UTF-8") in the same function ? Seems like a lack of consistency to me :|Demagoguery
Hint: you're calling toString() on a byte[]. You don't want to do that.Insensitive
@JonSkeet yes ! I think it causes the problem. How should I change it ?Ivonne
@JonSkeet probably I should just call new String(encodedEmail)Ivonne
Or better, use a base64 API that encodes to a string, not a byte[]. The library at iharder.net/base64 is pretty good...Insensitive
B
33

Your encoded text is [B@6499375d. That is not Base64, something went wrong while encoding. That decoding code looks good.

Use this code to convert the byte[] to a String before adding it to the URL:

String encodedEmailString = new String(encodedEmail, "UTF-8");
// ...
String confirmLink = "Complete your registration by clicking on following"
    + "\n<a href='" + confirmationURL + encodedEmailString + "'>link</a>";
Blanks answered 18/2, 2015 at 12:52 Comment(1)
as Jon Skeet pointed out i'm calling toString on array of bites. this is the causeIvonne
I
27

I encountered this error since my encoded image started with data:image/png;base64,iVBORw0....

This answer led me to the solution:

String partSeparator = ",";
if (data.contains(partSeparator)) {
  String encodedImg = data.split(partSeparator)[1];
  byte[] decodedImg = Base64.getDecoder().decode(encodedImg.getBytes(StandardCharsets.UTF_8));
  Path destinationFile = Paths.get("/path/to/imageDir", "myImage.png");
  Files.write(destinationFile, decodedImg);
}

That code removes the meta data in front of the Base64-encoded image and passes the Base64 string to Java's Base64.Decoder to get the image as bytes.

Importunity answered 22/10, 2016 at 19:11 Comment(0)
P
7

Just use the below code to resolve this:

JsonObject obj = Json.createReader(new ByteArrayInputStream(Base64.getDecoder().decode(accessToken.split("\\.")[1].
                        replace('-', '+').replace('_', '/')))).readObject();

In the above code replace('-', '+').replace('_', '/') did the job. For more details see the https://jwt.io/js/jwt.js. I understood the problem from the part of the code got from that link:

function url_base64_decode(str) {
  var output = str.replace(/-/g, '+').replace(/_/g, '/');
  switch (output.length % 4) {
    case 0:
      break;
    case 2:
      output += '==';
      break;
    case 3:
      output += '=';
      break;
    default:
      throw 'Illegal base64url string!';
  }
  var result = window.atob(output); //polifyll https://github.com/davidchambers/Base64.js
  try{
    return decodeURIComponent(escape(result));
  } catch (err) {
    return result;
  }
}
Punke answered 15/5, 2017 at 14:26 Comment(0)
O
2

The Base64.Encoder.encodeToString method automatically uses the ISO-8859-1 character set.

For an encryption utility I am writing, I took the input string of cipher text and Base64 encoded it for transmission, then reversed the process. Relevant parts shown below. NOTE: My file.encoding property is set to ISO-8859-1 upon invocation of the JVM so that may also have a bearing.

static String getBase64EncodedCipherText(String cipherText) {
    byte[] cText = cipherText.getBytes();
    // return an ISO-8859-1 encoded String
    return Base64.getEncoder().encodeToString(cText);
}

static String getBase64DecodedCipherText(String encodedCipherText) throws IOException {
    return new String((Base64.getDecoder().decode(encodedCipherText)));
}

public static void main(String[] args) {
    try {
        String cText = getRawCipherText(null, "Hello World of Encryption...");

        System.out.println("Text to encrypt/encode: Hello World of Encryption...");
        // This output is a simple sanity check to display that the text
        // has indeed been converted to a cipher text which 
        // is unreadable by all but the most intelligent of programmers.
        // It is absolutely inhuman of me to do such a thing, but I am a
        // rebel and cannot be trusted in any way.  Please look away.
        System.out.println("RAW CIPHER TEXT: " + cText);
        cText = getBase64EncodedCipherText(cText);
        System.out.println("BASE64 ENCODED: " + cText);
        // There he goes again!!
        System.out.println("BASE64 DECODED:  " + getBase64DecodedCipherText(cText));
        System.out.println("DECODED CIPHER TEXT: " + decodeRawCipherText(null, getBase64DecodedCipherText(cText)));
    } catch (Exception e) {
        e.printStackTrace();
    }

}

The output looks like:

Text to encrypt/encode: Hello World of Encryption...
RAW CIPHER TEXT: q$;�C�l��<8��U���X[7l
BASE64 ENCODED: HnEPJDuhQ+qDbInUCzw4gx0VDqtVwef+WFs3bA==
BASE64 DECODED:  q$;�C�l��<8��U���X[7l``
DECODED CIPHER TEXT: Hello World of Encryption...
Obit answered 20/2, 2016 at 14:41 Comment(2)
Basically trying to display encrypted data as text does not work because there are byte values that do not have a printable representation. In this case the "�" characters. For this reason encrypted data is best display in hexadecimal.Larynx
@Larynx That's just debug code, but displaying encrypted data as text works just fine if your encryption output is already printable characters. In this case they are not all printable, but it is also irrelevant.Obit
C
1

I have added my failures and findings and how I've overcome this issue here. I've been working on JASYPT ciphering with SpringBoot recently and there were many issues I encountered and fixed them along the way. For this question of Illegal character exception, I have already logged my answer is here for another thread.

Also, I've added another answer here which is related to JASYP encryption which is unrelated to this question but just a reference to the same context. Feel free to skip. And hope these findings help and save some time.

Contagion answered 4/2, 2022 at 13:30 Comment(0)
A
0

I got this error for my Linux Jenkins slave. I fixed it by changing from the node from "Known hosts file Verification Strategy" to "Non verifying Verification Strategy".

Aparejo answered 11/2, 2019 at 17:33 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.