├── packages
└── BouncyCastle.1.8.3.1
│ ├── BouncyCastle.1.8.3.1.nupkg
│ ├── lib
│ └── BouncyCastle.Crypto.dll
│ └── README.md
├── SM2Crypto
├── packages.config
├── App.config
├── Properties
│ └── AssemblyInfo.cs
├── Lib
│ ├── ByteUtils.cs
│ ├── SM4Utils.cs
│ ├── Chiper.cs
│ ├── SM2.cs
│ ├── SM2Utils.cs
│ ├── SM3.cs
│ └── SM4.cs
├── SM2Crypto.csproj
└── Program.cs
├── TestKeyPair
└── SM2Crypto.sln
/packages/BouncyCastle.1.8.3.1/BouncyCastle.1.8.3.1.nupkg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/njk888/SM2/HEAD/packages/BouncyCastle.1.8.3.1/BouncyCastle.1.8.3.1.nupkg
--------------------------------------------------------------------------------
/packages/BouncyCastle.1.8.3.1/lib/BouncyCastle.Crypto.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/njk888/SM2/HEAD/packages/BouncyCastle.1.8.3.1/lib/BouncyCastle.Crypto.dll
--------------------------------------------------------------------------------
/SM2Crypto/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/SM2Crypto/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/TestKeyPair:
--------------------------------------------------------------------------------
1 | testPublicKey:041E353292615666BB47F6358D3E893394D34AF30D64875E2E422182C15885D3ECA697C345EED99268D3CAC5F6054780C34433E1BF12EBFF1F744B67A2F6863CFB
2 | privateKey:00FAB34B54C026D158B54C88BC0463CB79B22661C7C870AD2A0455300E05471CE1
--------------------------------------------------------------------------------
/SM2Crypto.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.25420.1
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SM2Crypto", "SM2Crypto\SM2Crypto.csproj", "{DFC19643-ABE0-49F7-A087-31314B742408}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {DFC19643-ABE0-49F7-A087-31314B742408}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {DFC19643-ABE0-49F7-A087-31314B742408}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {DFC19643-ABE0-49F7-A087-31314B742408}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {DFC19643-ABE0-49F7-A087-31314B742408}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | EndGlobal
23 |
--------------------------------------------------------------------------------
/SM2Crypto/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // 有关程序集的一般信息由以下
6 | // 控制。更改这些特性值可修改
7 | // 与程序集关联的信息。
8 | [assembly: AssemblyTitle("SM2Crypto")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("SM2Crypto")]
13 | [assembly: AssemblyCopyright("Copyright © 2018")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | //将 ComVisible 设置为 false 将使此程序集中的类型
18 | //对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型,
19 | //请将此类型的 ComVisible 特性设置为 true。
20 | [assembly: ComVisible(false)]
21 |
22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
23 | [assembly: Guid("dfc19643-abe0-49f7-a087-31314b742408")]
24 |
25 | // 程序集的版本信息由下列四个值组成:
26 | //
27 | // 主版本
28 | // 次版本
29 | // 生成号
30 | // 修订号
31 | //
32 | //可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值,
33 | // 方法是按如下所示使用“*”: :
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/SM2Crypto/Lib/ByteUtils.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Globalization;
3 | using System.Text;
4 |
5 | namespace SM2Crypto.Lib
6 | {
7 | ///
8 | /// 字节数组操作扩展类
9 | ///
10 | static class ByteUtils
11 | {
12 | internal static byte[] AsciiBytes(string s)
13 | {
14 | byte[] bytes = new byte[s.Length];
15 |
16 | for (int i = 0; i < s.Length; i++)
17 | {
18 | bytes[i] = (byte)s[i];
19 | }
20 |
21 | return bytes;
22 | }
23 |
24 | internal static byte[] HexToByteArray(this string hexString)
25 | {
26 | byte[] bytes = new byte[hexString.Length / 2];
27 |
28 | for (int i = 0; i < hexString.Length; i += 2)
29 | {
30 | string s = hexString.Substring(i, 2);
31 | bytes[i / 2] = byte.Parse(s, NumberStyles.HexNumber, null);
32 | }
33 |
34 | return bytes;
35 | }
36 |
37 | internal static string ByteArrayToHex(this byte[] bytes)
38 | {
39 | StringBuilder builder = new StringBuilder(bytes.Length * 2);
40 |
41 | foreach (byte b in bytes)
42 | {
43 | builder.Append(b.ToString("X2"));
44 | }
45 |
46 | return builder.ToString();
47 | }
48 |
49 | internal static string ByteArrayToHex(this byte[] bytes, int len)
50 | {
51 | return ByteArrayToHex(bytes).Substring(0, len * 2);
52 | }
53 |
54 | internal static byte[] RepeatByte(byte b, int count)
55 | {
56 | byte[] value = new byte[count];
57 |
58 | for (int i = 0; i < count; i++)
59 | {
60 | value[i] = b;
61 | }
62 |
63 | return value;
64 | }
65 |
66 | internal static byte[] SubBytes(this byte[] bytes, int startIndex, int length )
67 | {
68 | byte[] res = new byte[length];
69 | Array.Copy(bytes, startIndex, res, 0, length);
70 | return res;
71 | }
72 |
73 | internal static byte[] XOR(this byte[] value)
74 | {
75 | byte[] res = new byte[value.Length];
76 | for (int i = 0; i < value.Length; i++)
77 | {
78 | res[i] ^= value[i];
79 | }
80 | return res;
81 | }
82 |
83 | internal static byte[] XOR(this byte[] valueA, byte[] valueB)
84 | {
85 | int len = valueA.Length;
86 | byte[] res = new byte[len];
87 | for (int i = 0; i < len; i++)
88 | {
89 | res[i] = (byte)(valueA[i] ^ valueB[i]);
90 | }
91 | return res;
92 | }
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/packages/BouncyCastle.1.8.3.1/README.md:
--------------------------------------------------------------------------------
1 | # The Bouncy Castle Crypto Package For C Sharp
2 |
3 | The Bouncy Castle Crypto package is a C\# implementation of cryptographic algorithms and protocols, it was developed by the Legion of the Bouncy Castle, a registered Australian Charity, with a little help! The Legion, and the latest goings on with this package, can be found at [http://www.bouncycastle.org](http://www.bouncycastle.org). In addition to providing basic cryptography algorithms, the package also provides support for CMS, TSP, X.509 certificate generation and a variety of other standards such as OpenPGP.
4 |
5 | The Legion also gratefully acknowledges the contributions made to this package by others (see [here](http://www.bouncycastle.org/csharp/contributors.html) for the current list). If you would like to contribute to our efforts please feel free to get in touch with us or visit our [donations page](https://www.bouncycastle.org/donate), sponsor some specific work, or purchase a support contract through [Crypto Workshop](http://www.cryptoworkshop.com).
6 |
7 | Except where otherwise stated, this software is distributed under a license based on the MIT X Consortium license. To view the license, [see here](http://www.bouncycastle.org/licence.html). The OpenPGP library also includes a modified BZIP2 library which is licensed under the [Apache Software License, Version 2.0](http://www.apache.org/licenses/).
8 |
9 | **Note**: this source tree is not the FIPS version of the APIs - if you are interested in our FIPS version please contact us directly at [office@bouncycastle.org](mailto:office@bouncycastle.org).
10 |
11 | ## Mailing Lists
12 |
13 | For those who are interested, there are 2 mailing lists for participation in this project. To subscribe use the links below and include the word subscribe in the message body. (To unsubscribe, replace **subscribe** with **unsubscribe** in the message body)
14 |
15 | * [announce-crypto-csharp-request@bouncycastle.org](mailto:announce-crypto-csharp-request@bouncycastle.org)
16 | This mailing list is for new release announcements only, general subscribers cannot post to it.
17 | * [dev-crypto-csharp-request@bouncycastle.org](mailto:dev-crypto-csharp-request@bouncycastle.org)
18 | This mailing list is for discussion of development of the package. This includes bugs, comments, requests for enhancements, questions about use or operation.
19 |
20 | **NOTE:**You need to be subscribed to send mail to the above mailing list.
21 |
22 | ## Feedback
23 |
24 | If you want to provide feedback directly to the members of **The Legion** then please use [feedback-crypto@bouncycastle.org](mailto:feedback-crypto@bouncycastle.org), if you want to help this project survive please consider [donating](https://www.bouncycastle.org/donate).
25 |
26 | For bug reporting/requests you can report issues here on github, via feedback-crypto if required, and we also have a [Jira issue tracker](http://www.bouncycastle.org/jira). We will accept pull requests based on this repository as well.
27 |
28 | ## Finally
29 |
30 | Enjoy!
31 |
--------------------------------------------------------------------------------
/SM2Crypto/SM2Crypto.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {DFC19643-ABE0-49F7-A087-31314B742408}
8 | Exe
9 | Properties
10 | SM2Crypto
11 | SM2Crypto
12 | v4.5.2
13 | 512
14 | true
15 |
16 |
17 | AnyCPU
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 |
26 |
27 | AnyCPU
28 | pdbonly
29 | true
30 | bin\Release\
31 | TRACE
32 | prompt
33 | 4
34 |
35 |
36 |
37 | ..\packages\BouncyCastle.1.8.3.1\lib\BouncyCastle.Crypto.dll
38 | True
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
72 |
--------------------------------------------------------------------------------
/SM2Crypto/Program.cs:
--------------------------------------------------------------------------------
1 | using Org.BouncyCastle.Math;
2 | using Org.BouncyCastle.Math.EC;
3 | using Org.BouncyCastle.Utilities.Encoders;
4 | using SM2Crypto.Lib;
5 | using System;
6 | using System.Collections.Generic;
7 | using System.IO;
8 | using System.Linq;
9 | using System.Text;
10 | using System.Threading.Tasks;
11 |
12 | namespace SM2Crypto
13 | {
14 | class Program
15 | {
16 | private static string PubKey= "041E353292615666BB47F6358D3E893394D34AF30D64875E2E422182C15885D3ECA697C345EED99268D3CAC5F6054780C34433E1BF12EBFF1F744B67A2F6863CFB";
17 | private static string PriKey = "00FAB34B54C026D158B54C88BC0463CB79B22661C7C870AD2A0455300E05471CE1";
18 |
19 | // 报送文件加密用公钥1 测试阶段无需修改,生产接入时另行发放
20 | public static readonly string PUB_X_KEY = "dc5f89775f11266dbb166638710463db31a91f7b3061aeddb69444d5ec748929";
21 | // 报送文件加密用公钥2 测试阶段无需修改,生产接入时另行发放
22 | public static readonly string PUB_Y_KEY = "740e50cb6e6e04003029a66920d1ba4bc39519035ea423bf0079ef58128202fb";
23 | // 反馈文件解密用私钥 测试阶段无需修改,生产接入时另行发放
24 | public static readonly string PRV_KEY = "9401d5a563967f8bd39fbd81d5dedea4e552bf97f5dd8cab95749421a477e7d0";
25 |
26 | static void Main(string[] args)
27 | {
28 |
29 | //byte a = 149;
30 | //var a1 = Hex.Encode(new byte[] { a });
31 | //var b = Hex.Decode(a1);
32 |
33 | ////生成公钥私钥对
34 | //TestSm2GetKeyPair();
35 |
36 | ////test
37 | //TestSm2Enc();
38 |
39 | tesdDecFile();
40 |
41 | Console.WriteLine("finish work");
42 | Console.ReadKey();
43 | }
44 |
45 | public static void TestSm2GetKeyPair()
46 | {
47 | SM2Utils sm2Utils = new SM2Utils();
48 | ECPoint pubk;
49 | BigInteger prik;
50 | SM2Utils.GenerateKeyPair( out pubk, out prik);
51 | PubKey = Encoding.ASCII.GetString(Hex.Encode(pubk.GetEncoded())).ToUpper();
52 | PriKey = Encoding.ASCII.GetString(Hex.Encode(prik.ToByteArray())).ToUpper();
53 | //System.Console.Out.WriteLine("公钥: " + Encoding.ASCII.GetString(Hex.Encode(publicKey.GetEncoded())).ToUpper());
54 | //System.Console.Out.WriteLine("私钥: " + Encoding.ASCII.GetString(Hex.Encode(privateKey.ToByteArray())).ToUpper());
55 | }
56 |
57 |
58 | public static void TestSm2Enc()
59 | {
60 | string testStr = "hello world";
61 | Console.WriteLine("原始数据 : " + testStr);
62 | byte[] sourceData = Encoding.ASCII.GetBytes(testStr);
63 | byte[] pubk = Encoding.ASCII.GetBytes(PubKey);
64 | string encStr = SM2Utils.Encrypt(Hex.Decode(pubk), sourceData);
65 |
66 | Console.WriteLine("加密后数据 : " + encStr);
67 |
68 | byte[] prik = Encoding.ASCII.GetBytes(PriKey);
69 | var data =Hex.Decode(Encoding.ASCII.GetBytes(encStr));
70 | var decodedData = SM2Utils.Decrypt(Hex.Decode(prik), data);
71 |
72 | var decodedStr = Encoding.ASCII.GetString(decodedData);
73 | Console.WriteLine("解密后数据 : " + decodedStr);
74 | }
75 |
76 | public static void tesdDecFile()
77 | {
78 | string filePath = @"D:\ProjectDemo\SM2Crypto\tmp\MA05M6KK9201810311620120201.enc";
79 | FileStream fs = new FileStream(filePath, FileMode.Open);
80 | byte[] data = new byte[fs.Length];
81 | fs.Seek(0, SeekOrigin.Begin);
82 | fs.Read(data,0,(int)fs.Length);
83 | fs.Close();
84 |
85 | byte[] prik = Encoding.ASCII.GetBytes(PRV_KEY);
86 | //var data = Hex.Decode(Encoding.ASCII.GetBytes(encStr));
87 | var decodedData = SM2Utils.Decrypt(Hex.Decode(prik), data);
88 |
89 | string zipFilePath = @"D:\ProjectDemo\SM2Crypto\test\MA05M6KK9201810311620120201.zip";
90 | FileStream zfs = new FileStream(zipFilePath, FileMode.Create);
91 | zfs.Write(decodedData, 0, decodedData.Length);
92 | zfs.Close();
93 | }
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/SM2Crypto/Lib/SM4Utils.cs:
--------------------------------------------------------------------------------
1 | using Org.BouncyCastle.Utilities.Encoders;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 |
6 | namespace SM2Crypto.Lib
7 | {
8 | class SM4Utils
9 | {
10 | public String secretKey = "";
11 | public String iv = "";
12 | public bool hexString = false;
13 | public byte[] secretKeyBuff;
14 |
15 | public String Encrypt_ECB(String plainText)
16 | {
17 | SM4_Context ctx = new SM4_Context();
18 | ctx.isPadding = true;
19 | ctx.mode = SM4.SM4_ENCRYPT;
20 |
21 | byte[] keyBytes;
22 | if (hexString)
23 | {
24 | keyBytes = Hex.Decode(secretKey);
25 | }
26 | else
27 | {
28 | keyBytes = Encoding.ASCII.GetBytes(secretKey);
29 | }
30 |
31 | SM4 sm4 = new SM4();
32 | sm4.sm4_setkey_enc(ctx, keyBytes);
33 | byte[] encrypted = sm4.sm4_crypt_ecb(ctx, Encoding.ASCII.GetBytes(plainText));
34 |
35 | String cipherText = Encoding.ASCII.GetString(Hex.Encode(encrypted));
36 | return cipherText;
37 | }
38 |
39 | public byte[] Encrypt_ECB(byte[] plainBytes, byte[] keyBytes)
40 | {
41 | SM4_Context ctx = new SM4_Context();
42 | ctx.isPadding = false;
43 | ctx.mode = SM4.SM4_ENCRYPT;
44 |
45 | SM4 sm4 = new SM4();
46 | sm4.sm4_setkey_enc(ctx, keyBytes);
47 | byte[] encrypted = sm4.sm4_crypt_ecb(ctx, plainBytes);
48 | return encrypted;
49 |
50 | //return Hex.Encode(encrypted);
51 | }
52 |
53 | public String Decrypt_ECB(String cipherText)
54 | {
55 | SM4_Context ctx = new SM4_Context();
56 | ctx.isPadding = true;
57 | ctx.mode = SM4.SM4_DECRYPT;
58 |
59 | byte[] keyBytes;
60 | if (hexString)
61 | {
62 | keyBytes = Hex.Decode(secretKey);
63 | }
64 | else
65 | {
66 | keyBytes = Encoding.ASCII.GetBytes(secretKey);
67 | }
68 |
69 | SM4 sm4 = new SM4();
70 | sm4.sm4_setkey_dec(ctx, keyBytes);
71 | byte[] decrypted = sm4.sm4_crypt_ecb(ctx, Hex.Decode(cipherText));
72 | return Encoding.ASCII.GetString(decrypted);
73 | }
74 | public String Encrypt_CBC(String plainText)
75 | {
76 | SM4_Context ctx = new SM4_Context();
77 | ctx.isPadding = true;
78 | ctx.mode = SM4.SM4_ENCRYPT;
79 |
80 | byte[] keyBytes;
81 | byte[] ivBytes;
82 | if (hexString)
83 | {
84 | keyBytes = Hex.Decode(secretKey);
85 | ivBytes = Hex.Decode(iv);
86 | }
87 | else
88 | {
89 | keyBytes = Encoding.ASCII.GetBytes(secretKey);
90 | ivBytes = Encoding.ASCII.GetBytes(iv);
91 | }
92 |
93 | SM4 sm4 = new SM4();
94 | sm4.sm4_setkey_enc(ctx, keyBytes);
95 | byte[] encrypted = sm4.sm4_crypt_cbc(ctx, ivBytes, Encoding.ASCII.GetBytes(plainText));
96 |
97 | String cipherText = Encoding.ASCII.GetString(Hex.Encode(encrypted));
98 | return cipherText;
99 | }
100 |
101 | public String Decrypt_CBC(String cipherText)
102 | {
103 | SM4_Context ctx = new SM4_Context();
104 | ctx.isPadding = true;
105 | ctx.mode = SM4.SM4_DECRYPT;
106 |
107 | byte[] keyBytes;
108 | byte[] ivBytes;
109 | if (hexString)
110 | {
111 | keyBytes = Hex.Decode(secretKey);
112 | ivBytes = Hex.Decode(iv);
113 | }
114 | else
115 | {
116 | keyBytes = Encoding.ASCII.GetBytes(secretKey);
117 | ivBytes = Encoding.ASCII.GetBytes(iv);
118 | }
119 |
120 | SM4 sm4 = new SM4();
121 | sm4.sm4_setkey_dec(ctx, keyBytes);
122 | byte[] decrypted = sm4.sm4_crypt_cbc(ctx, ivBytes, Hex.Decode(cipherText));
123 | return Encoding.ASCII.GetString(decrypted);
124 | }
125 | }
126 | }
--------------------------------------------------------------------------------
/SM2Crypto/Lib/Chiper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 | using Org.BouncyCastle.Math.EC;
5 | using Org.BouncyCastle.Crypto;
6 | using Org.BouncyCastle.Crypto.Parameters;
7 | using Org.BouncyCastle.Math;
8 |
9 | namespace SM2Crypto.Lib
10 | {
11 | public class Cipher
12 | {
13 | private int ct;
14 | private ECPoint p2;
15 | private SM3Digest sm3keybase;
16 | private SM3Digest sm3c3;
17 | private byte[] key;
18 | private byte keyOff;
19 |
20 | public Cipher()
21 | {
22 | this.ct = 1;
23 | this.key = new byte[32];
24 | this.keyOff = 0;
25 | }
26 |
27 | public static byte[] byteConvert32Bytes(BigInteger n)
28 | {
29 | byte[] tmpd = null;
30 | if (n == null)
31 | {
32 | return null;
33 | }
34 |
35 | if (n.ToByteArray().Length == 33)
36 | {
37 | tmpd = new byte[32];
38 | Array.Copy(n.ToByteArray(), 1, tmpd, 0, 32);
39 | }
40 | else if (n.ToByteArray().Length == 32)
41 | {
42 | tmpd = n.ToByteArray();
43 | }
44 | else
45 | {
46 | tmpd = new byte[32];
47 | for (int i = 0; i < 32 - n.ToByteArray().Length; i++)
48 | {
49 | tmpd[i] = 0;
50 | }
51 | Array.Copy(n.ToByteArray(), 0, tmpd, 32 - n.ToByteArray().Length, n.ToByteArray().Length);
52 | }
53 | return tmpd;
54 | }
55 |
56 | private void Reset()
57 | {
58 | this.sm3keybase = new SM3Digest();
59 | this.sm3c3 = new SM3Digest();
60 |
61 | byte[] p = byteConvert32Bytes(p2.Normalize().XCoord.ToBigInteger());
62 | this.sm3keybase.BlockUpdate(p, 0, p.Length);
63 | this.sm3c3.BlockUpdate(p, 0, p.Length);
64 |
65 | p = byteConvert32Bytes(p2.Normalize().YCoord.ToBigInteger());
66 | this.sm3keybase.BlockUpdate(p, 0, p.Length);
67 | this.ct = 1;
68 | NextKey();
69 | }
70 |
71 | private void NextKey()
72 | {
73 | SM3Digest sm3keycur = new SM3Digest(this.sm3keybase);
74 | sm3keycur.Update((byte)(ct >> 24 & 0xff));
75 | sm3keycur.Update((byte)(ct >> 16 & 0xff));
76 | sm3keycur.Update((byte)(ct >> 8 & 0xff));
77 | sm3keycur.Update((byte)(ct & 0xff));
78 | sm3keycur.DoFinal(key, 0);
79 | this.keyOff = 0;
80 | this.ct++;
81 | }
82 |
83 | public ECPoint Init_enc(SM2 sm2, ECPoint userKey)
84 | {
85 | AsymmetricCipherKeyPair key = sm2.ecc_key_pair_generator.GenerateKeyPair();
86 | ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters)key.Private;
87 | ECPublicKeyParameters ecpub = (ECPublicKeyParameters)key.Public;
88 | BigInteger k = ecpriv.D;
89 | ECPoint c1 = ecpub.Q;
90 | this.p2 = userKey.Multiply(k);
91 | Reset();
92 | return c1;
93 | }
94 |
95 | public void Encrypt(byte[] data)
96 | {
97 | this.sm3c3.BlockUpdate(data, 0, data.Length);
98 | for (int i = 0; i < data.Length; i++)
99 | {
100 | if (keyOff == key.Length)
101 | {
102 | NextKey();
103 | }
104 | data[i] ^= key[keyOff++];
105 | }
106 | }
107 |
108 | public void Init_dec(BigInteger userD, ECPoint c1)
109 | {
110 | this.p2 = c1.Multiply(userD);
111 | Reset();
112 | }
113 |
114 | public void Decrypt(byte[] data)
115 | {
116 | for (int i = 0; i < data.Length; i++)
117 | {
118 | if (keyOff == key.Length)
119 | {
120 | NextKey();
121 | }
122 | data[i] ^= key[keyOff++];
123 | }
124 |
125 | this.sm3c3.BlockUpdate(data, 0, data.Length);
126 | }
127 |
128 | public void Dofinal(byte[] c3)
129 | {
130 | byte[] p = byteConvert32Bytes(p2.Normalize().YCoord.ToBigInteger());
131 | this.sm3c3.BlockUpdate(p, 0, p.Length);
132 | this.sm3c3.DoFinal(c3, 0);
133 | Reset();
134 | }
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/SM2Crypto/Lib/SM2.cs:
--------------------------------------------------------------------------------
1 | using Org.BouncyCastle.Crypto.Generators;
2 | using Org.BouncyCastle.Math.EC;
3 | using Org.BouncyCastle.Math;
4 | using Org.BouncyCastle.Crypto;
5 | using Org.BouncyCastle.Crypto.Parameters;
6 | using Org.BouncyCastle.Security;
7 | using System;
8 | using System.Collections.Generic;
9 | using System.Text;
10 | using Org.BouncyCastle.Crypto.Digests;
11 |
12 | namespace SM2Crypto.Lib
13 | {
14 | public class SM2
15 | {
16 | public static SM2 Instance
17 | {
18 | get
19 | {
20 | return new SM2();
21 | }
22 |
23 | }
24 | public static SM2 InstanceTest
25 | {
26 | get
27 | {
28 | return new SM2();
29 | }
30 |
31 | }
32 |
33 | public static readonly string[] sm2_param = {
34 | "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF",// p,0
35 | "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC",// a,1
36 | "28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93",// b,2
37 | "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123",// n,3
38 | "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7",// gx,4
39 | "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0" // gy,5
40 | };
41 |
42 | public string[] ecc_param = sm2_param;
43 |
44 | public readonly BigInteger ecc_p;
45 | public readonly BigInteger ecc_a;
46 | public readonly BigInteger ecc_b;
47 | public readonly BigInteger ecc_n;
48 | public readonly BigInteger ecc_gx;
49 | public readonly BigInteger ecc_gy;
50 |
51 | public readonly ECCurve ecc_curve;
52 | public readonly ECPoint ecc_point_g;
53 |
54 | public readonly ECDomainParameters ecc_bc_spec;
55 |
56 | public readonly ECKeyPairGenerator ecc_key_pair_generator;
57 |
58 | private SM2()
59 | {
60 | ecc_param = sm2_param;
61 |
62 | ECFieldElement ecc_gx_fieldelement;
63 | ECFieldElement ecc_gy_fieldelement;
64 |
65 | ecc_p = new BigInteger(ecc_param[0], 16);
66 | ecc_a = new BigInteger(ecc_param[1], 16);
67 | ecc_b = new BigInteger(ecc_param[2], 16);
68 | ecc_n = new BigInteger(ecc_param[3], 16);
69 | ecc_gx = new BigInteger(ecc_param[4], 16);
70 | ecc_gy = new BigInteger(ecc_param[5], 16);
71 |
72 |
73 | ecc_gx_fieldelement = new FpFieldElement(ecc_p, ecc_gx);
74 | ecc_gy_fieldelement = new FpFieldElement(ecc_p, ecc_gy);
75 |
76 | ecc_curve = new FpCurve(ecc_p, ecc_a, ecc_b);
77 | ecc_point_g = new FpPoint(ecc_curve, ecc_gx_fieldelement, ecc_gy_fieldelement);
78 |
79 | ecc_bc_spec = new ECDomainParameters(ecc_curve, ecc_point_g, ecc_n);
80 |
81 | ECKeyGenerationParameters ecc_ecgenparam;
82 | ecc_ecgenparam = new ECKeyGenerationParameters(ecc_bc_spec, new SecureRandom());
83 |
84 | ecc_key_pair_generator = new ECKeyPairGenerator();
85 | ecc_key_pair_generator.Init(ecc_ecgenparam);
86 | }
87 |
88 | public virtual byte[] Sm2GetZ(byte[] userId, ECPoint userKey)
89 | {
90 | SM3Digest sm3 = new SM3Digest();
91 | byte[] p;
92 | // userId length
93 | int len = userId.Length * 8;
94 | sm3.Update((byte)(len >> 8 & 0x00ff));
95 | sm3.Update((byte)(len & 0x00ff));
96 |
97 | // userId
98 | sm3.BlockUpdate(userId, 0, userId.Length);
99 |
100 | // a,b
101 | p = ecc_a.ToByteArray();
102 | sm3.BlockUpdate(p, 0, p.Length);
103 | p = ecc_b.ToByteArray();
104 | sm3.BlockUpdate(p, 0, p.Length);
105 | // gx,gy
106 | p = ecc_gx.ToByteArray();
107 | sm3.BlockUpdate(p, 0, p.Length);
108 | p = ecc_gy.ToByteArray();
109 | sm3.BlockUpdate(p, 0, p.Length);
110 |
111 | // x,y
112 | p = userKey.AffineXCoord.ToBigInteger().ToByteArray();
113 | sm3.BlockUpdate(p, 0, p.Length);
114 | p = userKey.AffineYCoord.ToBigInteger().ToByteArray();
115 | sm3.BlockUpdate(p, 0, p.Length);
116 |
117 | // Z
118 | byte[] md = new byte[sm3.GetDigestSize()];
119 | sm3.DoFinal(md, 0);
120 |
121 | return md;
122 | }
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/SM2Crypto/Lib/SM2Utils.cs:
--------------------------------------------------------------------------------
1 | using Org.BouncyCastle.Crypto;
2 | using Org.BouncyCastle.Crypto.Parameters;
3 | using Org.BouncyCastle.Math;
4 | using Org.BouncyCastle.Math.EC;
5 | using Org.BouncyCastle.Utilities.Encoders;
6 | using System;
7 | using System.Collections.Generic;
8 | using System.Text;
9 |
10 | namespace SM2Crypto.Lib
11 | {
12 | class SM2Utils
13 | {
14 | public static void GenerateKeyPair(out ECPoint pubk, out BigInteger prik)
15 | {
16 | SM2 sm2 = SM2.Instance;
17 | AsymmetricCipherKeyPair key = sm2.ecc_key_pair_generator.GenerateKeyPair();
18 | ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters)key.Private;
19 | ECPublicKeyParameters ecpub = (ECPublicKeyParameters)key.Public;
20 | BigInteger privateKey = ecpriv.D;
21 | ECPoint publicKey = ecpub.Q;
22 |
23 | //System.Console.Out.WriteLine("公钥: " + Encoding.ASCII.GetString(Hex.Encode(publicKey.GetEncoded())).ToUpper());
24 | //System.Console.Out.WriteLine("私钥: " + Encoding.ASCII.GetString(Hex.Encode(privateKey.ToByteArray())).ToUpper());
25 | pubk = publicKey;
26 | prik = privateKey;
27 | }
28 |
29 | public static String Encrypt(byte[] publicKey, byte[] data)
30 | {
31 | if (null == publicKey || publicKey.Length == 0)
32 | {
33 | return null;
34 | }
35 | if (data == null || data.Length == 0)
36 | {
37 | return null;
38 | }
39 |
40 | byte[] source = new byte[data.Length];
41 | Array.Copy(data, 0, source, 0, data.Length);
42 |
43 | Cipher cipher = new Cipher();
44 | SM2 sm2 = SM2.Instance;
45 |
46 | ECPoint userKey = sm2.ecc_curve.DecodePoint(publicKey);
47 |
48 | ECPoint c1 = cipher.Init_enc(sm2, userKey);
49 | cipher.Encrypt(source);
50 |
51 | byte[] c3 = new byte[32];
52 | cipher.Dofinal(c3);
53 |
54 | String sc1 = Encoding.ASCII.GetString(Hex.Encode(c1.GetEncoded()));
55 | String sc2 = Encoding.ASCII.GetString(Hex.Encode(source));
56 | String sc3 = Encoding.ASCII.GetString(Hex.Encode(c3));
57 |
58 | return (sc1 + sc2 + sc3).ToUpper();
59 | }
60 |
61 | public static byte[] Decrypt(byte[] privateKey, byte[] encryptedData)
62 | {
63 | if (null == privateKey || privateKey.Length == 0)
64 | {
65 | return null;
66 | }
67 | if (encryptedData == null || encryptedData.Length == 0)
68 | {
69 | return null;
70 | }
71 |
72 | String data = Encoding.ASCII.GetString(Hex.Encode(encryptedData));
73 |
74 | byte[] c1Bytes = Hex.Decode(Encoding.ASCII.GetBytes(data.Substring(0, 130)));
75 | int c2Len = encryptedData.Length - 97;
76 | byte[] c2 = Hex.Decode(Encoding.ASCII.GetBytes(data.Substring(130, 2 * c2Len)));
77 | byte[] c3 = Hex.Decode(Encoding.ASCII.GetBytes(data.Substring(130 + 2 * c2Len, 64)));
78 |
79 | SM2 sm2 = SM2.Instance;
80 | BigInteger userD = new BigInteger(1, privateKey);
81 |
82 | //ECPoint c1 = sm2.ecc_curve.DecodePoint(c1Bytes);
83 |
84 | ECPoint c1 = sm2.ecc_curve.DecodePoint(c1Bytes);
85 | Cipher cipher = new Cipher();
86 | cipher.Init_dec(userD, c1);
87 | cipher.Decrypt(c2);
88 | cipher.Dofinal(c3);
89 |
90 | return c2;
91 | }
92 |
93 | //[STAThread]
94 | //public static void Main()
95 | //{
96 | // GenerateKeyPair();
97 |
98 | // String plainText = "ererfeiisgod";
99 | // byte[] sourceData = Encoding.Default.GetBytes(plainText);
100 |
101 | // //下面的秘钥可以使用generateKeyPair()生成的秘钥内容
102 | // // 国密规范正式私钥
103 | // String prik = "3690655E33D5EA3D9A4AE1A1ADD766FDEA045CDEAA43A9206FB8C430CEFE0D94";
104 | // // 国密规范正式公钥
105 | // String pubk = "04F6E0C3345AE42B51E06BF50B98834988D54EBC7460FE135A48171BC0629EAE205EEDE253A530608178A98F1E19BB737302813BA39ED3FA3C51639D7A20C7391A";
106 |
107 | // System.Console.Out.WriteLine("加密: ");
108 | // String cipherText = SM2Utils.Encrypt(Hex.Decode(pubk), sourceData);
109 | // System.Console.Out.WriteLine(cipherText);
110 | // System.Console.Out.WriteLine("解密: ");
111 | // plainText = Encoding.Default.GetString(SM2Utils.Decrypt(Hex.Decode(prik), Hex.Decode(cipherText)));
112 | // System.Console.Out.WriteLine(plainText);
113 |
114 | // Console.ReadLine();
115 | //}
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/SM2Crypto/Lib/SM3.cs:
--------------------------------------------------------------------------------
1 | using Org.BouncyCastle.Crypto;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 |
6 | namespace SM2Crypto.Lib
7 | {
8 | public abstract class GeneralDigest : IDigest
9 | {
10 | private const int BYTE_LENGTH = 64;
11 |
12 | private byte[] xBuf;
13 | private int xBufOff;
14 |
15 | private long byteCount;
16 |
17 | internal GeneralDigest()
18 | {
19 | xBuf = new byte[4];
20 | }
21 |
22 | internal GeneralDigest(GeneralDigest t)
23 | {
24 | xBuf = new byte[t.xBuf.Length];
25 | Array.Copy(t.xBuf, 0, xBuf, 0, t.xBuf.Length);
26 |
27 | xBufOff = t.xBufOff;
28 | byteCount = t.byteCount;
29 | }
30 |
31 | public void Update(byte input)
32 | {
33 | xBuf[xBufOff++] = input;
34 |
35 | if (xBufOff == xBuf.Length)
36 | {
37 | ProcessWord(xBuf, 0);
38 | xBufOff = 0;
39 | }
40 |
41 | byteCount++;
42 | }
43 |
44 | public void BlockUpdate(
45 | byte[] input,
46 | int inOff,
47 | int length)
48 | {
49 | //
50 | // fill the current word
51 | //
52 | while ((xBufOff != 0) && (length > 0))
53 | {
54 | Update(input[inOff]);
55 | inOff++;
56 | length--;
57 | }
58 |
59 | //
60 | // process whole words.
61 | //
62 | while (length > xBuf.Length)
63 | {
64 | ProcessWord(input, inOff);
65 |
66 | inOff += xBuf.Length;
67 | length -= xBuf.Length;
68 | byteCount += xBuf.Length;
69 | }
70 |
71 | //
72 | // load in the remainder.
73 | //
74 | while (length > 0)
75 | {
76 | Update(input[inOff]);
77 |
78 | inOff++;
79 | length--;
80 | }
81 | }
82 |
83 | public void Finish()
84 | {
85 | long bitLength = (byteCount << 3);
86 |
87 | //
88 | // add the pad bytes.
89 | //
90 | Update(unchecked((byte)128));
91 |
92 | while (xBufOff != 0) Update(unchecked((byte)0));
93 | ProcessLength(bitLength);
94 | ProcessBlock();
95 | }
96 |
97 | public virtual void Reset()
98 | {
99 | byteCount = 0;
100 | xBufOff = 0;
101 | Array.Clear(xBuf, 0, xBuf.Length);
102 | }
103 |
104 | public int GetByteLength()
105 | {
106 | return BYTE_LENGTH;
107 | }
108 |
109 | internal abstract void ProcessWord(byte[] input, int inOff);
110 | internal abstract void ProcessLength(long bitLength);
111 | internal abstract void ProcessBlock();
112 | public abstract string AlgorithmName { get; }
113 | public abstract int GetDigestSize();
114 | public abstract int DoFinal(byte[] output, int outOff);
115 | }
116 |
117 | public class SupportClass
118 | {
119 | ///
120 | /// Performs an unsigned bitwise right shift with the specified number
121 | ///
122 | ///Number to operate on
123 | ///Ammount of bits to shift
124 | /// The resulting number from the shift operation
125 | public static int URShift(int number, int bits)
126 | {
127 | if (number >= 0)
128 | return number >> bits;
129 | else
130 | return (number >> bits) + (2 << ~bits);
131 | }
132 |
133 | ///
134 | /// Performs an unsigned bitwise right shift with the specified number
135 | ///
136 | ///Number to operate on
137 | ///Ammount of bits to shift
138 | /// The resulting number from the shift operation
139 | public static int URShift(int number, long bits)
140 | {
141 | return URShift(number, (int)bits);
142 | }
143 |
144 | ///
145 | /// Performs an unsigned bitwise right shift with the specified number
146 | ///
147 | ///Number to operate on
148 | ///Ammount of bits to shift
149 | /// The resulting number from the shift operation
150 | public static long URShift(long number, int bits)
151 | {
152 | if (number >= 0)
153 | return number >> bits;
154 | else
155 | return (number >> bits) + (2L << ~bits);
156 | }
157 |
158 | ///
159 | /// Performs an unsigned bitwise right shift with the specified number
160 | ///
161 | ///Number to operate on
162 | ///Ammount of bits to shift
163 | /// The resulting number from the shift operation
164 | public static long URShift(long number, long bits)
165 | {
166 | return URShift(number, (int)bits);
167 | }
168 |
169 |
170 | }
171 |
172 | public class SM3Digest : GeneralDigest
173 | {
174 | public override string AlgorithmName
175 | {
176 | get
177 | {
178 | return "SM3";
179 | }
180 |
181 | }
182 | public override int GetDigestSize()
183 | {
184 | return DIGEST_LENGTH;
185 | }
186 |
187 | private const int DIGEST_LENGTH = 32;
188 |
189 | private static readonly int[] v0 = new int[] { 0x7380166f, 0x4914b2b9, 0x172442d7, unchecked((int)0xda8a0600), unchecked((int)0xa96f30bc), 0x163138aa, unchecked((int)0xe38dee4d), unchecked((int)0xb0fb0e4e) };
190 |
191 | private int[] v = new int[8];
192 | private int[] v_ = new int[8];
193 |
194 | private static readonly int[] X0 = new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
195 |
196 | private int[] X = new int[68];
197 | private int xOff;
198 |
199 | private int T_00_15 = 0x79cc4519;
200 | private int T_16_63 = 0x7a879d8a;
201 |
202 | public SM3Digest()
203 | {
204 | Reset();
205 | }
206 |
207 | public SM3Digest(SM3Digest t) : base(t)
208 | {
209 |
210 | Array.Copy(t.X, 0, X, 0, t.X.Length);
211 | xOff = t.xOff;
212 |
213 | Array.Copy(t.v, 0, v, 0, t.v.Length);
214 | }
215 |
216 | public override void Reset()
217 | {
218 | base.Reset();
219 |
220 | Array.Copy(v0, 0, v, 0, v0.Length);
221 |
222 | xOff = 0;
223 | Array.Copy(X0, 0, X, 0, X0.Length);
224 | }
225 |
226 | internal override void ProcessBlock()
227 | {
228 | int i;
229 |
230 | int[] ww = X;
231 | int[] ww_ = new int[64];
232 |
233 | for (i = 16; i < 68; i++)
234 | {
235 | ww[i] = P1(ww[i - 16] ^ ww[i - 9] ^ (ROTATE(ww[i - 3], 15))) ^ (ROTATE(ww[i - 13], 7)) ^ ww[i - 6];
236 | }
237 |
238 | for (i = 0; i < 64; i++)
239 | {
240 | ww_[i] = ww[i] ^ ww[i + 4];
241 | }
242 |
243 | int[] vv = v;
244 | int[] vv_ = v_;
245 |
246 | Array.Copy(vv, 0, vv_, 0, v0.Length);
247 |
248 | int SS1, SS2, TT1, TT2, aaa;
249 | for (i = 0; i < 16; i++)
250 | {
251 | aaa = ROTATE(vv_[0], 12);
252 | SS1 = aaa + vv_[4] + ROTATE(T_00_15, i);
253 | SS1 = ROTATE(SS1, 7);
254 | SS2 = SS1 ^ aaa;
255 |
256 | TT1 = FF_00_15(vv_[0], vv_[1], vv_[2]) + vv_[3] + SS2 + ww_[i];
257 | TT2 = GG_00_15(vv_[4], vv_[5], vv_[6]) + vv_[7] + SS1 + ww[i];
258 | vv_[3] = vv_[2];
259 | vv_[2] = ROTATE(vv_[1], 9);
260 | vv_[1] = vv_[0];
261 | vv_[0] = TT1;
262 | vv_[7] = vv_[6];
263 | vv_[6] = ROTATE(vv_[5], 19);
264 | vv_[5] = vv_[4];
265 | vv_[4] = P0(TT2);
266 | }
267 | for (i = 16; i < 64; i++)
268 | {
269 | aaa = ROTATE(vv_[0], 12);
270 | SS1 = aaa + vv_[4] + ROTATE(T_16_63, i);
271 | SS1 = ROTATE(SS1, 7);
272 | SS2 = SS1 ^ aaa;
273 |
274 | TT1 = FF_16_63(vv_[0], vv_[1], vv_[2]) + vv_[3] + SS2 + ww_[i];
275 | TT2 = GG_16_63(vv_[4], vv_[5], vv_[6]) + vv_[7] + SS1 + ww[i];
276 | vv_[3] = vv_[2];
277 | vv_[2] = ROTATE(vv_[1], 9);
278 | vv_[1] = vv_[0];
279 | vv_[0] = TT1;
280 | vv_[7] = vv_[6];
281 | vv_[6] = ROTATE(vv_[5], 19);
282 | vv_[5] = vv_[4];
283 | vv_[4] = P0(TT2);
284 | }
285 | for (i = 0; i < 8; i++)
286 | {
287 | vv[i] ^= vv_[i];
288 | }
289 |
290 | // Reset
291 | xOff = 0;
292 | Array.Copy(X0, 0, X, 0, X0.Length);
293 | }
294 |
295 | internal override void ProcessWord(byte[] in_Renamed, int inOff)
296 | {
297 | int n = in_Renamed[inOff] << 24;
298 | n |= (in_Renamed[++inOff] & 0xff) << 16;
299 | n |= (in_Renamed[++inOff] & 0xff) << 8;
300 | n |= (in_Renamed[++inOff] & 0xff);
301 | X[xOff] = n;
302 |
303 | if (++xOff == 16)
304 | {
305 | ProcessBlock();
306 | }
307 | }
308 |
309 | internal override void ProcessLength(long bitLength)
310 | {
311 | if (xOff > 14)
312 | {
313 | ProcessBlock();
314 | }
315 |
316 | X[14] = (int)(SupportClass.URShift(bitLength, 32));
317 | X[15] = (int)(bitLength & unchecked((int)0xffffffff));
318 | }
319 |
320 | public static void IntToBigEndian(int n, byte[] bs, int off)
321 | {
322 | bs[off] = (byte)(SupportClass.URShift(n, 24));
323 | bs[++off] = (byte)(SupportClass.URShift(n, 16));
324 | bs[++off] = (byte)(SupportClass.URShift(n, 8));
325 | bs[++off] = (byte)(n);
326 | }
327 |
328 | public override int DoFinal(byte[] out_Renamed, int outOff)
329 | {
330 | Finish();
331 |
332 | for (int i = 0; i < 8; i++)
333 | {
334 | IntToBigEndian(v[i], out_Renamed, outOff + i * 4);
335 | }
336 |
337 | Reset();
338 |
339 | return DIGEST_LENGTH;
340 | }
341 |
342 | private int ROTATE(int x, int n)
343 | {
344 | return (x << n) | (SupportClass.URShift(x, (32 - n)));
345 | }
346 |
347 | private int P0(int X)
348 | {
349 | return ((X) ^ ROTATE((X), 9) ^ ROTATE((X), 17));
350 | }
351 |
352 | private int P1(int X)
353 | {
354 | return ((X) ^ ROTATE((X), 15) ^ ROTATE((X), 23));
355 | }
356 |
357 | private int FF_00_15(int X, int Y, int Z)
358 | {
359 | return (X ^ Y ^ Z);
360 | }
361 |
362 | private int FF_16_63(int X, int Y, int Z)
363 | {
364 | return ((X & Y) | (X & Z) | (Y & Z));
365 | }
366 |
367 | private int GG_00_15(int X, int Y, int Z)
368 | {
369 | return (X ^ Y ^ Z);
370 | }
371 |
372 | private int GG_16_63(int X, int Y, int Z)
373 | {
374 | return ((X & Y) | (~X & Z));
375 | }
376 |
377 | //[STAThread]
378 | //public static void Main()
379 | //{
380 | // byte[] md = new byte[32];
381 | // byte[] msg1 = Encoding.Default.GetBytes("ererfeiisgod");
382 | // SM3Digest sm3 = new SM3Digest();
383 | // sm3.BlockUpdate(msg1, 0, msg1.Length);
384 | // sm3.DoFinal(md, 0);
385 | // System.String s = new UTF8Encoding().GetString(Hex.Encode(md));
386 | // System.Console.Out.WriteLine(s.ToUpper());
387 |
388 | // Console.ReadLine();
389 | //}
390 | }
391 | }
392 |
--------------------------------------------------------------------------------
/SM2Crypto/Lib/SM4.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace SM2Crypto.Lib
6 | {
7 | class SM4
8 | {
9 | public const int SM4_ENCRYPT = 1;
10 | public const int SM4_DECRYPT = 0;
11 |
12 | private long GET_ULONG_BE(byte[] b, int i)
13 | {
14 | long n = (long)(b[i] & 0xff) << 24 | (long)((b[i + 1] & 0xff) << 16) | (long)((b[i + 2] & 0xff) << 8) | (long)(b[i + 3] & 0xff) & 0xffffffffL;
15 | return n;
16 | }
17 |
18 | private void PUT_ULONG_BE(long n, byte[] b, int i)
19 | {
20 | b[i] = (byte)(int)(0xFF & n >> 24);
21 | b[i + 1] = (byte)(int)(0xFF & n >> 16);
22 | b[i + 2] = (byte)(int)(0xFF & n >> 8);
23 | b[i + 3] = (byte)(int)(0xFF & n);
24 | }
25 |
26 | private long SHL(long x, int n)
27 | {
28 | return (x & 0xFFFFFFFF) << n;
29 | }
30 |
31 | private long ROTL(long x, int n)
32 | {
33 | return SHL(x, n) | x >> (32 - n);
34 | }
35 |
36 | private void SWAP(long[] sk, int i)
37 | {
38 | long t = sk[i];
39 | sk[i] = sk[(31 - i)];
40 | sk[(31 - i)] = t;
41 | }
42 |
43 | public byte[] SboxTable = new byte[] {
44 | 0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7,
45 | 0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c, 0x05,
46 | 0x2b, 0x67, 0x9a, 0x76, 0x2a, 0xbe, 0x04, 0xc3,
47 | 0xaa, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99,
48 | 0x9c, 0x42, 0x50, 0xf4, 0x91, 0xef, 0x98, 0x7a,
49 | 0x33, 0x54, 0x0b, 0x43, 0xed, 0xcf, 0xac, 0x62,
50 | 0xe4, 0xb3, 0x1c, 0xa9, 0xc9, 0x08, 0xe8, 0x95,
51 | 0x80, 0xdf, 0x94, 0xfa, 0x75, 0x8f, 0x3f, 0xa6,
52 | 0x47, 0x07, 0xa7, 0xfc, 0xf3, 0x73, 0x17, 0xba,
53 | 0x83, 0x59, 0x3c, 0x19, 0xe6, 0x85, 0x4f, 0xa8,
54 | 0x68, 0x6b, 0x81, 0xb2, 0x71, 0x64, 0xda, 0x8b,
55 | 0xf8, 0xeb, 0x0f, 0x4b, 0x70, 0x56, 0x9d, 0x35,
56 | 0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, 0xd1, 0xa2,
57 | 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, 0x87,
58 | 0xd4, 0x00, 0x46, 0x57, 0x9f, 0xd3, 0x27, 0x52,
59 | 0x4c, 0x36, 0x02, 0xe7, 0xa0, 0xc4, 0xc8, 0x9e,
60 | 0xea, 0xbf, 0x8a, 0xd2, 0x40, 0xc7, 0x38, 0xb5,
61 | 0xa3, 0xf7, 0xf2, 0xce, 0xf9, 0x61, 0x15, 0xa1,
62 | 0xe0, 0xae, 0x5d, 0xa4, 0x9b, 0x34, 0x1a, 0x55,
63 | 0xad, 0x93, 0x32, 0x30, 0xf5, 0x8c, 0xb1, 0xe3,
64 | 0x1d, 0xf6, 0xe2, 0x2e, 0x82, 0x66, 0xca, 0x60,
65 | 0xc0, 0x29, 0x23, 0xab, 0x0d, 0x53, 0x4e, 0x6f,
66 | 0xd5, 0xdb, 0x37, 0x45, 0xde, 0xfd, 0x8e, 0x2f,
67 | 0x03, 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51,
68 | 0x8d, 0x1b, 0xaf, 0x92, 0xbb, 0xdd, 0xbc, 0x7f,
69 | 0x11, 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, 0xd8,
70 | 0x0a, 0xc1, 0x31, 0x88, 0xa5, 0xcd, 0x7b, 0xbd,
71 | 0x2d, 0x74, 0xd0, 0x12, 0xb8, 0xe5, 0xb4, 0xb0,
72 | 0x89, 0x69, 0x97, 0x4a, 0x0c, 0x96, 0x77, 0x7e,
73 | 0x65, 0xb9, 0xf1, 0x09, 0xc5, 0x6e, 0xc6, 0x84,
74 | 0x18, 0xf0, 0x7d, 0xec, 0x3a, 0xdc, 0x4d, 0x20,
75 | 0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39, 0x48
76 | };
77 |
78 | public uint[] FK = {
79 | 0xa3b1bac6,
80 | 0x56aa3350,
81 | 0x677d9197,
82 | 0xb27022dc
83 | };
84 |
85 | public uint[] CK = {
86 | 0x00070e15,0x1c232a31,0x383f464d,0x545b6269,
87 | 0x70777e85,0x8c939aa1,0xa8afb6bd,0xc4cbd2d9,
88 | 0xe0e7eef5,0xfc030a11,0x181f262d,0x343b4249,
89 | 0x50575e65,0x6c737a81,0x888f969d,0xa4abb2b9,
90 | 0xc0c7ced5,0xdce3eaf1,0xf8ff060d,0x141b2229,
91 | 0x30373e45,0x4c535a61,0x686f767d,0x848b9299,
92 | 0xa0a7aeb5,0xbcc3cad1,0xd8dfe6ed,0xf4fb0209,
93 | 0x10171e25,0x2c333a41,0x484f565d,0x646b7279
94 | };
95 |
96 | private byte sm4Sbox(byte inch)
97 | {
98 | int i = inch & 0xFF;
99 | byte retVal = SboxTable[i];
100 | return retVal;
101 | }
102 |
103 | private long sm4Lt(long ka)
104 | {
105 | long bb = 0L;
106 | long c = 0L;
107 | byte[] a = new byte[4];
108 | byte[] b = new byte[4];
109 | PUT_ULONG_BE(ka, a, 0);
110 | b[0] = sm4Sbox(a[0]);
111 | b[1] = sm4Sbox(a[1]);
112 | b[2] = sm4Sbox(a[2]);
113 | b[3] = sm4Sbox(a[3]);
114 | bb = GET_ULONG_BE(b, 0);
115 | c = bb ^ ROTL(bb, 2) ^ ROTL(bb, 10) ^ ROTL(bb, 18) ^ ROTL(bb, 24);
116 | return c;
117 | }
118 |
119 | private long sm4F(long x0, long x1, long x2, long x3, long rk)
120 | {
121 | return x0 ^ sm4Lt(x1 ^ x2 ^ x3 ^ rk);
122 | }
123 |
124 | private long sm4CalciRK(long ka)
125 | {
126 | long bb = 0L;
127 | long rk = 0L;
128 | byte[] a = new byte[4];
129 | byte[] b = new byte[4];
130 | PUT_ULONG_BE(ka, a, 0);
131 | b[0] = sm4Sbox(a[0]);
132 | b[1] = sm4Sbox(a[1]);
133 | b[2] = sm4Sbox(a[2]);
134 | b[3] = sm4Sbox(a[3]);
135 | bb = GET_ULONG_BE(b, 0);
136 | rk = bb ^ ROTL(bb, 13) ^ ROTL(bb, 23);
137 | return rk;
138 | }
139 |
140 | private void sm4_setkey(long[] SK, byte[] key)
141 | {
142 | long[] MK = new long[4];
143 | long[] k = new long[36];
144 | int i = 0;
145 | MK[0] = GET_ULONG_BE(key, 0);
146 | MK[1] = GET_ULONG_BE(key, 4);
147 | MK[2] = GET_ULONG_BE(key, 8);
148 | MK[3] = GET_ULONG_BE(key, 12);
149 | k[0] = MK[0] ^ (long)FK[0];
150 | k[1] = MK[1] ^ (long)FK[1];
151 | k[2] = MK[2] ^ (long)FK[2];
152 | k[3] = MK[3] ^ (long)FK[3];
153 | for (; i < 32; i++)
154 | {
155 | k[(i + 4)] = (k[i] ^ sm4CalciRK(k[(i + 1)] ^ k[(i + 2)] ^ k[(i + 3)] ^ (long)CK[i]));
156 | SK[i] = k[(i + 4)];
157 | }
158 | }
159 |
160 | private void sm4_one_round(long[] sk, byte[] input, byte[] output)
161 | {
162 | int i = 0;
163 | long[] ulbuf = new long[36];
164 | ulbuf[0] = GET_ULONG_BE(input, 0);
165 | ulbuf[1] = GET_ULONG_BE(input, 4);
166 | ulbuf[2] = GET_ULONG_BE(input, 8);
167 | ulbuf[3] = GET_ULONG_BE(input, 12);
168 | while (i < 32)
169 | {
170 | ulbuf[(i + 4)] = sm4F(ulbuf[i], ulbuf[(i + 1)], ulbuf[(i + 2)], ulbuf[(i + 3)], sk[i]);
171 | i++;
172 | }
173 | PUT_ULONG_BE(ulbuf[35], output, 0);
174 | PUT_ULONG_BE(ulbuf[34], output, 4);
175 | PUT_ULONG_BE(ulbuf[33], output, 8);
176 | PUT_ULONG_BE(ulbuf[32], output, 12);
177 | }
178 |
179 | private byte[] padding(byte[] input, int mode)
180 | {
181 | if (input == null)
182 | {
183 | return null;
184 | }
185 |
186 | byte[] ret = (byte[])null;
187 | if (mode == SM4_ENCRYPT)
188 | {
189 | int p = 16 - input.Length % 16;
190 | ret = new byte[input.Length + p];
191 | Array.Copy(input, 0, ret, 0, input.Length);
192 | for (int i = 0; i < p; i++)
193 | {
194 | ret[input.Length + i] = (byte)p;
195 | }
196 | }
197 | else
198 | {
199 | int p = input[input.Length - 1];
200 | ret = new byte[input.Length - p];
201 | Array.Copy(input, 0, ret, 0, input.Length - p);
202 | }
203 | return ret;
204 | }
205 |
206 | public void sm4_setkey_enc(SM4_Context ctx, byte[] key)
207 | {
208 | ctx.mode = SM4_ENCRYPT;
209 | sm4_setkey(ctx.sk, key);
210 | }
211 |
212 | public void sm4_setkey_dec(SM4_Context ctx, byte[] key)
213 | {
214 | int i = 0;
215 | ctx.mode = SM4_DECRYPT;
216 | sm4_setkey(ctx.sk, key);
217 | for (i = 0; i < 16; i++)
218 | {
219 | SWAP(ctx.sk, i);
220 | }
221 | }
222 |
223 | public byte[] sm4_crypt_ecb(SM4_Context ctx, byte[] input)
224 | {
225 | if ((ctx.isPadding) && (ctx.mode == SM4_ENCRYPT))
226 | {
227 | input = padding(input, SM4_ENCRYPT);
228 | }
229 |
230 | int length = input.Length;
231 | byte[] bins = new byte[length];
232 | Array.Copy(input, 0, bins, 0, length);
233 | byte[] bous = new byte[length];
234 | for (int i = 0; length > 0; length -= 16, i++)
235 | {
236 | byte[] inBytes = new byte[16];
237 | byte[] outBytes = new byte[16];
238 | Array.Copy(bins, i * 16, inBytes, 0, length > 16 ? 16 : length);
239 | sm4_one_round(ctx.sk, inBytes, outBytes);
240 | Array.Copy(outBytes, 0, bous, i * 16, length > 16 ? 16 : length);
241 | }
242 |
243 | if (ctx.isPadding && ctx.mode == SM4_DECRYPT)
244 | {
245 | bous = padding(bous, SM4_DECRYPT);
246 | }
247 | return bous;
248 | }
249 |
250 | public byte[] sm4_crypt_cbc(SM4_Context ctx, byte[] iv, byte[] input)
251 | {
252 | if (ctx.isPadding && ctx.mode == SM4_ENCRYPT)
253 | {
254 | input = padding(input, SM4_ENCRYPT);
255 | }
256 |
257 | int i = 0;
258 | int length = input.Length;
259 | byte[] bins = new byte[length];
260 | Array.Copy(input, 0, bins, 0, length);
261 | byte[] bous = null;
262 | List bousList = new List();
263 | if (ctx.mode == SM4_ENCRYPT)
264 | {
265 | for (int j = 0; length > 0; length -= 16, j++)
266 | {
267 | byte[] inBytes = new byte[16];
268 | byte[] outBytes = new byte[16];
269 | byte[] out1 = new byte[16];
270 |
271 | Array.Copy(bins, j * 16, inBytes, 0, length > 16 ? 16 : length);
272 | for (i = 0; i < 16; i++)
273 | {
274 | outBytes[i] = ((byte)(inBytes[i] ^ iv[i]));
275 | }
276 | sm4_one_round(ctx.sk, outBytes, out1);
277 | Array.Copy(out1, 0, iv, 0, 16);
278 | for (int k = 0; k < 16; k++)
279 | {
280 | bousList.Add(out1[k]);
281 | }
282 | }
283 | }
284 | else
285 | {
286 | byte[] temp = new byte[16];
287 | for (int j = 0; length > 0; length -= 16, j++)
288 | {
289 | byte[] inBytes = new byte[16];
290 | byte[] outBytes = new byte[16];
291 | byte[] out1 = new byte[16];
292 |
293 | Array.Copy(bins, i * 16, inBytes, 0, length > 16 ? 16 : length);
294 | Array.Copy(inBytes, 0, temp, 0, 16);
295 | sm4_one_round(ctx.sk, inBytes, outBytes);
296 | for (i = 0; i < 16; i++)
297 | {
298 | out1[i] = ((byte)(outBytes[i] ^ iv[i]));
299 | }
300 | Array.Copy(temp, 0, iv, 0, 16);
301 | for (int k = 0; k < 16; k++)
302 | {
303 | bousList.Add(out1[k]);
304 | }
305 | }
306 |
307 | }
308 |
309 | if (ctx.isPadding && ctx.mode == SM4_DECRYPT)
310 | {
311 | bous = padding(bousList.ToArray(), SM4_DECRYPT);
312 | return bous;
313 | }
314 | else
315 | {
316 | return bousList.ToArray();
317 | }
318 | }
319 | }
320 |
321 | class SM4_Context
322 | {
323 | public int mode;
324 |
325 | public long[] sk;
326 |
327 | public bool isPadding;
328 |
329 | public SM4_Context()
330 | {
331 | this.mode = 1;
332 | this.isPadding = true;
333 | this.sk = new long[32];
334 | }
335 | }
336 | }
337 |
--------------------------------------------------------------------------------