標準的Base64並不適合直接放在URL裡傳輸,因為URL編碼器會把標準Base64中的“/”和“+”字元變為形如“%XX”的形式,而這些“%”號在存入資料庫時還需要再進行轉換,因為ANSI SQL中已將“%”號用作萬用字元。
為解決此問題,可採用一種用於URL的改進Base64編碼,它在末尾填充’=’號,並將標準Base64中的“+”和“/”分別改成了“-”和“_”,這樣就免去了在URL編解碼和資料庫儲存時所要作的轉換,避免了編碼資訊長度在此過程中的增加,並統一了資料庫、表單等處物件識別碼的格式。
另有一種用於Regex的改進Base64變種,它將“+”和“/”改成了“!”和“-”,因為“+”,“*”以及前面在IRCu中用到的“[”和“]”在Regex中都可能具有特殊含義。
此外還有一些變種,它們將“+/”改為“-”或“.”(用作程式設計語言中的標識符名稱)或“.-”(用於XML中的Nmtoken)甚至“_:”(用於XML中的Name)。
Base64要求把每三個8Bit的位元組轉換為四個6Bit的位元組(3*8 = 4*6 = 24),然後把6Bit再添兩位高位0,組成四個8Bit的位元組,也就是說,轉換後的字串理論上將要比原來的長1/3。
規則 關於這個編碼的規則:
①.把3個字元變成4個字元。
②每76個字元加一個分行符號。
③.最後的結束符也要處理。
例子(1)
轉換前 11111111, 11111111, 11111111 (二進位)
轉換後 00111111, 00111111, 00111111, 00111111 (二進位)
上面的三個位元組是原文,下面的四個位元組是轉換後的Base64編碼,其前兩位均為0。
轉換後,我們用一個碼錶來得到我們想要的字串(也就是最終的Base64編碼),這個表是這樣的:(摘自RFC2045) 轉換表
| 索引 |
對應字元 |
索引 |
對應字元 |
索引 |
對應字元 |
索引 |
對應字元 |
| 0 |
A |
17 |
R |
34 |
i |
51 |
z |
| 1 |
B |
18 |
S |
35 |
j |
52 |
0 |
| 2 |
C |
19 |
T |
36 |
k |
53 |
1 |
| 3 |
D |
20 |
U |
37 |
l |
54 |
2 |
| 4 |
E |
21 |
V |
38 |
m |
55 |
3 |
| 5 |
F |
22 |
W |
39 |
n |
56 |
4 |
| 6 |
G |
23 |
X |
40 |
o |
57 |
5 |
| 7 |
H |
24 |
Y |
41 |
p |
58 |
6 |
| 8 |
I |
25 |
Z |
42 |
q |
59 |
7 |
| 9 |
J |
26 |
a |
43 |
r |
60 |
8 |
| 10 |
K |
27 |
b |
44 |
s |
61 |
9 |
| 11 |
L |
28 |
c |
45 |
t |
62 |
+ |
| 12 |
M |
29 |
d |
46 |
u |
63 |
/ |
| 13 |
N |
30 |
e |
47 |
v |
|
|
| 14 |
O |
31 |
f |
48 |
w |
|
|
| 15 |
P |
32 |
g |
49 |
x |
|
|
| 16 |
Q |
33 |
h |
50 |
y |
|
|
//自己完成演算法實現 /// <summary> /// Base64加密 /// </summary> /// <param name="Message"></param> /// <returns></returns> public string Base64Code(string Message) { char[] Base64Code = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', '=' }; byte empty = 0; var byteMessage = new ArrayList(Encoding.Default.GetBytes(Message)); StringBuilder outmessage; int messageLen = byteMessage.Count; //將字元分成3個位元組一組,如果不足,則以0補齊 int page = messageLen/3; int use = 0; if ((use = messageLen%3) > 0) { for (int i = 0; i < 3 - use; i++) byteMessage.Add(empty); page++; } //將3個位元組的每組字元轉換成4個位元組一組的。3個一組,一組一組變成4個位元組一組 //方法是:轉換成ASCII碼,按順序排列24位元據,再把這24位元據分成4組,即每組6位。再在每組的的最高位前補兩個0湊足一個位元組。 outmessage = new StringBuilder(page*4); for (int i = 0; i < page; i++) { //取一組3個位元組的組 var instr = new byte[3]; instr[0] = (byte) byteMessage[i*3]; instr[1] = (byte) byteMessage[i*3 + 1]; instr[2] = (byte) byteMessage[i*3 + 2]; //六個位為一組,補0變成4個位元組 var outstr = new int[4]; //第一個輸出位元組:取第一輸入位元組的前6位,並且在高位補0,使其變成8位(一個位元組) outstr[0] = instr[0] >> 2; //第二個輸出位元組:取第一輸入位元組的後2位和第二個輸入位元組的前4位(共6位),並且在高位補0,使其變成8位(一個位元組) outstr[1] = ((instr[0] & 0x03) << 4) ^ (instr[1] >> 4); //第三個輸出位元組:取第二輸入位元組的後4位和第三個輸入位元組的前2位(共6位),並且在高位補0,使其變成8位(一個位元組) if (!instr[1].Equals(empty)) outstr[2] = ((instr[1] & 0x0f) << 2) ^ (instr[2] >> 6); else outstr[2] = 64; //第四個輸出位元組:取第三輸入位元組的後6位,並且在高位補0,使其變成8位(一個位元組) if (!instr[2].Equals(empty)) outstr[3] = (instr[2] & 0x3f); else outstr[3] = 64; outmessage.Append(Base64Code[outstr[0]]); outmessage.Append(Base64Code[outstr[1]]); outmessage.Append(Base64Code[outstr[2]]); outmessage.Append(Base64Code[outstr[3]]); } return outmessage.ToString(); } /// <summary> /// Base64解密 /// </summary> /// <param name="Message"></param> /// <returns></returns> public string Base64Decode(string Message) { if ((Message.Length%4) != 0) { throw new ArgumentException("不是正確的BASE64編碼,請檢查。", "Message"); } if (!Regex.IsMatch(Message, "^[A-Z0-9/+=]*$", RegexOptions.IgnoreCase)) { throw new ArgumentException("包含不正確的BASE64編碼,請檢查。", "Message"); } string Base64Code = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; int page = Message.Length/4; var outMessage = new ArrayList(page*3); char[] message = Message.ToCharArray(); for (int i = 0; i < page; i++) { var instr = new byte[4]; instr[0] = (byte) Base64Code.IndexOf(message[i*4]); instr[1] = (byte) Base64Code.IndexOf(message[i*4 + 1]); instr[2] = (byte) Base64Code.IndexOf(message[i*4 + 2]); instr[3] = (byte) Base64Code.IndexOf(message[i*4 + 3]); var outstr = new byte[3]; outstr[0] = (byte) ((instr[0] << 2) ^ ((instr[1] & 0x30) >> 4)); if (instr[2] != 64) { outstr[1] = (byte) ((instr[1] << 4) ^ ((instr[2] & 0x3c) >> 2)); } else { outstr[2] = 0; } if (instr[3] != 64) { outstr[2] = (byte) ((instr[2] << 6) ^ instr[3]); } else { outstr[2] = 0; } outMessage.Add(outstr[0]); if (outstr[1] != 0) outMessage.Add(outstr[1]); if (outstr[2] != 0) outMessage.Add(outstr[2]); } var outbyte = (byte[]) outMessage.ToArray(Type.GetType("System.Byte")); return Encoding.Default.GetString(outbyte); }
//直接使用.NET中的的庫類函數 ///<summary> ///Base64加密 ///</summary> ///<param name="Message"></param> ///<returns></returns> public string Base64Code(string Message) { byte[] bytes = Encoding.Default.GetBytes(Message); return Convert.ToBase64String(bytes); } ///<summary> ///Base64解密 ///</summary> ///<param name="Message"></param> ///<returns></returns> public string Base64Decode(string Message) { byte[] bytes = Convert.FromBase64String(Message); return Encoding.Default.GetString(bytes); }