This and that about Base64 (Java)

I had the opportunity to base64 encode / decode by embedding image data in JSON, so I will record the investigation as a memorandum.

What is Base64

I will quote this article because it was explained in an easy-to-understand manner. https://qiita.com/PlanetMeron/items/2905e2d0aa7fe46a36d4 The Base64 conversion algorithm is carefully described in an easy-to-understand manner for your reference.

Simply put ・ A-z (26 characters) ・ A-Z (26 characters) ・ 0-9 (10 characters) ・ + ・ / ・ = (Used as a padding character to the end to make the data length uniform) It seems that it is an encoding method expressed with a total of 65 characters. * The last "=" is a 64-character expression if padding is not required.

Binary data etc. can be converted to 64 (or 65) character strings so that special characters are not included in JSON, and data can be sent and received safely. Since it is expressed only with 64 (or 65) types of characters, it is also a feature that the amount of data increases by about 1.3 times (133%).

When Base64 encoding as the MIME format of e-mail, a line feed code (CRLF) is entered every 76 characters according to the MIME standard. Including these 2 bytes, the amount of data is about 137%.

The Base64 formats are classified into the following three patterns.

1. Basic Base64

gu2CoIKigqSCpoKogqmCq4Ktgq+CsYKzgrWCt4K5gruCvYK/gsKCxILGgsiCyYLKgsuCzILNgtCC04LWgtmC3ILdgt6C34LggqCCoA==

・ The last 2 characters that are multiples of 4 are padding characters "=" ・ Includes +, / symbols (* If this is used in a URL, it will be subject to percent encoding)

2. Base64 including line feed code for every 76 characters of MIME standard

gu2CoIKigqSCpoKogqmCq4Ktgq+CsYKzgrWCt4K5gruCvYK/gsKCxILGgsiCyYLKgsuCzILNgtCC
04LWgtmC3ILdgt6C34LggqCCoA==

・ The last 2 characters that are multiples of 4 are padding characters "=" ・ Includes +, / symbols (* If this is used in a URL, it will be subject to percent encoding)

3. URL-Safe Base64

gu2CoIKigqSCpoKogqmCq4Ktgq-CsYKzgrWCt4K5gruCvYK_gsKCxILGgsiCyYLKgsuCzILNgtCC04LWgtmC3ILdgt6C34LggqCCoA

-URL unsafe symbols have been converted. Remove "+" → "-", "/" → "_", "="

Use applications

--Use base64 character string for image data so that special characters are not included in JSON etc. --Basic authentication uses a Base64-encoded character string with the user name and password separated by a colon (:). --Embed base64 encoded image as it is in html to reduce the number of requests when displaying a web page. -Widely used in e-mail that can only handle 7-bit data.

How to use with Java7,8 ~

Java8~ Since Java8 or later, the utility of java.util.Base64 is provided in the JDK standard, so it seems good to use this. Java 8 or later has not been verified on the actual machine. This is a very simple and easy-to-understand code sample, so it was helpful. https://gist.github.com/komiya-atsushi/d878e6e4bf9ba6dae8fa

Java7 To handle Base64 with Java7 ...

--Use Apache Commons Codec --Use javax.mail (using JavaMail's MimeUtility) --Using Seasar2's Base64Util --Make your own

And so on. This time, I would like to base64 encode / decode using the top two "Apache Commons Codec" and "javax.mail" that I had at hand. The implementation here implements a sample that encodes / decodes binary data (byte []) into a Base64 string (String).

Apache Commons Codec Version: Validated with 1.11.

Basic Base64 encoding

public static String encodeBase64(byte[] data) {
	return Base64.encodeBase64String(data);
}

Base64 # encodeBase64String is used.

Base64 encoding with line feed code for every 76 characters of MIME standard

public static String encodeBase64Chunked(byte[] data) {
	byte[] encoded = Base64.encodeBase64Chunked(data);
	return new String(encoded);
}

⇒ I am using Base64 # encodeBase64Chunked. An interface for adding a line feed code was prepared.

URL-Safe Base64 encoding

public static String encodeBase64URLSafe(byte[] data) {
	return Base64.encodeBase64URLSafeString(data);
}

Base64 # encodeBase64URLSafeString is used. There was a dedicated interface for URL-Safe.

Decode

public static byte[] decodeBase64(String data) {
	return Base64.decodeBase64(data);
}

⇒ It seems that decoding can be done uniformly with this.

javax.mail Version: Verified with 1.4.6

Basic Base64 encoding

private static String trimCRLF(ByteArrayOutputStream encodedCRLF) {
	byte inputArray[] = encodedCRLF.toByteArray();
	byte outputArray[] = new byte[encodedCRLF.size()];

	// CR(0x0d)、LF(0x0a)Skip the part and copy it to the output array
	int n = 0;
	for (int i = 0; i < encodedCRLF.size() - 1; i++) {
		if (inputArray[i] == 0x0d) {// CR
			if (inputArray[i + 1] == 0x0a) {// LF
				i++;
				continue;
			}
		}
		outputArray[n] = inputArray[i];
		n++;
	}
	return new String(outputArray, 0, n);
}

public static String encodeBase64(byte[] data) {
	try (ByteArrayOutputStream encodedChunked = new ByteArrayOutputStream()) {
		try (OutputStream os = MimeUtility.encode(encodedChunked, "base64")) {
			os.write(data);
			os.flush();
		}
		//Remove newline characters
		String encodedStr = trimCRLF(encodedChunked);
		return encodedStr;

	} catch (IOException e) {
		e.printStackTrace();
		return "Bad Encryption";
	} catch (MessagingException e) {
		e.printStackTrace();
		return "Bad Encryption";
	}
}

⇒ In MimeUtility, it seems that you can encode with MimeUtility.encode, By default, it is in a MIME-based format that includes line breaks. Therefore, the line feed code is removed to eliminate line breaks.

Base64 encoding with line feed code for every 76 characters of MIME standard

public static String encodeBase64Chunked(byte[] data) {
	try (ByteArrayOutputStream encodedChunked = new ByteArrayOutputStream()) {
		try (OutputStream os = MimeUtility.encode(encodedChunked, "base64")) {
			os.write(data);
			os.flush();
		}
		return encodedChunked.toString();

	} catch (IOException e) {
		e.printStackTrace();
		return "Bad Encryption";
	} catch (MessagingException e) {
		e.printStackTrace();
		return "Bad Encryption";
	}
}

⇒ I am using MimeUtility.encode.

URL-Safe Base64 encoding

private static String urlSafeEncode(ByteArrayOutputStream encodedCRLF) {
	byte inputArray[] = encodedCRLF.toByteArray();
	byte outputArray[] = new byte[encodedCRLF.size()];

	// CR(0x0d)、LF(0x0a)Skip the part and copy it to the output array
	int n = 0;
	for (int i = 0; i < encodedCRLF.size() - 1; i++) {
		if (inputArray[i] == 0x0d) {// CR
			if (inputArray[i + 1] == 0x0a) {// LF
				i++;
				continue;
			}
		}

		// URL-Convert to Safe
		if (inputArray[i] == 0x2b) {// 「+」
			outputArray[n] = 0x2d;// 「-」
		}
		else if (inputArray[i] == 0x2f) {// 「/」
			outputArray[n] = 0x5f;// 「_」
		}
		else if (inputArray[i] == 0x3d) {// 「=」
			continue;
		}
		else {
			outputArray[n] = inputArray[i];
		}
		n++;
	}
	return new String(outputArray, 0, n);
}

public static String encodeBase64URLSafe(byte[] data) {
	try (ByteArrayOutputStream encodedChunked = new ByteArrayOutputStream()) {
		try (OutputStream os = MimeUtility.encode(encodedChunked, "base64")) {
			os.write(data);
			os.flush();
		}
		//URL with newline characters removed-Make it Safe
		String encodedURLSafe = urlSafeEncode(encodedChunked);
		return encodedURLSafe;

	} catch (IOException e) {
		e.printStackTrace();
		return "Bad Encryption";
	} catch (MessagingException e) {
		e.printStackTrace();
		return "Bad Encryption";
	}

⇒ In order to make URL-Safe, the symbols "+", "/" and "=" are converted in addition to the line feed code removal. It's very long. ..

Decode

public static byte[] decodeBase64(String data) {
	byte[] urlsafe = data.getBytes();
	int mod = urlsafe.length % 4;
	byte[] nosafe = new byte[urlsafe.length + mod];
	for (int i = 0; i < urlsafe.length; i++) {
		if (urlsafe[i] == 0x2d) {// 「-」
			nosafe[i] = 0x2b;// 「+」
		}
		else if (urlsafe[i] == 0x5f) {// 「_」
			nosafe[i] = 0x2f;// 「/」
		}
		else {
			nosafe[i] = urlsafe[i];
		}
	}
	//Those that are less than a multiple of the fixed length 4=Padding with
	for (int i = urlsafe.length + mod - 1; i >= urlsafe.length; i--) {
		nosafe[i] = 0x3d;// 「=」
	}

	ByteArrayInputStream from = new ByteArrayInputStream(nosafe);
	try (InputStream is = MimeUtility.decode(from, "base64"); ByteArrayOutputStream to = new ByteArrayOutputStream()) {
		byte[] buf = new byte[8192];
		int readCnt;
		while ((readCnt = is.read(buf)) != -1) {
			to.write(buf, 0, readCnt);
		}
		to.flush();
		return to.toByteArray();

	} catch (MessagingException | IOException e) {
		e.printStackTrace();
		return "Bad Decryption".getBytes();
	}
}

⇒ It is forcible. .. In the decoding process, it is converted back to URL-UnSafe on the assumption that the converted character string will be entered in URL-Safe. After padding with "=" according to the number of digits to a multiple of 4, MimeUtility.decode is used for decoding. I don't think I usually write this kind of code.

Summary

--There are three main types of Base64: "basic format", "MIME standard format including line feed code", and "URL-Safe converted format". --For Java 8 or later, use the standard java.util.Base64 class. --Apache Commons Codec is easy to use in Java 7. If you can't use it, use javax.mail.

that's all.

Recommended Posts

This and that about Base64 (Java)
Base64 encoder this and that
[About JDBC that connects Java and SQL]
Docker settings and this and that
[Rails] strftime this and that
About Java Packages and imports
Digital certificate this and that
[Java] Upload images and base64
This and that for editing ini in Java. : inieditor-java
About Java static and non-static methods
About fastqc of Biocontainers and Java
[Java beginner] About abstraction and interface
This and that of the JDK
About this ()
This and that of Core Graphics
About Java primitive types and reference types
This and that of exclusive control
This and that of Swift corner Radius
About Java interface
[Java] About arrays
Something about java
Where about java
About Java features
About Java threads
[Java] About interface
About Java class
Java and JavaScript
About Java arrays
XXE and Java
About java inheritance
About List [Java]
About java var
About Java literals
About Java commands
This and that of conditional branching of rails development
About Java log output
About Java functional interface
Java, about 2D arrays
About class division (Java)
About [Java] [StreamAPI] allMatch ()
Getters and setters (Java)
About Java StringBuilder class
[Java] Thread and Runnable
Java true and false
[Java] About Singleton Class
About classes and instances
[Java] String comparison and && and ||
[Java] About anonymous classes
About method splitting (Java)
About gets and gets.chomp
[Java Silver] About initialization
About Java Array List
About Java Polymorphism super ()
About redirect and forward
[Java] About Objects.equals () and Review of String comparisons (== and equals)
About Java String class
Java --Serialization and Deserialization
[Java] Arguments and parameters
About Java access modifiers
About Java basic data types and reference type memory
About encapsulation and inheritance