OpenSSL Base64 Encode & Decode

OpenSSL can encode and decode Base64 via openssl enc -base64. It is especially useful when working with certificates and keys, but has a critical gotcha: by default it wraps output at 64 characters per line.

Basic encode and decode with openssl enc -base64

OpenSSL ships with a generic encoding/cipher subcommand, enc. Base64 is implemented as one of its encodings, so you reach it through openssl enc -base64 (or the shorter alias openssl base64). The same command both encodes and decodes; the -d flag switches it into decode mode.

To encode a short string, pipe it into the command. Use echo -n so the shell does not append a trailing newline that would change the encoded result.

$ echo -n "Hello, World" | openssl enc -base64
SGVsbG8sIFdvcmxk

To decode, add -d. OpenSSL reads the Base64 from standard input and writes the decoded bytes back out.

$ echo "SGVsbG8sIFdvcmxk" | openssl enc -base64 -d
Hello, World

You can also use the alias form, which behaves identically. Both of these are equivalent:

$ echo -n "data" | openssl base64
$ echo -n "data" | openssl enc -base64

The -n in echo -n matters. Without it, echo adds a newline byte (0x0A) to the input, and that byte gets encoded too — so "Hello" and "Hello\n" produce different Base64. For exact round-trips, always strip the trailing newline.

The -A flag: output as a single line (no wrapping)

This is the single most important thing to know about OpenSSL Base64. By default, openssl enc -base64 wraps its output to a maximum of 64 characters per line, inserting a newline after each chunk. That convention comes from PEM and MIME formatting, but it breaks any tool that expects one continuous Base64 string — JSON fields, HTTP headers, environment variables, and shell variable assignments.

Watch what happens when you encode something longer than 64 bytes without -A:

$ echo -n "The quick brown fox jumps over the lazy dog. Pack my box." \
  | openssl enc -base64
VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZy4gUGFj
ayBteSBib3gu

The output spans two lines. Adding -A ("all on one line") produces a single, unwrapped string:

$ echo -n "The quick brown fox jumps over the lazy dog. Pack my box." \
  | openssl enc -base64 -A
VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZy4gUGFjayBteSBib3gu

The -A flag also matters on the decode side. When decoding without -A, OpenSSL processes the input line by line and is strict about line lengths; long single-line input can fail or be truncated. With -A, it treats the entire input as one block. The safe rule is to use -A on both encode and decode whenever you are handling a single-line Base64 string.

$ echo "VGhlIHF1aWNrIGJyb3duIGZveA==" | openssl enc -base64 -d -A
The quick brown fox

Forgetting -A when decoding a long single-line string is a classic source of silent data corruption. Older OpenSSL builds may stop reading at the first 80-ish characters and produce partial output without any error. Always pair -A with single-line input.

Encode and decode files

Instead of piping through standard input and output, you can point OpenSSL directly at files with -in and -out. This avoids shell mangling of binary data and is the right approach for anything larger than a few bytes.

To encode a binary file — say an image — into a Base64 text file:

$ openssl enc -base64 -A -in logo.png -out logo.b64

To decode it back to the original bytes, add -d and swap the file roles:

$ openssl enc -base64 -d -A -in logo.b64 -out logo.png

You can verify the round-trip was byte-for-byte exact by comparing checksums of the original and decoded files:

$ shasum logo.png logo.png.decoded
3a7bd3e2360a3d29eea436fcfb7e44c7  logo.png
3a7bd3e2360a3d29eea436fcfb7e44c7  logo.png.decoded

If you omit -out, OpenSSL prints the result to the terminal. That is convenient for inspection but dangerous for binary output, since raw bytes can scramble your terminal. For decoding binary, always send the result to a file with -out or redirect it.

For files, whether you include -A is a style choice: with -A the encoded file is one long line; without it, the file is wrapped at 64 characters. As long as you decode with the same convention OpenSSL will read both, but a single line is friendlier to tools that read the value back into a variable.

Using openssl base64 with pipes

Because openssl enc reads stdin and writes stdout, it composes naturally with other commands in a pipeline. A common pattern is hashing or compressing data and then Base64-encoding the result so it is safe to embed in text.

For example, compute a SHA-256 digest of a file and Base64-encode the raw binary digest (this is the form used in Subresource Integrity and Content-Security-Policy hashes):

$ openssl dgst -sha256 -binary app.js | openssl enc -base64 -A
9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08

You can also gzip a payload before encoding it, which is handy for packing data into a single environment variable:

$ cat config.json | gzip | openssl enc -base64 -A
H4sIAAAAAAAAA6tWSkksSVSyUlAvLknNTc0rUVCqVQIA...

To reverse that pipeline, decode first, then decompress:

$ echo "$PACKED" | openssl enc -base64 -d -A | gzip -d
{"setting": "value"}

Capturing the encoded output into a shell variable is one of the most common reasons people reach for -A — without it, the embedded newlines make the variable awkward to use:

$ TOKEN=$(echo -n "$SECRET" | openssl enc -base64 -A)
$ echo "Authorization: Basic $TOKEN"

Working with PEM certificates (already Base64)

If you work with TLS certificates and keys, you are already looking at Base64 every day. The PEM format is simply DER-encoded binary that has been Base64-encoded, wrapped at 64 characters per line, and bracketed with -----BEGIN----- / -----END----- header lines. That 64-character wrapping is exactly why OpenSSL's Base64 default wraps at 64.

A PEM certificate looks like this:

-----BEGIN CERTIFICATE-----
MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ
RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD
...
-----END CERTIFICATE-----

To see the actual Base64 body decoded into the underlying DER structure, you usually use the dedicated x509 tool rather than raw Base64, because it understands the ASN.1 structure:

$ openssl x509 -in cert.pem -text -noout

But if you only want to convert between the PEM (Base64 text) and DER (raw binary) representations, you can do it explicitly. To extract the raw DER bytes from a PEM file, strip the header lines and Base64-decode the body — or just use OpenSSL's format conversion:

$ openssl x509 -in cert.pem -outform DER -out cert.der

Going the other direction, you can take DER bytes and re-encode them as PEM Base64. Manually, that is what the default 64-column wrapping is for:

$ openssl enc -base64 -in cert.der -out cert-body.txt

Do not use plain openssl enc -base64 to "decode a certificate" and expect something readable. The Base64 body decodes to DER — a compact binary ASN.1 structure, not text. Use openssl x509, openssl req, or openssl asn1parse to actually inspect the contents.

OpenSSL base64 vs the base64 command — when to use each

Most systems also ship a standalone base64 command. It and openssl enc -base64 implement the same standard alphabet (RFC 4648) and produce interchangeable output, but their defaults and ergonomics differ.

  • Line wrapping defaults differ. openssl enc -base64 wraps at 64 characters. GNU base64 (Linux) wraps at 76 characters but accepts -w 0 to disable wrapping. macOS/BSD base64 does not wrap at all by default.
  • Single-line flag differs. OpenSSL uses -A; GNU base64 uses -w 0; BSD base64 needs nothing because it never wraps.
  • Decode flag differs. OpenSSL uses -d; the base64 command uses -d (GNU) or -D (macOS).

Use OpenSSL when you are already in a certificate, key, or cryptography workflow — converting DER to PEM, encoding a binary digest, or scripting alongside other openssl subcommands. It is also the most portable choice across Unix-like systems where the standalone base64 flags vary between GNU and BSD.

Use the base64 command when you want the simplest possible one-off encode or decode and you know which platform you are on. It has a smaller, more memorable interface and is slightly faster to type.

Here are the equivalent single-line encode commands across all three:

$ echo -n "data" | openssl enc -base64 -A      # OpenSSL
$ echo -n "data" | base64 -w 0                 # GNU / Linux
$ echo -n "data" | base64                      # macOS / BSD

If you need a script that runs unchanged on both Linux and macOS, reaching for openssl enc -base64 -A is often the cleanest answer because the flags are identical everywhere OpenSSL is installed.


FAQ

How do I base64 encode a string with OpenSSL?

Use: echo -n "your string" | openssl enc -base64 -A. The -A flag outputs a single line with no wrapping. Without -A, OpenSSL wraps every 64 characters which can break downstream tools.

How do I decode Base64 with OpenSSL?

Use: echo "SGVsbG8=" | openssl enc -base64 -d -A. The -d flag means decode, -A means single-line (no line-break handling). You can also decode a file: openssl enc -base64 -d -A -in encoded.txt -out decoded.bin

What is the difference between openssl base64 and the base64 command?

They both do Base64 but with different defaults. openssl enc -base64 wraps at 64 chars by default; the base64 command wraps at 76 chars (GNU) or not at all (macOS). For certificate work, openssl is standard. For scripting, the base64 command is simpler.

Try Base64 encoding and decoding instantly

Paste any string or file — base64.dev auto-detects and converts it instantly.

Open base64.dev →