GOST3411Digest.cs 8.0 KB

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