Advertisement
Guest User

Untitled

a guest
Oct 31st, 2014
140
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.31 KB | None | 0 0
  1. string key = BuildKey(myHiddenByte); // give that to the end user
  2. ...
  3. byte hidden;
  4. if (!TryReadKey(key, out hidden))
  5. {
  6. Console.WriteLine("key is not ok");
  7. }
  8. else
  9. {
  10. Console.WriteLine("key is ok and hidden byte is " + hidden);
  11. }
  12.  
  13. KZGMB0-XYJC2-YRKH3-8LD8G-5FUZG
  14. YKU93K-M34PD-E5PL0-QM91J-QLDZF
  15. DH27H9-NCW8E-EMGPL-YCJXJ-N2PRG
  16. WDAKDE-G56NR-6BA3R-0JE6U-625EB
  17. 6D5EJ0-NJDAK-EMGZR-Z6ZDF-JHJGF
  18. ....
  19.  
  20. // need 32 characters, so we can use a 5-bit base encoding
  21. // 0 1 2 3
  22. // 01234567890123456789012345678901
  23. private const string KeyChars = "ABCDEFGHJKLMNPQRTUWXYZ0123456789";
  24. private const int MinSum = 2000;
  25. private const int Mask = 0xFFFFF; // beware, this can have a dramatic influence on performance
  26.  
  27. /// <summary>
  28. /// Builds a key and hides data in it.
  29. /// Key format is XXXXXX-XXXXX-XXXXX-XXXXX-XXXXX.
  30. /// </summary>
  31. /// <param name="hiddenData">The hidden data.</param>
  32. /// <returns>The build key</returns>
  33. public static string BuildKey(byte hiddenData)
  34. {
  35. int index;
  36. Guid guid;
  37. uint[] word = new uint[4];
  38. byte[] array;
  39. while (true)
  40. {
  41. // we use guid initial randomness characteristics
  42. guid = Guid.NewGuid();
  43. array = guid.ToByteArray();
  44.  
  45. int sum = array.Aggregate(0, (current, b) => current + b);
  46.  
  47. // a simple check to make sure the guid is not filled with too much zeros...
  48. if (sum < MinSum)
  49. continue;
  50.  
  51. // build a 32-bit word array
  52. for (int i = 0; i < 4; i++)
  53. {
  54. word[i] = BitConverter.ToUInt32(array, i * 4) & Mask;
  55. }
  56.  
  57. // Here we check the guid follows some algorithm. if it doesn't we skip it
  58. // the algorithm presented here is to check one of the 32-bit word is equal to the sum of the others
  59. // (modulo a mask otherwise it takes too long!)
  60. //
  61. // This algorithm can be changed at your will (and change the TryReadKey as well)
  62.  
  63. if ((word[0] + word[1] + word[2]) == word[3])
  64. {
  65. index = 3;
  66. break;
  67. }
  68.  
  69. if ((word[0] + word[1] + word[3]) == word[2])
  70. {
  71. index = 2;
  72. break;
  73. }
  74.  
  75. if ((word[0] + word[3] + word[2]) == word[1])
  76. {
  77. index = 1;
  78. break;
  79. }
  80.  
  81. if ((word[3] + word[1] + word[2]) == word[0])
  82. {
  83. index = 0;
  84. break;
  85. }
  86. }
  87.  
  88. // hidden info is also xor'd with other words hi order (except the one we masked)
  89. // so it's not too easy to guess
  90. hiddenData = (byte)(hiddenData ^ array[0] ^ array[4] ^ array[8] ^ array[12]);
  91.  
  92. // rebuild words without mask
  93. for (int i = 0; i < 4; i++)
  94. {
  95. word[i] = BitConverter.ToUInt32(array, i * 4);
  96. }
  97.  
  98. // hidden info is stored in the block that is the sum of other blocks, in hi order byte (outside the mask)
  99. word[index] &= 0x00FFFFFF;
  100. word[index] |= ((uint)hiddenData) << 24;
  101.  
  102. // rebuild the array back
  103. for (int i = 0; i < 4; i++)
  104. {
  105. byte[] ui = BitConverter.GetBytes(word[i]);
  106. for (int j = 0; j < 4; j++)
  107. {
  108. array[i * 4 + j] = ui[j];
  109. }
  110. }
  111.  
  112. // now use 5-bits encoding
  113. int encodingBitIndex = 0;
  114. StringBuilder key = new StringBuilder();
  115. while (encodingBitIndex < 128)
  116. {
  117. byte encodingByte = Get5Bits(array, encodingBitIndex);
  118. if ((key.Length > 0) && (key.Length % 6) == 0)
  119. {
  120. key.Append('-');
  121. }
  122. key.Append(KeyChars[encodingByte]);
  123. encodingBitIndex += 5;
  124. }
  125. return key.ToString();
  126. }
  127.  
  128. /// <summary>
  129. /// Validates the specified key and reads hidden data from it.
  130. /// </summary>
  131. /// <param name="key">The key.</param>
  132. /// <param name="hiddenData">The hidden data.</param>
  133. /// <returns>true if the key is valid and hidden data was read; false otherwise.</returns>
  134. public static bool TryReadKey(string key, out byte hiddenData)
  135. {
  136. hiddenData = 0;
  137. if (key == null)
  138. return false;
  139.  
  140. key = key.Replace("-", string.Empty);
  141. if (key.Length != 26)
  142. return false;
  143.  
  144. byte[] array = new byte[16];
  145. int encodingBitIndex = 0;
  146. foreach (char t in key)
  147. {
  148. byte b = 255;
  149. for (byte k = 0; k < KeyChars.Length; k++)
  150. {
  151. if (KeyChars[k] != t) continue;
  152. b = k;
  153. break;
  154. }
  155. if (b == 255) // char not found
  156. return false;
  157.  
  158. Put5Bits(array, encodingBitIndex, b);
  159. encodingBitIndex += 5;
  160. }
  161.  
  162. // quick sum check
  163. int sum = array.Aggregate(0, (current, b) => current + b);
  164.  
  165. // add 256 because we changed the hidden byte
  166. sum += 256;
  167. if (sum < MinSum)
  168. return false;
  169.  
  170. uint[] word = new uint[4];
  171. for (int i = 0; i < 4; i++)
  172. {
  173. word[i] = BitConverter.ToUInt32(array, i * 4) & Mask;
  174. }
  175.  
  176. // This must match BuildKey algorithm
  177.  
  178. int index;
  179. if ((word[0] + word[1] + word[2]) == word[3])
  180. {
  181. index = 3;
  182. }
  183. else if ((word[0] + word[1] + word[3]) == word[2])
  184. {
  185. index = 2;
  186. }
  187. else if ((word[0] + word[3] + word[2]) == word[1])
  188. {
  189. index = 1;
  190. }
  191. else if ((word[3] + word[1] + word[2]) == word[0])
  192. {
  193. index = 0;
  194. }
  195. else
  196. return false;
  197.  
  198. // reread word & extract hidden byte back
  199. word[index] = BitConverter.ToUInt32(array, index * 4);
  200. hiddenData = (byte)(word[index] >> 24);
  201. hiddenData = (byte)(hiddenData ^ array[0] ^ array[4] ^ array[8] ^ array[12]);
  202. return true;
  203. }
  204.  
  205. // get 5 bits from a byte buffer at an arbitrary bit index
  206. private static byte Get5Bits(byte[] buffer, int bitIndex)
  207. {
  208. int r = bitIndex % 8;
  209. if (r < 4)
  210. return (byte)(((buffer[bitIndex / 8]) & (0xFF >> r)) >> (3 - r));
  211.  
  212. byte b0 = (byte)((buffer[bitIndex / 8] & (0xFF >> r)) << (r - 3));
  213. if ((1 + (bitIndex / 8)) == buffer.Length) // last
  214. return (byte)(buffer[buffer.Length - 1] & 0x7);
  215.  
  216. if ((bitIndex / 8) < 16)
  217. return (byte)(b0 | buffer[1 + (bitIndex / 8)] >> (11 - r));
  218.  
  219. return b0;
  220. }
  221.  
  222. // put 5 bits into a byte buffer at an arbitrary bit index
  223. private static void Put5Bits(byte[] buffer, int bitIndex, byte value)
  224. {
  225. int r = bitIndex % 8;
  226. if (r < 4)
  227. {
  228. buffer[bitIndex / 8] |= (byte)((value << (3 - r)));
  229. }
  230. else
  231. {
  232. if ((1 + (bitIndex / 8)) == buffer.Length) // last
  233. {
  234. buffer[buffer.Length - 1] |= (byte)(value & 0x7);
  235. }
  236. else if ((bitIndex / 8) < 16)
  237. {
  238. buffer[bitIndex / 8] |= (byte)((value >> (r - 3)));
  239. buffer[1 + (bitIndex / 8)] |= (byte)((value << (11 - r)));
  240. }
  241. }
  242. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement