Home | History | Annotate | Download | only in ext2fs
      1 /*
      2  * lib/ext2fs/digest_encode.c
      3  *
      4  * A function to encode a digest using 64 characters that are valid in a
      5  * filename per ext2fs rules.
      6  *
      7  * Written by Uday Savagaonkar, 2014.
      8  *
      9  * Copyright 2014 Google Inc.  All Rights Reserved.
     10  *
     11  * %Begin-Header%
     12  * This file may be redistributed under the terms of the GNU Library
     13  * General Public License, version 2.
     14  * %End-Header%
     15  */
     16 
     17 #include "config.h"
     18 #if HAVE_SYS_TYPES_H
     19 #include <sys/types.h>
     20 #endif
     21 #include "ext2fs.h"
     22 
     23 static const char *lookup_table =
     24 	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,";
     25 
     26 /**
     27  * ext2fs_digest_encode() -
     28  *
     29  * Encodes the input digest using characters from the set [a-zA-Z0-9_+].
     30  * The encoded string is roughly 4/3 times the size of the input string.
     31  */
     32 int ext2fs_digest_encode(const char *src, int len, char *dst)
     33 {
     34 	int i = 0, bits = 0, ac = 0;
     35 	char *cp = dst;
     36 
     37 	while (i < len) {
     38 		ac += (((unsigned char) src[i]) << bits);
     39 		bits += 8;
     40 		do {
     41 			*cp++ = lookup_table[ac & 0x3f];
     42 			ac >>= 6;
     43 			bits -= 6;
     44 		} while (bits >= 6);
     45 		i++;
     46 	}
     47 	if (bits)
     48 		*cp++ = lookup_table[ac & 0x3f];
     49 	return cp - dst;
     50 }
     51 
     52 int ext2fs_digest_decode(const char *src, int len, char *dst)
     53 {
     54 	int i = 0, bits = 0, ac = 0;
     55 	const char *p;
     56 	char *cp = dst;
     57 
     58 	while (i < len) {
     59 		p = strchr(lookup_table, src[i]);
     60 		if (p == NULL || src[i] == 0)
     61 			return -1;
     62 		ac += (p - lookup_table) << bits;
     63 		bits += 6;
     64 		if (bits >= 8) {
     65 			*cp++ = ac & 0xff;
     66 			ac >>= 8;
     67 			bits -= 8;
     68 		}
     69 		i++;
     70 	}
     71 	if (ac)
     72 		return -1;
     73 	return cp - dst;
     74 }
     75 
     76 
     77 #ifdef UNITTEST
     78 static const struct {
     79 	unsigned char d[32];
     80 	unsigned int len;
     81 	const unsigned char *ed;
     82 } tests[] = {
     83 	{ { 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14,
     84 	    0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
     85 	    0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c,
     86 	    0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55 }, 32,
     87 	"jDLxChJ,cQhm7TPyZ+WukcirBROZbOJTkWZmbgnU4WF"
     88 	},
     89 	{ { 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea,
     90 	    0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23,
     91 	    0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c,
     92 	    0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad }, 32,
     93 	"6inF,+YAPreQBBk3d5qIjA7AhNqlXoHn0Cx,hJPAV0K"
     94 	},
     95 	{ { 0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8,
     96 	    0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39,
     97 	    0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67,
     98 	    0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1 }, 32,
     99 	"k0oahJtB4gb5AbykM4DY5MKPknFZ,HyZ2ze7Unx2GEM"
    100 	},
    101 	{ { 0x00, }, 1,
    102 	"AA"
    103 	},
    104 	{ { 0x01, }, 1,
    105 	"BA"
    106 	},
    107 	{ { 0x01, 0x02 }, 2,
    108 	"BIA"
    109 	},
    110 	{ { 0x01, 0x02, 0x03 }, 3,
    111 	"BIwA"
    112 	},
    113 	{ { 0x01, 0x02, 0x03, 0x04 }, 4,
    114 	"BIwAEA"
    115 	},
    116 	{ { 0x01, 0x02, 0x03, 0x04, 0xff }, 5,
    117 	"BIwAE8P"
    118 	},
    119 	{ { 0x01, 0x02, 0x03, 0x04, 0xff, 0xfe }, 6,
    120 	"BIwAE8v,"
    121 	},
    122 	{ { 0x01, 0x02, 0x03, 0x04, 0xff, 0xfe, 0xfd }, 7,
    123 	"BIwAE8v,9D"
    124 	},
    125 };
    126 
    127 int main(int argc, char **argv)
    128 {
    129 	int i, ret, len, len2;
    130 	int errors = 0;
    131 	unsigned char tmp[1024], tmp2[1024];
    132 
    133 	if (argc == 3 && !strcmp(argv[1], "encode")) {
    134 		memset(tmp, 0, sizeof(tmp));
    135 		ext2fs_digest_encode(argv[2], strlen(argv[2]), tmp);
    136 		puts(tmp);
    137 		exit(0);
    138 	}
    139 	if (argc == 3 && !strcmp(argv[1], "decode")) {
    140 		memset(tmp, 0, sizeof(tmp));
    141 		ret = ext2fs_digest_decode(argv[2], strlen(argv[2]), tmp);
    142 		puts(tmp);
    143 		fprintf(stderr, "returned %d\n", ret);
    144 		exit(0);
    145 	}
    146 	for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) {
    147 		memset(tmp, 0, sizeof(tmp));
    148 		ret = ext2fs_digest_encode(tests[i].d, tests[i].len, tmp);
    149 		len = strlen(tmp);
    150 		printf("Test Digest %d (returned %d): ", i, ret);
    151 		if (ret != len) {
    152 			printf("FAILED returned %d, string length was %d\n",
    153 			       ret, len);
    154 			errors++;
    155 			continue;
    156 		} else if (strcmp(tmp, tests[i].ed) != 0) {
    157 			printf("FAILED: got %s, expected %s\n", tmp,
    158 			       tests[i].ed);
    159 			errors++;
    160 			continue;
    161 		}
    162 		ret = ext2fs_digest_decode(tmp, len, tmp2);
    163 		if (ret != tests[i].len) {
    164 			printf("FAILED decode returned %d, expected %d\n",
    165 			       ret, tests[i].len);
    166 			errors++;
    167 			continue;
    168 		}
    169 		if (memcmp(tmp2, tests[i].d, ret) != 0) {
    170 			puts("FAILED: decode mismatched");
    171 			errors++;
    172 			continue;
    173 		}
    174 		printf("OK\n");
    175 	}
    176 	for (i = 1; i < argc; i++) {
    177 		memset(tmp, 0, sizeof(tmp));
    178 		ret = ext2fs_digest_encode(argv[i], strlen(argv[i]), tmp);
    179 		len = strlen(tmp);
    180 		printf("Digest of '%s' is '%s' (returned %d, length %d)\n",
    181 		       argv[i], tmp, ret, len);
    182 	}
    183 	return errors;
    184 }
    185 
    186 #endif /* UNITTEST */
    187