Loading page…
Rust walkthroughs
Loading page…
Base64 is a crate for encoding and decoding base64 data in Rust. Base64 is a binary-to-text encoding scheme that represents binary data in an ASCII string format. It's commonly used for encoding binary data in contexts that only support text, such as email attachments, JSON payloads, and data URLs.
Key concepts:
= padding charactersWhen to use Base64:
When NOT to use Base64:
use base64::{Engine as _, engine::general_purpose};
fn main() {
let data = b"hello world";
// Encode to base64
let encoded = general_purpose::STANDARD.encode(data);
println!("Encoded: {}", encoded); // "aGVsbG8gd29ybGQ="
// Decode from base64
let decoded = general_purpose::STANDARD.decode(&encoded).unwrap();
println!("Decoded: {}", String::from_utf8_lossy(&decoded));
}use base64::{Engine as _, engine::general_purpose};
fn main() {
let data = b"hello world?param=value";
// Standard encoding (contains + and /)
let standard = general_purpose::STANDARD.encode(data);
println!("Standard: {}", standard);
// URL-safe encoding (uses - and _ instead)
let url_safe = general_purpose::URL_SAFE.encode(data);
println!("URL-safe: {}", url_safe);
// URL-safe without padding
let url_safe_no_pad = general_purpose::URL_SAFE_NO_PAD.encode(data);
println!("URL-safe (no pad): {}", url_safe_no_pad);
}use base64::{Engine as _, engine::general_purpose};
fn main() {
let data = b"hello";
// With padding
let with_pad = general_purpose::STANDARD.encode(data);
println!("With padding: {}", with_pad); // "aGVsbG8="
// Without padding
let no_pad = general_purpose::STANDARD_NO_PAD.encode(data);
println!("No padding: {}", no_pad); // "aGVsbG8"
// Decoding works with or without padding
let decoded = general_purpose::STANDARD.decode(&no_pad).unwrap();
println!("Decoded: {:?}", decoded);
}use base64::{Engine as _, engine::general_purpose};
fn encode_string(input: &str) -> String {
general_purpose::STANDARD.encode(input.as_bytes())
}
fn decode_to_string(encoded: &str) -> Option<String> {
general_purpose::STANDARD
.decode(encoded)
.ok()
.and_then(|bytes| String::from_utf8(bytes).ok())
}
fn main() {
let original = "Hello, Rust!";
let encoded = encode_string(original);
println!("Encoded: {}", encoded);
let decoded = decode_to_string(&encoded).unwrap();
println!("Decoded: {}", decoded);
}use base64::{Engine as _, engine::general_purpose};
fn main() {
// Binary data (e.g., image header)
let binary_data: Vec<u8> = vec![0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A];
let encoded = general_purpose::STANDARD.encode(&binary_data);
println!("Encoded binary: {}", encoded);
let decoded = general_purpose::STANDARD.decode(&encoded).unwrap();
assert_eq!(binary_data, decoded);
}use base64::{Engine as _, engine::general_purpose, write::EncoderWriter};
use std::io::Write;
fn main() -> std::io::Result<()> {
// Encode while writing to a Vec
let mut output = Vec::new();
{
let mut encoder = EncoderWriter::new(&mut output, &general_purpose::STANDARD);
encoder.write_all(b"hello world")?;
}
let encoded = String::from_utf8(output).unwrap();
println!("Streamed: {}", encoded);
Ok(())
}use base64::{Engine as _, engine::general_purpose, read::DecoderReader};
use std::io::Read;
fn main() -> std::io::Result<()> {
let encoded = b"aGVsbG8gd29ybGQ=";
// Decode while reading
let mut decoder = DecoderReader::new(&encoded[..], &general_purpose::STANDARD);
let mut decoded = String::new();
decoder.read_to_string(&mut decoded)?;
println!("Decoded: {}", decoded);
Ok(())
}use base64::{Engine as _, engine::general_purpose::GeneralPurpose, alphabet, Config};
fn main() {
// Custom configuration
let config = Config::new()
.with_encode_padding(true)
.with_decode_padding_mode(base64::engine::DecodePaddingMode::Indifferent);
let engine = GeneralPurpose::new(&alphabet::STANDARD, config);
let encoded = engine.encode(b"custom config");
println!("Custom encoded: {}", encoded);
}use base64::{Engine as _, engine::general_purpose};
#[derive(Debug)]
struct JwtHeader {
alg: String,
typ: String,
}
impl JwtHeader {
fn to_json(&self) -> String {
format!(r#"{{"alg":"{}","typ":"{}"}}"#", self.alg, self.typ)
}
}
fn encode_jwt_part(data: &str) -> String {
// URL-safe without padding for JWT
general_purpose::URL_SAFE_NO_PAD.encode(data.as_bytes())
}
fn main() {
let header = JwtHeader {
alg: "HS256".to_string(),
typ: "JWT".to_string(),
};
let payload = r#"{"sub":"1234567890","name":"John"}"#;
let header_b64 = encode_jwt_part(&header.to_json());
let payload_b64 = encode_jwt_part(payload);
println!("Header: {}", header_b64);
println!("Payload: {}", payload_b64);
println!("JWT: {}.{}.SIGNATURE", header_b64, payload_b64);
}use base64::{Engine as _, engine::general_purpose};
fn create_data_url(mime_type: &str, data: &[u8]) -> String {
let encoded = general_purpose::STANDARD.encode(data);
format!("data:{};base64,{}", mime_type, encoded)
}
fn main() {
// Small PNG-like header
let image_data = b"\x89PNG\r\n\x1a\nfake image data";
let data_url = create_data_url("image/png", image_data);
println!("Data URL: {}", data_url);
}use base64::{Engine as _, engine::general_purpose};
fn decode_safe(encoded: &str) -> Result<Vec<u8>, base64::DecodeError> {
general_purpose::STANDARD.decode(encoded)
}
fn main() {
// Valid input
match decode_safe("aGVsbG8=") {
Ok(data) => println!("Decoded: {:?}", data),
Err(e) => eprintln!("Error: {}", e),
}
// Invalid input
match decode_safe("not-valid-base64!!!") {
Ok(data) => println!("Decoded: {:?}", data),
Err(e) => eprintln!("Expected error: {}", e),
}
}use base64::{Engine as _, engine::general_purpose};
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Debug)]
struct UserSession {
user_id: u64,
username: String,
expires_at: u64,
}
fn encode_session(session: &UserSession) -> Result<String, serde_json::Error> {
let json = serde_json::to_string(session)?;
Ok(general_purpose::STANDARD.encode(json.as_bytes()))
}
fn decode_session(encoded: &str) -> Result<UserSession, Box<dyn std::error::Error>> {
let decoded = general_purpose::STANDARD.decode(encoded)?;
let json = String::from_utf8(decoded)?;
Ok(serde_json::from_str(&json)?)
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let session = UserSession {
user_id: 42,
username: "alice".to_string(),
expires_at: 1700000000,
};
let encoded = encode_session(&session)?;
println!("Encoded session: {}", encoded);
let decoded = decode_session(&encoded)?;
println!("Decoded: {:?}", decoded);
Ok(())
}use base64::{Engine as _, engine::general_purpose};
fn hex_to_base64(hex: &str) -> Result<String, hex::FromHexError> {
let bytes = hex::decode(hex)?;
Ok(general_purpose::STANDARD.encode(&bytes))
}
fn base64_to_hex(encoded: &str) -> Result<String, base64::DecodeError> {
let bytes = general_purpose::STANDARD.decode(encoded)?;
Ok(hex::encode(&bytes))
}
fn main() {
let hex_str = "48656c6c6f"; // "Hello" in hex
match hex_to_base64(hex_str) {
Ok(b64) => println!("Base64: {}", b64),
Err(e) => eprintln!("Error: {}", e),
}
}use base64::{Engine as _, engine::general_purpose};
struct CryptoKey {
key_data: Vec<u8>,
}
impl CryptoKey {
fn new(data: Vec<u8>) -> Self {
Self { key_data: data }
}
fn to_base64(&self) -> String {
general_purpose::STANDARD.encode(&self.key_data)
}
fn from_base64(encoded: &str) -> Result<Self, base64::DecodeError> {
let decoded = general_purpose::STANDARD.decode(encoded)?;
Ok(Self { key_data: decoded })
}
}
fn main() {
// 32-byte key
let key = CryptoKey::new(vec![0u8; 32]);
let encoded = key.to_base64();
println!("Encoded key: {}", encoded);
let decoded = CryptoKey::from_base64(&encoded).unwrap();
assert_eq!(key.key_data, decoded.key_data);
}use base64::{Engine as _, engine::general_purpose};
struct EmailAttachment {
filename: String,
mime_type: String,
data: Vec<u8>,
}
impl EmailAttachment {
fn to_mime(&self) -> String {
let encoded = general_purpose::STANDARD.encode(&self.data);
let chunked = encoded
.as_bytes()
.chunks(76) // Standard MIME line length
.map(|chunk| std::str::from_utf8(chunk).unwrap())
.collect::<Vec<_>>()
.join("\r\n");
format!(
"Content-Type: {}\r\n\
Content-Transfer-Encoding: base64\r\n\
Content-Disposition: attachment; filename=\"{}\"\r\n\
\r\n{}",
self.mime_type,
self.filename,
chunked
)
}
}
fn main() {
let attachment = EmailAttachment {
filename: "document.txt".to_string(),
mime_type: "text/plain".to_string(),
data: b"Hello, this is an attachment.".to_vec(),
};
println!("{}", attachment.to_mime());
}use base64::{Engine as _, engine::general_purpose};
fn main() {
let data = vec![0u8; 1_000_000]; // 1 MB
// Encoding speed
let start = std::time::Instant::now();
let encoded = general_purpose::STANDARD.encode(&data);
let encode_time = start.elapsed();
// Decoding speed
let start = std::time::Instant::now();
let decoded = general_purpose::STANDARD.decode(&encoded).unwrap();
let decode_time = start.elapsed();
println!("Original size: {} bytes", data.len());
println!("Encoded size: {} bytes", encoded.len());
println!("Overhead: {:.1}%", (encoded.len() as f64 / data.len() as f64 - 1.0) * 100.0);
println!("Encode time: {:?}", encode_time);
println!("Decode time: {:?}", decode_time);
}use base64::{Engine as _, engine::general_purpose};
fn is_valid_base64(input: &str) -> bool {
general_purpose::STANDARD.decode(input).is_ok()
}
fn main() {
let test_cases = [
("aGVsbG8=", true),
("SGVsbG8gV29ybGQ=", true),
("invalid!!!", false),
("not base64", false),
];
for (input, expected) in test_cases {
let result = is_valid_base64(input);
println!("{}: {} (expected {})", input, result, expected);
}
}use base64::{Engine as _, engine::general_purpose};
fn encode_image_to_data_url(image_data: &[u8], format: &str) -> String {
let encoded = general_purpose::STANDARD.encode(image_data);
format!("data:image/{};base64,{}", format, encoded)
}
fn main() {
// Fake PNG signature + data
let png_data = b"\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR";
let data_url = encode_image_to_data_url(png_data, "png");
println!("Data URL (truncated): {}...", &data_url[..50]);
}use base64::{Engine as _, engine::general_purpose};
struct ApiKey {
prefix: String,
key: Vec<u8>,
}
impl ApiKey {
fn new(prefix: &str, key: Vec<u8>) -> Self {
Self {
prefix: prefix.to_string(),
key,
}
}
fn encode(&self) -> String {
format!("{}.{}", self.prefix, general_purpose::URL_SAFE_NO_PAD.encode(&self.key))
}
fn decode(s: &str) -> Option<Self> {
let parts: Vec<&str> = s.splitn(2, '.').collect();
if parts.len() != 2 {
return None;
}
let key = general_purpose::URL_SAFE_NO_PAD.decode(parts[1]).ok()?;
Some(Self {
prefix: parts[0].to_string(),
key,
})
}
}
fn main() {
let api_key = ApiKey::new("sk", vec![1, 2, 3, 4, 5]);
let encoded = api_key.encode();
println!("API Key: {}", encoded);
let decoded = ApiKey::decode(&encoded).unwrap();
assert_eq!(api_key.key, decoded.key);
}Base64 Key Imports:
use base64::{Engine as _, engine::general_purpose};Encoding Engines:
| Engine | Description |
|--------|-------------|
| STANDARD | Standard base64 with +/ and padding |
| STANDARD_NO_PAD | Standard without padding |
| URL_SAFE | URL-safe with -_ and padding |
| URL_SAFE_NO_PAD | URL-safe without padding |
Core Methods:
// Encoding
let encoded = general_purpose::STANDARD.encode(data);
// Decoding
let decoded = general_purpose::STANDARD.decode(&encoded)?;Character Sets:
| Type | Characters |
|------|------------|
| Standard | A-Za-z0-9+/ |
| URL-safe | A-Za-z0-9-_ |
| Padding | = |
Common Use Cases:
| Use Case | Recommended Engine |
|----------|-------------------|
| General purpose | STANDARD |
| URLs/Filenames | URL_SAFE_NO_PAD |
| JWT tokens | URL_SAFE_NO_PAD |
| Email/MIME | STANDARD |
Key Points:
Engine trait for custom configurationsDecodeError