CTF-RE 从0到N: 理解base64算法

Base64是一种常用的编码方式,用于将二进制数据转换为文本格式。它常用于在需要通过文本传输二进制数据的场景中,例如在电子邮件和URL中传递二进制文件。Base64的核心原理如下:

原理

  1. 输入数据分组

    • 将输入的二进制数据按字节分成每组3字节(24位)。
  2. 转换为6位块

    • 将每3字节(24位)的数据块分成4个6位块。这样,每个6位块可以表示一个范围在0到63之间的整数。
  3. 映射到Base64字符集

    • 使用Base64字符表将每个6位块映射到一个Base64字符。Base64字符集包含64个字符,包括大写字母A-Z,小写字母a-z,数字0-9,以及两个特殊字符"+"和"/"。
  4. 处理不足3字节的数据

    • 如果最后一组数据不足3字节,则用0字节填充,以保证数据长度是3的倍数。编码后,用一个或两个等号(=)填充,以表明原始数据的长度。

Base64字符表

Base64字符表如下:

ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/

示例

假设我们要编码字符串"Man"。

  1. 输入数据

    • 字符串"Man"的ASCII码是:

      M: 77 (01001101)
      a: 97 (01100001)
      n: 110 (01101110)
      
    • 合并成二进制数据:

      01001101 01100001 01101110
      
  2. 分成6位块

    • 划分后得到:

      010011 010110 000101 101110
      
  3. 转换为十进制

    • 每个6位块对应的整数是:

      19 22 5 46
      
  4. 映射到Base64字符集

    • 使用Base64字符表对应的字符是:

      T W F u
      

因此,字符串"Man"被Base64编码后就是"TWFu"。

处理不足3字节的数据

假设我们要编码字符串"Ma"。

  1. 输入数据

    • 字符串"Ma"的ASCII码是:

      M: 77 (01001101)
      a: 97 (01100001)
      
  2. 补齐到3字节

    • 补齐后变成:

      01001101 01100001 00000000
      
  3. 分成6位块

    • 划分后得到:

      010011 010110 000100 000000
      
  4. 转换为十进制

    • 每个6位块对应的整数是:

      19 22 16 0
      
  5. 映射到Base64字符集

    • 使用Base64字符表对应的字符是:

      T W Q A
      
  6. 添加填充字符

    • 因为原始数据不足3字节,我们在末尾添加一个等号(=),表示有1字节填充。

    • 最终结果是:

      TWFu==
      

解码过程

解码过程与编码过程相反,分以下几步:

  1. 移除填充字符

    • 移除结尾的等号(=)。
  2. 转换Base64字符为6位块

    • 将每个Base64字符转换回对应的6位二进制块。
  3. 重新组合为8位块

    • 将6位块重新组合成8位块。
  4. 转换为原始字节

    • 将8位块转回原始的字节数据。

通过这些步骤,Base64编码和解码可以在文本和二进制数据之间无损转换。

读懂这段代码!

c 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// Base64编码表
static const char base64_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
                                   "abcdefghijklmnopqrstuvwxyz"
                                   "0123456789+/";

// 判断字符是否为Base64编码字符
int is_base64(unsigned char c) {
    return (c >= 'A' && c <= 'Z') || 
           (c >= 'a' && c <= 'z') || 
           (c >= '0' && c <= '9') || 
           (c == '+') || (c == '/');
}

// Base64编码函数
char *base64_encode(const unsigned char *data, size_t input_length, size_t *output_length) {
    // 计算编码后的字符串长度
    *output_length = 4 * ((input_length + 2) / 3);

    // 为输出字符串分配内存
    char *encoded_data = (char *)malloc(*output_length + 1);
    if (encoded_data == NULL) return NULL;

    // 编码过程
    for (size_t i = 0, j = 0; i < input_length;) {
        uint32_t octet_a = i < input_length ? data[i++] : 0;
        uint32_t octet_b = i < input_length ? data[i++] : 0;
        uint32_t octet_c = i < input_length ? data[i++] : 0;

        uint32_t triple = (octet_a << 16) | (octet_b << 8) | octet_c;

        encoded_data[j++] = base64_chars[(triple >> 18) & 0x3F];
        encoded_data[j++] = base64_chars[(triple >> 12) & 0x3F];
        encoded_data[j++] = base64_chars[(triple >> 6) & 0x3F];
        encoded_data[j++] = base64_chars[triple & 0x3F];
    }

    // 添加填充字符
    for (size_t i = 0; i < (3 - input_length % 3) % 3; i++) {
        encoded_data[*output_length - 1 - i] = '=';
    }

    // 添加字符串终止符
    encoded_data[*output_length] = '\0';
    return encoded_data;
}

// 测试函数
int main() {
    const char *text = "Hello, World!";
    size_t input_length = strlen(text);
    size_t output_length;

    // Base64编码
    char *encoded_text = base64_encode((const unsigned char *)text, input_length, &output_length);
    if (encoded_text == NULL) {
        fprintf(stderr, "内存分配失败\n");
        return 1;
    }

    // 输出编码后的字符串
    printf("Base64编码后的结果:%s\n", encoded_text);

    // 释放内存
    free(encoded_text);
    return 0;
}
相关推荐
云梦姐姐7 小时前
第四届“网鼎杯”网络安全大赛 - 青龙组
ctf·wp
A5rZ1 天前
ctf-pwn: 数组越界
pwn·ctf
风飘红技术中心3 天前
2024-网鼎杯第二次模拟练习-web02
sql·web·ctf·sql注入·网鼎杯
A5rZ4 天前
CTF-RE 从0到N: TEA
ctf·ctf-re
Gnevergiveup4 天前
NewStar CTF 2024 Week1,Week2部分
web安全·网络安全·ctf·misc
孪生质数-6 天前
记录:网鼎杯2024赛前热身CRYPT02密码学
网络安全·密码学·ctf·网鼎杯
雪痕春风天音九重色7 天前
Re:从零开始的pwn学习(栈溢出篇)
pwn·ctf·栈溢出
石氏是时试9 天前
[NewStar 2024] week3
ctf
梦 & 醒9 天前
SHCTF-2024-week2-wp(web)
web安全·网络安全·ctf