GOST3411Digest.cs 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. using System;
  3. using Org.BouncyCastle.Crypto.Engines;
  4. using Org.BouncyCastle.Crypto.Parameters;
  5. using Org.BouncyCastle.Crypto.Utilities;
  6. using Org.BouncyCastle.Utilities;
  7. namespace Org.BouncyCastle.Crypto.Digests
  8. {
  9. /**
  10. * implementation of GOST R 34.11-94
  11. */
  12. public class Gost3411Digest
  13. : IDigest, IMemoable
  14. {
  15. private const int DIGEST_LENGTH = 32;
  16. private byte[] H = new byte[32], L = new byte[32],
  17. M = new byte[32], Sum = new byte[32];
  18. private byte[][] C = MakeC();
  19. private byte[] xBuf = new byte[32];
  20. private int xBufOff;
  21. private ulong byteCount;
  22. private readonly IBlockCipher cipher = new Gost28147Engine();
  23. private byte[] sBox;
  24. private static byte[][] MakeC()
  25. {
  26. byte[][] c = new byte[4][];
  27. for (int i = 0; i < 4; ++i)
  28. {
  29. c[i] = new byte[32];
  30. }
  31. return c;
  32. }
  33. /**
  34. * Standard constructor
  35. */
  36. public Gost3411Digest()
  37. {
  38. sBox = Gost28147Engine.GetSBox("D-A");
  39. cipher.Init(true, new ParametersWithSBox(null, sBox));
  40. Reset();
  41. }
  42. /**
  43. * Constructor to allow use of a particular sbox with GOST28147
  44. * @see GOST28147Engine#getSBox(String)
  45. */
  46. public Gost3411Digest(byte[] sBoxParam)
  47. {
  48. sBox = Arrays.Clone(sBoxParam);
  49. cipher.Init(true, new ParametersWithSBox(null, sBox));
  50. Reset();
  51. }
  52. /**
  53. * Copy constructor. This will copy the state of the provided
  54. * message digest.
  55. */
  56. public Gost3411Digest(Gost3411Digest t)
  57. {
  58. Reset(t);
  59. }
  60. public string AlgorithmName
  61. {
  62. get { return "Gost3411"; }
  63. }
  64. public int GetDigestSize()
  65. {
  66. return DIGEST_LENGTH;
  67. }
  68. public void Update(
  69. byte input)
  70. {
  71. xBuf[xBufOff++] = input;
  72. if (xBufOff == xBuf.Length)
  73. {
  74. sumByteArray(xBuf); // calc sum M
  75. processBlock(xBuf, 0);
  76. xBufOff = 0;
  77. }
  78. byteCount++;
  79. }
  80. public void BlockUpdate(
  81. byte[] input,
  82. int inOff,
  83. int length)
  84. {
  85. while ((xBufOff != 0) && (length > 0))
  86. {
  87. Update(input[inOff]);
  88. inOff++;
  89. length--;
  90. }
  91. while (length > xBuf.Length)
  92. {
  93. Array.Copy(input, inOff, xBuf, 0, xBuf.Length);
  94. sumByteArray(xBuf); // calc sum M
  95. processBlock(xBuf, 0);
  96. inOff += xBuf.Length;
  97. length -= xBuf.Length;
  98. byteCount += (uint)xBuf.Length;
  99. }
  100. // load in the remainder.
  101. while (length > 0)
  102. {
  103. Update(input[inOff]);
  104. inOff++;
  105. length--;
  106. }
  107. }
  108. // (i + 1 + 4(k - 1)) = 8i + k i = 0-3, k = 1-8
  109. private byte[] K = new byte[32];
  110. private byte[] P(byte[] input)
  111. {
  112. int fourK = 0;
  113. for(int k = 0; k < 8; k++)
  114. {
  115. K[fourK++] = input[k];
  116. K[fourK++] = input[8 + k];
  117. K[fourK++] = input[16 + k];
  118. K[fourK++] = input[24 + k];
  119. }
  120. return K;
  121. }
  122. //A (x) = (x0 ^ x1) || x3 || x2 || x1
  123. byte[] a = new byte[8];
  124. private byte[] A(byte[] input)
  125. {
  126. for(int j=0; j<8; j++)
  127. {
  128. a[j]=(byte)(input[j] ^ input[j+8]);
  129. }
  130. Array.Copy(input, 8, input, 0, 24);
  131. Array.Copy(a, 0, input, 24, 8);
  132. return input;
  133. }
  134. //Encrypt function, ECB mode
  135. private void E(byte[] key, byte[] s, int sOff, byte[] input, int inOff)
  136. {
  137. cipher.Init(true, new KeyParameter(key));
  138. cipher.ProcessBlock(input, inOff, s, sOff);
  139. }
  140. // (in:) n16||..||n1 ==> (out:) n1^n2^n3^n4^n13^n16||n16||..||n2
  141. internal short[] wS = new short[16], w_S = new short[16];
  142. private void fw(byte[] input)
  143. {
  144. cpyBytesToShort(input, wS);
  145. w_S[15] = (short)(wS[0] ^ wS[1] ^ wS[2] ^ wS[3] ^ wS[12] ^ wS[15]);
  146. Array.Copy(wS, 1, w_S, 0, 15);
  147. cpyShortToBytes(w_S, input);
  148. }
  149. // block processing
  150. internal byte[] S = new byte[32], U = new byte[32], V = new byte[32], W = new byte[32];
  151. private void processBlock(byte[] input, int inOff)
  152. {
  153. Array.Copy(input, inOff, M, 0, 32);
  154. //key step 1
  155. // H = h3 || h2 || h1 || h0
  156. // S = s3 || s2 || s1 || s0
  157. H.CopyTo(U, 0);
  158. M.CopyTo(V, 0);
  159. for (int j=0; j<32; j++)
  160. {
  161. W[j] = (byte)(U[j]^V[j]);
  162. }
  163. // Encrypt gost28147-ECB
  164. E(P(W), S, 0, H, 0); // s0 = EK0 [h0]
  165. //keys step 2,3,4
  166. for (int i=1; i<4; i++)
  167. {
  168. byte[] tmpA = A(U);
  169. for (int j=0; j<32; j++)
  170. {
  171. U[j] = (byte)(tmpA[j] ^ C[i][j]);
  172. }
  173. V = A(A(V));
  174. for (int j=0; j<32; j++)
  175. {
  176. W[j] = (byte)(U[j]^V[j]);
  177. }
  178. // Encrypt gost28147-ECB
  179. E(P(W), S, i * 8, H, i * 8); // si = EKi [hi]
  180. }
  181. // x(M, H) = y61(H^y(M^y12(S)))
  182. for(int n = 0; n < 12; n++)
  183. {
  184. fw(S);
  185. }
  186. for(int n = 0; n < 32; n++)
  187. {
  188. S[n] = (byte)(S[n] ^ M[n]);
  189. }
  190. fw(S);
  191. for(int n = 0; n < 32; n++)
  192. {
  193. S[n] = (byte)(H[n] ^ S[n]);
  194. }
  195. for(int n = 0; n < 61; n++)
  196. {
  197. fw(S);
  198. }
  199. Array.Copy(S, 0, H, 0, H.Length);
  200. }
  201. private void finish()
  202. {
  203. ulong bitCount = byteCount * 8;
  204. Pack.UInt64_To_LE(bitCount, L);
  205. while (xBufOff != 0)
  206. {
  207. Update((byte)0);
  208. }
  209. processBlock(L, 0);
  210. processBlock(Sum, 0);
  211. }
  212. public int DoFinal(
  213. byte[] output,
  214. int outOff)
  215. {
  216. finish();
  217. H.CopyTo(output, outOff);
  218. Reset();
  219. return DIGEST_LENGTH;
  220. }
  221. /**
  222. * reset the chaining variables to the IV values.
  223. */
  224. private static readonly byte[] C2 = {
  225. 0x00,(byte)0xFF,0x00,(byte)0xFF,0x00,(byte)0xFF,0x00,(byte)0xFF,
  226. (byte)0xFF,0x00,(byte)0xFF,0x00,(byte)0xFF,0x00,(byte)0xFF,0x00,
  227. 0x00,(byte)0xFF,(byte)0xFF,0x00,(byte)0xFF,0x00,0x00,(byte)0xFF,
  228. (byte)0xFF,0x00,0x00,0x00,(byte)0xFF,(byte)0xFF,0x00,(byte)0xFF
  229. };
  230. public void Reset()
  231. {
  232. byteCount = 0;
  233. xBufOff = 0;
  234. Array.Clear(H, 0, H.Length);
  235. Array.Clear(L, 0, L.Length);
  236. Array.Clear(M, 0, M.Length);
  237. Array.Clear(C[1], 0, C[1].Length); // real index C = +1 because index array with 0.
  238. Array.Clear(C[3], 0, C[3].Length);
  239. Array.Clear(Sum, 0, Sum.Length);
  240. Array.Clear(xBuf, 0, xBuf.Length);
  241. C2.CopyTo(C[2], 0);
  242. }
  243. // 256 bitsblock modul -> (Sum + a mod (2^256))
  244. private void sumByteArray(
  245. byte[] input)
  246. {
  247. int carry = 0;
  248. for (int i = 0; i != Sum.Length; i++)
  249. {
  250. int sum = (Sum[i] & 0xff) + (input[i] & 0xff) + carry;
  251. Sum[i] = (byte)sum;
  252. carry = sum >> 8;
  253. }
  254. }
  255. private static void cpyBytesToShort(byte[] S, short[] wS)
  256. {
  257. for(int i = 0; i < S.Length / 2; i++)
  258. {
  259. wS[i] = (short)(((S[i*2+1]<<8)&0xFF00)|(S[i*2]&0xFF));
  260. }
  261. }
  262. private static void cpyShortToBytes(short[] wS, byte[] S)
  263. {
  264. for(int i=0; i<S.Length/2; i++)
  265. {
  266. S[i*2 + 1] = (byte)(wS[i] >> 8);
  267. S[i*2] = (byte)wS[i];
  268. }
  269. }
  270. public int GetByteLength()
  271. {
  272. return 32;
  273. }
  274. public IMemoable Copy()
  275. {
  276. return new Gost3411Digest(this);
  277. }
  278. public void Reset(IMemoable other)
  279. {
  280. Gost3411Digest t = (Gost3411Digest)other;
  281. this.sBox = t.sBox;
  282. cipher.Init(true, new ParametersWithSBox(null, sBox));
  283. Reset();
  284. Array.Copy(t.H, 0, this.H, 0, t.H.Length);
  285. Array.Copy(t.L, 0, this.L, 0, t.L.Length);
  286. Array.Copy(t.M, 0, this.M, 0, t.M.Length);
  287. Array.Copy(t.Sum, 0, this.Sum, 0, t.Sum.Length);
  288. Array.Copy(t.C[1], 0, this.C[1], 0, t.C[1].Length);
  289. Array.Copy(t.C[2], 0, this.C[2], 0, t.C[2].Length);
  290. Array.Copy(t.C[3], 0, this.C[3], 0, t.C[3].Length);
  291. Array.Copy(t.xBuf, 0, this.xBuf, 0, t.xBuf.Length);
  292. this.xBufOff = t.xBufOff;
  293. this.byteCount = t.byteCount;
  294. }
  295. }
  296. }
  297. #endif