b64.c 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. #include "b64.h"
  2. static inline uint8_t b64char(uint8_t c) {
  3. if(c >= 'a') return c - 'a' + 26;
  4. if(c >= 'A') return c - 'A';
  5. if(c >= '0') return c - '0' + 52;
  6. if(c == '/') return 63;
  7. if(c == '+') return 62;
  8. return 0;
  9. }
  10. void base64_decode(char* in, uint64_t inLen, uint8_t* out, uint64_t* outLen) {
  11. uint64_t quads = inLen / 4;
  12. uint32_t rem = inLen % 4;
  13. uint64_t o = 0;
  14. uint64_t i = 0;
  15. for(uint64_t j = 0; j < quads; j++, i += 4) {
  16. union {
  17. uint64_t q;
  18. uint8_t b[4];
  19. } x;
  20. uint8_t c0 = b64char(in[i + 0]);
  21. uint8_t c1 = b64char(in[i + 1]);
  22. uint8_t c2 = b64char(in[i + 2]);
  23. uint8_t c3 = b64char(in[i + 3]);
  24. x.q = (c0 << 18) | (c1 << 12) | (c2 << 6) | c3;
  25. out[o + 0] = x.b[2];
  26. out[o + 1] = x.b[1];
  27. out[o + 2] = x.b[0];
  28. o += 3;
  29. }
  30. *outLen = quads * 3;
  31. // adjust length for padding
  32. if(in[i - 2] == '=') (*outLen) -= 2;
  33. else if(in[i - 1] == '=') (*outLen)--;
  34. if(!rem) return;
  35. uint8_t c0 = 0, c1 = 0, c2 = 0;
  36. union {
  37. uint64_t q;
  38. uint8_t b[4];
  39. } x;
  40. x.q = 0;
  41. switch(rem) {
  42. case 3:
  43. c2 = b64char(in[i + 2]);
  44. /* fallthrough */
  45. case 2:
  46. c1 = b64char(in[i + 1]);
  47. /* fallthrough */
  48. case 1:
  49. c0 = b64char(in[i + 0]);
  50. default:
  51. }
  52. x.q = (c0 << 18) | (c1 << 12) | (c2 << 6);
  53. if(x.b[0]) {
  54. out[o + 2] = x.b[0];
  55. (*outLen)++;
  56. }
  57. if(x.b[1]) {
  58. out[o + 1] = x.b[1];
  59. (*outLen)++;
  60. }
  61. if(x.b[2]) {
  62. out[o + 0] = x.b[2];
  63. (*outLen)++;
  64. }
  65. }
  66. static inline char charfromhextet(uint8_t h) {
  67. if(h < 26) return h + 'A';
  68. if(h < 52) return h - 26 + 'a';
  69. if(h < 62) return h - 52 + '0';
  70. if(h == 62) return '+';
  71. if(h == 63) return '/';
  72. return 0;
  73. }
  74. void base64_encode(char* in, uint64_t inLen, char* out, uint64_t* outLen) {
  75. uint64_t trios = inLen / 3;
  76. uint64_t rem = inLen % 3;
  77. uint64_t o = 0;
  78. uint64_t i = 0;
  79. for(uint64_t j = 0; j < trios; j++, i += 3) {
  80. uint32_t x = 0;
  81. x = (in[i + 0] << 16 | in[i + 1] << 8 | in[i + 2]);
  82. out[o + 0] = charfromhextet((x >> 18) & 0b00111111);
  83. out[o + 1] = charfromhextet((x >> 12) & 0b00111111);
  84. out[o + 2] = charfromhextet((x >> 6) & 0b00111111);
  85. out[o + 3] = charfromhextet((x >> 0) & 0b00111111);
  86. o += 4;
  87. }
  88. *outLen = trios * 4;
  89. if(!rem) return;
  90. (*outLen) += 4;
  91. out[o + 3] = '=';
  92. uint32_t x = 0;
  93. x = (in[i + 0] << 16);
  94. if(rem == 2) {
  95. x |= (in[i + 1] << 8);
  96. out[o + 2] = charfromhextet((x >> 6) & 0b00111111);
  97. }
  98. else {
  99. out[o + 2] = '=';
  100. }
  101. out[o + 0] = charfromhextet((x >> 18) & 0b00111111);
  102. out[o + 1] = charfromhextet((x >> 12) & 0b00111111);
  103. }