Additional instruments - Cryptography and Encoding
Most people prefer working with readable text, while computer storage and communications operate exclusively in bytes. This leads us to the concept of encoding—a crucial process that converts text into binary. Among the numerous encoding schemes, Base64 stands out, as it allows the conversion of binary data into text using a set of 64 ASCII symbols. In this topic, we will explore Base64 encoding and decoding in Kotlin, providing you with the ability to encode and decode data with ease.
Base64 from Kotlin
The use of Base64 from kotlin.io.encoding is illustrated in the following example:
import kotlin.io.encoding.Base64
import kotlin.io.encoding.ExperimentalEncodingApi
@OptIn(ExperimentalEncodingApi::class)
fun main() {
val text = "Hola!"
val encodedText = Base64.Default.encode(text.toByteArray())
println(encodedText) // SG9sYSE=
}
Let's break it down:
- The
@OptIn(ExperimentalEncodingApi::class)annotation is used to indicate that the following code makes use of an experimental API. In this case, it's used to inform the compiler that theBase64encoding methods are being used, which are still considered experimental features that might change in the future. - Here, the
Base64class is not supposed to be instantiated or inherited, so we usedDefault, as the companion objectBase64.Defaultis the default instance of Base64. We can also useBase64.UrlSafeandBase64.Mime.
@OptIn(ExperimentalEncodingApi::class)
fun main() {
val text = "Hola!"
val encodedText = Base64.Default.encode(text.toByteArray())
println(encodedText) // SG9sYSE=
println(String(Base64.Default.decode(encodedText))) // Hola!
}
Below is an example of UrlSafe encoding:
import kotlin.io.encoding.Base64
import kotlin.io.encoding.ExperimentalEncodingApi
@OptIn(ExperimentalEncodingApi::class)
fun main() {
val url = "https://hyperskill.org/study-plan"
val encodedText: String = Base64.UrlSafe.encode(url.toByteArray())
println(encodedText) // aHR0cHM6Ly9oeXBlcnNraWxsLm9yZy9zdHVkeS1wbGFu
}
And here's a decoding example:
import kotlin.io.encoding.Base64
import kotlin.io.encoding.ExperimentalEncodingApi
@OptIn(ExperimentalEncodingApi::class)
fun main() {
val url = "https://hyperskill.org/study-plan"
val encodedText: String = Base64.UrlSafe.encode(url.toByteArray())
println(encodedText) // aHR0cHM6Ly9oeXBlcnNraWxsLm9yZy9zdHVkeS1wbGFu
println(String(Base64.UrlSafe.decode(encodedText)))
}Basic encoding and decoding
Let's encode text using Base64 from java.util:
import java.util.Base64
fun main() {
val text = "Hola!"
val encodedText: String = Base64.getEncoder().encodeToString(text.toByteArray())
println(encodedText) // SG9sYSE=
}
Base64 is a class from the java.util package that provides static methods for encoding and decoding data using Base64.
Quoting official docs, "The encodeToString() encodes the specified byte array into a String using the Base64 encoding scheme. This method first encodes all input bytes into a Base64-encoded byte array and then constructs a new String by using the encoded byte array and the ISO-8859-1 charset."
Now let's decode it:
fun main() {
val text = "Hola!"
val encodedText: String = Base64.getEncoder().encodeToString(text.toByteArray())
println(encodedText) // SG9sYSE=
val decodedText = String(Base64.getDecoder().decode(encodedText))
println(decodedText) // Hola!
}
For simplicity, let's break it down:
Base64.getDecoder()returns an instance of the Base64 decoder.decode(encodedText)takes the Base64-encoded text as input, decodes it back to the original binary data, and returns a byte array.String(...)converts the byte array back into a string using the appropriate character encoding (UTF_8 in this case).
Base64 URL encoding
Let's take an example:
import java.util.Base64
fun main() {
val url = "https://hyperskill.org/study-plan"
val encodedUri = Base64.getUrlEncoder().encode(url.toByteArray())
println(String(encodedUri)) // aHR0cHM6Ly9oeXBlcnNraWxsLm9yZy9zdHVkeS1wbGFu
}
getUrlEncoder(): Returns aBase64.Encoderthat encodes using the URL and Filename safe type Base64 encoding scheme.
Here's how to decode it back:
fun main() {
val url = "https://hyperskill.org/study-plan"
val encodedUri = Base64.getUrlEncoder().encode(url.toByteArray())
println(String(encodedUri)) // aHR0cHM6Ly9oeXBlcnNraWxsLm9yZy9zdHVkeS1wbGFu
println(String(Base64.getUrlDecoder().decode(encodedUri))) // https://hyperskill.org/study-plan
}Base64 MIME encoding
MIME (Multipurpose Internet Mail Extensions) is a standard that defines how data is formatted and transmitted over the Internet. It is used to identify the type of data being sent, such as text, image, or audio.
The encoded output must be represented in lines of no more than 76 characters each. The line separator is a carriage return (\r) followed immediately by a linefeed (\n). No line separator is added to the end of the encoded output. All line separators or other characters not found in the Base64 alphabet table are ignored in the decoding operation.
Let's take an example:
import java.util.Base64
fun main() {
val mime = "k333d6ebc30f8a22d993-0iikik3-4fc3-a9b1-949b2d5463ddk333d6ebc30f8a22d993-0iikik3-4fc3-a9b1-949b2d5463ddk333d6ebc30f8a22d993-0iikik3-4fc3-a9b1-949b2d5463dd"
val encodedMime = Base64.getMimeEncoder().encodeToString(mime.toByteArray())
println(encodedMime)
}
The output:
azMzM2Q2ZWJjMzBmOGEyMmQ5OTMtMGlpa2lrMy00ZmMzLWE5YjEtOTQ5YjJkNTQ2M2RkazMzM2Q2
ZWJjMzBmOGEyMmQ5OTMtMGlpa2lrMy00ZmMzLWE5YjEtOTQ5YjJkNTQ2M2RkazMzM2Q2ZWJjMzBm
OGEyMmQ5OTMtMGlpa2lrMy00ZmMzLWE5YjEtOTQ5YjJkNTQ2M2Rk
We simply used getMimeEncoder() to encode it. That's it.
Using Apache Commons Codec
First, we need to add the following dependency:
Maven
<!-- https://mvnrepository.com/artifact/commons-codec/commons-codec -->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.16.0</version>
</dependency>
Gradle
implementation group: 'commons-codec', name: 'commons-codec', version: '1.16.0'
Gradle(Kotlin)
// https://mvnrepository.com/artifact/commons-codec/commons-codec
implementation("commons-codec:commons-codec:1.16.0")
Now let's rewrite one of the previous examples using Apache Commons Codec:
import org.apache.commons.codec.binary.Base64
fun main() {
val text = "Hola!"
val encodedText: String = String(Base64.encodeBase64(text.toByteArray()))
println(encodedText) // SG9sYSE=
}
It's the same as before, but in this case, we used Base64 from org.apache.commons.codec.binary.
Decoding also goes in the same way:
import org.apache.commons.codec.binary.Base64
fun main() {
val text = "Hola!"
val encodedText: String = String(Base64.encodeBase64(text.toByteArray()))
println(encodedText) // SG9sYSE=
println(String(Base64.decodeBase64(encodedText))) // Hola!
}Conclusion
In this topic, we've learned how to decode and encode using the Base64 schema. We've also discussed some use cases, such as basic, URL, and MIME encoding. We've found out how to work with Base64 from java.util, kotlin.io.encoding, and org.apache.commons.codec.binary. Now let's practice!