Whiz Tools

Base64 编码/解码器

将文本转换为 Base64 编码或从 Base64 编码转换

复制

Base64 编码和解码器

介绍

Base64 是一种二进制到文本的编码方案,它以 ASCII 字符串格式表示二进制数据。它旨在通过仅可靠支持文本内容的通道传输存储在二进制格式中的数据。Base64 编码将二进制数据转换为一组 64 个字符(因此得名),可以安全地通过基于文本的协议传输,而不会导致数据损坏。

Base64 字符集由以下部分组成:

  • 大写字母 A-Z(26 个字符)
  • 小写字母 a-z(26 个字符)
  • 数字 0-9(10 个字符)
  • 另外两个字符,通常是 "+" 和 "/"(2 个字符)

该工具允许您轻松地将文本编码为 Base64 格式或将 Base64 字符串解码回其原始文本。它对开发人员、IT 专业人员以及任何需要安全传输数据的人员特别有用。

Base64 编码的工作原理

编码过程

Base64 编码通过将每组三个字节(24 位)的二进制数据转换为四个 Base64 字符来工作。该过程遵循以下步骤:

  1. 将输入文本转换为其二进制表示(使用 ASCII 或 UTF-8 编码)
  2. 将二进制数据分组为 24 位(3 字节)的块
  3. 将每个 24 位块拆分为四个 6 位组
  4. 将每个 6 位组转换为其对应的 Base64 字符

当输入长度不能被 3 整除时,会添加 "=" 字符进行填充,以保持输出与输入长度的 4:3 比率。

数学表示

对于字节序列 b1,b2,b3b_1, b_2, b_3,相应的 Base64 字符 c1,c2,c3,c4c_1, c_2, c_3, c_4 的计算如下:

c1=Base64[(b1>>2)]c_1 = \text{Base64}[(b_1 >> 2)]
c2=Base64[((b1&3)<<4)(b2>>4)]c_2 = \text{Base64}[((b_1 \& 3) << 4) | (b_2 >> 4)]
c3=Base64[((b2&15)<<2)(b3>>6)]c_3 = \text{Base64}[((b_2 \& 15) << 2) | (b_3 >> 6)]
c4=Base64[(b3&63)]c_4 = \text{Base64}[(b_3 \& 63)]

其中 Base64[i]\text{Base64}[i] 表示 Base64 字母表中的第 ii 个字符。

解码过程

Base64 解码反转编码过程:

  1. 将每个 Base64 字符转换为其 6 位值
  2. 将这些 6 位值连接起来
  3. 将位分组为 8 位块(字节)
  4. 将每个字节转换为其对应的字符

填充

当要编码的字节数不能被 3 整除时,会应用填充:

  • 如果剩下一个字节,则将其转换为两个 Base64 字符后跟 "=="
  • 如果剩下两个字节,则将其转换为三个 Base64 字符后跟 "="

示例

让我们将文本 "Hello" 编码为 Base64:

  1. "Hello" 的 ASCII 表示:72 101 108 108 111
  2. 二进制表示:01001000 01100101 01101100 01101100 01101111
  3. 分组为 6 位块:010010 000110 010101 101100 011011 000110 1111
  4. 最后一块只有 4 位,因此我们用零填充:010010 000110 010101 101100 011011 000110 111100
  5. 转换为十进制:18, 6, 21, 44, 27, 6, 60
  6. 在 Base64 字母表中查找:S, G, V, s, b, G, 8
  7. 结果是 "SGVsbG8="

请注意,由于输入长度(5 字节)不能被 3 整除,因此最后有 "=" 填充。

公式

计算 Base64 编码字符串长度的一般公式为:

encoded_length=4×input_length3\text{encoded\_length} = 4 \times \lceil \frac{\text{input\_length}}{3} \rceil

其中 x\lceil x \rceil 表示天花板函数(向上取整到最接近的整数)。

用例

Base64 编码在各种应用中被广泛使用:

  1. 电子邮件附件:MIME(多用途互联网邮件扩展)使用 Base64 编码电子邮件中的二进制附件。

  2. 数据 URL:使用 data: URL 方案将小图像、字体或其他资源直接嵌入 HTML、CSS 或 JavaScript 中。

  3. API 通信:在 JSON 有效负载或其他基于文本的 API 格式中安全地传输二进制数据。

  4. 在文本格式中存储二进制数据:当需要在 XML、JSON 或其他基于文本的格式中存储二进制数据时。

  5. 身份验证系统:HTTP 中的基本身份验证使用 Base64 编码(尽管这不是出于安全目的,仅仅是为了编码)。

  6. 加密:作为各种加密协议和系统的一部分,通常用于编码密钥或证书。

  7. Cookie 值:编码复杂数据结构以存储在 Cookie 中。

替代方案

虽然 Base64 被广泛使用,但在某些情况下可能有更合适的替代方案:

  1. URL 安全 Base64:一种变体,使用 "-" 和 "_" 代替 "+" 和 "/",以避免 URL 编码问题。适用于将包含在 URL 中的数据。

  2. Base32:使用 32 个字符集,导致输出更长,但可读性更好且不区分大小写。

  3. 十六进制编码:简单地转换为十六进制,效率较低(大小加倍),但非常简单且广泛支持。

  4. 二进制传输:对于大文件或当效率至关重要时,直接的二进制传输协议,如带有适当 Content-Type 头的 HTTP 更可取。

  5. 压缩 + Base64:对于大文本数据,先压缩再编码可以减轻大小增加。

  6. JSON/XML 序列化:对于结构化数据,使用本机 JSON 或 XML 序列化可能比 Base64 编码更合适。

历史

Base64 编码源于早期计算机和电信系统,其中二进制数据需要通过设计用于文本的通道进行传输。

Base64 的正式规范首次于 1987 年作为 RFC 989 发布,定义了隐私增强邮件(PEM)。此后在 RFC 1421(1993 年)和 RFC 2045(1996 年,作为 MIME 的一部分)中进行了更新。

“Base64”一词源于编码使用 64 个不同的 ASCII 字符来表示二进制数据。选择 64 个字符是经过深思熟虑的,因为 64 是 2 的幂(2^6),这使得二进制与 Base64 之间的转换效率高。

随着时间的推移,出现了几种 Base64 的变体:

  • 标准 Base64:如 RFC 4648 所定义,使用 A-Z、a-z、0-9、+、/ 和 = 作为填充
  • URL 安全 Base64:使用 - 和 _ 代替 + 和 /,以避免 URL 编码问题
  • 文件名安全 Base64:类似于 URL 安全,设计用于文件名
  • IMAP 的修改 Base64:在 IMAP 协议中使用,具有不同的特殊字符集

尽管已经有三十多年的历史,Base64 仍然是现代计算中的基本工具,特别是在网络应用和依赖于基于文本的数据格式(如 JSON)的 API 迅速崛起的背景下。

代码示例

以下是各种编程语言中 Base64 编码和解码的示例:

// JavaScript Base64 编码/解码
function encodeToBase64(text) {
  return btoa(text);
}

function decodeFromBase64(base64String) {
  try {
    return atob(base64String);
  } catch (e) {
    throw new Error("无效的 Base64 字符串");
  }
}

// 示例用法
const originalText = "Hello, World!";
const encoded = encodeToBase64(originalText);
console.log("编码:", encoded);  // SGVsbG8sIFdvcmxkIQ==

try {
  const decoded = decodeFromBase64(encoded);
  console.log("解码:", decoded);  // Hello, World!
} catch (error) {
  console.error(error.message);
}
# Python Base64 编码/解码
import base64

def encode_to_base64(text):
    # 将字符串转换为字节,然后编码
    text_bytes = text.encode('utf-8')
    base64_bytes = base64.b64encode(text_bytes)
    return base64_bytes.decode('utf-8')

def decode_from_base64(base64_string):
    try:
        # 将 base64 字符串转换为字节,然后解码
        base64_bytes = base64_string.encode('utf-8')
        text_bytes = base64.b64decode(base64_bytes)
        return text_bytes.decode('utf-8')
    except Exception as e:
        raise ValueError(f"无效的 Base64 字符串: {e}")

# 示例用法
original_text = "Hello, World!"
encoded = encode_to_base64(original_text)
print(f"编码: {encoded}")  # SGVsbG8sIFdvcmxkIQ==

try:
    decoded = decode_from_base64(encoded)
    print(f"解码: {decoded}")  # Hello, World!
except ValueError as e:
    print(e)
// Java Base64 编码/解码
import java.util.Base64;
import java.nio.charset.StandardCharsets;

public class Base64Example {
    public static String encodeToBase64(String text) {
        byte[] textBytes = text.getBytes(StandardCharsets.UTF_8);
        byte[] encodedBytes = Base64.getEncoder().encode(textBytes);
        return new String(encodedBytes, StandardCharsets.UTF_8);
    }
    
    public static String decodeFromBase64(String base64String) {
        try {
            byte[] base64Bytes = base64String.getBytes(StandardCharsets.UTF_8);
            byte[] decodedBytes = Base64.getDecoder().decode(base64Bytes);
            return new String(decodedBytes, StandardCharsets.UTF_8);
        } catch (IllegalArgumentException e) {
            throw new IllegalArgumentException("无效的 Base64 字符串: " + e.getMessage());
        }
    }
    
    public static void main(String[] args) {
        String originalText = "Hello, World!";
        String encoded = encodeToBase64(originalText);
        System.out.println("编码: " + encoded);  // SGVsbG8sIFdvcmxkIQ==
        
        try {
            String decoded = decodeFromBase64(encoded);
            System.out.println("解码: " + decoded);  // Hello, World!
        } catch (IllegalArgumentException e) {
            System.err.println(e.getMessage());
        }
    }
}
<?php
// PHP Base64 编码/解码
function encodeToBase64($text) {
    return base64_encode($text);
}

function decodeFromBase64($base64String) {
    $decoded = base64_decode($base64String, true);
    if ($decoded === false) {
        throw new Exception("无效的 Base64 字符串");
    }
    return $decoded;
}

// 示例用法
$originalText = "Hello, World!";
$encoded = encodeToBase64($originalText);
echo "编码: " . $encoded . "\n";  // SGVsbG8sIFdvcmxkIQ==

try {
    $decoded = decodeFromBase64($encoded);
    echo "解码: " . $decoded . "\n";  // Hello, World!
} catch (Exception $e) {
    echo "错误: " . $e->getMessage() . "\n";
}
?>
// C# Base64 编码/解码
using System;
using System.Text;

class Base64Example
{
    public static string EncodeToBase64(string text)
    {
        byte[] textBytes = Encoding.UTF8.GetBytes(text);
        return Convert.ToBase64String(textBytes);
    }
    
    public static string DecodeFromBase64(string base64String)
    {
        try
        {
            byte[] base64Bytes = Convert.FromBase64String(base64String);
            return Encoding.UTF8.GetString(base64Bytes);
        }
        catch (FormatException)
        {
            throw new FormatException("无效的 Base64 字符串");
        }
    }
    
    static void Main()
    {
        string originalText = "Hello, World!";
        string encoded = EncodeToBase64(originalText);
        Console.WriteLine($"编码: {encoded}");  // SGVsbG8sIFdvcmxkIQ==
        
        try
        {
            string decoded = DecodeFromBase64(encoded);
            Console.WriteLine($"解码: {decoded}");  // Hello, World!
        }
        catch (FormatException e)
        {
            Console.WriteLine($"错误: {e.Message}");
        }
    }
}
# Ruby Base64 编码/解码
require 'base64'

def encode_to_base64(text)
  Base64.strict_encode64(text)
end

def decode_from_base64(base64_string)
  begin
    Base64.strict_decode64(base64_string)
  rescue ArgumentError => e
    raise "无效的 Base64 字符串: #{e.message}"
  end
end

# 示例用法
original_text = "Hello, World!"
encoded = encode_to_base64(original_text)
puts "编码: #{encoded}"  # SGVsbG8sIFdvcmxkIQ==

begin
  decoded = decode_from_base64(encoded)
  puts "解码: #{decoded}"  # Hello, World!
rescue StandardError => e
  puts "错误: #{e.message}"
end
// Go Base64 编码/解码
package main

import (
    "encoding/base64"
    "fmt"
)

func encodeToBase64(text string) string {
    return base64.StdEncoding.EncodeToString([]byte(text))
}

func decodeFromBase64(base64String string) (string, error) {
    bytes, err := base64.StdEncoding.DecodeString(base64String)
    if err != nil {
        return "", fmt.Errorf("无效的 Base64 字符串: %v", err)
    }
    return string(bytes), nil
}

func main() {
    originalText := "Hello, World!"
    encoded := encodeToBase64(originalText)
    fmt.Println("编码:", encoded)  // SGVsbG8sIFdvcmxkIQ==
    
    decoded, err := decodeFromBase64(encoded)
    if err != nil {
        fmt.Println("错误:", err)
    } else {
        fmt.Println("解码:", decoded)  // Hello, World!
    }
}
// Swift Base64 编码/解码
import Foundation

func encodeToBase64(_ text: String) -> String? {
    if let data = text.data(using: .utf8) {
        return data.base64EncodedString()
    }
    return nil
}

func decodeFromBase64(_ base64String: String) -> String? {
    if let data = Data(base64Encoded: base64String) {
        return String(data: data, encoding: .utf8)
    }
    return nil
}

// 示例用法
let originalText = "Hello, World!"
if let encoded = encodeToBase64(originalText) {
    print("编码: \(encoded)")  // SGVsbG8sIFdvcmxkIQ==
    
    if let decoded = decodeFromBase64(encoded) {
        print("解码: \(decoded)")  // Hello, World!
    } else {
        print("错误: 无法解码 Base64 字符串")
    }
} else {
    print("错误: 无法编码文本")
}
' Excel VBA Base64 编码/解码
' 注意:这需要引用 Microsoft XML, v6.0
Function EncodeToBase64(text As String) As String
    Dim xmlObj As Object
    Set xmlObj = CreateObject("MSXML2.DOMDocument")
    
    Dim xmlNode As Object
    Set xmlNode = xmlObj.createElement("b64")
    
    xmlNode.DataType = "bin.base64"
    xmlNode.nodeTypedValue = StrConv(text, vbFromUnicode)
    
    EncodeToBase64 = xmlNode.text
    
    Set xmlNode = Nothing
    Set xmlObj = Nothing
End Function

Function DecodeFromBase64(base64String As String) As String
    On Error GoTo ErrorHandler
    
    Dim xmlObj As Object
    Set xmlObj = CreateObject("MSXML2.DOMDocument")
    
    Dim xmlNode As Object
    Set xmlNode = xmlObj.createElement("b64")
    
    xmlNode.DataType = "bin.base64"
    xmlNode.text = base64String
    
    DecodeFromBase64 = StrConv(xmlNode.nodeTypedValue, vbUnicode)
    
    Set xmlNode = Nothing
    Set xmlObj = Nothing
    Exit Function
    
ErrorHandler:
    DecodeFromBase64 = "错误: 无效的 Base64 字符串"
End Function

' 在工作表中的用法:
' =EncodeToBase64("Hello, World!")
' =DecodeFromBase64("SGVsbG8sIFdvcmxkIQ==")
# R Base64 编码/解码
# 需要 'base64enc' 包
# install.packages("base64enc")
library(base64enc)

encode_to_base64 <- function(text) {
  # 将文本转换为原始字节,然后编码
  text_raw <- charToRaw(text)
  base64_encoded <- base64encode(text_raw)
  return(rawToChar(base64_encoded))
}

decode_from_base64 <- function(base64_string) {
  tryCatch({
    # 将 base64 字符串转换为原始字节,然后解码
    base64_raw <- charToRaw(base64_string)
    decoded_raw <- base64decode(base64_raw)
    return(rawToChar(decoded_raw))
  }, error = function(e) {
    stop(paste("无效的 Base64 字符串:", e$message))
  })
}

# 示例用法
original_text <- "Hello, World!"
encoded <- encode_to_base64(original_text)
cat("编码:", encoded, "\n")  # SGVsbG8sIFdvcmxkIQ==

tryCatch({
  decoded <- decode_from_base64(encoded)
  cat("解码:", decoded, "\n")  # Hello, World!
}, error = function(e) {
  cat("错误:", e$message, "\n")
})
% MATLAB Base64 编码/解码
function demo_base64()
    originalText = 'Hello, World!';
    
    % 编码
    encoded = encode_to_base64(originalText);
    fprintf('编码: %s\n', encoded);  % SGVsbG8sIFdvcmxkIQ==
    
    % 解码
    try
        decoded = decode_from_base64(encoded);
        fprintf('解码: %s\n', decoded);  % Hello, World!
    catch e
        fprintf('错误: %s\n', e.message);
    end
end

function encoded = encode_to_base64(text)
    % 将文本转换为 uint8 数组并编码
    bytes = uint8(text);
    encoded = base64encode(bytes);
end

function decoded = decode_from_base64(base64String)
    try
        % 将 base64 字符串解码为 uint8 数组
        bytes = base64decode(base64String);
        decoded = char(bytes);
    catch
        error('无效的 Base64 字符串');
    end
end
// C Base64 编码/解码 使用 OpenSSL
#include <stdio.h>
#include <string.h>
#include <openssl/bio.h>
#include <openssl/evp.h>
#include <openssl/buffer.h>
#include <stdint.h>

char* encode_to_base64(const char* input) {
    BIO *bio, *b64;
    BUF_MEM *bufferPtr;
    
    b64 = BIO_new(BIO_f_base64());
    bio = BIO_new(BIO_s_mem());
    bio = BIO_push(b64, bio);
    
    BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);
    BIO_write(bio, input, strlen(input));
    BIO_flush(bio);
    BIO_get_mem_ptr(bio, &bufferPtr);
    
    char* result = (char*)malloc(bufferPtr->length + 1);
    memcpy(result, bufferPtr->data, bufferPtr->length);
    result[bufferPtr->length] = '\0';
    
    BIO_free_all(bio);
    
    return result;
}

char* decode_from_base64(const char* input) {
    BIO *bio, *b64;
    size_t length = strlen(input);
    char* buffer = (char*)malloc(length);
    
    b64 = BIO_new(BIO_f_base64());
    bio = BIO_new_mem_buf(input, -1);
    bio = BIO_push(b64, bio);
    
    BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);
    int decoded_length = BIO_read(bio, buffer, length);
    
    if (decoded_length <= 0) {
        free(buffer);
        BIO_free_all(bio);
        return NULL; // 无效的 Base64 输入
    }
    
    buffer[decoded_length] = '\0';
    
    BIO_free_all(bio);
    
    return buffer;
}

int main() {
    const char* original_text = "Hello, World!";
    
    char* encoded = encode_to_base64(original_text);
    printf("编码: %s\n", encoded);  // SGVsbG8sIFdvcmxkIQ==
    
    char* decoded = decode_from_base64(encoded);
    if (decoded) {
        printf("解码: %s\n", decoded);  // Hello, World!
        free(decoded);
    } else {
        printf("错误: 无效的 Base64 字符串\n");
    }
    
    free(encoded);
    
    return 0;
}
// Rust Base64 编码/解码
use base64::{encode, decode};
use std::str;

fn encode_to_base64(text: &str) -> String {
    encode(text)
}

fn decode_from_base64(base64_string: &str) -> Result<String, String> {
    match decode(base64_string) {
        Ok(bytes) => {
            match str::from_utf8(&bytes) {
                Ok(text) => Ok(text.to_string()),
                Err(e) => Err(format!("无效的 UTF-8 序列: {}", e))
            }
        },
        Err(e) => Err(format!("无效的 Base64 字符串: {}", e))
    }
}

fn main() {
    let original_text = "Hello, World!";
    let encoded = encode_to_base64(original_text);
    println!("编码: {}", encoded);  // SGVsbG8sIFdvcmxkIQ==
    
    match decode_from_base64(&encoded) {
        Ok(decoded) => println!("解码: {}", decoded),  // Hello, World!
        Err(e) => println!("错误: {}", e)
    }
}

边缘案例和注意事项

在使用 Base64 编码和解码时,请注意以下重要事项:

  1. Unicode 和非 ASCII 字符:在编码包含非 ASCII 字符的文本时,确保在 Base64 编码之前使用适当的字符编码(通常是 UTF-8)。

  2. 填充:标准 Base64 使用 "=" 字符进行填充,以确保输出长度是 4 的倍数。一些实现允许省略填充,这可能会导致兼容性问题。

  3. 换行符:传统的 Base64 实现会插入换行符(通常每 76 个字符)以提高可读性,但现代应用程序通常省略这些。

  4. URL 安全 Base64:标准 Base64 使用 "+" 和 "/" 字符,这在 URL 中具有特殊含义。对于 URL 上下文,请使用 URL 安全 Base64,它用 "-" 和 "_" 替换这些字符。

  5. 空格:在解码时,一些实现是宽容的,忽略空格,而其他实现则要求输入完全准确。

  6. 大小增加:Base64 编码会使数据大小增加大约 33%(每 3 个输入字节输出 4 个字节)。

  7. 性能:对于非常大的数据,Base64 编码/解码可能会消耗大量计算资源。对于大文件,考虑使用流式处理方法。

参考文献

  1. RFC 4648 - Base16、Base32 和 Base64 数据编码
  2. RFC 2045 - MIME 第一部分:互联网邮件主体的格式
  3. MDN Web Docs: Base64 编码和解码
  4. Base64 - 维基百科
  5. MIME - 维基百科
Feedback