├── 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 | --------------------------------------------------------------------------------