|
|
|
@ -120,7 +120,68 @@ char *grpc_base64_encode(const void *vdata, size_t data_size, int url_safe, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
gpr_slice grpc_base64_decode(const char *b64, int url_safe) { |
|
|
|
|
size_t b64_len = strlen(b64); |
|
|
|
|
return grpc_base64_decode_with_len(b64, strlen(b64), url_safe); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void decode_one_char(const unsigned char *codes, unsigned char *result, |
|
|
|
|
size_t *result_offset) { |
|
|
|
|
gpr_uint32 packed = (codes[0] << 2) | (codes[1] >> 4); |
|
|
|
|
result[(*result_offset)++] = (unsigned char)packed; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void decode_two_chars(const unsigned char *codes, unsigned char *result, |
|
|
|
|
size_t *result_offset) { |
|
|
|
|
gpr_uint32 packed = (codes[0] << 10) | (codes[1] << 4) | (codes[2] >> 2); |
|
|
|
|
result[(*result_offset)++] = (unsigned char)(packed >> 8); |
|
|
|
|
result[(*result_offset)++] = (unsigned char)(packed); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int decode_group(const unsigned char *codes, size_t num_codes, |
|
|
|
|
unsigned char *result, size_t *result_offset) { |
|
|
|
|
GPR_ASSERT(num_codes <= 4); |
|
|
|
|
|
|
|
|
|
/* Short end groups that may not have padding. */ |
|
|
|
|
if (num_codes == 1) { |
|
|
|
|
gpr_log(GPR_ERROR, "Invalid group. Must be at least 2 bytes."); |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
if (num_codes == 2) { |
|
|
|
|
decode_one_char(codes, result, result_offset); |
|
|
|
|
return 1; |
|
|
|
|
} |
|
|
|
|
if (num_codes == 3) { |
|
|
|
|
decode_two_chars(codes, result, result_offset); |
|
|
|
|
return 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Regular 4 byte groups with padding or not. */ |
|
|
|
|
GPR_ASSERT(num_codes == 4); |
|
|
|
|
if (codes[0] == GRPC_BASE64_PAD_BYTE || codes[1] == GRPC_BASE64_PAD_BYTE) { |
|
|
|
|
gpr_log(GPR_ERROR, "Invalid padding detected."); |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
if (codes[2] == GRPC_BASE64_PAD_BYTE) { |
|
|
|
|
if (codes[3] == GRPC_BASE64_PAD_BYTE) { |
|
|
|
|
decode_one_char(codes, result, result_offset); |
|
|
|
|
} else { |
|
|
|
|
gpr_log(GPR_ERROR, "Invalid padding detected."); |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
} else if (codes[3] == GRPC_BASE64_PAD_BYTE) { |
|
|
|
|
decode_two_chars(codes, result, result_offset); |
|
|
|
|
} else { |
|
|
|
|
/* No padding. */ |
|
|
|
|
gpr_uint32 packed = |
|
|
|
|
(codes[0] << 18) | (codes[1] << 12) | (codes[2] << 6) | codes[3]; |
|
|
|
|
result[(*result_offset)++] = (unsigned char)(packed >> 16); |
|
|
|
|
result[(*result_offset)++] = (unsigned char)(packed >> 8); |
|
|
|
|
result[(*result_offset)++] = (unsigned char)(packed); |
|
|
|
|
} |
|
|
|
|
return 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
gpr_slice grpc_base64_decode_with_len(const char *b64, size_t b64_len, |
|
|
|
|
int url_safe) { |
|
|
|
|
gpr_slice result = gpr_slice_malloc(b64_len); |
|
|
|
|
unsigned char *current = GPR_SLICE_START_PTR(result); |
|
|
|
|
size_t result_size = 0; |
|
|
|
@ -151,43 +212,15 @@ gpr_slice grpc_base64_decode(const char *b64, int url_safe) { |
|
|
|
|
} else { |
|
|
|
|
codes[num_codes++] = (unsigned char)code; |
|
|
|
|
if (num_codes == 4) { |
|
|
|
|
if (codes[0] == GRPC_BASE64_PAD_BYTE || |
|
|
|
|
codes[1] == GRPC_BASE64_PAD_BYTE) { |
|
|
|
|
gpr_log(GPR_ERROR, "Invalid padding detected."); |
|
|
|
|
goto fail; |
|
|
|
|
} |
|
|
|
|
if (codes[2] == GRPC_BASE64_PAD_BYTE) { |
|
|
|
|
if (codes[3] == GRPC_BASE64_PAD_BYTE) { |
|
|
|
|
/* Double padding. */ |
|
|
|
|
gpr_uint32 packed = (gpr_uint32)((codes[0] << 2) | (codes[1] >> 4)); |
|
|
|
|
current[result_size++] = (unsigned char)packed; |
|
|
|
|
} else { |
|
|
|
|
gpr_log(GPR_ERROR, "Invalid padding detected."); |
|
|
|
|
goto fail; |
|
|
|
|
} |
|
|
|
|
} else if (codes[3] == GRPC_BASE64_PAD_BYTE) { |
|
|
|
|
/* Single padding. */ |
|
|
|
|
gpr_uint32 packed = |
|
|
|
|
(gpr_uint32)((codes[0] << 10) | (codes[1] << 4) | (codes[2] >> 2)); |
|
|
|
|
current[result_size++] = (unsigned char)(packed >> 8); |
|
|
|
|
current[result_size++] = (unsigned char)(packed); |
|
|
|
|
} else { |
|
|
|
|
/* No padding. */ |
|
|
|
|
gpr_uint32 packed = |
|
|
|
|
(gpr_uint32)((codes[0] << 18) | (codes[1] << 12) | (codes[2] << 6) | codes[3]); |
|
|
|
|
current[result_size++] = (unsigned char)(packed >> 16); |
|
|
|
|
current[result_size++] = (unsigned char)(packed >> 8); |
|
|
|
|
current[result_size++] = (unsigned char)(packed); |
|
|
|
|
} |
|
|
|
|
if (!decode_group(codes, num_codes, current, &result_size)) goto fail; |
|
|
|
|
num_codes = 0; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (num_codes != 0) { |
|
|
|
|
gpr_log(GPR_ERROR, "Invalid base64."); |
|
|
|
|
gpr_slice_unref(result); |
|
|
|
|
return gpr_empty_slice(); |
|
|
|
|
if (num_codes != 0 && |
|
|
|
|
!decode_group(codes, num_codes, current, &result_size)) { |
|
|
|
|
goto fail; |
|
|
|
|
} |
|
|
|
|
GPR_SLICE_SET_LENGTH(result, result_size); |
|
|
|
|
return result; |
|
|
|
|