{"id":13822402,"url":"https://github.com/marshallpierce/rust-base64","last_synced_at":"2026-01-15T22:20:18.771Z","repository":{"id":39332243,"uuid":"47371310","full_name":"marshallpierce/rust-base64","owner":"marshallpierce","description":"base64, in rust","archived":false,"fork":false,"pushed_at":"2025-04-21T00:46:04.000Z","size":797,"stargazers_count":659,"open_issues_count":19,"forks_count":123,"subscribers_count":13,"default_branch":"master","last_synced_at":"2025-05-09T00:06:04.681Z","etag":null,"topics":["base64","nostd","rust"],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/marshallpierce.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE-APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2015-12-04T00:51:54.000Z","updated_at":"2025-05-03T13:30:32.000Z","dependencies_parsed_at":"2023-02-14T15:40:23.670Z","dependency_job_id":"15a29a90-077c-48a8-9c45-59f08b7214a8","html_url":"https://github.com/marshallpierce/rust-base64","commit_stats":{"total_commits":378,"total_committers":55,"mean_commits":6.872727272727273,"dds":0.6137566137566137,"last_synced_commit":"87880e49825d1ef5b3b5ffc6aa2280eb9e0da16f"},"previous_names":[],"tags_count":40,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marshallpierce%2Frust-base64","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marshallpierce%2Frust-base64/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marshallpierce%2Frust-base64/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marshallpierce%2Frust-base64/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/marshallpierce","download_url":"https://codeload.github.com/marshallpierce/rust-base64/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253342061,"owners_count":21893556,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["base64","nostd","rust"],"created_at":"2024-08-04T08:01:58.991Z","updated_at":"2026-01-15T22:20:18.721Z","avatar_url":"https://github.com/marshallpierce.png","language":"Rust","funding_links":[],"categories":["Rust"],"sub_categories":[],"readme":"# [base64](https://crates.io/crates/base64)\n\n[![](https://img.shields.io/crates/v/base64.svg)](https://crates.io/crates/base64) [![Docs](https://docs.rs/base64/badge.svg)](https://docs.rs/base64) [![CircleCI](https://circleci.com/gh/marshallpierce/rust-base64/tree/master.svg?style=shield)](https://circleci.com/gh/marshallpierce/rust-base64/tree/master) [![codecov](https://codecov.io/gh/marshallpierce/rust-base64/branch/master/graph/badge.svg)](https://codecov.io/gh/marshallpierce/rust-base64) [![unsafe forbidden](https://img.shields.io/badge/unsafe-forbidden-success.svg)](https://github.com/rust-secure-code/safety-dance/)\n\n\u003ca href=\"https://www.jetbrains.com/?from=rust-base64\"\u003e\u003cimg src=\"/icon_CLion.svg\" height=\"40px\"/\u003e\u003c/a\u003e\n\nMade with CLion. Thanks to JetBrains for supporting open source!\n\nIt's base64. What more could anyone want?\n\nThis library's goals are to be *correct* and *fast*. It's thoroughly tested and widely used. It exposes functionality at\nmultiple levels of abstraction so you can choose the level of convenience vs performance that you want,\ne.g. `decode_engine_slice` decodes into an existing `\u0026mut [u8]` and is pretty fast (2.6GiB/s for a 3 KiB input),\nwhereas `decode_engine` allocates a new `Vec\u003cu8\u003e` and returns it, which might be more convenient in some cases, but is\nslower (although still fast enough for almost any purpose) at 2.1 GiB/s.\n\nSee the [docs](https://docs.rs/base64) for all the details.\n\n## FAQ\n\n### I need to decode base64 with whitespace/null bytes/other random things interspersed in it. What should I do?\n\nRemove non-base64 characters from your input before decoding.\n\nIf you have a `Vec` of base64, [retain](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.retain) can be used to\nstrip out whatever you need removed.\n\nIf you have a `Read` (e.g. reading a file or network socket), there are various approaches.\n\n- Use [iter_read](https://crates.io/crates/iter-read) together with `Read`'s `bytes()` to filter out unwanted bytes.\n- Implement `Read` with a `read()` impl that delegates to your actual `Read`, and then drops any bytes you don't want.\n\n### I need to line-wrap base64, e.g. for MIME/PEM.\n\n[line-wrap](https://crates.io/crates/line-wrap) does just that.\n\n### I want canonical base64 encoding/decoding.\n\nFirst, don't do this. You should no more expect Base64 to be canonical than you should expect compression algorithms to\nproduce canonical output across all usage in the wild (hint: they don't).\nHowever, [people are drawn to their own destruction like moths to a flame](https://eprint.iacr.org/2022/361), so here we\nare.\n\nThere are two opportunities for non-canonical encoding (and thus, detection of the same during decoding): the final bits\nof the last encoded token in two or three token suffixes, and the `=` token used to inflate the suffix to a full four\ntokens.\n\nThe trailing bits issue is unavoidable: with 6 bits available in each encoded token, 1 input byte takes 2 tokens,\nwith the second one having some bits unused. Same for two input bytes: 16 bits, but 3 tokens have 18 bits. Unless we\ndecide to stop shipping whole bytes around, we're stuck with those extra bits that a sneaky or buggy encoder might set\nto 1 instead of 0.\n\nThe `=` pad bytes, on the other hand, are entirely a self-own by the Base64 standard. They do not affect decoding other\nthan to provide an opportunity to say \"that padding is incorrect\". Exabytes of storage and transfer have no doubt been\nwasted on pointless `=` bytes. Somehow we all seem to be quite comfortable with, say, hex-encoded data just stopping\nwhen it's done rather than requiring a confirmation that the author of the encoder could count to four. Anyway, there\nare two ways to make pad bytes predictable: require canonical padding to the next multiple of four bytes as per the RFC,\nor, if you control all producers and consumers, save a few bytes by requiring no padding (especially applicable to the\nurl-safe alphabet).\n\nAll `Engine` implementations must at a minimum support treating non-canonical padding of both types as an error, and\noptionally may allow other behaviors.\n\n## Rust version compatibility\n\nThe minimum supported Rust version is 1.48.0.\n\n# Contributing\n\nContributions are very welcome. However, because this library is used widely, and in security-sensitive contexts, all\nPRs will be carefully scrutinized. Beyond that, this sort of low level library simply needs to be 100% correct. Nobody\nwants to chase bugs in encoding of any sort.\n\nAll this means that it takes me a fair amount of time to review each PR, so it might take quite a while to carve out the\nfree time to give each PR the attention it deserves. I will get to everyone eventually!\n\n## Developing\n\nBenchmarks are in `benches/`.\n\n```bash\ncargo bench\n```\n\n## no_std\n\nThis crate supports no_std. By default the crate targets std via the `std` feature. You can deactivate\nthe `default-features` to target `core` instead. In that case you lose out on all the functionality revolving\naround `std::io`, `std::error::Error`, and heap allocations. There is an additional `alloc` feature that you can activate\nto bring back the support for heap allocations.\n\n## Profiling\n\nOn Linux, you can use [perf](https://perf.wiki.kernel.org/index.php/Main_Page) for profiling. Then compile the\nbenchmarks with `cargo bench --no-run`.\n\nRun the benchmark binary with `perf` (shown here filtering to one particular benchmark, which will make the results\neasier to read). `perf` is only available to the root user on most systems as it fiddles with event counters in your\nCPU, so use `sudo`. We need to run the actual benchmark binary, hence the path into `target`. You can see the actual\nfull path with `cargo bench -v`; it will print out the commands it runs. If you use the exact path\nthat `bench` outputs, make sure you get the one that's for the benchmarks, not the tests. You may also want\nto `cargo clean` so you have only one `benchmarks-` binary (they tend to accumulate).\n\n```bash\nsudo perf record target/release/deps/benchmarks-* --bench decode_10mib_reuse\n```\n\nThen analyze the results, again with perf:\n\n```bash\nsudo perf annotate -l\n```\n\nYou'll see a bunch of interleaved rust source and assembly like this. The section with `lib.rs:327` is telling us that\n4.02% of samples saw the `movzbl` aka bit shift as the active instruction. However, this percentage is not as exact as\nit seems due to a phenomenon called *skid*. Basically, a consequence of how fancy modern CPUs are is that this sort of\ninstruction profiling is inherently inaccurate, especially in branch-heavy code.\n\n```text\n lib.rs:322    0.70 :     10698:       mov    %rdi,%rax\n    2.82 :        1069b:       shr    $0x38,%rax\n         :                  if morsel == decode_tables::INVALID_VALUE {\n         :                      bad_byte_index = input_index;\n         :                      break;\n         :                  };\n         :                  accum = (morsel as u64) \u003c\u003c 58;\n lib.rs:327    4.02 :     1069f:       movzbl (%r9,%rax,1),%r15d\n         :              // fast loop of 8 bytes at a time\n         :              while input_index \u003c length_of_full_chunks {\n         :                  let mut accum: u64;\n         :\n         :                  let input_chunk = BigEndian::read_u64(\u0026input_bytes[input_index..(input_index + 8)]);\n         :                  morsel = decode_table[(input_chunk \u003e\u003e 56) as usize];\n lib.rs:322    3.68 :     106a4:       cmp    $0xff,%r15\n         :                  if morsel == decode_tables::INVALID_VALUE {\n    0.00 :        106ab:       je     1090e \u003cbase64::decode_config_buf::hbf68a45fefa299c1+0x46e\u003e\n```\n\n## Fuzzing\n\nThis uses [cargo-fuzz](https://github.com/rust-fuzz/cargo-fuzz). See `fuzz/fuzzers` for the available fuzzing scripts.\nTo run, use an invocation like these:\n\n```bash\ncargo +nightly fuzz run roundtrip\ncargo +nightly fuzz run roundtrip_no_pad\ncargo +nightly fuzz run roundtrip_random_config -- -max_len=10240\ncargo +nightly fuzz run decode_random\n```\n\n## License\n\nThis project is dual-licensed under MIT and Apache 2.0.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarshallpierce%2Frust-base64","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmarshallpierce%2Frust-base64","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarshallpierce%2Frust-base64/lists"}