SM3.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  1. // 麻省理工学院许可证
  2. //
  3. // 版权所有 (c) 2021-2023 zuohuaijun,大名科技(天津)有限公司 联系电话/微信:18020030720 QQ:515096995
  4. //
  5. // 特此免费授予获得本软件的任何人以处理本软件的权利,但须遵守以下条件:在所有副本或重要部分的软件中必须包括上述版权声明和本许可声明。
  6. //
  7. // 软件按“原样”提供,不提供任何形式的明示或暗示的保证,包括但不限于对适销性、适用性和非侵权的保证。
  8. // 在任何情况下,作者或版权持有人均不对任何索赔、损害或其他责任负责,无论是因合同、侵权或其他方式引起的,与软件或其使用或其他交易有关。
  9. using Org.BouncyCastle.Crypto;
  10. namespace Admin.NET.Core;
  11. public abstract class GeneralDigest : IDigest
  12. {
  13. private const int BYTE_LENGTH = 64;
  14. private readonly byte[] xBuf;
  15. private int xBufOff;
  16. private long byteCount;
  17. internal GeneralDigest()
  18. {
  19. xBuf = new byte[4];
  20. }
  21. internal GeneralDigest(GeneralDigest t)
  22. {
  23. xBuf = new byte[t.xBuf.Length];
  24. Array.Copy(t.xBuf, 0, xBuf, 0, t.xBuf.Length);
  25. xBufOff = t.xBufOff;
  26. byteCount = t.byteCount;
  27. }
  28. public void Update(byte input)
  29. {
  30. xBuf[xBufOff++] = input;
  31. if (xBufOff == xBuf.Length)
  32. {
  33. ProcessWord(xBuf, 0);
  34. xBufOff = 0;
  35. }
  36. byteCount++;
  37. }
  38. public void BlockUpdate(byte[] input, int inOff, int length)
  39. {
  40. //
  41. // fill the current word
  42. //
  43. while ((xBufOff != 0) && (length > 0))
  44. {
  45. Update(input[inOff]);
  46. inOff++;
  47. length--;
  48. }
  49. //
  50. // process whole words.
  51. //
  52. while (length > xBuf.Length)
  53. {
  54. ProcessWord(input, inOff);
  55. inOff += xBuf.Length;
  56. length -= xBuf.Length;
  57. byteCount += xBuf.Length;
  58. }
  59. //
  60. // load in the remainder.
  61. //
  62. while (length > 0)
  63. {
  64. Update(input[inOff]);
  65. inOff++;
  66. length--;
  67. }
  68. }
  69. public void Finish()
  70. {
  71. long bitLength = (byteCount << 3);
  72. //
  73. // add the pad bytes.
  74. //
  75. Update(unchecked((byte)128));
  76. while (xBufOff != 0) Update(unchecked((byte)0));
  77. ProcessLength(bitLength);
  78. ProcessBlock();
  79. }
  80. public virtual void Reset()
  81. {
  82. byteCount = 0;
  83. xBufOff = 0;
  84. Array.Clear(xBuf, 0, xBuf.Length);
  85. }
  86. public int GetByteLength()
  87. {
  88. return BYTE_LENGTH;
  89. }
  90. internal abstract void ProcessWord(byte[] input, int inOff);
  91. internal abstract void ProcessLength(long bitLength);
  92. internal abstract void ProcessBlock();
  93. public abstract string AlgorithmName { get; }
  94. public abstract int GetDigestSize();
  95. public abstract void BlockUpdate(ReadOnlySpan<byte> input);
  96. public abstract int DoFinal(byte[] output, int outOff);
  97. public abstract int DoFinal(Span<byte> output);
  98. }
  99. public class SupportClass
  100. {
  101. /// <summary>
  102. /// Performs an unsigned bitwise right shift with the specified number
  103. /// </summary>
  104. /// <param name="number">Number to operate on</param>
  105. /// <param name="bits">Ammount of bits to shift</param>
  106. /// <returns>The resulting number from the shift operation</returns>
  107. public static int URShift(int number, int bits)
  108. {
  109. if (number >= 0)
  110. return number >> bits;
  111. else
  112. return (number >> bits) + (2 << ~bits);
  113. }
  114. /// <summary>
  115. /// Performs an unsigned bitwise right shift with the specified number
  116. /// </summary>
  117. /// <param name="number">Number to operate on</param>
  118. /// <param name="bits">Ammount of bits to shift</param>
  119. /// <returns>The resulting number from the shift operation</returns>
  120. public static int URShift(int number, long bits)
  121. {
  122. return URShift(number, (int)bits);
  123. }
  124. /// <summary>
  125. /// Performs an unsigned bitwise right shift with the specified number
  126. /// </summary>
  127. /// <param name="number">Number to operate on</param>
  128. /// <param name="bits">Ammount of bits to shift</param>
  129. /// <returns>The resulting number from the shift operation</returns>
  130. public static long URShift(long number, int bits)
  131. {
  132. if (number >= 0)
  133. return number >> bits;
  134. else
  135. return (number >> bits) + (2L << ~bits);
  136. }
  137. /// <summary>
  138. /// Performs an unsigned bitwise right shift with the specified number
  139. /// </summary>
  140. /// <param name="number">Number to operate on</param>
  141. /// <param name="bits">Ammount of bits to shift</param>
  142. /// <returns>The resulting number from the shift operation</returns>
  143. public static long URShift(long number, long bits)
  144. {
  145. return URShift(number, (int)bits);
  146. }
  147. }
  148. public class SM3Digest : GeneralDigest
  149. {
  150. public override string AlgorithmName
  151. {
  152. get
  153. {
  154. return "SM3";
  155. }
  156. }
  157. public override int GetDigestSize()
  158. {
  159. return DIGEST_LENGTH;
  160. }
  161. private const int DIGEST_LENGTH = 32;
  162. private static readonly int[] v0 = new int[] { 0x7380166f, 0x4914b2b9, 0x172442d7, unchecked((int)0xda8a0600), unchecked((int)0xa96f30bc), 0x163138aa, unchecked((int)0xe38dee4d), unchecked((int)0xb0fb0e4e) };
  163. private readonly int[] v = new int[8];
  164. private readonly int[] v_ = new int[8];
  165. private static readonly int[] X0 = new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  166. private readonly int[] X = new int[68];
  167. private int xOff;
  168. private readonly int T_00_15 = 0x79cc4519;
  169. private readonly int T_16_63 = 0x7a879d8a;
  170. public SM3Digest()
  171. {
  172. Reset();
  173. }
  174. public SM3Digest(SM3Digest t) : base(t)
  175. {
  176. Array.Copy(t.X, 0, X, 0, t.X.Length);
  177. xOff = t.xOff;
  178. Array.Copy(t.v, 0, v, 0, t.v.Length);
  179. }
  180. public override void Reset()
  181. {
  182. base.Reset();
  183. Array.Copy(v0, 0, v, 0, v0.Length);
  184. xOff = 0;
  185. Array.Copy(X0, 0, X, 0, X0.Length);
  186. }
  187. internal override void ProcessBlock()
  188. {
  189. int i;
  190. int[] ww = X;
  191. int[] ww_ = new int[64];
  192. for (i = 16; i < 68; i++)
  193. {
  194. ww[i] = P1(ww[i - 16] ^ ww[i - 9] ^ (ROTATE(ww[i - 3], 15))) ^ (ROTATE(ww[i - 13], 7)) ^ ww[i - 6];
  195. }
  196. for (i = 0; i < 64; i++)
  197. {
  198. ww_[i] = ww[i] ^ ww[i + 4];
  199. }
  200. int[] vv = v;
  201. int[] vv_ = v_;
  202. Array.Copy(vv, 0, vv_, 0, v0.Length);
  203. int SS1, SS2, TT1, TT2, aaa;
  204. for (i = 0; i < 16; i++)
  205. {
  206. aaa = ROTATE(vv_[0], 12);
  207. SS1 = aaa + vv_[4] + ROTATE(T_00_15, i);
  208. SS1 = ROTATE(SS1, 7);
  209. SS2 = SS1 ^ aaa;
  210. TT1 = FF_00_15(vv_[0], vv_[1], vv_[2]) + vv_[3] + SS2 + ww_[i];
  211. TT2 = GG_00_15(vv_[4], vv_[5], vv_[6]) + vv_[7] + SS1 + ww[i];
  212. vv_[3] = vv_[2];
  213. vv_[2] = ROTATE(vv_[1], 9);
  214. vv_[1] = vv_[0];
  215. vv_[0] = TT1;
  216. vv_[7] = vv_[6];
  217. vv_[6] = ROTATE(vv_[5], 19);
  218. vv_[5] = vv_[4];
  219. vv_[4] = P0(TT2);
  220. }
  221. for (i = 16; i < 64; i++)
  222. {
  223. aaa = ROTATE(vv_[0], 12);
  224. SS1 = aaa + vv_[4] + ROTATE(T_16_63, i);
  225. SS1 = ROTATE(SS1, 7);
  226. SS2 = SS1 ^ aaa;
  227. TT1 = FF_16_63(vv_[0], vv_[1], vv_[2]) + vv_[3] + SS2 + ww_[i];
  228. TT2 = GG_16_63(vv_[4], vv_[5], vv_[6]) + vv_[7] + SS1 + ww[i];
  229. vv_[3] = vv_[2];
  230. vv_[2] = ROTATE(vv_[1], 9);
  231. vv_[1] = vv_[0];
  232. vv_[0] = TT1;
  233. vv_[7] = vv_[6];
  234. vv_[6] = ROTATE(vv_[5], 19);
  235. vv_[5] = vv_[4];
  236. vv_[4] = P0(TT2);
  237. }
  238. for (i = 0; i < 8; i++)
  239. {
  240. vv[i] ^= vv_[i];
  241. }
  242. // Reset
  243. xOff = 0;
  244. Array.Copy(X0, 0, X, 0, X0.Length);
  245. }
  246. internal override void ProcessWord(byte[] in_Renamed, int inOff)
  247. {
  248. int n = in_Renamed[inOff] << 24;
  249. n |= (in_Renamed[++inOff] & 0xff) << 16;
  250. n |= (in_Renamed[++inOff] & 0xff) << 8;
  251. n |= (in_Renamed[++inOff] & 0xff);
  252. X[xOff] = n;
  253. if (++xOff == 16)
  254. {
  255. ProcessBlock();
  256. }
  257. }
  258. internal override void ProcessLength(long bitLength)
  259. {
  260. if (xOff > 14)
  261. {
  262. ProcessBlock();
  263. }
  264. X[14] = (int)(SupportClass.URShift(bitLength, 32));
  265. X[15] = (int)(bitLength & unchecked((int)0xffffffff));
  266. }
  267. public static void IntToBigEndian(int n, byte[] bs, int off)
  268. {
  269. bs[off] = (byte)(SupportClass.URShift(n, 24));
  270. bs[++off] = (byte)(SupportClass.URShift(n, 16));
  271. bs[++off] = (byte)(SupportClass.URShift(n, 8));
  272. bs[++off] = (byte)(n);
  273. }
  274. public override int DoFinal(byte[] out_Renamed, int outOff)
  275. {
  276. Finish();
  277. for (int i = 0; i < 8; i++)
  278. {
  279. IntToBigEndian(v[i], out_Renamed, outOff + i * 4);
  280. }
  281. Reset();
  282. return DIGEST_LENGTH;
  283. }
  284. private static int ROTATE(int x, int n)
  285. {
  286. return (x << n) | (SupportClass.URShift(x, (32 - n)));
  287. }
  288. private static int P0(int X)
  289. {
  290. return ((X) ^ ROTATE((X), 9) ^ ROTATE((X), 17));
  291. }
  292. private static int P1(int X)
  293. {
  294. return ((X) ^ ROTATE((X), 15) ^ ROTATE((X), 23));
  295. }
  296. private static int FF_00_15(int X, int Y, int Z)
  297. {
  298. return (X ^ Y ^ Z);
  299. }
  300. private static int FF_16_63(int X, int Y, int Z)
  301. {
  302. return ((X & Y) | (X & Z) | (Y & Z));
  303. }
  304. private static int GG_00_15(int X, int Y, int Z)
  305. {
  306. return (X ^ Y ^ Z);
  307. }
  308. private static int GG_16_63(int X, int Y, int Z)
  309. {
  310. return ((X & Y) | (~X & Z));
  311. }
  312. public override void BlockUpdate(ReadOnlySpan<byte> input)
  313. {
  314. }
  315. public override int DoFinal(Span<byte> output)
  316. {
  317. return DIGEST_LENGTH;
  318. }
  319. //[STAThread]
  320. //public static void Main()
  321. //{
  322. // byte[] md = new byte[32];
  323. // byte[] msg1 = Encoding.Default.GetBytes("ererfeiisgod");
  324. // SM3Digest sm3 = new SM3Digest();
  325. // sm3.BlockUpdate(msg1, 0, msg1.Length);
  326. // sm3.DoFinal(md, 0);
  327. // System.String s = new UTF8Encoding().GetString(Hex.Encode(md));
  328. // System.Console.Out.WriteLine(s.ToUpper());
  329. // Console.ReadLine();
  330. //}
  331. }