base32.rs 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2025 Dyne.org foundation
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. //! Base32 encoding as specified by RFC4648
  19. //! Optional padding is the `=` character.
  20. // Taken from https://github.com/andreasots/base32
  21. use core::cmp::min;
  22. /// Standard Base32 alphabet.
  23. const ENCODE_STD: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
  24. /// Encode a byte slice with the given base32 alphabet into a base32 string.
  25. pub fn encode(padding: bool, data: &[u8]) -> String {
  26. let mut ret = Vec::with_capacity((data.len() + 3) / 4 * 5);
  27. for chunk in data.chunks(5) {
  28. let buf = {
  29. let mut buf = [0u8; 5];
  30. for (i, &b) in chunk.iter().enumerate() {
  31. buf[i] = b;
  32. }
  33. buf
  34. };
  35. ret.push(ENCODE_STD[((buf[0] & 0xf8) >> 3) as usize]);
  36. ret.push(ENCODE_STD[(((buf[0] & 0x07) << 2) | ((buf[1] & 0xc0) >> 6)) as usize]);
  37. ret.push(ENCODE_STD[((buf[1] & 0x3e) >> 1) as usize]);
  38. ret.push(ENCODE_STD[(((buf[1] & 0x01) << 4) | ((buf[2] & 0xf0) >> 4)) as usize]);
  39. ret.push(ENCODE_STD[(((buf[2] & 0x0f) << 1) | (buf[3] >> 7)) as usize]);
  40. ret.push(ENCODE_STD[((buf[3] & 0x7c) >> 2) as usize]);
  41. ret.push(ENCODE_STD[(((buf[3] & 0x03) << 3) | ((buf[4] & 0xe0) >> 5)) as usize]);
  42. ret.push(ENCODE_STD[(buf[4] & 0x1f) as usize]);
  43. }
  44. if data.len() % 5 != 0 {
  45. let len = ret.len();
  46. let num_extra = 8 - (data.len() % 5 * 8 + 4) / 5;
  47. if padding {
  48. for i in 1..num_extra + 1 {
  49. ret[len - i] = b'=';
  50. }
  51. } else {
  52. ret.truncate(len - num_extra);
  53. }
  54. }
  55. String::from_utf8(ret).unwrap()
  56. }
  57. const STD_INV_ALPHABET: [i8; 43] = [
  58. -1, -1, 26, 27, 28, 29, 30, 31, -1, -1, -1, -1, -1, 0, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8,
  59. 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
  60. ];
  61. /// Tries to decode a base32 string into a byte vector. Returns `None` if
  62. /// something fails.
  63. pub fn decode(data: &str) -> Option<Vec<u8>> {
  64. if !data.is_ascii() {
  65. return None
  66. }
  67. let data = data.as_bytes();
  68. let mut unpadded_data_len = data.len();
  69. for i in 1..min(6, data.len()) + 1 {
  70. if data[data.len() - i] != b'=' {
  71. break
  72. }
  73. unpadded_data_len -= 1;
  74. }
  75. let output_length = unpadded_data_len * 5 / 8;
  76. let mut ret = Vec::with_capacity((output_length + 4) / 5 * 5);
  77. for chunk in data.chunks(8) {
  78. let buf = {
  79. let mut buf = [0u8; 8];
  80. for (i, &c) in chunk.iter().enumerate() {
  81. match STD_INV_ALPHABET.get(c.to_ascii_uppercase().wrapping_sub(b'0') as usize) {
  82. Some(&-1) | None => return None,
  83. Some(&value) => buf[i] = value as u8,
  84. };
  85. }
  86. buf
  87. };
  88. ret.push((buf[0] << 3) | (buf[1] >> 2));
  89. ret.push((buf[1] << 6) | (buf[2] << 1) | (buf[3] >> 4));
  90. ret.push((buf[3] << 4) | (buf[4] >> 1));
  91. ret.push((buf[4] << 7) | (buf[5] << 2) | (buf[6] >> 3));
  92. ret.push((buf[6] << 5) | buf[7]);
  93. }
  94. ret.truncate(output_length);
  95. Some(ret)
  96. }
  97. #[cfg(test)]
  98. mod tests {
  99. #[test]
  100. fn base32_encoding_decoding() {
  101. let s = b"b32Test"; // This should pad with 4 =
  102. let encoded = super::encode(true, &s[..]);
  103. assert_eq!(&encoded, "MIZTEVDFON2A====");
  104. assert_eq!(super::decode(&encoded).unwrap(), s);
  105. let s = b"b32Testoor"; // This shouldn't pad
  106. let encoded = super::encode(true, &s[..]);
  107. assert_eq!(&encoded, "MIZTEVDFON2G633S");
  108. assert_eq!(super::decode(&encoded).unwrap(), s);
  109. }
  110. }