Base32Encoding.cs 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. using System;
  2. namespace Quadarax.Foundation.Core.Value
  3. {
  4. public class Base32Encoding
  5. {
  6. public static byte[] ToBytes(string input)
  7. {
  8. if (string.IsNullOrEmpty(input))
  9. {
  10. throw new ArgumentNullException(nameof(input));
  11. }
  12. input = input.TrimEnd('='); //remove padding characters
  13. var byteCount = input.Length * 5 / 8; //this must be TRUNCATED
  14. var returnArray = new byte[byteCount];
  15. byte curByte = 0, bitsRemaining = 8;
  16. int mask = 0, arrayIndex = 0;
  17. foreach (var c in input)
  18. {
  19. var cValue = CharToValue(c);
  20. if (bitsRemaining > 5)
  21. {
  22. mask = cValue << (bitsRemaining - 5);
  23. curByte = (byte)(curByte | mask);
  24. bitsRemaining -= 5;
  25. }
  26. else
  27. {
  28. mask = cValue >> (5 - bitsRemaining);
  29. curByte = (byte)(curByte | mask);
  30. returnArray[arrayIndex++] = curByte;
  31. curByte = (byte)(cValue << (3 + bitsRemaining));
  32. bitsRemaining += 3;
  33. }
  34. }
  35. //if we didn't end with a full byte
  36. if (arrayIndex != byteCount)
  37. {
  38. returnArray[arrayIndex] = curByte;
  39. }
  40. return returnArray;
  41. }
  42. public static string ToString(byte[] input)
  43. {
  44. if (input == null || input.Length == 0)
  45. {
  46. throw new ArgumentNullException(nameof(input));
  47. }
  48. var charCount = (int)Math.Ceiling(input.Length / 5d) * 8;
  49. var returnArray = new char[charCount];
  50. byte nextChar = 0, bitsRemaining = 5;
  51. var arrayIndex = 0;
  52. foreach (var b in input)
  53. {
  54. nextChar = (byte)(nextChar | (b >> (8 - bitsRemaining)));
  55. returnArray[arrayIndex++] = ValueToChar(nextChar);
  56. if (bitsRemaining < 4)
  57. {
  58. nextChar = (byte)((b >> (3 - bitsRemaining)) & 31);
  59. returnArray[arrayIndex++] = ValueToChar(nextChar);
  60. bitsRemaining += 5;
  61. }
  62. bitsRemaining -= 3;
  63. nextChar = (byte)((b << bitsRemaining) & 31);
  64. }
  65. //if we didn't end with a full char
  66. if (arrayIndex != charCount)
  67. {
  68. returnArray[arrayIndex++] = ValueToChar(nextChar);
  69. while (arrayIndex != charCount) returnArray[arrayIndex++] = '='; //padding
  70. }
  71. return new string(returnArray);
  72. }
  73. private static int CharToValue(char c)
  74. {
  75. var value = (int)c;
  76. //65-90 == uppercase letters
  77. if (value < 91 && value > 64)
  78. {
  79. return value - 65;
  80. }
  81. //50-55 == numbers 2-7
  82. if (value < 56 && value > 49)
  83. {
  84. return value - 24;
  85. }
  86. //97-122 == lowercase letters
  87. if (value < 123 && value > 96)
  88. {
  89. return value - 97;
  90. }
  91. throw new ArgumentException("Character is not a Base32 character.", "c");
  92. }
  93. private static char ValueToChar(byte b)
  94. {
  95. if (b < 26)
  96. {
  97. return (char)(b + 65);
  98. }
  99. if (b < 32)
  100. {
  101. return (char)(b + 24);
  102. }
  103. throw new ArgumentException("Byte is not a value Base32 value.", "b");
  104. }
  105. }
  106. }