Base 64 Encoding & Decoding
Base 64 Format으로 인코딩하고 디코딩하는 웹페이지를 만들어달라고 하신다 –_-^
C#으로 한다면 라이브러리의 힘을 빌어 아래 메소드를 살짝쿵 이용해주면 된다.
[FromBase64CharArray, FromBase64String 참조]
그런데 이 간편함과는 아랑곳하지 않고 VB로 짜여진 소스를 C#으로 변환해 달라 하신다…
먼저 VB 소스를 분석해야 했기에 위키[http://en.wikipedia.org/wiki/Base64]에서 간략하게 훑어본 후 소스 분석에 들어갔다.
간략하게 Base64 인코딩을 살펴보면 3문자씩 끊어서 4문자로 만든다.
Base64 인코딩 테이블에는 [a-zA-Z0-9+/] 문자만 쓰인다. 물론 자리수가 모자라면 치환을 위해 = 도 쓰인다.
인코딩 테이블
Value Char Value Char Value Char Value Char 0 A 16 Q 32 g 48 w 1 B 17 R 33 h 49 x 2 C 18 S 34 i 50 y 3 D 19 T 35 j 51 z 4 E 20 U 36 k 52 0 5 F 21 V 37 l 53 1 6 G 22 W 38 m 54 2 7 H 23 X 39 n 55 3 8 I 24 Y 40 o 56 4 9 J 25 Z 41 p 57 5 10 K 26 a 42 q 58 6 11 L 27 b 43 r 59 7 12 M 28 c 44 s 60 8 13 N 29 d 45 t 61 9 14 O 30 e 46 u 62 + 15 P 31 f 47 v 63 /
결국 Encoding Data는 무조건 [원본 * 4/3] 이상의 크기가 되어버린다.
위키의 예처럼 Man 을 TWFu로 바꾸려면
- 'Man'을 ASCII 코드(10진수)로 변환. 77(M), 97(a), 110(n).
- 위 결과를 Binary(2진수)로 변환. 01001101(M), 01100001(a), 01101110(n)
- 위 결과를 6자리씩 끊음. 010011 010110 000101 101110
- 위 결과를 Base 64 Encode Table에 매칭시킴. 결과 = 'TWFu'
그러면 M은 어떻게 될까? 우선 결론은 TQ== 이다. 위와 같이 해보자.
- 'M'을 ASCII 코드로 변환. *3문자씩 끊어야 하므로~ 77(M)0(null)0(null)
- Binary로. 01001101(M), 00000000(null), 00000000(null)
- 6자리씩 끊음. 010011, 010000, 000000, 000000
- Base 64 Encode Table에 매칭시킴 결과 'TQAA' ? 아니다!!!
한 문자를 Base64로 인코딩하면 뒤에는 무조건 ==로 변환되어 'TQ==' 가 되고,
두 문자를 Base64로 인코딩하면 뒤에는 무조건 =로 변환된다.
그런데 소스를 들여다 보니 byte들을 가지고 놀아서 당장에 때려치고 싶었다. -_-a
그.래.서. -_- 꼼수를 썼다… >_<
VB to C# converter…
http://www.tangiblesoftwaresolutions.com/Product_Details/Instant_CSharp.html
그냥 아주그냥 잘 바꿔준다. 변환이 안되거나 주위를 요하는 것은 주석으로 친절하게 설명도 해주니 알랍.
하지만 구매하지 않으면 100줄 이상의 소스는 번환이 안되므로 참고하자.
이것말고도 홈페이지에 가면 다른 언어간의 변환프로그램도 있으니 한번 둘러보시길.. >_<
Base 64 En-Decoding Source
1: using System.Text;
2:
3: namespace Base64
4: {
5: public class Base64
6: {
7: #region mask variables
8: private const int clOneMask = 16515072; //000000 111111 111111 111111
9: private const int clTwoMask = 258048; //111111 000000 111111 111111
10: private const int clThreeMask = 4032; //111111 111111 000000 111111
11: private const int clFourMask = 63; //111111 111111 111111 000000
12:
13: private const int clHighMask = 16711680; //11111111 00000000 00000000
14: private const int clMidMask = 65280; //00000000 11111111 00000000
15: private const int clLowMask = 255; //00000000 00000000 11111111
16: #endregion
17:
18: #region power of 2 variables
19: private const int cl2Exp18 = 262144; //2 to the 18th power
20: private const int cl2Exp12 = 4096; //2 to the 12th
21: private const int cl2Exp6 = 64; //2 to the 6th
22: private const int cl2Exp8 = 256; //2 to the 8th
23: private const int cl2Exp16 = 65536; //2 to the 16th
24: #endregion
25:
26: #region array variables
27: private byte[] cbTransTo = new byte[64];
28: private byte[] cbTransFrom = new byte[256];
29: private long[] clPowers8 = new long[256];
30: private long[] clPowers16 = new long[256];
31: private long[] clPowers6 = new long[64];
32: private long[] clPowers12 = new long[64];
33: private long[] clPowers18 = new long[64];
34: #endregion
35:
36: #region .ctor
37: public Base64()
38: {
39: long lTemp = 0;
40:
41: for (lTemp = 0; lTemp <= 63; lTemp++) //Fill the translation table.
42: {
43: if (lTemp >= 0 && lTemp <= 25)
44: {
45: cbTransTo[lTemp] = (byte)(65 + lTemp); //A - Z
46: }
47: else if (lTemp >= 26 && lTemp <= 51)
48: {
49: cbTransTo[lTemp] = (byte)(71 + lTemp); //a - z
50: }
51: else if (lTemp >= 52 && lTemp <= 61)
52: {
53: cbTransTo[lTemp] = (byte)(lTemp - 4); //1 - 0
54: }
55: else if (lTemp == 62)
56: {
57: cbTransTo[lTemp] = 43; //Chr(43) = "+"
58: }
59: else if (lTemp == 63)
60: {
61: cbTransTo[lTemp] = 47; //Chr(47) = "/"
62: }
63: }
64:
65: for (lTemp = 0; lTemp <= 255; lTemp++) //Fill the lookup tables.
66: {
67: clPowers8[lTemp] = lTemp * cl2Exp8;
68: clPowers16[lTemp] = lTemp * cl2Exp16;
69: }
70:
71: for (lTemp = 0; lTemp <= 63; lTemp++)
72: {
73: clPowers6[lTemp] = lTemp * cl2Exp6;
74: clPowers12[lTemp] = lTemp * cl2Exp12;
75: clPowers18[lTemp] = lTemp * cl2Exp18;
76: }
77:
78: for (lTemp = 0; lTemp <= 255; lTemp++) //Fill the translation table.
79: {
80: if (lTemp >= 65 && lTemp <= 90)
81: {
82: cbTransFrom[lTemp] = (byte)(lTemp - 65); //A - Z
83: }
84: else if (lTemp >= 97 && lTemp <= 122)
85: {
86: cbTransFrom[lTemp] = (byte)(lTemp - 71); //a - z
87: }
88: else if (lTemp >= 48 && lTemp <= 57)
89: {
90: cbTransFrom[lTemp] = (byte)(lTemp + 4); //1 - 0
91: }
92: else if (lTemp == 43)
93: {
94: cbTransFrom[lTemp] = 62; //Chr(43) = "+"
95: }
96: else if (lTemp == 47)
97: {
98: cbTransFrom[lTemp] = 63; //Chr(47) = "/"
99: }
100: }
101: }
102: #endregion
103:
104: //String --> Base 64 Format String
105: public string Encode(string sString)
106: {
107: byte[] bTrans = new byte[64];
108: byte[] bOut, bIn;
109: int iPad = 0;
110: long lOutSize = 0;
111: long lChar = 0;
112: long lTrip = 0;
113: long lLen = 0;
114: long lTemp = 0;
115: long lPos = 0;
116:
117: iPad = sString.Length % 3; //Check if the length is divisible by 3 for 3 character
118: if (iPad != 0) //If not, figure out the end pad and resize the input.
119: {
120: iPad = 3 - iPad;
121: sString = sString.PadRight(iPad + sString.Length, '\0');
122: }
123:
124: bIn = Encoding.Default.GetBytes(sString); //Load the input string.
125: lLen = ((bIn.GetUpperBound(0) + 1) / 3) * 4; //Length of resulting string.
126: lOutSize = lLen - 1; //Calculate the size of the output buffer.
127: bOut = new byte[lOutSize + 1]; //Make the output buffer.
128:
129: lLen = 0; //Reusing this one, so reset it.
130:
131: for (lChar = bIn.GetLowerBound(0); lChar <= bIn.GetUpperBound(0); lChar += 3)
132: {
133: lTrip = clPowers16[bIn[lChar]]
134: + clPowers8[bIn[lChar + 1]]
135: + bIn[lChar + 2]; //Combine the 3 bytes
136: lTemp = lTrip & clOneMask; //Mask for the first 6 bits
137: bOut[lPos] = cbTransTo[lTemp / cl2Exp18]; //Shift it down to the low 6 bits and get the value
138: lTemp = lTrip & clTwoMask; //Mask for the second set.
139: bOut[lPos + 1] = cbTransTo[lTemp / cl2Exp12]; //Shift it down and translate.
140: lTemp = lTrip & clThreeMask; //Mask for the third set.
141: bOut[lPos + 2] = cbTransTo[lTemp / cl2Exp6]; //Shift it down and translate.
142: bOut[lPos + 3] = cbTransTo[lTrip & clFourMask]; //Mask for the low set.
143:
144: lLen = lLen + 4;
145: lPos = lPos + 4;
146: }
147:
148: if (iPad == 1) //Add the padding chars if any.
149: {
150: bOut[lOutSize] = 61; //Chr(61) = "="
151: }
152: else if (iPad == 2)
153: {
154: bOut[lOutSize] = 61;
155: bOut[lOutSize - 1] = 61;
156: }
157:
158: return Encoding.Default.GetString(bOut); // Encoding.Unicode.GetString(bOut);
159: }
160:
161: //Base64 Format String --> String
162: public string Decode(string sString)
163: {
164: byte[] bOut = null;
165: byte[] bIn = null;
166: int iPad = 0;
167: long lQuad = 0;
168: long lChar = 0;
169: long lPos = 0;
170: long lTemp = 0;
171: string sOut = null;
172:
173: lTemp = sString.Length % 4; //Test for valid input.
174: if (lTemp != 0)
175: {
176: return "Error: It's not base64 format string";
177: }
178:
179: if ((sString.LastIndexOf("==") + 1) != 0) //InStrRev is faster when you know it's at the end.
180: {
181: iPad = 2; //Note: These translate to 0, so you can leave them...
182: }
183: else if ((sString.LastIndexOf("=") + 1) != 0) //in the string and just resize the output.
184: {
185: iPad = 1;
186: }
187:
188: bIn = Encoding.Default.GetBytes(sString); //Load the input byte array.
189: bOut = new byte[(((bIn.GetUpperBound(0) + 1) / 4) * 3)]; //Prepare the output buffer.
190:
191: for (lChar = 0; lChar <= bIn.GetUpperBound(0); lChar += 4)
192: {
193: lQuad = clPowers18[cbTransFrom[bIn[lChar]]] + clPowers12[cbTransFrom[bIn[lChar + 1]]] + clPowers6[cbTransFrom[bIn[lChar + 2]]] + cbTransFrom[bIn[lChar + 3]]; //Rebuild the bits.
194: lTemp = lQuad & clHighMask; //Mask for the first byte
195: bOut[lPos] = (byte)(lTemp / cl2Exp16); //Shift it down
196: lTemp = lQuad & clMidMask; //Mask for the second byte
197: bOut[lPos + 1] = (byte)(lTemp / cl2Exp8); //Shift it down
198: bOut[lPos + 2] = (byte)(lQuad & clLowMask); //Mask for the third byte
199: lPos = lPos + 3;
200: }
201:
202: sOut = Encoding.Default.GetString(bOut); //Encoding.Unicode.GetString(bOut); //Convert back to a string.
203:
204: if (iPad != 0) //Chop off any extra bytes.
205: {
206: sOut = sOut.Substring(0, sOut.Length - iPad);
207: }
208:
209: return sOut;
210: }
211: }
212: }
관련 아티클: http://naaams.blogspot.com/2009/12/vb-c-c-java.html
참고: 영문 위키 - http://en.wikipedia.org/wiki/Base64
한글 위키 - http://ko.wikipedia.org/wiki/Base64
MSDN - http://msdn.microsoft.com/ko-kr/library/system.convert_methods.aspx
댓글 없음:
댓글 쓰기