1 /*------------------------------------------------------------------------- 2 * 3 * base64.c 4 * Encoding and decoding routines for base64 without whitespace. 5 * 6 * Copyright (c) 2001-2018, PostgreSQL Global Development Group 7 * 8 * 9 * IDENTIFICATION 10 * src/common/base64.c 11 * 12 *------------------------------------------------------------------------- 13 */ 14 15 #ifndef FRONTEND 16 #include "postgres.h" 17 #else 18 #include "postgres_fe.h" 19 #endif 20 21 #include "common/base64.h" 22 23 /* 24 * BASE64 25 */ 26 27 static const char _base64[] = 28 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 29 30 static const int8 b64lookup[128] = { 31 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 32 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 33 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 34 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, 35 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 36 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, 37 -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 38 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, 39 }; 40 41 /* 42 * pg_b64_encode 43 * 44 * Encode into base64 the given string. Returns the length of the encoded 45 * string. 46 */ 47 int 48 pg_b64_encode(const char *src, int len, char *dst) 49 { 50 char *p; 51 const char *s, 52 *end = src + len; 53 int pos = 2; 54 uint32 buf = 0; 55 56 s = src; 57 p = dst; 58 59 while (s < end) 60 { 61 buf |= (unsigned char) *s << (pos << 3); 62 pos--; 63 s++; 64 65 /* write it out */ 66 if (pos < 0) 67 { 68 *p++ = _base64[(buf >> 18) & 0x3f]; 69 *p++ = _base64[(buf >> 12) & 0x3f]; 70 *p++ = _base64[(buf >> 6) & 0x3f]; 71 *p++ = _base64[buf & 0x3f]; 72 73 pos = 2; 74 buf = 0; 75 } 76 } 77 if (pos != 2) 78 { 79 *p++ = _base64[(buf >> 18) & 0x3f]; 80 *p++ = _base64[(buf >> 12) & 0x3f]; 81 *p++ = (pos == 0) ? _base64[(buf >> 6) & 0x3f] : '='; 82 *p++ = '='; 83 } 84 85 return p - dst; 86 } 87 88 /* 89 * pg_b64_decode 90 * 91 * Decode the given base64 string. Returns the length of the decoded 92 * string on success, and -1 in the event of an error. main(int argc,char * argv[])93 */ 94 int 95 pg_b64_decode(const char *src, int len, char *dst) 96 { 97 const char *srcend = src + len, 98 *s = src; 99 char *p = dst; 100 char c; 101 int b = 0; 102 uint32 buf = 0; 103 int pos = 0, 104 end = 0; 105 106 while (s < srcend) 107 { 108 c = *s++; 109 110 /* Leave if a whitespace is found */ 111 if (c == ' ' || c == '\t' || c == '\n' || c == '\r') 112 return -1; 113 114 if (c == '=') 115 { 116 /* end sequence */ 117 if (!end) 118 { 119 if (pos == 2) 120 end = 1; 121 else if (pos == 3) 122 end = 2; 123 else 124 { 125 /* 126 * Unexpected "=" character found while decoding base64 127 * sequence. 128 */ 129 return -1; 130 } 131 } 132 b = 0; 133 } 134 else 135 { 136 b = -1; 137 if (c > 0 && c < 127) 138 b = b64lookup[(unsigned char) c]; 139 if (b < 0) 140 { 141 /* invalid symbol found */ 142 return -1; 143 } 144 } 145 /* add it to buffer */ 146 buf = (buf << 6) + b; 147 pos++; 148 if (pos == 4) 149 { 150 *p++ = (buf >> 16) & 255; 151 if (end == 0 || end > 1) 152 *p++ = (buf >> 8) & 255; 153 if (end == 0 || end > 2) 154 *p++ = buf & 255; 155 buf = 0; 156 pos = 0; 157 } 158 } 159 160 if (pos != 0) 161 { 162 /* 163 * base64 end sequence is invalid. Input data is missing padding, is 164 * truncated or is otherwise corrupted. 165 */ 166 return -1; 167 } 168 169 return p - dst; 170 } 171 172 /* 173 * pg_b64_enc_len 174 * 175 * Returns to caller the length of the string if it were encoded with 176 * base64 based on the length provided by caller. This is useful to 177 * estimate how large a buffer allocation needs to be done before doing 178 * the actual encoding. 179 */ 180 int 181 pg_b64_enc_len(int srclen) 182 { 183 /* 3 bytes will be converted to 4 */ 184 return (srclen + 2) * 4 / 3; 185 } 186 187 /* 188 * pg_b64_dec_len 189 * 190 * Returns to caller the length of the string if it were to be decoded 191 * with base64, based on the length given by caller. This is useful to 192 * estimate how large a buffer allocation needs to be done before doing 193 * the actual decoding. 194 */ 195 int 196 pg_b64_dec_len(int srclen) 197 { 198 return (srclen * 3) >> 2; 199 } 200