base64.rs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2023 Dyne.org foundation
  4. * Copyright (C) 2021-2023 Kavan Mevada (MIT) (https://github.com/kavanmevada/base64cr)
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU Affero General Public License as
  8. * published by the Free Software Foundation, either version 3 of the
  9. * License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU Affero General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Affero General Public License
  17. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  18. */
  19. #![forbid(unsafe_code)]
  20. macro_rules! seq4 {
  21. [$($e:expr),*] => { [$($e,$e,$e,$e,)*] }
  22. }
  23. macro_rules! rep4 {
  24. [$($e:expr),*] => { [$($e,)*$($e,)*$($e,)*$($e,)*] }
  25. }
  26. static E0: [char; 256] = seq4![
  27. 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
  28. 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
  29. 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4',
  30. '5', '6', '7', '8', '9', '+', '/'
  31. ];
  32. static E1: [char; 256] = rep4![
  33. 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
  34. 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
  35. 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4',
  36. '5', '6', '7', '8', '9', '+', '/'
  37. ];
  38. static E2: [char; 256] = E1;
  39. const FF: u32 = 33554431;
  40. static D0: [u32; 256] = [
  41. FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
  42. FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, 248, FF, FF, FF,
  43. 252, 208, 212, 216, 220, 224, 228, 232, 236, 240, 244, FF, FF, FF, FF, FF, FF, FF, 0, 4, 8, 12,
  44. 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 84, 88, 92, 96, 100, FF,
  45. FF, FF, FF, FF, FF, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, 148, 152, 156, 160,
  46. 164, 168, 172, 176, 180, 184, 188, 192, 196, 200, 204, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
  47. FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
  48. FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
  49. FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
  50. FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
  51. FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
  52. FF, FF, FF,
  53. ];
  54. static D1: [u32; 256] = [
  55. FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
  56. FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, 57347, FF, FF, FF,
  57. 61443, 16387, 20483, 24579, 28675, 32771, 36867, 40963, 45059, 49155, 53251, FF, FF, FF, FF,
  58. FF, FF, FF, 0, 4096, 8192, 12288, 16384, 20480, 24576, 28672, 32768, 36864, 40960, 45056,
  59. 49152, 53248, 57344, 61440, 1, 4097, 8193, 12289, 16385, 20481, 24577, 28673, 32769, 36865, FF,
  60. FF, FF, FF, FF, FF, 40961, 45057, 49153, 53249, 57345, 61441, 2, 4098, 8194, 12290, 16386,
  61. 20482, 24578, 28674, 32770, 36866, 40962, 45058, 49154, 53250, 57346, 61442, 3, 4099, 8195,
  62. 12291, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
  63. FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
  64. FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
  65. FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
  66. FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
  67. FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
  68. ];
  69. static D2: [u32; 256] = [
  70. FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
  71. FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, 8392448, FF, FF,
  72. FF, 12586752, 3328, 4197632, 8391936, 12586240, 3584, 4197888, 8392192, 12586496, 3840,
  73. 4198144, FF, FF, FF, FF, FF, FF, FF, 0, 4194304, 8388608, 12582912, 256, 4194560, 8388864,
  74. 12583168, 512, 4194816, 8389120, 12583424, 768, 4195072, 8389376, 12583680, 1024, 4195328,
  75. 8389632, 12583936, 1280, 4195584, 8389888, 12584192, 1536, 4195840, FF, FF, FF, FF, FF, FF,
  76. 8390144, 12584448, 1792, 4196096, 8390400, 12584704, 2048, 4196352, 8390656, 12584960, 2304,
  77. 4196608, 8390912, 12585216, 2560, 4196864, 8391168, 12585472, 2816, 4197120, 8391424, 12585728,
  78. 3072, 4197376, 8391680, 12585984, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
  79. FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
  80. FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
  81. FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
  82. FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
  83. FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
  84. ];
  85. static D3: [u32; 256] = [
  86. FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
  87. FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, 4063232, FF, FF,
  88. FF, 4128768, 3407872, 3473408, 3538944, 3604480, 3670016, 3735552, 3801088, 3866624, 3932160,
  89. 3997696, FF, FF, FF, FF, FF, FF, FF, 0, 65536, 131072, 196608, 262144, 327680, 393216, 458752,
  90. 524288, 589824, 655360, 720896, 786432, 851968, 917504, 983040, 1048576, 1114112, 1179648,
  91. 1245184, 1310720, 1376256, 1441792, 1507328, 1572864, 1638400, FF, FF, FF, FF, FF, FF, 1703936,
  92. 1769472, 1835008, 1900544, 1966080, 2031616, 2097152, 2162688, 2228224, 2293760, 2359296,
  93. 2424832, 2490368, 2555904, 2621440, 2686976, 2752512, 2818048, 2883584, 2949120, 3014656,
  94. 3080192, 3145728, 3211264, 3276800, 3342336, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
  95. FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
  96. FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
  97. FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
  98. FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
  99. FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
  100. FF,
  101. ];
  102. /// Encode a byte slice into a base64 string
  103. pub fn encode(data: &[u8]) -> String {
  104. let len = data.len();
  105. let mut dest = vec![0u8; ((4 * len / 3) + 3) & !3];
  106. let mut i = 0;
  107. let mut j = 0;
  108. if len > 2 {
  109. while i < len - 2 {
  110. let t1 = data[i];
  111. let t2 = data[i + 1];
  112. let t3 = data[i + 2];
  113. dest[j] = E0[t1 as usize] as u8;
  114. dest[j + 1] = E1[(((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)) as usize] as u8;
  115. dest[j + 2] = E1[(((t2 & 0x0F) << 2) | ((t3 >> 6) & 0x03)) as usize] as u8;
  116. dest[j + 3] = E2[t3 as usize] as u8;
  117. i += 3;
  118. j += 4;
  119. }
  120. }
  121. match len - i {
  122. 0 => {}
  123. 1 => {
  124. let t1 = data[i];
  125. dest[j] = E0[t1 as usize] as u8;
  126. dest[j + 1] = E1[((t1 & 0x03) << 4) as usize] as u8;
  127. dest[j + 2] = b'=';
  128. dest[j + 3] = b'=';
  129. }
  130. _ => {
  131. /* case 2 */
  132. let t1 = data[i] as usize;
  133. let t2 = data[i + 1] as usize;
  134. dest[j] = E0[t1] as u8;
  135. dest[j + 1] = E1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)] as u8;
  136. dest[j + 2] = E2[(t2 & 0x0F) << 2] as u8;
  137. dest[j + 3] = b'=';
  138. }
  139. }
  140. String::from_utf8(dest).unwrap()
  141. }
  142. /// Tries to decode a base64 string into a byte vector.
  143. /// Returns `None` if something fails.
  144. pub fn decode(data: &str) -> Option<Vec<u8>> {
  145. if !data.is_ascii() {
  146. return None
  147. }
  148. let data = data.as_bytes();
  149. let mut len = data.len();
  150. if data[len - 1] == b'=' {
  151. len -= 1;
  152. if data[len - 1] == b'=' {
  153. len -= 1;
  154. }
  155. }
  156. let mut dest = vec![0u8; (3 * (data.len() / 4)) - (data.len() - len)];
  157. let leftover = len % 4;
  158. let chunks = if leftover == 0 { len / 4 - 1 } else { len / 4 };
  159. let mut j = 0;
  160. let mut k = 0;
  161. for _ in 0..chunks {
  162. let x: u32 = D0[data[k] as usize] |
  163. D1[data[1 + k] as usize] |
  164. D2[data[2 + k] as usize] |
  165. D3[data[3 + k] as usize];
  166. dest[j] = x as u8;
  167. dest[j + 1] = (x >> 8) as u8;
  168. dest[j + 2] = (x >> 16) as u8;
  169. j += 3;
  170. k += 4;
  171. }
  172. match leftover {
  173. 0 => {
  174. let x: u32 = D0[data[k] as usize] |
  175. D1[data[1 + k] as usize] |
  176. D2[data[2 + k] as usize] |
  177. D3[data[3 + k] as usize];
  178. dest[j] = x as u8;
  179. dest[j + 1] = (x >> 8) as u8;
  180. dest[j + 2] = (x >> 16) as u8;
  181. // (chunks + 1) * 3)
  182. return Some(dest)
  183. }
  184. 1 => {
  185. /* with padding this is an impossible case */
  186. let x: u32 = D0[data[k] as usize]; // i.e. first char/byte in int
  187. dest[j] = x as u8;
  188. }
  189. 2 => {
  190. // * case 2, 1 output byte */
  191. let x: u32 = D0[data[k] as usize] | D1[data[1 + k] as usize]; // i.e. first char
  192. dest[j] = x as u8;
  193. }
  194. _ => {
  195. let x: u32 = D0[data[k] as usize] | D1[data[1 + k] as usize] | D2[data[2 + k] as usize]; /* 0x3c */
  196. dest[j] = x as u8;
  197. dest[j + 1] = (x >> 8) as u8;
  198. }
  199. }
  200. // 3 * chunks + (6 * leftover) / 8
  201. Some(dest)
  202. }
  203. #[cfg(test)]
  204. mod tests {
  205. use super::*;
  206. #[test]
  207. pub fn b64_encdec() {
  208. const EXAMPLES: [(&[u8], &str); 3] = [
  209. (b"abc123!?$*&()'-=@~", "YWJjMTIzIT8kKiYoKSctPUB+"),
  210. (b"gm world", "Z20gd29ybGQ="),
  211. (
  212. b"Man is distinguished, not only by his reason, but by this singular passion from \
  213. other animals, which is a lust of the mind, that by a perseverance of delight \
  214. in the continued and indefatigable generation of knowledge, exceeds the short \
  215. vehemence of any carnal pleasure.",
  216. "TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlz\
  217. IHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2Yg\
  218. dGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGlu\
  219. dWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRo\
  220. ZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4=",
  221. ),
  222. ];
  223. for &(input, answer) in EXAMPLES.iter() {
  224. let res = encode(input);
  225. assert_eq!(answer, res);
  226. let res = decode(answer).unwrap();
  227. assert_eq!(input, res);
  228. }
  229. }
  230. }