at_base64url.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. #include "at_log.h"
  2. #include "at_base64url.h"
  3. // defines
  4. #define B64_BYTE1(ptr) (((*ptr) & 0xfc) >> 2)
  5. #define B64_BYTE2(ptr) ((((*ptr) & 0x03) << 4) | ((*(ptr + 1) & 0xf0) >> 4))
  6. #define B64_BYTE3(ptr) (((*(ptr + 1) & 0x0f) << 2) | ((*(ptr + 2) & 0xc0) >> 6))
  7. #define B64_BYTE4(ptr) (*(ptr + 2) & 0x3f)
  8. // internal data
  9. static const char *ALPHABET_B64U = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
  10. static const uint8_t TEBAHPLA_B64[]
  11. = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  12. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  13. 0xff, 0xff, 0xff, 0x3e, 0xff, 0x3e, 0xff, 0x3f, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0xff, 0xff,
  14. 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
  15. 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0x1a, 0x1b, 0x1c,
  16. 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
  17. 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  18. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  19. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  20. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  21. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  22. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  23. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
  24. // internal functions
  25. ////////////////////////////////////////////////////////////////////////////////
  26. int at_base64url_decode(const char *input, size_t inlen, uint8_t **output, size_t *outlen)
  27. {
  28. if ((NULL == input) || (NULL == output) || (NULL == outlen))
  29. {
  30. ATLOGE("param error.\n");
  31. return -1;
  32. }
  33. // return empty string on 0 length input
  34. if (0 == inlen)
  35. {
  36. uint8_t *retVal = (uint8_t *)malloc(sizeof(uint8_t));
  37. if (NULL == retVal)
  38. {
  39. ATLOGE("malloc error.\n");
  40. return -1;
  41. }
  42. retVal[0] = 0;
  43. *output = retVal;
  44. *outlen = 0;
  45. return 0;
  46. }
  47. // extra validation -- inlen is a multiple of 4
  48. if (inlen % 4 == 1)
  49. {
  50. ATLOGE("param error.\n");;
  51. return -1;
  52. }
  53. // rlen takes a best guess on size;
  54. // might be too large for base64url, but never too small.
  55. size_t rlen = ((inlen * 3) >> 2) + 3;
  56. uint8_t *buffer = (uint8_t *)malloc(sizeof(uint8_t) * rlen);
  57. if (NULL == buffer)
  58. {
  59. ATLOGE("malloc error.\n");;
  60. return -1;
  61. }
  62. (void)memset(buffer, 0, rlen);
  63. size_t idx = 0;
  64. size_t pos = 0;
  65. size_t shift = 0;
  66. uint32_t packed = 0;
  67. while (inlen > idx)
  68. {
  69. uint8_t val;
  70. val = input[idx];
  71. if ('=' == val)
  72. {
  73. break;
  74. }
  75. else if ('+' == val || '/' == val)
  76. {
  77. ATLOGE("param error.\n");
  78. goto b64_decode_failed;
  79. }
  80. val = TEBAHPLA_B64[val];
  81. if (0xff == val)
  82. {
  83. ATLOGE("param error.\n");
  84. free(buffer);
  85. return -1;
  86. }
  87. idx++;
  88. packed = packed | (val << (18 - (6 * shift++)));
  89. if (4 == shift)
  90. {
  91. buffer[pos++] = (packed >> 16) & 0xff;
  92. buffer[pos++] = (packed >> 8) & 0xff;
  93. buffer[pos++] = packed & 0xff;
  94. shift = 0;
  95. packed = 0;
  96. }
  97. }
  98. assert(shift != 1);
  99. assert(shift != 4);
  100. if (shift == 3)
  101. {
  102. buffer[pos++] = (packed >> 16) & 0xff;
  103. buffer[pos++] = (packed >> 8) & 0xff;
  104. }
  105. if (shift == 2)
  106. {
  107. buffer[pos++] = (packed >> 16) & 0xff;
  108. }
  109. *output = buffer;
  110. *outlen = pos;
  111. assert(*outlen <= rlen);
  112. return 0;
  113. b64_decode_failed:
  114. if (NULL != buffer)
  115. {
  116. free(buffer);
  117. }
  118. return -1;
  119. }
  120. ////////////////////////////////////////////////////////////////////////////////
  121. int at_base64url_encode(const uint8_t *input, size_t inlen, char **output, size_t *outlen)
  122. {
  123. if ((inlen > 0 && NULL == input) || (NULL == output) || (NULL == outlen))
  124. {
  125. ATLOGE("param error.\n");
  126. return -1;
  127. }
  128. // return empty string on 0 length input
  129. if (!inlen)
  130. {
  131. char *retVal = (char *)malloc(sizeof(char));
  132. if (!retVal)
  133. {
  134. ATLOGE("malloc error.\n");
  135. return -1;
  136. }
  137. retVal[0] = '\0';
  138. *output = retVal;
  139. *outlen = 0;
  140. return 0;
  141. }
  142. size_t rlen = (((inlen + 2) / 3) << 2);
  143. char *base;
  144. base = (char *)malloc(sizeof(char) * (rlen + 1));
  145. if (NULL == base)
  146. {
  147. ATLOGE("malloc error.\n");
  148. return -1;
  149. }
  150. (void)memset(base, 0, rlen + 1);
  151. size_t pos = 0, idx = 0;
  152. while ((idx + 2) < inlen)
  153. {
  154. base[pos++] = ALPHABET_B64U[0x3f & (input[idx] >> 2)];
  155. base[pos++] = ALPHABET_B64U[(0x3f & (input[idx] << 4)) | (0x3f & (input[idx + 1] >> 4))];
  156. base[pos++] = ALPHABET_B64U[(0x3f & (input[idx + 1] << 2)) | (0x3f & (input[idx + 2] >> 6))];
  157. base[pos++] = ALPHABET_B64U[0x3f & input[idx + 2]];
  158. idx += 3;
  159. }
  160. if (idx < inlen)
  161. {
  162. if ((inlen - 1) == idx)
  163. {
  164. base[pos++] = ALPHABET_B64U[0x3f & (input[idx] >> 2)];
  165. base[pos++] = ALPHABET_B64U[0x3f & (input[idx] << 4)];
  166. }
  167. else
  168. {
  169. base[pos++] = ALPHABET_B64U[0x3f & (input[idx] >> 2)];
  170. base[pos++] = ALPHABET_B64U[(0x3f & (input[idx] << 4)) | (0x3f & (input[idx + 1] >> 4))];
  171. base[pos++] = ALPHABET_B64U[0x3f & (input[idx + 1] << 2)];
  172. }
  173. rlen = pos;
  174. }
  175. base[rlen] = '\0';
  176. *output = base;
  177. *outlen = rlen;
  178. return 0;
  179. }