SM3Digest.cs 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  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.Utilities;
  5. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Utilities;
  6. namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Digests
  7. {
  8. /// <summary>
  9. /// Implementation of Chinese SM3 digest as described at
  10. /// http://tools.ietf.org/html/draft-shen-sm3-hash-00
  11. /// and at .... ( Chinese PDF )
  12. /// </summary>
  13. /// <remarks>
  14. /// The specification says "process a bit stream",
  15. /// but this is written to process bytes in blocks of 4,
  16. /// meaning this will process 32-bit word groups.
  17. /// But so do also most other digest specifications,
  18. /// including the SHA-256 which was a origin for
  19. /// this specification.
  20. /// </remarks>
  21. public class SM3Digest
  22. : GeneralDigest
  23. {
  24. private const int DIGEST_LENGTH = 32; // bytes
  25. private const int BLOCK_SIZE = 64 / 4; // of 32 bit ints (16 ints)
  26. private uint[] V = new uint[DIGEST_LENGTH / 4]; // in 32 bit ints (8 ints)
  27. private uint[] inwords = new uint[BLOCK_SIZE];
  28. private int xOff;
  29. // Work-bufs used within processBlock()
  30. private uint[] W = new uint[68];
  31. // Round constant T for processBlock() which is 32 bit integer rolled left up to (63 MOD 32) bit positions.
  32. private static readonly uint[] T = new uint[64];
  33. static SM3Digest()
  34. {
  35. for (int i = 0; i < 16; ++i)
  36. {
  37. uint t = 0x79CC4519;
  38. T[i] = (t << i) | (t >> (32 - i));
  39. }
  40. for (int i = 16; i < 64; ++i)
  41. {
  42. int n = i % 32;
  43. uint t = 0x7A879D8A;
  44. T[i] = (t << n) | (t >> (32 - n));
  45. }
  46. }
  47. /// <summary>
  48. /// Standard constructor
  49. /// </summary>
  50. public SM3Digest()
  51. {
  52. Reset();
  53. }
  54. /// <summary>
  55. /// Copy constructor. This will copy the state of the provided
  56. /// message digest.
  57. /// </summary>
  58. public SM3Digest(SM3Digest t)
  59. : base(t)
  60. {
  61. CopyIn(t);
  62. }
  63. private void CopyIn(SM3Digest t)
  64. {
  65. Array.Copy(t.V, 0, this.V, 0, this.V.Length);
  66. Array.Copy(t.inwords, 0, this.inwords, 0, this.inwords.Length);
  67. xOff = t.xOff;
  68. }
  69. public override string AlgorithmName
  70. {
  71. get { return "SM3"; }
  72. }
  73. public override int GetDigestSize()
  74. {
  75. return DIGEST_LENGTH;
  76. }
  77. public override IMemoable Copy()
  78. {
  79. return new SM3Digest(this);
  80. }
  81. public override void Reset(IMemoable other)
  82. {
  83. SM3Digest d = (SM3Digest)other;
  84. base.CopyIn(d);
  85. CopyIn(d);
  86. }
  87. /// <summary>
  88. /// reset the chaining variables
  89. /// </summary>
  90. public override void Reset()
  91. {
  92. base.Reset();
  93. this.V[0] = 0x7380166F;
  94. this.V[1] = 0x4914B2B9;
  95. this.V[2] = 0x172442D7;
  96. this.V[3] = 0xDA8A0600;
  97. this.V[4] = 0xA96F30BC;
  98. this.V[5] = 0x163138AA;
  99. this.V[6] = 0xE38DEE4D;
  100. this.V[7] = 0xB0FB0E4E;
  101. this.xOff = 0;
  102. }
  103. public override int DoFinal(byte[] output, int outOff)
  104. {
  105. Finish();
  106. Pack.UInt32_To_BE(V, output, outOff);
  107. Reset();
  108. return DIGEST_LENGTH;
  109. }
  110. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  111. public override int DoFinal(Span<byte> output)
  112. {
  113. Finish();
  114. Pack.UInt32_To_BE(V, output);
  115. Reset();
  116. return DIGEST_LENGTH;
  117. }
  118. #endif
  119. internal override void ProcessWord(byte[] input, int inOff)
  120. {
  121. inwords[xOff++] = Pack.BE_To_UInt32(input, inOff);
  122. if (this.xOff >= 16)
  123. {
  124. ProcessBlock();
  125. }
  126. }
  127. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  128. internal override void ProcessWord(ReadOnlySpan<byte> word)
  129. {
  130. inwords[xOff++] = Pack.BE_To_UInt32(word);
  131. if (this.xOff >= 16)
  132. {
  133. ProcessBlock();
  134. }
  135. }
  136. #endif
  137. internal override void ProcessLength(long bitLength)
  138. {
  139. if (this.xOff > (BLOCK_SIZE - 2))
  140. {
  141. // xOff == 15 --> can't fit the 64 bit length field at tail..
  142. this.inwords[this.xOff] = 0; // fill with zero
  143. ++this.xOff;
  144. ProcessBlock();
  145. }
  146. // Fill with zero words, until reach 2nd to last slot
  147. while (this.xOff < (BLOCK_SIZE - 2))
  148. {
  149. this.inwords[this.xOff] = 0;
  150. ++this.xOff;
  151. }
  152. // Store input data length in BITS
  153. this.inwords[this.xOff++] = (uint)(bitLength >> 32);
  154. this.inwords[this.xOff++] = (uint)(bitLength);
  155. }
  156. /*
  157. 3.4.2. Constants
  158. Tj = 79cc4519 when 0 < = j < = 15
  159. Tj = 7a879d8a when 16 < = j < = 63
  160. 3.4.3. Boolean function
  161. FFj(X;Y;Z) = X XOR Y XOR Z when 0 < = j < = 15
  162. = (X AND Y) OR (X AND Z) OR (Y AND Z) when 16 < = j < = 63
  163. GGj(X;Y;Z) = X XOR Y XOR Z when 0 < = j < = 15
  164. = (X AND Y) OR (NOT X AND Z) when 16 < = j < = 63
  165. The X, Y, Z in the fomular are words!GBP
  166. 3.4.4. Permutation function
  167. P0(X) = X XOR (X <<< 9) XOR (X <<< 17) ## ROLL, not SHIFT
  168. P1(X) = X XOR (X <<< 15) XOR (X <<< 23) ## ROLL, not SHIFT
  169. The X in the fomular are a word.
  170. ----------
  171. Each ROLL converted to Java expression:
  172. ROLL 9 : ((x << 9) | (x >> (32-9))))
  173. ROLL 17 : ((x << 17) | (x >> (32-17)))
  174. ROLL 15 : ((x << 15) | (x >> (32-15)))
  175. ROLL 23 : ((x << 23) | (x >> (32-23)))
  176. */
  177. private uint P0(uint x)
  178. {
  179. uint r9 = ((x << 9) | (x >> (32 - 9)));
  180. uint r17 = ((x << 17) | (x >> (32 - 17)));
  181. return (x ^ r9 ^ r17);
  182. }
  183. private uint P1(uint x)
  184. {
  185. uint r15 = ((x << 15) | (x >> (32 - 15)));
  186. uint r23 = ((x << 23) | (x >> (32 - 23)));
  187. return (x ^ r15 ^ r23);
  188. }
  189. private uint FF0(uint x, uint y, uint z)
  190. {
  191. return (x ^ y ^ z);
  192. }
  193. private uint FF1(uint x, uint y, uint z)
  194. {
  195. return ((x & y) | (x & z) | (y & z));
  196. }
  197. private uint GG0(uint x, uint y, uint z)
  198. {
  199. return (x ^ y ^ z);
  200. }
  201. private uint GG1(uint x, uint y, uint z)
  202. {
  203. return ((x & y) | ((~x) & z));
  204. }
  205. internal override void ProcessBlock()
  206. {
  207. for (int j = 0; j < 16; ++j)
  208. {
  209. this.W[j] = this.inwords[j];
  210. }
  211. for (int j = 16; j < 68; ++j)
  212. {
  213. uint wj3 = this.W[j - 3];
  214. uint r15 = ((wj3 << 15) | (wj3 >> (32 - 15)));
  215. uint wj13 = this.W[j - 13];
  216. uint r7 = ((wj13 << 7) | (wj13 >> (32 - 7)));
  217. this.W[j] = P1(this.W[j - 16] ^ this.W[j - 9] ^ r15) ^ r7 ^ this.W[j - 6];
  218. }
  219. uint A = this.V[0];
  220. uint B = this.V[1];
  221. uint C = this.V[2];
  222. uint D = this.V[3];
  223. uint E = this.V[4];
  224. uint F = this.V[5];
  225. uint G = this.V[6];
  226. uint H = this.V[7];
  227. for (int j = 0; j < 16; ++j)
  228. {
  229. uint a12 = ((A << 12) | (A >> (32 - 12)));
  230. uint s1_ = a12 + E + T[j];
  231. uint SS1 = ((s1_ << 7) | (s1_ >> (32 - 7)));
  232. uint SS2 = SS1 ^ a12;
  233. uint Wj = W[j];
  234. uint W1j = Wj ^ W[j + 4];
  235. uint TT1 = FF0(A, B, C) + D + SS2 + W1j;
  236. uint TT2 = GG0(E, F, G) + H + SS1 + Wj;
  237. D = C;
  238. C = ((B << 9) | (B >> (32 - 9)));
  239. B = A;
  240. A = TT1;
  241. H = G;
  242. G = ((F << 19) | (F >> (32 - 19)));
  243. F = E;
  244. E = P0(TT2);
  245. }
  246. // Different FF,GG functions on rounds 16..63
  247. for (int j = 16; j < 64; ++j)
  248. {
  249. uint a12 = ((A << 12) | (A >> (32 - 12)));
  250. uint s1_ = a12 + E + T[j];
  251. uint SS1 = ((s1_ << 7) | (s1_ >> (32 - 7)));
  252. uint SS2 = SS1 ^ a12;
  253. uint Wj = W[j];
  254. uint W1j = Wj ^ W[j + 4];
  255. uint TT1 = FF1(A, B, C) + D + SS2 + W1j;
  256. uint TT2 = GG1(E, F, G) + H + SS1 + Wj;
  257. D = C;
  258. C = ((B << 9) | (B >> (32 - 9)));
  259. B = A;
  260. A = TT1;
  261. H = G;
  262. G = ((F << 19) | (F >> (32 - 19)));
  263. F = E;
  264. E = P0(TT2);
  265. }
  266. this.V[0] ^= A;
  267. this.V[1] ^= B;
  268. this.V[2] ^= C;
  269. this.V[3] ^= D;
  270. this.V[4] ^= E;
  271. this.V[5] ^= F;
  272. this.V[6] ^= G;
  273. this.V[7] ^= H;
  274. this.xOff = 0;
  275. }
  276. }
  277. }
  278. #pragma warning restore
  279. #endif