1
/* Copyright (C) 2008 PrimeBase Technologies GmbH, Germany
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19
* Created by Barry Leslie on 10/21/08.
31
static const u_char base64URLMap[64] = {
32
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
33
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
34
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
35
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
36
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
37
'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
38
'w', 'x', 'y', 'z', '0', '1', '2', '3',
39
'4', '5', '6', '7', '8', '9', '-', '_'
41
static const u_char base64STDMap[64] = {
42
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
43
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
44
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
45
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
46
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
47
'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
48
'w', 'x', 'y', 'z', '0', '1', '2', '3',
49
'4', '5', '6', '7', '8', '9', '+', '/'
52
static const u_char decodeBase64Map[128] = {
53
0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF,
54
0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF,
55
0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF,
56
0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF,
57
0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF,
58
0XFF, 0XFF, 0XFF, 0X3E, 0XFF, 0X3E, 0XFF, 0X3F,
59
0X34, 0X35, 0X36, 0X37, 0X38, 0X39, 0X3A, 0X3B,
60
0X3C, 0X3D, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF,
61
0XFF, 0X00, 0X01, 0X02, 0X03, 0X04, 0X05, 0X06,
62
0X07, 0X08, 0X09, 0X0A, 0X0B, 0X0C, 0X0D, 0X0E,
63
0X0F, 0X10, 0X11, 0X12, 0X13, 0X14, 0X15, 0X16,
64
0X17, 0X18, 0X19, 0XFF, 0XFF, 0XFF, 0XFF, 0X3F,
65
0XFF, 0X1A, 0X1B, 0X1C, 0X1D, 0X1E, 0X1F, 0X20,
66
0X21, 0X22, 0X23, 0X24, 0X25, 0X26, 0X27, 0X28,
67
0X29, 0X2A, 0X2B, 0X2C, 0X2D, 0X2E, 0X2F, 0X30,
68
0X31, 0X32, 0X33, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF,
72
static bool base64Encoded(const u_char *data, size_t len, const u_char *vc)
79
while ( i && data[i-1] == '=') i--;
84
for (; i ; i--, data++) {
85
if (((*data < 'A') || (*data > 'Z')) &&
86
((*data < 'a') || (*data > 'z')) &&
87
((*data < '0') || (*data > '9')) &&
88
((*data != vc[0]) && (*data != vc[1])))
92
return true; // Actually this isn't so much 'true' as 'maybe'
96
static char *genericBase64Encode(const void *data, size_t len, char *encode_buffer, size_t encode_buffer_len, const u_char base64Map[])
98
u_char *wptr, *rptr, *encoding;
102
size = ((len + 2) / 3) * 4 +1;
103
if ((encode_buffer != NULL) && (encode_buffer_len < size))
104
CSException::throwException(CS_CONTEXT, CS_ERR_GENERIC_ERROR, "Base64 encode buffer is too small.");
107
encoding = (u_char *) encode_buffer;
109
encoding = (u_char *) cs_malloc(size);
115
rptr = (u_char *) data;
118
wptr[0] = base64Map[rptr[0] >>2];
119
wptr[1] = base64Map[((rptr[0] & 0X03) <<4) + (rptr[1] >> 4)];
120
wptr[2] = base64Map[((rptr[1] & 0X0F) <<2) + (rptr[2] >> 6)];
121
wptr[3] = base64Map[(rptr[2] & 0X3F)];
128
wptr[0] = base64Map[rptr[0] >>2];
131
wptr[1] = base64Map[(rptr[0] & 0x03) << 4];
132
wptr[2] = wptr[3] = '=';
134
wptr[1] = base64Map[((rptr[0] & 0X03) <<4) + (rptr[1] >> 4)];
135
wptr[2] = base64Map[(rptr[1] & 0X0F) <<2];
141
return_((char*)encoding);
145
static void *genericBase64Decode(const char *data, size_t len, void *decode_buffer, size_t decode_buffer_len, const u_char base64Map[])
147
u_char *wptr, *rptr, *decoding;
150
rptr = (u_char *) data;
152
if (!base64Encoded(rptr, len, base64Map +62))
153
CSException::throwException(CS_CONTEXT, CS_ERR_GENERIC_ERROR, "String was not Base64 encoded.");
155
if ((decode_buffer != NULL) && (decode_buffer_len < ((len/ 4) * 3)))
156
CSException::throwException(CS_CONTEXT, CS_ERR_GENERIC_ERROR, "Base64 decoded buffer is too small.");
159
decoding = (u_char *) decode_buffer;
161
decoding = (u_char *) cs_malloc((len/ 4) * 3);
165
while (rptr[len-1] == '=')
169
wptr[0] = ( ((decodeBase64Map[rptr[0]] << 2) & 0xFF) | ((decodeBase64Map[rptr[1]] >> 4) & 0x03) );
170
wptr[1] = ( ((decodeBase64Map[rptr[1]] << 4) & 0xFF) | ((decodeBase64Map[rptr[2]] >> 2) & 0x0F) );
171
wptr[2] = ( ((decodeBase64Map[rptr[2]] << 6) & 0xFF) | (decodeBase64Map[rptr[3]] & 0x3F) );
179
wptr[0] = ( ((decodeBase64Map[rptr[0]] << 2) & 0xFF) | ((decodeBase64Map[rptr[1]] >> 4) & 0x03) );
181
wptr[1] = ( ((decodeBase64Map[rptr[1]] << 4) & 0xFF) | ((decodeBase64Map[rptr[2]] >> 2) & 0x0F) );
188
char *base64Encode(const void *data, size_t len, char *encode_buffer, size_t encode_buffer_len)
190
return genericBase64Encode(data, len, encode_buffer, encode_buffer_len, base64STDMap);
194
void *base64Decode(const char *data, size_t len, void *decode_buffer, size_t decode_buffer_len)
196
return genericBase64Decode(data, len, decode_buffer, decode_buffer_len, base64STDMap);
200
char *base64UrlEncode(const void *data, size_t len, char *encode_buffer, size_t encode_buffer_len)
202
return genericBase64Encode(data, len, encode_buffer, encode_buffer_len, base64URLMap);
206
void *base64UrlDecode(const char *data, size_t len, void *decode_buffer, size_t decode_buffer_len)
208
return genericBase64Decode(data, len, decode_buffer, decode_buffer_len, base64URLMap);
212
//-----------------------------------------------------
213
void hmac_md5(u_char *text, size_t text_len, u_char *key, size_t key_len, Md5Digest *digest)
216
unsigned char k_ipad[65]; /* inner padding -
219
unsigned char k_opad[65]; /* outer padding -
222
unsigned char tk[16];
225
/* if key is longer than 64 bytes reset it to key=MD5(key) */
230
md5.md5_append(key, key_len);
231
md5.md5_digest(digest);
237
/* start out by storing key in pads */
238
memset(k_ipad, 0, sizeof(k_ipad));
239
memset(k_opad, 0, sizeof(k_opad));
241
memcpy(k_ipad, key, key_len);
242
memcpy(k_opad, key, key_len);
244
/* XOR key with ipad and opad values */
245
for (i=0; i<64; i++) {
250
* perform inner encoding
253
md5.md5_append(k_ipad, 64);
254
md5.md5_append(text, strlen(text));
255
md5.md5_digest(digest);
258
* perform outer encoding
261
md5.md5_append(k_opad, 64);
262
md5.md5_append((u_char*)digest, 16);
263
md5.md5_digest(digest);
269
//-----------------------------------------------------
270
void hmac_sha1(const char *text, const char *key, Sha1Digest *digest)
273
size_t key_len = strlen(key);
274
unsigned char k_ipad[65]; /* inner padding -
277
unsigned char k_opad[65]; /* outer padding -
282
/* if key is longer than 64 bytes reset it to key=MD5(key) */
287
sha1.sha1_input(key, key_len);
288
sha1.sha1_digest(digest);
290
key = (char *) digest->val;
294
/* start out by storing key in pads */
295
memset(k_ipad, 0, sizeof(k_ipad));
296
memset(k_opad, 0, sizeof(k_opad));
298
memcpy(k_ipad, key, key_len);
299
memcpy(k_opad, key, key_len);
301
/* XOR key with ipad and opad values */
302
for (i=0; i<64; i++) {
308
* perform inner encoding
311
sha1.sha1_input(k_ipad, 64);
312
sha1.sha1_input(text, strlen(text));
313
sha1.sha1_digest(digest);
317
* perform outer encoding
320
sha1.sha1_input(k_opad, 64);
321
sha1.sha1_input(digest, 20);
322
sha1.sha1_digest(digest);
326
//-----------------------------------------------------
327
CSString *signature(const char *text, const char *key)
331
CSString *signed_str;
333
memset(&digest, 0, sizeof(digest));
334
hmac_sha1(text, key, &digest);
336
encoding = base64Encode(digest.val, SHA1_HASH_SIZE);
337
signed_str = CSString::newString(encoding);
343
//-----------------------------------------------------
344
// Encode url unsafe characters
345
CSString *urlEncode(CSString *src)
347
const char *hex = "0123456789ABCDEF", *start, *ptr;
354
new_(url, CSStringBuffer(10));
357
start = ptr = src->getCString();
361
if (!isalnum(*ptr)) {
375
url->append(start, ptr-start);
377
encoded[1] = hex[*ptr/16];
378
encoded[2] = hex[*ptr%16];
379
url->append(encoded, 3);
384
url->append(start, ptr-start);
386
CSString *safe_str = CSString::newString(url->getCString());