C語言版的Base-64加密解密函數

jopen 9年前發布 | 2K 次閱讀 C/C++

#include <stdint.h>

include <stdlib.h>

include <string.h>

define BLOCK_BYTE 3 // Number of bytes in each base-64 24-bit block

define BLOCK_CHAR 4 // Number of base-64 characters in a 24-bit block

define BASE64_LINE_LEN 76 // Maximum line length of a base-64 string

define NEWLINE_LEN 2 // Number of characters in the newline sequence

static const char digits = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static const char newline = "\r\n"; static const char padding = '='; static size_t digit_value(char ch); static void check_append_newline(char dst, size_t end); static void convert_block(char dst, size_t end, const uint8_t src, size_t bytes); / @description: Converts n bytes pointed to by src into base-64 representation. / extern char encode_base64(const void src, size_t n) { size_t partial_block_bytes = n % BLOCK_BYTE; size_t full_blocks = n / BLOCK_BYTE; // Make room for all full blocks plus one extra for a partial block char dst = malloc((full_blocks + 1) BLOCK_CHAR + 1); if (!dst) return NULL; const uint8_t bytes = src; size_t k; // Convert all complete 24-bit blocks to base-64 for (k = 0; full_blocks--; bytes += BLOCK_BYTE) { check_append_newline(dst + k, &k); convert_block(dst, &k, bytes, BLOCK_BYTE); } // Convert the final (possibly empty) partial block check_append_newline(dst + k, &k); convert_block(dst, &k, bytes, partial_block_bytes); dst[k] = '\0'; return dst; } / @description: Converts a valid base-64 string into a decoded array of bytes and stores the number of decoded bytes in the object pointed to by n./ extern void decode_base64(const char src, size_t n) { size_t len = strlen(src); if (len % BLOCK_CHAR) return NULL; // Invalid number of base-64 characters // There will never be more bytes than base-64 characters by definition uint8_t dst = malloc(len + 1); for (n = 0; src; src += BLOCK_CHAR) { if (src == '\r') { ++src; // Skip the CR part of CRLF if (src != '\n') { free(dst); return NULL; // Unmatched CR } ++src; // Skip the LF part of CRLF } size_t encoded[] = { digit_value(src[0]), digit_value(src[1]), digit_value(src[2]), digit_value(src[3]) }; // Check for invalid base-64 characters for (size_t i = 0; i < sizeof encoded / sizeof encoded; ++i) { if (encoded[i] == (size_t)-1) { free(dst); return NULL; } } // Precompute the decoded bytes to faciliate handling of zero byte values uint8_t bytes[] = { (encoded[0] << 2) + ((encoded[1] & 0x30) >> 4), ((encoded[1] & 0x0f) << 4) + ((encoded[2] & 0x3c) >> 2), ((encoded[2] & 0x03) << 6) + encoded[3] }; // Push non-zero decoded bytes into the destination for (size_t i = 0; i < BLOCK_BYTE; ++i) { // Zero bytes should only occur for padding, which we don't save if (bytes[i]) dst[(n)++] = bytes[i]; } } return dst; } / @description: Locates the index value of a base-64 character for decoding./ static size_t digit_value(char ch) { if (ch == padding) return 0; const char p = strchr(digits, ch); return p ? p - digits : (size_t)-1; } / @description: Appends a newline to dst if the value of end is at the correct position. Returns the updated value of end, which may not change if a newline was not appended. / static void check_append_newline(char dst, size_t end) { if ((end + 1) % BASE64_LINE_LEN == 0) { memcpy(dst, newline, NEWLINE_LEN); end += NEWLINE_LEN; } } / @description: Converts a 24-bit block represented by 3 octets into four base-64 characters and stores them in dst starting at end. Returns the updated value of end for convenience. / static void convert_block(char dst, size_t end, const uint8_t src, size_t bytes) { switch (bytes) { case 3: dst[(end)++] = digits[src[0] >> 2]; dst[(end)++] = digits[((src[0] & 0x03) << 4) | (src[1] >> 4)]; dst[(end)++] = digits[((src[1] & 0x0f) << 2) | (src[2] >> 6)]; dst[(end)++] = digits[src[2] & 0x3f]; break; case 2: dst[(end)++] = digits[src[0] >> 2]; dst[(end)++] = digits[((src[0] & 0x03) << 4) | (src[1] >> 4)]; dst[(end)++] = digits[((src[1] & 0x0f) << 2)]; dst[(end)++] = padding; break; case 1: dst[(end)++] = digits[src[0] >> 2]; dst[(end)++] = digits[((src[0] & 0x03) << 4)]; dst[(end)++] = padding; dst[(end)++] = padding; break; } }

define TEST_DRIVER

ifdef TEST_DRIVER

include <stdbool.h>

include <stdio.h>

include <stdlib.h>

include <string.h>

int main(void) { const char test[] = {"", "f", "fo", "foo", "foob", "fooba", "foobar"}; size_t n; for (size_t i = 0; i < sizeof test / sizeof test; ++i) { char p = encode_base64(test[i], strlen(test[i])); char q = decode_base64(p, &n); printf("BASE64(\"%s\") = \"%s\" = (%zd)\"%.*s\"\n", test[i], p, n, n, q); free(p); free(q); } return 0; }

endif</pre>


 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!