Skip to main content

Crate bouncycastle_base64

Crate bouncycastle_base64 

Source
Expand description

Good old fashioned base64 encoder and decoder.

It should just work the way you expect: encode takes any bytes-like rust type and returns a String, while decode takes a String (which can be in any bytes-like container) and returns a Vec<u8>.

 use bouncycastle_base64 as base64;

 let out = base64::encode(b"\x00"); // "AA=="
 let out = base64::encode(b"Hello, World!"); // "SGVsbG8sIFdvcmxkIQ=="
 let out = base64::encode(b"\x00\x01\x02\x03\x04\x05\x06"); // "AAECAwQFBg=="

 let out = base64::decode("AA==").unwrap(); // b"\x00"
 let out = base64::decode("SGVsbG8sIFdvcmxkIQ==").unwrap(); // b"Hello, World!"
 let out = base64::decode("AAECAwQFBg==").unwrap(); // b"\x00\x01\x02\x03\x04\x05\x06"

 // note that the decoder automatically ignores whitespace in the b64 input
 let out1 = base64::decode("AAEC   Aw QFB\ng==").unwrap(); // b"\x00\x01\x02\x03\x04\x05\x06"
 assert_eq!(out, out1);

 // it is also tolerant of missing padding characters
 let out = base64::decode("AAECAwQFBg==").unwrap(); // b"\x00\x01\x02\x03\x04\x05\x06"
 let out1 = base64::decode("AAECAwQFBg=").unwrap(); // b"\x00\x01\x02\x03\x04\x05\x06"
 assert_eq!(out, out1);
 let out2 = base64::decode("AAECAwQFBg").unwrap(); // b"\x00\x01\x02\x03\x04\x05\x06"
 assert_eq!(out, out2);

§Streaming

Unlike Hex, Base64 does not align cleanly to byte boundaries. That means that the above one-shot APIs should only be used if you have the entire content to process at the same time. In other words, if you arbitrarily break your data into chunks and hand it to the one-shot encode and decode APIs, you will get incorrect results. If you need to process your data in chunks, you need to use the streaming API that allows repeated calls to do_update, producing output as it goes, and correctly holds on to the unprocessed partial block until either do_update or do_final is called.

use bouncycastle_base64 as base64;

let mut b64_str: String = String::new();
let mut encoder = base64::Base64Encoder::new();
b64_str.push_str( encoder.do_update(b"Hello,").as_str() );
b64_str.push_str( encoder.do_final(b" World!").as_str() );
assert_eq!(b64_str, "SGVsbG8sIFdvcmxkIQ==");

let mut out_bytes = Vec::<u8>::new();
let mut decoder = base64::Base64Decoder::new(/*skip_whitespace*/ false);
out_bytes.extend( decoder.do_update("SGVs").unwrap() );
out_bytes.extend( decoder.do_final("bG8sIFdvcmxkIQ==").unwrap() );
assert_eq!(out_bytes, b"Hello, World!");

§Security and constant-time

The following paper proves that extremely clever attack algorithms exist to recover private keys if the attacker is allowed to observe closely side-channels of the base64 decode process.

Util::Lookup: Exploiting key decoding in cryptographic libraries (Sieck, 2021),

As this is a cryptography library, we are assuming that this base64 implementation will be used to encode and decode private keys in PEM and JWK formats and so we are only providing a constant-time implementation in order to remove the temptation to shoot yourself in the foot in the name of a small performance gain.

In our testing, a naïve lookup table-based implementation of base64::decode was 1.7x faster than our constant-time implementation, and we are quite sure that optimized base64 implementations exist that provide still better performance. So if you find yourself in a position of needing to base64 encode gigabytes of non-sensitive data, then we recommend you use one of the good, fast, but non-constant-time base64 implementations available from other projects.

§Alphabets:

At the present time, this base64 implementation only supports the standard alphabet with “+” and “/”, specifically:

ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=

but additional alphabets such as the URLSafe alphabet will likely be added in future versions.

Structs§

Base64Decoder
The stateful base64 decoder that supports streaming.
Base64Encoder
The stateful base64 encoder that supports streaming.

Enums§

Base64Error

Functions§

decode
One-shot decode from a base64-encoded string to bytes using a constant-time implementation.
encode
One-shot encode from bytes to a base64-encoded string using a constant-time implementation.