山本ワールド
Windowsプログラミング
アルゴリズム Vitual C++ 2008/2013によるWin32/Win64 APIレベルのプログラム 基礎 Vitual C++ 2008/2013によるAPIレベルのプログラム(32/64bit) Wix3でインストーラーを作る Visual C++ 2008 Standard Editonによるフォームアプリケーションのプログラム(32/64bit) Vitual C++ 2008 Standard EditonによるAPIレベルのプログラム(32/64bit) Windows 7対応 Visual C++ 2008 ExpressによるAPIレベルのプログラム Visual C++ 2005 ExpressによるAPIレベルのプログラム Visual C++ Versiosn 5 BORLAND C++ Windowsプログラム全般 Excel VBA その他Base64エンコード・デコード
概要
Base64はデータを64種類の大文字及び小文字の英字と数字及び+と/に割り当てるエンコード方法でありMIMEに規定されている。
電子メールの認証や電子メールでバイナリー形式を扱う場合やhttpのBasic認証に用いられる。
本プログラムはBase64 testという文字列をBase64でエンコードしその結果をデコードするのものである。
コマンドプロンプトで動作し、エンコード結果とデコード結果を表示する。
電子メールの認証や電子メールでバイナリー形式を扱う場合やhttpのBasic認証に用いられる。
本プログラムはBase64 testという文字列をBase64でエンコードしその結果をデコードするのものである。
コマンドプロンプトで動作し、エンコード結果とデコード結果を表示する。
テスト環境
コンパイラ
Visual C++ 2013 Express 32bit/64bit実行環境
Windows 7 Enterprise Service Pack 1 64bit(Sandy Bridge-E)Base64でエンコードする方法
概要
Base64は入力データを6bitずつに分解し、6bitの0~63の値に以下の文字を当てはめたものである。
変換前の10の桁 1 2 3 4 5 6
変換前の 1の桁 0123456789012345678901234567890123456789012345678901234567890123
変換後の文字 ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
ANSI文字は8bitなので8と6の最小公倍数である24bit(3byte)単位で処理すると都合がよい。変換例
入力文字列 ABCDEFG上記を16進数及び2進数で表現すると以下のとおりである。
16進数 0x41 0x42 0x43 0x44 0x45 0x46 0x47
2進数 01000001-01000010-01000011-01000100-01000101-01000110-01000111-0000
6bit単位で分割した場合の最後6bitに満たない場合は下位に0を追加して6bitにする。
6bit単位を10進数で表すと
10進数 16 20 9 3 17 4 21 6 17 48
0~63の値に対して文字を割り当てる。
QUJDREVGRw
文字列の長さが4の倍数でない場合は、末尾に=を追加して4の倍数に合わせる。
QUJDREVGRw==
プログラムソースの概要
main
変数srcにbase64へエンコードしたい文字列を指定します。base64Encode関数によりbase64へエンコードして変数b64に格納します。
base64Decode関数により変数b64の文字列をデコードします。結果は変数srcと同じとなります。
base64Encode
文字数に一番近い3の倍数の文字数(文字数より小さい)に対して以下の処理をします。
3文字分(3byte)を抽出して24bitの整数値にします。24bitの上位から6bitずつ切り出し、o0~o3に代入します。
テーブルによりo0~o3を文字に変換し先頭から格納します。 次の3文字に対して上記の処理を繰り返します。
文字数を3で割ったときの余りの文字が無い場合は、変換後の文字の末尾に0を付加して終了します。
文字数を3で割ったときの余りの文字が1文字の時
1byteの上位6bitをo0に代入,1byteの下位2bitをo1の上位2bit残り4bitを0とし、テーブルによりo0~o1を文字に変換します。変換後の文字の末尾に=を2文字と0を付加して終了します。
文字数を3で割ったときの余りの文字が2文字の時
文字2byteと0を合成して24bit値を作成し、上位から6bitずつ分割しo0~o2に代入します。テーブルによりo0~o1を文字に変換します。
変換後の文字の末尾に=を1文字と0を付加して終了します。
base64Decode
エンコード時に文字数がちょうど4の倍数になるように調整されているので、4文字ずつ切り出して処理ができます。各文字をbase64_to_6bit関数により文字に対する6bitの値を算出します。
4個の6bit値を24bit(3byte)の整数に変換します。
base64_to_6bit
Base64文字から6bitの整数に変換します。引数が文字=の場合は0を返します。C言語の文字列は、終了文字が0なので害はありません。ソースコード
#include <stdio.h>
#include <string.h>
// base64の1文字を6bitの値に変換する
inline int base64_to_6bit(int c){
if (c == '=')
return 0;
if (c == '/')
return 63;
if (c == '+')
return 62;
if (c <= '9')
return (c - '0') + 52;
if ('a'<=c)
return (c - 'a') + 26;
return (c - 'A');
}
// base64の文字列srcをデコードしてバイナリ値に変換しdtcに格納
// lenはbase64の文字数
// 変換後のバイト数を返す
int base64Decode(char* src, char* dtc){
unsigned o0, o1, o2, o3;
char* p = dtc;
for (int n = 0; src[n];){
o0 = base64_to_6bit(src[n]);
o1 = base64_to_6bit(src[n + 1]);
o2 = base64_to_6bit(src[n + 2]);
o3 = base64_to_6bit(src[n + 3]);
*p++ = (o0 << 2) | ((o1 & 0x30) >> 4);
*p++ = ((o1 & 0xf) << 4) | ((o2 & 0x3c) >> 2);
*p++ = ((o2 & 0x3) << 6) | o3 & 0x3f;
n += 4;
}
*p = 0;
return int(p - dtc);
}
// バイナリの配列srcをbase64でエンコードする
// src:バイナリ配列 len:バイナリ配列長さ
// dtc:変換後の文字列を保存するアドレス dtc_len:変換後のバイト数を保存するアドレス
void base64Encode(char* src, char* dtc, int len, int* dtc_len){
// 6bitからbase64の文字へ変換するテーブル
// 1 2 3 4 5 6
// 0123456789012345678901234567890123456789012345678901234567890123456789
// 1 2 3
// 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF
const char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
int n;
int mod = len % 3;
int adj_len = len - mod; // 3の倍数に修正
char* p = dtc;
int o0, o1, o2, o3;
for (n = 0; n < adj_len;){
unsigned x = ((unsigned)src[n] << 16) + ((unsigned)src[n + 1] << 8) + unsigned(src[n + 2]);
o0 = (x >> 18) & 0x3f;
o1 = (x >> 12) & 0x3f;
o2 = (x >> 6) & 0x3f;
o3 = x & 0x3f;
*p++ = table[o0];
*p++ = table[o1];
*p++ = table[o2];
*p++ = table[o3];
n += 3;
}
if (mod){
if (mod==1){
unsigned x = (unsigned)src[n] << 16;
o0 = (x >> 18) & 0x3f;
o1 = (x >> 12) & 0x3f;
*p++ = table[o0];
*p++ = table[o1];
*p++ = '=';
*p++ = '=';
}
else if (mod==2){
unsigned x = ((unsigned)src[n] << 16) + ((unsigned)src[n + 1] << 8) ;
o0 = (x >> 18) & 0x3f;
o1 = (x >> 12) & 0x3f;
o2 = (x >> 6) & 0x3f;
*p++ = table[o0];
*p++ = table[o1];
*p++ = table[o2];
*p++ = '=';
}
}
*p = 0;
*dtc_len = int(p - dtc);
}
void main(void){
char* src = "Base64 test";
char b64[32];
char dtc[32];
int len;
base64Encode(src, b64, (int)strlen(src), &len);
base64Decode(b64, dtc);
printf("base64Encode:%s\n", b64);
printf("base64Decode:%s\n", dtc);
}
Copyright (C) 2012 山本ワールド All Rights Reserved.