C言語でBase64のエンコードとデコードを教えて!
こういった悩みにお答えします.
本記事の信頼性
- リアルタイムシステムの研究歴12年.
- 東大教員の時に,英語でOS(Linuxカーネル)の授業.
- 2012年9月~2013年8月にアメリカのノースカロライナ大学チャペルヒル校(UNC)コンピュータサイエンス学部で客員研究員として勤務.C言語でリアルタイムLinuxの研究開発.
- プログラミング歴15年以上,習得している言語: C/C++,Python,Solidity/Vyper,Java,Ruby,Go,Rust,D,HTML/CSS/JS/PHP,MATLAB,Verse(UEFN), Assembler (x64,ARM).
- 東大教員の時に,C++言語で開発した「LLVMコンパイラの拡張」,C言語で開発した独自のリアルタイムOS「Mcube Kernel」をGitHubにオープンソースとして公開.
- 2020年1月~現在はアメリカのノースカロライナ州チャペルヒルにあるGuarantee Happiness LLCのCTOとしてECサイト開発やWeb/SNSマーケティングの業務.2022年6月~現在はアメリカのノースカロライナ州チャペルヒルにあるJapanese Tar Heel, Inc.のCEO兼CTO.
- 最近は自然言語処理AIとイーサリアムに関する有益な情報発信に従事.
- (AI全般を含む)自然言語処理AIの論文の日本語訳や,AIチャットボット(ChatGPT,Auto-GPT,Gemini(旧Bard)など)の記事を50本以上執筆.アメリカのサンフランシスコ(広義のシリコンバレー)の会社でプロンプトエンジニア・マネージャー・Quality Assurance(QA)の業務委託の経験あり.
- (スマートコントラクトのプログラミングを含む)イーサリアムや仮想通貨全般の記事を200本以上執筆.イギリスのロンドンの会社で仮想通貨の英語の記事を日本語に翻訳する業務委託の経験あり.
こういった私から学べます.
C言語を独学で習得することは難しいです.
私にC言語の無料相談をしたいあなたは,公式LINE「ChishiroのC言語」の友だち追加をお願い致します.
私のキャパシティもあり,一定数に達したら終了しますので,今すぐ追加しましょう!
独学が難しいあなたは,元東大教員がおすすめするC言語を学べるオンラインプログラミングスクール5社で自分に合うスクールを見つけましょう.後悔はさせません!
目次
Base64
Base64とは,バイナリデータをテキストデータに変換するエンコード方式です.
テキストデータには,以下の65文字を利用します.
- A-Z:26文字
- a-z:26文字
- 0-9:10文字
- +,/:2文字
- =:1文字(パディングの記号)
Base64のエンコードの手順は以下になります.
- 元データを6ビットずつに分割します.(6ビットに満たない分は0を追加して6ビットにします.)
- 各6ビットの値を以下の変換表を使って4文字ずつ変換します.(4文字に満たない分は=記号を追加して4文字にします.)
10進数 | 2進数 | 文字 | 10進数 | 2進数 | 文字 |
---|---|---|---|---|---|
0 | 000000 | A | 32 | 100000 | g |
1 | 000001 | B | 33 | 100001 | h |
2 | 000010 | C | 34 | 100010 | i |
3 | 000011 | D | 35 | 100011 | j |
4 | 000100 | E | 36 | 100100 | k |
5 | 000101 | F | 37 | 100101 | l |
6 | 000110 | G | 38 | 100110 | m |
7 | 000111 | H | 39 | 100111 | n |
8 | 001000 | I | 40 | 101000 | o |
9 | 001001 | J | 41 | 101001 | p |
10 | 001010 | K | 42 | 101010 | q |
11 | 001011 | L | 43 | 101011 | r |
12 | 001100 | M | 44 | 101100 | s |
13 | 001101 | N | 45 | 101101 | t |
14 | 001110 | O | 46 | 101110 | u |
15 | 001111 | P | 47 | 101111 | v |
16 | 010000 | Q | 48 | 110000 | w |
17 | 010001 | R | 49 | 110001 | x |
18 | 010010 | S | 50 | 110010 | y |
19 | 010011 | T | 51 | 110011 | z |
20 | 010100 | U | 52 | 110100 | 0 |
21 | 010101 | V | 53 | 110101 | 1 |
22 | 010110 | W | 54 | 110110 | 2 |
23 | 010111 | X | 55 | 110111 | 3 |
24 | 011000 | Y | 56 | 111000 | 4 |
25 | 011001 | Z | 57 | 111001 | 5 |
26 | 011010 | a | 58 | 111010 | 6 |
27 | 011011 | b | 59 | 111011 | 7 |
28 | 011100 | c | 60 | 111100 | 8 |
29 | 011101 | d | 61 | 111101 | 9 |
30 | 011110 | e | 62 | 111110 | + |
31 | 011111 | f | 63 | 111111 | / |
Base64のエンコードは仮想通貨イーサリアムで利用されています(go-ethereum/cmd/devp2p/README.md).
イーサリアムを知りたいあなたはこちらからどうぞ.
C言語でBase64のエンコードとデコードのコード
C言語でBase64のエンコードとデコードのコードは以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <stdlib.h> #include <string.h> #define BUFSIZE 128 int decode_base64_to_6bit(int c) { if (c >= 'A' && c <= 'Z') { return c - 'A'; } else if (c >= 'a' && c <= 'z') { return c - 'a' + 26; } else if (c >= '0' && c <= '9') { return c - '0' + 52; } else if (c == '+') { return 62; } else if (c == '/') { return 63; } else if (c == '=') { return 0; } else { fprintf(stderr, "Error: unknown data %d\n", c); exit(1); } } void decode_base64(char *dst, char *src) { unsigned int o[4]; char *p = dst; size_t i; for (i = 0; src[i]; i += 4) { o[0] = decode_base64_to_6bit(src[i]); o[1] = decode_base64_to_6bit(src[i + 1]); o[2] = decode_base64_to_6bit(src[i + 2]); o[3] = decode_base64_to_6bit(src[i + 3]); *p++ = (o[0] << 2) | ((o[1] & 0x30) >> 4); *p++ = ((o[1] & 0xf) << 4) | ((o[2] & 0x3c) >> 2); *p++ = ((o[2] & 0x3) << 6) | (o[3] & 0x3f); } *p = '\0'; } void encode_base64(char *dst, char *src) { size_t i; unsigned int o[4]; unsigned int x; const char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; size_t len = strlen(src); size_t mod = len % 3; size_t mod_len = len - mod; char *p = dst; for (i = 0; i < mod_len; i += 3) { x = ((unsigned int) src[i] << 16) + ((unsigned int) src[i + 1] << 8) + (unsigned int) src[i + 2]; o[0] = (x >> 18) & 0x3f; o[1] = (x >> 12) & 0x3f; o[2] = (x >> 6) & 0x3f; o[3] = x & 0x3f; *p++ = table[o[0]]; *p++ = table[o[1]]; *p++ = table[o[2]]; *p++ = table[o[3]]; } /* do nothing if mod == 0. */ if (mod == 1) { x = (unsigned int) src[i] << 16; o[0] = (x >> 18) & 0x3f; o[1] = (x >> 12) & 0x3f; *p++ = table[o[0]]; *p++ = table[o[1]]; *p++ = '='; *p++ = '='; } else if (mod == 2) { x = ((unsigned int) src[i] << 16) + ((unsigned int) src[i + 1] << 8); o[0] = (x >> 18) & 0x3f; o[1] = (x >> 12) & 0x3f; o[2] = (x >> 6) & 0x3f; *p++ = table[o[0]]; *p++ = table[o[1]]; *p++ = table[o[2]]; *p++ = '='; } *p = '\0'; } int main(int argc, char *argv[]) { char enc[BUFSIZE], dec[BUFSIZE]; if (argc != 2) { fprintf(stderr, "Error: %s str\n", argv[0]); exit(1); } encode_base64(enc, argv[1]); decode_base64(dec, enc); printf("encode_base64:%s\n", enc); printf("decode_base64:%s\n", dec); return 0; } |
実行結果は以下になります.
こちらのBase64のエンコード・デコード変換ツールと同じ結果になるか確認してみましょう.
1 2 3 4 5 6 7 |
$ gcc base64.c $ a.out base64 encode_base64:YmFzZTY0 decode_base64:base64 $ a.out base64_ encode_base64:YmFzZTY0Xw== decode_base64:base64_ |
参考:stdlib.hのa64l/l64a関数
1 2 |
long a64l(const char *str64); char *l64a(long value); |
stdlib.hのa64l/l64a関数は,32ビットlong整数とリトルエンディアンbase-64ASCII文字列(長さ0 〜 6)の間の変換を行います.
a64l関数の引数の文字列が7文字以上の場合,最初の6バイトが利用されます.
long型が32ビットより大きい場合,l64a関数はvalueの下位32ビットのみを利用し,a64l関数は32ビットの結果を符号拡張します.
base-64システムで利用される64個の文字は以下の通りです.
※先述した一般的なBase64とは異なることに注意して下さい.
- '.':0
- '/':1
- 0-9:2-11
- A-Z:12-37
- a-z:38-63
a64l/l64a関数の使い方は以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { long base64; char *str; int i; const char table[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; if (argc != 2) { fprintf(stderr, "Error: %s str\n", argv[0]); exit(1); } base64 = a64l(argv[1]); str = l64a(base64); printf("a64l():%ld\n", base64); for (i = base64; i > 0; i >>= 6) { printf("c = %c\n", table[i & 0x3f]); } printf("l64a():%s\n", str); return 0; } |
実行結果は以下になります.
1 2 3 4 5 6 7 |
$ gcc base64_stdlib.c $ a.out abc a64l():166374 c = a c = b c = c l64a():abc |
まとめ
C言語でBase64のエンコードとデコードを紹介しました.
Base64はバイナリデータをテキストデータに変換する時に有用です!
ビットコインやリップルで利用されるBase58を知りたいあなたはこちらからどうぞ.
C言語を独学で習得することは難しいです.
私にC言語の無料相談をしたいあなたは,公式LINE「ChishiroのC言語」の友だち追加をお願い致します.
私のキャパシティもあり,一定数に達したら終了しますので,今すぐ追加しましょう!
独学が難しいあなたは,元東大教員がおすすめするC言語を学べるオンラインプログラミングスクール5社で自分に合うスクールを見つけましょう.後悔はさせません!