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