Skip to content

crohn/not-base64

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

not-base64

This is an educational, simple, dependency-free implementation of Base64 encoding, written as a learning exercise. This project focuses on a clear and understandable implementation of the Base64 algorithm (RFC 4648) from scratch.


Disclaimer: For Educational Use Only

This library was written to practice Rust. It has not been audited for security or optimized for all edge cases. It is not recommended for production use.

For a battle-tested, production-ready library, please use the official base64 crate.


Features

  • Base64 Encoding: Provides functions to encode byte slices (&[u8]) into a String or write them into a mutable byte slice (&mut [u8]).
  • Zero Dependencies: Written from scratch in pure, stable Rust.

Usage

The API is straightforward. It exposes three functions: encode, encode_bytes and calc_out_capacity.

encode

encode takes an input byte slice and returns an owned String.

fn main() {
    let input = "Hello world! ☀️";

    let encoded = not_base64::encode(input.as_bytes());
    assert_eq!(encoded, "SGVsbG8gd29ybGQhIOKYgO+4jw==");
}

encode_bytes

encode_bytes, takes an input and a mutable output byte slices, filling the output with the Base64 encoded bytes. It expects a pre-allocated buffer and panics if output has not enough capacity. calc_out_capacity can be used to compute the exact capacity needed to encode the input slice.

fn main() {
    let input = "Hello world! ☀️".as_bytes();

    let capacity = not_base64::calc_out_capacity(input);
    let mut output = vec![0u8; capacity];

    not_base64::encode_bytes(input, &mut output);
    assert_eq!(output, b"SGVsbG8gd29ybGQhIOKYgO+4jw==");
}

How it works

Base64 encoding works by taking 3 bytes of input and reorganizing the contained 24-bits into 4 groups of 6-bits. Each of the 4 bytes are zero-prefixed.

This implementation processes the input in chunks of 3 bytes, so the encoder can face three possible scenarios, the numeric values are meant to illustrate how the bits are re-distributed in the encoding process:

Full 3-byte chunk

input  -> 1111 2222 | 3333 4444 | 5555 6666
output -> 0011 1122 | 0022 3333 | 0044 4455 | 0055 6666

In case the input length is not multiple of 3, the remaining bytes are handled separately and the output will be padded with = character.

2-byte remainder

input  -> 1111 2222 | 3333 4444 | 0000 0000
output -> 0011 1122 | 0022 3333 | 0044 4400 | 0000 0000
                                              (pad '=')

1-byte remainder

input  -> 1111 2222 | 0000 0000 | 0000 0000
output -> 0011 1122 | 0022 0000 | 0000 0000 | 0000 0000
                                  (pad '=')   (pad '=')

Bit masking

The encoder uses bitwise masks and shifts to extract the 6-bits values from the original 8-bit values.

For example, on the first input byte, we first apply the mask to isolate the first 6-bits, which will be grouped into the first output byte.

input  b"i" 0x69   -> 0110 1001 &
mask        0xfc   -> 1111 1100
                      0110 1000

We then shift the resulting word by two bits to the right, to place the bits in position.

masked 6-bits      -> 0110 1000 >>
shift positions    ->         2
                      0001 1010
          zero-prefix ^^

Future

A corresponding decode function is a potential future addition. The initial implementation focused solely on the encoding functionality required for another project.

License

not-base64 is released under MIT license. See LICENSE in this source distribution for more information.

About

Educational, simple, dependency-free Base64 encoding implementation.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages