Base64 private key → HEX, WIF, addresses
Paste a Base64-encoded 32-byte private key and get the decoded HEX, the decoded byte length, both WIFs, both public keys, the hash160 and all five address types. Base64 is a transport encoding with no checksum, so this page checks the decoded length before it trusts anything.
Enter a value above and press Convert. Not sure what to type? Press “Use example” to load the sample from the placeholder.
What this page computes
Some wallets, exchanges and OpenSSL-based tools never show a private key as 64 hex digits. They print the raw 32 bytes as Base64, because Base64 survives any text-only channel: JSON, INI files, chat messages, QR codes, clipboards. This page reverses that step — decode the text back into bytes, check that the result really is one valid secp256k1 private key, then run the whole derivation chain on it.
It never guesses: a decoded length that is not 32 bytes is an error, and an empty box produces an empty state rather than a result.
1. The Base64 alphabet, and why it holds 64 symbols
A private key is 32 bytes, and a byte can hold any of 256 values — roughly half of them control characters, quotes or bytes that are simply illegal in a text protocol. Base64 avoids all of that by re-grouping the bits into 6-bit chunks and mapping each chunk onto one of 64 harmless printable characters.
Why 64? Because 26 = 64, and 6 bits is the largest chunk that still maps onto printable ASCII: 7 bits would need 128 symbols, and most of the upper range is control codes. The alphabet is fixed and public, and one character means one 6-bit value — nothing more:
| Index | Characters | Count | Note |
|---|---|---|---|
| 0 – 25 | A … Z | 26 | upper case |
| 26 – 51 | a … z | 26 | so A ≠ a |
| 52 – 61 | 0 … 9 | 10 | digits |
| 62 | + | 1 | breaks URLs |
| 63 | / | 1 | breaks file paths |
| — | = | — | not a symbol: a padding marker |
26 + 26 + 10 + 1 + 1 = 64. Every 6-bit value from 000000 to
111111 has exactly one character, and every character has exactly one value. That is the
entire trick.
2. Four characters carry three bytes — and where = comes from
6 bits per character and 8 bits per byte do not line up. The smallest common multiple is 24 bits: 24 = 3 bytes = 4 Base64 characters. Base64 therefore always processes input in 3-byte blocks and emits 4 characters per block, wasting no bits anywhere in the middle of the stream.
A 32-byte key is not a multiple of 3, so the final block is short and has to be padded. The arithmetic for the demo key is:
n = 32 bytes
full blocks = floor(32 / 3) = 10 -> 10 × 4 = 40 characters
leftover = 32 mod 3 = 2 bytes -> needs ceil(2·8 / 6) = 3 characters
padding = 4 − 3 = 1 -> one "=" marker
total = 40 + 3 + 1 = 44 characters = 4 · ⌈32/3⌉
That matches the sample exactly: 44 characters, ending in a single =.
| Input | Example | Encoded | Padding | Chars |
|---|---|---|---|---|
| 1 byte | 01 | AQ== | 2 × = | 4 |
| 2 bytes | 0102 | AQI= | 1 × = | 4 |
| 3 bytes | 010203 | AQID | none | 4 |
| 20 bytes (hash160) | 21f57b6d…189012 | IfV7bevPxbZxgt+0rxZB8KgYkBI= | 1 × = | 28 |
| 32 bytes (a key) | this page's demo key | CCTDFHcr…ehcco= | 1 × = | 44 |
| 33 bytes | key + one extra byte | — | none | 44 |
The last two rows matter: a 32-byte and a 33-byte blob both encode to 44 characters. Only the
= count separates them — one pad means n mod 3 = 2, none means
n mod 3 = 0. Characters alone never reveal the byte length.
Base64 length is always a multiple of 4, and the trailing = count recovers
n mod 3: 0 pads → n ≡ 0, 1 pad → n ≡ 2, 2 pads →
n ≡ 1. The decoded byte length is therefore known before decoding — and it is
reported as a result here, because a private key must decode to exactly 32 bytes.
3. An encoding is neither encryption nor compression
- Encryption hides data behind a secret. Base64 has no secret: the alphabet is published in RFC 4648, the mapping is one-to-one, and anyone holding the string can decode it in one line of code. A Base64 private key is a plaintext private key.
- Compression shrinks data by exploiting redundancy. Base64 does the opposite — it always enlarges, because 8 bits of input cost 4/3 of a character. A uniformly random 256-bit key has no redundancy to exploit, so a "compressed" Base64 key is a contradiction.
- Encoding changes only the representation, so that bytes can travel through a channel which accepts only text. That is all Base64 does.
| Representation of the same 32-byte key | Characters | Size vs raw bytes | Bits per character |
|---|---|---|---|
| Raw bytes | 32 bytes | 1.00× (baseline) | 8 |
| Base64 | 44 | 1.375× (+37.5 %) | 6 |
| Hex | 64 | 2.00× (+100 %) | 4 |
| Base58 (bare) | 43 | 1.344× (+34.4 %) | ≈5.858 |
| WIF compressed (Base58Check) | 52 | 1.625× (+62.5 %) | ≈5.858 |
For this key size Base64 is the tightest text alphabet — 44 characters against 64 for hex — yet still 37.5 % larger than the raw bytes. It buys nothing in security, everything in compatibility.
4. Base64 next to hex, Base58 and Bech32
Bitcoin's ecosystem uses four text alphabets, and picking the wrong decoder is one of the most common ways to end up with a "key" no wallet recognises.
| Base64 | Hex | Base58 / Base58Check | Bech32 / Bech32m | |
|---|---|---|---|---|
| Alphabet size | 64 | 16 | 58 | 32 |
| Symbols | A–Z a–z 0–9 + / | 0–9 a–f | 1–9 A–Z a–z minus 0 O I l | qpzry9x8gf2tvdw0s3jn54khce6mua7l |
| Bits per character | 6 | 4 | ≈5.858 | 5 |
| Case sensitivity | Yes | No | Yes | No, but mixed case is forbidden |
| Checksum | None | None | Only in the Check variant (4 bytes of SHA256d) | Yes — a 6-character BCH code |
| Typo detection | None — a wrong character silently gives different bytes | None | Rejects almost every typo | Up to 4 errors detected, 2 located |
| Typical use | PEM/DER files, JSON config, API exports | BIP test vectors, debug dumps | Legacy addresses, WIF | SegWit addresses |
5. Where a Base64 private key actually comes from
Bitcoin Core itself exports WIF, not Base64. Base64 keys appear in the seams between Bitcoin and general-purpose software:
- OpenSSL / PEM key files. The file body is Base64 of an ASN.1 DER structure. Extracting the raw 32-byte scalar from it and re-printing it as Base64 is a standard migration path.
- Application config files. JSON has no byte type, so a service that stores a signing
key in JSON almost always stores it Base64 —
base64_encode()in PHP,base64.b64encode()in Python,Convert.ToBase64String()in .NET. - Exchange and API exports. Some custodial services hand you a "raw private key" as Base64 rather than WIF, because their backend keys are not Bitcoin-specific.
- QR codes and printed backups. 44 characters fit a low-density QR symbol — though
Base64 brings its own
+//hazards.
If a string decodes to 300 bytes it is a PEM/DER key file, a keystore or a backup archive, not a raw 32-byte scalar. This page therefore enforces an exact length and refuses anything longer than 32 bytes rather than truncating it into a valid-looking key that controls something else.
6. Worked example — the demo key in every representation
These are the values this page produces for the sample Base64 in the input box:
| Step | Value |
|---|---|
Base64 input (44 chars, one =) | CCTDFHcrLChZyIlHE5Cja/ZuU6HKFkL5bw8skwehcco= |
| Decoded hex (64 digits) | 0824c314772b2c2859c889471390a36bf66e53a1ca1642f96f0f2c9307a171ca |
| Decoded length | 32 bytes = 256 bits |
| Padding characters | 1 → consistent with 32 mod 3 = 2 |
| Re-encoded Base64 | CCTDFHcrLChZyIlHE5Cja/ZuU6HKFkL5bw8skwehcco= — identical, so nothing was lost |
| WIF, compressed | KwVYL77Lcs1ckM39NvGjrtfKhU4KKdR2iB9Wq2FSMN6rbGK5tVqG |
| WIF, uncompressed | 5HssbguBnjbaUVZCsH9YuzUG7T4vYQf51iiodi4izdVy6aVNekU |
| P2PKH address | 146ZNjH7XTXnMd1ofe3z7CL2i8WM7N2UqT |
| P2WPKH address | bc1qy86hkm0telzmvuvzm76279jp7z5p3yqjnaerk6 |
Now change exactly one character — the leading C becomes a 0. Both are legal
Base64 symbols, so the decoder has nothing to complain about:
Original — CC…
CCTDFHcrLChZyIlHE5Cja/ZuU6HKFkL5bw8skwehcco=
decodes to 0824c314…171ca, P2PKH
146ZNjH7XTXnMd1ofe3z7CL2i8WM7N2UqT
One character different — 0C…
0CTDFHcrLChZyIlHE5Cja/ZuU6HKFkL5bw8skwehcco=
decodes to d024c314…171ca, P2PKH
1HW3HfyXS3UFRJDMQ5LJjVyk12UMf6uoGB
The first byte moved from 08 to d0, and the key, both WIFs and every address
changed with it. Base64 flagged nothing.
Base58Check and Bech32 carry a checksum inside the string, so a single mistyped character is caught at once (a WIF simply refuses to decode). Base64 carries nothing: one wrong character produces a perfectly valid different private key, and the first you hear of it is an empty wallet. Before moving funds to an address derived from a Base64 export, re-encode the decoded bytes and compare the two strings.
7. Base64 and WIF are not two spellings of the same thing
Both are text encodings of one 32-byte secret, and that is where the similarity ends. A WIF is
Base58Check(0x80 ‖ key ‖ 0x01): it adds a version byte naming the network, a flag byte saying
whether the key is used in compressed form, and a 4-byte double-SHA256 checksum. Base64 adds padding and
nothing else.
| Form of the demo key | Alphabet | Version byte | Compression flag | Checksum | Length |
|---|---|---|---|---|---|
| Hex | 16 | — | — | none | 64 |
| Base64 | 64 | — | — | none | 44 |
| WIF uncompressed | 58 | 0x80 | absent | 4 bytes | 51 |
| WIF compressed | 58 | 0x80 | 0x01 | 4 bytes | 52 |
The alphabets are the practical test. Base58 excludes 0, O, I
and l so that handwritten paper wallets cannot be misread, and it excludes +,
/ and = as well. Base64 uses all of those. So a string containing
+, / or = is not a WIF, and a string containing
0, O, I or l is not Base58 at all.
The reverse test is the dangerous one. Every Base58 character is also a legal Base64 character, and a
compressed WIF is 52 characters — exactly divisible by 4. Paste
KwVYL77Lcs1ckM39NvGjrtfKhU4KKdR2iB9Wq2FSMN6rbGK5tVqG into a Base64 decoder and nothing
errors: it produces 39 bytes. Hence the length check here, and hence the byte count being
a first-class result. A Base64 box that accepted a WIF would hand you a 39-byte "private key" that is not
your key.
8. What this page rejects, and why
| Input | Result | Reason |
|---|---|---|
CCTDFHcr…ehcco= | accepted | 44 chars, 1 pad, decodes to exactly 32 bytes |
CCTDFHcr…ehcco (padding stripped) | accepted | trailing padding is optional in most decoders; the page re-encodes canonically |
CCTDFHcr…ehcco== | rejected | at most two =, and only at the very end |
CCTDFHcr…cc=o | rejected | padding in the middle |
CCTDFHcr…cc! | rejected | character outside the 64-symbol alphabet |
…cc-cc_= (base64url) | rejected | URL-safe Base64 swaps +// for -/_: a different alphabet |
| spaces or newlines inside | accepted | whitespace is stripped first, so a wrapped paste works |
| 33 or 34 decoded bytes | rejected | a raw private key is exactly 32 bytes |
| a WIF pasted here | rejected | decodes to 39 or 38 bytes — recognised and refused instead of mangled |
| a hash160 (20 bytes) | rejected | too short: that is a public-key hash |
One subtlety: Base64 is not injective. In a partial final block the bits that do not
fit are ignored, so for a 32-byte key …ehcco= and …ehccp= decode to identical
bytes even though the strings differ, and decoders accept both. Never compare two Base64 keys as strings —
decode first, then compare bytes.
9. Security notes and common mistakes
- Base64 is plaintext. Not obfuscation, not encryption, not a password: anyone who can read the string can spend the coins it protects.
- Never type a real key into a page you do not control. This page computes on the server you are already talking to and sends nothing elsewhere — but a funded key belongs in a hardware wallet or on an offline machine.
- No checksum means no typo alarm. If you must transcribe a key by hand, write it as a WIF and let its 4-byte checksum work for you.
- Treating Base64 as encryption or expecting it to be shorter than the raw bytes. "It looks like gibberish" is not protection, and 44 characters is still more than 32 bytes.
- Pasting a WIF or a PEM block. A WIF decodes (to 39 bytes) because Base58 is a subset of the Base64 alphabet; a PEM body decodes to DER, hundreds of bytes long.
- Using base64url data. JWT-style
-/_alphabets are not standard Base64; conversion is one substitution, but decoders reject them as-is. - Comparing two Base64 keys as strings instead of comparing decoded bytes.
10. Quick reference
| Item | Value |
|---|---|
| Decoded length | must be exactly 32 bytes (256 bits) |
| Alphabet | A–Z a–z 0–9 + /, = as padding |
| Length formula | 4 · ⌈n/3⌉, always a multiple of 4 |
| Padding rule | n mod 3 = 0 → none, 1 → two, 2 → one |
| Size for a 32-byte key | 44 characters, +37.5 % over the raw bytes |
| Checksum | none — typos are undetectable |
| Encryption / compression | neither: it is a reversible transport encoding |