Fossil SCM

fossil-scm / src / encode.c
Blame History Raw 935 lines
1
/*
2
** Copyright (c) 2006 D. Richard Hipp
3
**
4
** This program is free software; you can redistribute it and/or
5
** modify it under the terms of the Simplified BSD License (also
6
** known as the "2-Clause License" or "FreeBSD License".)
7
8
** This program is distributed in the hope that it will be useful,
9
** but without any warranty; without even the implied warranty of
10
** merchantability or fitness for a particular purpose.
11
**
12
** Author contact information:
13
** [email protected]
14
** http://www.hwaci.com/drh/
15
**
16
*******************************************************************************
17
**
18
** Routines for encoding and decoding text.
19
*/
20
#include "config.h"
21
#include "encode.h"
22
23
/*
24
** Make the given string safe for HTML by converting every "<" into "&lt;",
25
** every ">" into "&gt;" and every "&" into "&amp;". Return a pointer
26
** to a new string obtained from malloc().
27
**
28
** We also encode " as &quot; and ' as &#39; so they can appear as an argument
29
** to markup.
30
*/
31
char *htmlize(const char *z, int n){
32
unsigned char c;
33
int i = 0;
34
int count = 0;
35
unsigned char *zOut;
36
const unsigned char *zIn = (const unsigned char*)z;
37
38
if( n<0 ) n = strlen(z);
39
while( i<n ){
40
switch( zIn[i] ){
41
case '<': count += 3; break;
42
case '>': count += 3; break;
43
case '&': count += 4; break;
44
case '"': count += 5; break;
45
case '\'': count += 4; break;
46
case 0: n = i; break;
47
}
48
i++;
49
}
50
i = 0;
51
zOut = fossil_malloc( count+n+1 );
52
if( count==0 ){
53
memcpy(zOut, zIn, n);
54
zOut[n] = 0;
55
return (char*)zOut;
56
}
57
while( n-->0 ){
58
c = *(zIn++);
59
switch( c ){
60
case '<':
61
zOut[i++] = '&';
62
zOut[i++] = 'l';
63
zOut[i++] = 't';
64
zOut[i++] = ';';
65
break;
66
case '>':
67
zOut[i++] = '&';
68
zOut[i++] = 'g';
69
zOut[i++] = 't';
70
zOut[i++] = ';';
71
break;
72
case '&':
73
zOut[i++] = '&';
74
zOut[i++] = 'a';
75
zOut[i++] = 'm';
76
zOut[i++] = 'p';
77
zOut[i++] = ';';
78
break;
79
case '"':
80
zOut[i++] = '&';
81
zOut[i++] = 'q';
82
zOut[i++] = 'u';
83
zOut[i++] = 'o';
84
zOut[i++] = 't';
85
zOut[i++] = ';';
86
break;
87
case '\'':
88
zOut[i++] = '&';
89
zOut[i++] = '#';
90
zOut[i++] = '3';
91
zOut[i++] = '9';
92
zOut[i++] = ';';
93
break;
94
default:
95
zOut[i++] = c;
96
break;
97
}
98
}
99
zOut[i] = 0;
100
return (char*)zOut;
101
}
102
103
/*
104
** Append HTML-escaped text to a Blob.
105
*/
106
void htmlize_to_blob(Blob *p, const char *zIn, int n){
107
int c, i, j;
108
if( n<0 ) n = strlen(zIn);
109
for(i=j=0; i<n; i++){
110
c = zIn[i];
111
switch( c ){
112
case '<':
113
if( j<i ) blob_append(p, zIn+j, i-j);
114
blob_append(p, "&lt;", 4);
115
j = i+1;
116
break;
117
case '>':
118
if( j<i ) blob_append(p, zIn+j, i-j);
119
blob_append(p, "&gt;", 4);
120
j = i+1;
121
break;
122
case '&':
123
if( j<i ) blob_append(p, zIn+j, i-j);
124
blob_append(p, "&amp;", 5);
125
j = i+1;
126
break;
127
case '"':
128
if( j<i ) blob_append(p, zIn+j, i-j);
129
blob_append(p, "&quot;", 6);
130
j = i+1;
131
break;
132
case '\'':
133
if( j<i ) blob_append(p, zIn+j, i-j);
134
blob_append(p, "&#39;", 5);
135
j = i+1;
136
break;
137
case '\r':
138
if( j<i ) blob_append(p, zIn+j, i-j);
139
blob_append(p, " ", 1);
140
j = i+1;
141
break;
142
}
143
}
144
if( j<i ) blob_append(p, zIn+j, i-j);
145
}
146
147
/*
148
** Make the given string safe for HTML by converting syntax characters
149
** into alternatives that do not have the special syntactic meaning.
150
**
151
** < --> U+227a
152
** > --> U+227b
153
** & --> +
154
** " --> U+201d
155
** ' --> U+2019
156
**
157
** Return a pointer to a new string obtained from fossil_malloc().
158
*/
159
char *html_lookalike(const char *z, int n){
160
unsigned char c;
161
int i = 0;
162
int count = 0;
163
unsigned char *zOut;
164
const unsigned char *zIn = (const unsigned char*)z;
165
166
if( n<0 ) n = strlen(z);
167
while( i<n ){
168
switch( zIn[i] ){
169
case '<': count += 3; break;
170
case '>': count += 3; break;
171
case '"': count += 3; break;
172
case '\'': count += 3; break;
173
case 0: n = i; break;
174
}
175
i++;
176
}
177
i = 0;
178
zOut = fossil_malloc( count+n+1 );
179
if( count==0 ){
180
memcpy(zOut, zIn, n);
181
zOut[n] = 0;
182
return (char*)zOut;
183
}
184
while( n-->0 ){
185
c = *(zIn++);
186
switch( c ){
187
case '<':
188
zOut[i++] = 0xe2;
189
zOut[i++] = 0x89;
190
zOut[i++] = 0xba;
191
break;
192
case '>':
193
zOut[i++] = 0xe2;
194
zOut[i++] = 0x89;
195
zOut[i++] = 0xbb;
196
break;
197
case '&':
198
zOut[i++] = '+';
199
break;
200
case '"':
201
zOut[i++] = 0xe2;
202
zOut[i++] = 0x80;
203
zOut[i++] = 0x9d;
204
break;
205
case '\'':
206
zOut[i++] = 0xe2;
207
zOut[i++] = 0x80;
208
zOut[i++] = 0x99;
209
break;
210
default:
211
zOut[i++] = c;
212
break;
213
}
214
}
215
zOut[i] = 0;
216
return (char*)zOut;
217
}
218
219
220
/*
221
** Encode a string for HTTP. This means converting lots of
222
** characters into the "%HH" where H is a hex digit. It also
223
** means converting spaces to "+".
224
**
225
** This is the opposite of DeHttpizeString below.
226
*/
227
static char *EncodeHttp(const char *zIn, int n, int encodeSlash){
228
int c;
229
int i = 0;
230
int count = 0;
231
char *zOut;
232
# define IsSafeChar(X) \
233
(fossil_isalnum(X) || (X)=='.' || (X)=='$' \
234
|| (X)=='~' || (X)=='-' || (X)=='_' \
235
|| (!encodeSlash && ((X)=='/' || (X)==':')))
236
237
if( zIn==0 ) return 0;
238
if( n<0 ) n = strlen(zIn);
239
while( i<n && (c = zIn[i])!=0 ){
240
if( IsSafeChar(c) || c==' ' ){
241
count++;
242
}else{
243
count += 3;
244
}
245
i++;
246
}
247
i = 0;
248
zOut = fossil_malloc( count+1 );
249
while( n-->0 && (c = *zIn)!=0 ){
250
if( IsSafeChar(c) ){
251
zOut[i++] = c;
252
}else if( c==' ' ){
253
zOut[i++] = '+';
254
}else{
255
zOut[i++] = '%';
256
zOut[i++] = "0123456789ABCDEF"[(c>>4)&0xf];
257
zOut[i++] = "0123456789ABCDEF"[c&0xf];
258
}
259
zIn++;
260
}
261
zOut[i] = 0;
262
#undef IsSafeChar
263
return zOut;
264
}
265
266
/*
267
** Convert the input string into a form that is suitable for use as
268
** a token in the HTTP protocol. Spaces are encoded as '+' and special
269
** characters are encoded as "%HH" where HH is a two-digit hexadecimal
270
** representation of the character. The "/" character is encoded
271
** as "%2F".
272
*/
273
char *httpize(const char *z, int n){
274
return EncodeHttp(z, n, 1);
275
}
276
277
/*
278
** Convert the input string into a form that is suitable for use as
279
** a token in the HTTP protocol. Spaces are encoded as '+' and special
280
** characters are encoded as "%HH" where HH is a two-digit hexidecimal
281
** representation of the character. The "/" character is not encoded
282
** by this routine.
283
*/
284
char *urlize(const char *z, int n){
285
return EncodeHttp(z, n, 0);
286
}
287
288
/*
289
** If input string does not contain quotes (neither ' nor ")
290
** then return the argument itself. Otherwise return a newly allocated
291
** copy of input with all quotes %-escaped.
292
*/
293
const char* escape_quotes(const char *zIn){
294
char *zRet, *zOut;
295
size_t i, n = 0;
296
for(i=0; zIn[i]; i++){
297
if( zIn[i]== '"' || zIn[i]== '\'' ) n++;
298
}
299
if( !n ) return zIn;
300
zRet = zOut = fossil_malloc( i + 2*n + 1 );
301
for(i=0; zIn[i]; i++){
302
if( zIn[i]=='"' ){
303
*(zOut++) = '%';
304
*(zOut++) = '2';
305
*(zOut++) = '2';
306
}else if( zIn[i]=='\'' ){
307
*(zOut++) = '%';
308
*(zOut++) = '2';
309
*(zOut++) = '7';
310
}else{
311
*(zOut++) = zIn[i];
312
}
313
}
314
*zOut = 0;
315
return zRet;
316
}
317
318
/*
319
** Convert a single HEX digit to an integer
320
*/
321
int fossil_hexvalue(int c){
322
if( c>='a' && c<='f' ){
323
c += 10 - 'a';
324
}else if( c>='A' && c<='F' ){
325
c += 10 - 'A';
326
}else if( c>='0' && c<='9' ){
327
c -= '0';
328
}else{
329
c = 0;
330
}
331
return c;
332
}
333
334
/*
335
** Remove the HTTP encodings from a string. The conversion is done
336
** in-place. Return the length of the string after conversion.
337
*/
338
int dehttpize(char *z){
339
int i, j;
340
341
/* Treat a null pointer as a zero-length string. */
342
if( !z ) return 0;
343
344
i = j = 0;
345
while( z[i] ){
346
switch( z[i] ){
347
case '%':
348
if( z[i+1] && z[i+2] ){
349
z[j] = fossil_hexvalue(z[i+1]) << 4;
350
z[j] |= fossil_hexvalue(z[i+2]);
351
i += 2;
352
}
353
break;
354
case '+':
355
z[j] = ' ';
356
break;
357
default:
358
z[j] = z[i];
359
break;
360
}
361
i++;
362
j++;
363
}
364
z[j] = 0;
365
return j;
366
}
367
368
/*
369
** The "fossilize" encoding is used in the headers of records
370
** (aka "content files") to escape special characters. The
371
** fossilize encoding passes most characters through unchanged.
372
** The changes are these:
373
**
374
** space -> \s
375
** tab -> \t
376
** newline -> \n
377
** cr -> \r
378
** formfeed -> \f
379
** vtab -> \v
380
** nul -> \0
381
** \ -> \\
382
**
383
** The fossilize() routine does an encoding of its input and
384
** returns a pointer to the encoding in space obtained from
385
** malloc.
386
*/
387
char *fossilize(const char *zIn, int nIn){
388
int n, i, j, c;
389
char *zOut;
390
if( nIn<0 ) nIn = strlen(zIn);
391
for(i=n=0; i<nIn; i++){
392
c = zIn[i];
393
if( c==0 || c==' ' || c=='\n' || c=='\t' || c=='\r' || c=='\f' || c=='\v'
394
|| c=='\\' ) n++;
395
}
396
n += nIn;
397
zOut = fossil_malloc( n+1 );
398
if( zOut ){
399
for(i=j=0; i<nIn; i++){
400
int c = zIn[i];
401
if( c==0 ){
402
zOut[j++] = '\\';
403
zOut[j++] = '0';
404
}else if( c=='\\' ){
405
zOut[j++] = '\\';
406
zOut[j++] = '\\';
407
}else if( fossil_isspace(c) ){
408
zOut[j++] = '\\';
409
switch( c ){
410
case '\n': c = 'n'; break;
411
case ' ': c = 's'; break;
412
case '\t': c = 't'; break;
413
case '\r': c = 'r'; break;
414
case '\v': c = 'v'; break;
415
case '\f': c = 'f'; break;
416
}
417
zOut[j++] = c;
418
}else{
419
zOut[j++] = c;
420
}
421
}
422
zOut[j] = 0;
423
}
424
return zOut;
425
}
426
427
/*
428
** Decode a fossilized string in-place.
429
*/
430
void defossilize(char *z){
431
int i, j, c;
432
char *zSlash = strchr(z, '\\');
433
if( zSlash==0 ) return;
434
i = zSlash - z;
435
for(j=i; (c=z[i])!=0; i++){
436
if( c=='\\' && z[i+1] ){
437
i++;
438
switch( z[i] ){
439
case 'n': c = '\n'; break;
440
case 's': c = ' '; break;
441
case 't': c = '\t'; break;
442
case 'r': c = '\r'; break;
443
case 'v': c = '\v'; break;
444
case 'f': c = '\f'; break;
445
case '0': c = 0; break;
446
case '\\': c = '\\'; break;
447
default: c = z[i]; break;
448
}
449
}
450
z[j++] = c;
451
}
452
if( z[j] ) z[j] = 0;
453
}
454
455
456
/*
457
** The *pz variable points to a UTF8 string. Read the next character
458
** off of that string and return its codepoint value. Advance *pz to the
459
** next character
460
*/
461
u32 fossil_utf8_read(
462
const unsigned char **pz /* Pointer to string from which to read char */
463
){
464
unsigned int c;
465
466
/*
467
** This lookup table is used to help decode the first byte of
468
** a multi-byte UTF8 character.
469
*/
470
static const unsigned char utf8Trans1[] = {
471
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
472
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
473
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
474
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
475
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
476
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
477
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
478
0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00,
479
};
480
481
c = *((*pz)++);
482
if( c>=0xc0 ){
483
c = utf8Trans1[c-0xc0];
484
while( (*(*pz) & 0xc0)==0x80 ){
485
c = (c<<6) + (0x3f & *((*pz)++));
486
}
487
if( c<0x80
488
|| (c&0xFFFFF800)==0xD800
489
|| (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; }
490
}
491
return c;
492
}
493
494
/*
495
** Encode a UTF8 string as a JSON string literal (with or without the
496
** surrounding "...", depending on whether the 2nd argument is true or
497
** false) and return a pointer to the encoding. Space to hold the
498
** encoding is obtained from fossil_malloc() and must be freed by the
499
** caller.
500
**
501
** If nOut is not NULL then it is assigned to the length, in bytes, of
502
** the returned string (its strlen(), not counting the terminating
503
** NUL).
504
*/
505
char *encode_json_string_literal(const char *zStr, int fAddQuotes,
506
int * nOut){
507
const unsigned char *z;
508
char *zOut;
509
u32 c;
510
int n, i, j;
511
z = (const unsigned char*)zStr;
512
n = 0;
513
while( (c = *(z++))!=0 ){
514
if( c=='\\' || c=='"' ){
515
n += 2;
516
}else if( c<' ' ){
517
if( c=='\n' || c=='\r' ){
518
n += 2;
519
}else{
520
n += 6;
521
}
522
}else{
523
n++;
524
}
525
}
526
if(fAddQuotes){
527
n += 2;
528
}
529
zOut = fossil_malloc(n+1);
530
if( zOut==0 ) return 0;
531
z = (const unsigned char*)zStr;
532
i = 0;
533
if(fAddQuotes){
534
zOut[i++] = '"';
535
}
536
while( (c = *(z++))!=0 ){
537
if( c=='\\' || c=='"' ){
538
zOut[i++] = '\\';
539
zOut[i++] = c;
540
}else if( c<' ' ){
541
zOut[i++] = '\\';
542
if( c=='\n' ){
543
zOut[i++] = 'n';
544
}else if( c=='\r' ){
545
zOut[i++] = 'r';
546
}else{
547
zOut[i++] = 'u';
548
for(j=3; j>=0; j--){
549
zOut[i+j] = "0123456789abcdef"[c&0xf];
550
c >>= 4;
551
}
552
i += 4;
553
}
554
}else{
555
zOut[i++] = c;
556
}
557
}
558
if(fAddQuotes){
559
zOut[i++] = '"';
560
}
561
zOut[i] = 0;
562
if(nOut!=0){
563
*nOut = i;
564
}
565
return zOut;
566
}
567
568
/*
569
** The characters used for HTTP base64 encoding.
570
*/
571
static unsigned char zBase[] =
572
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
573
574
/*
575
** Translate nData bytes of content from zData into
576
** ((nData+2)/3)*4) bytes of base64 encoded content and
577
** put the result in z64. Add a zero-terminator at the end.
578
*/
579
int translateBase64(const char *zData, int nData, char *z64){
580
int i, n;
581
for(i=n=0; i+2<nData; i+=3){
582
z64[n++] = zBase[ (zData[i]>>2) & 0x3f ];
583
z64[n++] = zBase[ ((zData[i]<<4) & 0x30) | ((zData[i+1]>>4) & 0x0f) ];
584
z64[n++] = zBase[ ((zData[i+1]<<2) & 0x3c) | ((zData[i+2]>>6) & 0x03) ];
585
z64[n++] = zBase[ zData[i+2] & 0x3f ];
586
}
587
if( i+1<nData ){
588
z64[n++] = zBase[ (zData[i]>>2) & 0x3f ];
589
z64[n++] = zBase[ ((zData[i]<<4) & 0x30) | ((zData[i+1]>>4) & 0x0f) ];
590
z64[n++] = zBase[ ((zData[i+1]<<2) & 0x3c) ];
591
z64[n++] = '=';
592
}else if( i<nData ){
593
z64[n++] = zBase[ (zData[i]>>2) & 0x3f ];
594
z64[n++] = zBase[ ((zData[i]<<4) & 0x30) ];
595
z64[n++] = '=';
596
z64[n++] = '=';
597
}
598
z64[n] = 0;
599
return n;
600
}
601
602
/*
603
** Encode a string using a base-64 encoding.
604
** The encoding can be reversed using the <b>decode64</b> function.
605
**
606
** Space to hold the result comes from malloc().
607
*/
608
char *encode64(const char *zData, int nData){
609
char *z64;
610
if( nData<=0 ){
611
nData = strlen(zData);
612
}
613
z64 = fossil_malloc( (nData*4)/3 + 8 );
614
translateBase64(zData, nData, z64);
615
return z64;
616
}
617
618
/*
619
** COMMAND: test-encode64
620
**
621
** Usage: %fossil test-encode64 STRING
622
*/
623
void test_encode64_cmd(void){
624
char *z;
625
int i;
626
for(i=2; i<g.argc; i++){
627
z = encode64(g.argv[i], -1);
628
fossil_print("%s\n", z);
629
free(z);
630
}
631
}
632
633
634
/* Decode base64 text. Write the output into zData. The caller
635
** must ensure that zData is large enough. It is ok for z64 and
636
** zData to be the same buffer. In other words, it is ok to decode
637
** in-place. A zero terminator is always placed at the end of zData.
638
*/
639
void decodeBase64(const char *z64, int *pnByte, char *zData){
640
const unsigned char *zIn = (const unsigned char*)z64;
641
int i, j, k;
642
int x[4];
643
static int isInit = 0;
644
static signed char trans[256];
645
646
if( !isInit ){
647
for(i=0; i<256; i++){ trans[i] = -1; }
648
for(i=0; zBase[i]; i++){ trans[zBase[i] & 0x7f] = i; }
649
isInit = 1;
650
}
651
for(j=k=0; zIn[0]; zIn++){
652
int v = trans[zIn[0]];
653
if( v>=0 ){
654
x[k++] = v;
655
if( k==4 ){
656
zData[j++] = ((x[0]<<2) & 0xfc) | ((x[1]>>4) & 0x03);
657
zData[j++] = ((x[1]<<4) & 0xf0) | ((x[2]>>2) & 0x0f);
658
zData[j++] = ((x[2]<<6) & 0xc0) | (x[3] & 0x3f);
659
k = 0;
660
}
661
}
662
}
663
if( k>=2 ){
664
zData[j++] = ((x[0]<<2) & 0xfc) | ((x[1]>>4) & 0x03);
665
if( k==3 ){
666
zData[j++] = ((x[1]<<4) & 0xf0) | ((x[2]>>2) & 0x0f);
667
}
668
}
669
zData[j] = 0;
670
*pnByte = j;
671
}
672
673
674
/*
675
** This function treats its input as a base-64 string and returns the
676
** decoded value of that string. Characters of input that are not
677
** valid base-64 characters (such as spaces and newlines) are ignored.
678
**
679
** Space to hold the decoded string is obtained from malloc().
680
**
681
** The number of bytes decoded is returned in *pnByte
682
*/
683
char *decode64(const char *z64, int *pnByte){
684
char *zData;
685
int n64 = (int)strlen(z64);
686
while( n64>0 && z64[n64-1]=='=' ) n64--;
687
zData = fossil_malloc( (n64*3)/4 + 4 );
688
decodeBase64(z64, pnByte, zData);
689
return zData;
690
}
691
692
/*
693
** COMMAND: test-decode64
694
**
695
** Usage: %fossil test-decode64 STRING
696
*/
697
void test_decode64_cmd(void){
698
char *z;
699
int i, n;
700
for(i=2; i<g.argc; i++){
701
z = decode64(g.argv[i], &n);
702
fossil_print("%d: %s\n", n, z);
703
fossil_free(z);
704
}
705
}
706
707
/*
708
** The base-16 encoding using the following characters:
709
**
710
** 0123456789abcdef
711
**
712
*/
713
714
/*
715
** The array used for encoding
716
*/ /* 123456789 12345 */
717
static const char zEncode[] = "0123456789abcdef";
718
719
/*
720
** Encode a N-digit base-256 in base-16. Return zero on success
721
** and non-zero if there is an error.
722
*/
723
int encode16(const unsigned char *pIn, unsigned char *zOut, int N){
724
int i;
725
for(i=0; i<N; i++){
726
*(zOut++) = zEncode[pIn[i]>>4];
727
*(zOut++) = zEncode[pIn[i]&0xf];
728
}
729
*zOut = 0;
730
return 0;
731
}
732
733
/*
734
** An array for translating single base-16 characters into a value.
735
** Disallowed input characters have a value of 64. Upper and lower
736
** case is the same.
737
*/
738
static const char zDecode[] = {
739
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
740
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
741
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
742
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 64, 64, 64, 64, 64, 64,
743
64, 10, 11, 12, 13, 14, 15, 64, 64, 64, 64, 64, 64, 64, 64, 64,
744
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
745
64, 10, 11, 12, 13, 14, 15, 64, 64, 64, 64, 64, 64, 64, 64, 64,
746
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
747
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
748
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
749
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
750
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
751
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
752
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
753
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
754
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
755
};
756
757
/*
758
** Decode a N-character base-16 number into base-256. N must be a
759
** multiple of 2. The output buffer must be at least N/2 characters
760
** in length
761
*/
762
int decode16(const unsigned char *zIn, unsigned char *pOut, int N){
763
int i, j;
764
if( (N&1)!=0 ) return 1;
765
for(i=j=0; i<N; i += 2, j++){
766
int v1, v2, a;
767
a = zIn[i];
768
if( (a & 0x80)!=0 || (v1 = zDecode[a])==64 ) return 1;
769
a = zIn[i+1];
770
if( (a & 0x80)!=0 || (v2 = zDecode[a])==64 ) return 1;
771
pOut[j] = (v1<<4) + v2;
772
}
773
return 0;
774
}
775
776
777
/*
778
** Return true if the input string contains only valid base-16 digits.
779
** If any invalid characters appear in the string, return false.
780
*/
781
int validate16(const char *zIn, int nIn){
782
int i;
783
if( nIn<0 ) nIn = (int)strlen(zIn);
784
if( zIn[nIn]==0 ){
785
return (int)strspn(zIn,"0123456789abcdefABCDEF")==nIn;
786
}
787
for(i=0; i<nIn; i++, zIn++){
788
if( zDecode[zIn[0]&0xff]>63 ){
789
return zIn[0]==0;
790
}
791
}
792
return 1;
793
}
794
795
/*
796
** The input string is a base16 value. Convert it into its canonical
797
** form. This means that digits are all lower case and that conversions
798
** like "l"->"1" and "O"->"0" occur.
799
*/
800
void canonical16(char *z, int n){
801
while( *z && n-- ){
802
*z = zEncode[zDecode[(*z)&0x7f]&0x1f];
803
z++;
804
}
805
}
806
807
/*
808
** Decode hexadecimal into a string and return the new string. Space to
809
** hold the string is obtained from fossil_malloc() and should be released
810
** by the caller.
811
**
812
** If the input is not hex, return NULL.
813
*/
814
char *decode16_dup(const char *zIn){
815
int nIn = (int)strlen(zIn);
816
char *zOut;
817
if( !validate16(zIn, nIn) ) return 0;
818
zOut = fossil_malloc(nIn/2+1);
819
decode16((const u8*)zIn, (u8*)zOut, nIn);
820
zOut[nIn/2] = 0;
821
return zOut;
822
}
823
824
825
/*
826
** Decode a string encoded using "quoted-printable".
827
**
828
** (1) "=" followed by two hex digits becomes a single
829
** byte specified by the two digits
830
**
831
** The decoding is done in-place.
832
*/
833
void decodeQuotedPrintable(char *z, int *pnByte){
834
int i, j, c;
835
for(i=j=0; (c = z[i])!=0; i++){
836
if( c=='=' ){
837
if( z[i+1]!='\r' ){
838
decode16((unsigned char*)&z[i+1], (unsigned char*)&z[j], 2);
839
j++;
840
}
841
i += 2;
842
}else{
843
z[j++] = c;
844
}
845
}
846
if( pnByte ) *pnByte = j;
847
z[j] = 0;
848
}
849
850
/* Randomness used for XOR-ing by the obscure() and unobscure() routines */
851
static const unsigned char aObscurer[16] = {
852
0xa7, 0x21, 0x31, 0xe3, 0x2a, 0x50, 0x2c, 0x86,
853
0x4c, 0xa4, 0x52, 0x25, 0xff, 0x49, 0x35, 0x85
854
};
855
856
857
/*
858
** Obscure plain text so that it is not easily readable.
859
**
860
** This is used for storing sensitive information (such as passwords) in a
861
** way that prevents their exposure through idle browsing. This is not
862
** encryption. Anybody who really wants the password can still get it.
863
**
864
** The text is XOR-ed with a repeating pattern then converted to hex.
865
** Space to hold the returned string is obtained from malloc and should
866
** be freed by the caller.
867
*/
868
char *obscure(const char *zIn){
869
int n, i;
870
unsigned char salt;
871
char *zOut;
872
873
if( zIn==0 ) return 0;
874
n = strlen(zIn);
875
zOut = fossil_malloc( n*2+3 );
876
sqlite3_randomness(1, &salt);
877
zOut[n+1] = (char)salt;
878
for(i=0; i<n; i++) zOut[i+n+2] = zIn[i]^aObscurer[i&0x0f]^salt;
879
encode16((unsigned char*)&zOut[n+1], (unsigned char*)zOut, n+1);
880
return zOut;
881
}
882
883
/*
884
** Undo the obscuring of text performed by obscure(). Or, if the input is
885
** not hexadecimal (meaning the input is not the output of obscure()) then
886
** do the equivalent of strdup().
887
**
888
** The result is memory obtained from malloc that should be freed by the caller.
889
*/
890
char *unobscure(const char *zIn){
891
int n, i;
892
unsigned char salt;
893
char *zOut;
894
895
if( zIn==0 ) return 0;
896
n = strlen(zIn);
897
zOut = fossil_malloc( n + 1 );
898
if( n<2
899
|| decode16((unsigned char*)zIn, &salt, 2)
900
|| decode16((unsigned char*)&zIn[2], (unsigned char*)zOut, n-2)
901
){
902
memcpy(zOut, zIn, n+1);
903
}else{
904
n = n/2 - 1;
905
for(i=0; i<n; i++) zOut[i] = zOut[i]^aObscurer[i&0x0f]^salt;
906
zOut[n] = 0;
907
}
908
return zOut;
909
}
910
911
/*
912
** Command to test obscure() and unobscure(). These commands are also useful
913
** utilities for decoding passwords found in the database.
914
**
915
** COMMAND: test-obscure
916
**
917
** For each command-line argument X, run both obscure(X) and
918
** unobscure(obscure(X)) and print the results. This is used for testing
919
** and debugging of the obscure() and unobscure() functions.
920
*/
921
void test_obscure_cmd(void){
922
int i;
923
char *z, *z2;
924
for(i=2; i<g.argc; i++){
925
z = obscure(g.argv[i]);
926
z2 = unobscure(z);
927
fossil_print("OBSCURE: %s -> %s (%s)\n", g.argv[i], z, z2);
928
free(z);
929
free(z2);
930
z = unobscure(g.argv[i]);
931
fossil_print("UNOBSCURE: %s -> %s\n", g.argv[i], z);
932
free(z);
933
}
934
}
935

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button