C#.NET 国密SM4对称加解密 与JAVA互通 ver:20230731

.NET 环境:.NET6 控制台程序(.net core)。

JAVA 环境:JAVA8,带maven 的JAVA控制台程序。

简要解析:

1:加密的KEY、明文等输入参数都需要string转 byte [] ,要约定好编码,如:UTF8。

2:加密后的输出参数:byte [] ,在传输时需要转为string,要约定好编码,如:16进制字符串。

这里演示的是“SM4/ECB/PKCS5Padding”,CBC的自行探索。

.NET 代码:

GmUtil 工具类,需要nuget下载 Portable.BouncyCastle 1.9.0 版本:

using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.GM;
using Org.BouncyCastle.Asn1.X9;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities;
using Org.BouncyCastle.Utilities.Encoders;
using Org.BouncyCastle.X509;
using System;
using System.Collections.Generic;
using System.IO; namespace CommonUtils
{
/**
* need lib:
* BouncyCastle.Crypto.dll(http://www.bouncycastle.org/csharp/index.html) * 用BC的注意点:
* 这个版本的BC对SM3withSM2的结果为asn1格式的r和s,如果需要直接拼接的r||s需要自己转换。下面rsAsn1ToPlainByteArray、rsPlainByteArrayToAsn1就在干这事。
* 这个版本的BC对SM2的结果为C1||C2||C3,据说为旧标准,新标准为C1||C3||C2,用新标准的需要自己转换。下面(被注释掉的)changeC1C2C3ToC1C3C2、changeC1C3C2ToC1C2C3就在干这事。java版的高版本有加上C1C3C2,csharp版没准以后也会加,但目前还没有,java版的目前可以初始化时“ SM2Engine sm2Engine = new SM2Engine(SM2Engine.Mode.C1C3C2);”。
*
* 按要求国密算法仅允许使用加密机,本demo国密算法仅供学习使用,请不要用于生产用途。
*/
public class GmUtil
{ //private static readonly ILog log = LogManager.GetLogger(typeof(GmUtil)); private static X9ECParameters x9ECParameters = GMNamedCurves.GetByName("sm2p256v1");
private static ECDomainParameters ecDomainParameters = new ECDomainParameters(x9ECParameters.Curve, x9ECParameters.G, x9ECParameters.N); /**
*
* @param msg
* @param userId
* @param privateKey
* @return r||s,直接拼接byte数组的rs
*/
public static byte[] SignSm3WithSm2(byte[] msg, byte[] userId, AsymmetricKeyParameter privateKey)
{
return RsAsn1ToPlainByteArray(SignSm3WithSm2Asn1Rs(msg, userId, privateKey));
} /**
* @param msg
* @param userId
* @param privateKey
* @return rs in <b>asn1 format</b>
*/
public static byte[] SignSm3WithSm2Asn1Rs(byte[] msg, byte[] userId, AsymmetricKeyParameter privateKey)
{
try
{
ISigner signer = SignerUtilities.GetSigner("SM3withSM2");
signer.Init(true, new ParametersWithID(privateKey, userId));
signer.BlockUpdate(msg, 0, msg.Length);
byte[] sig = signer.GenerateSignature();
return sig;
}
catch (Exception e)
{
//log.Error("SignSm3WithSm2Asn1Rs error: " + e.Message, e);
return null;
}
} /**
*
* @param msg
* @param userId
* @param rs r||s,直接拼接byte数组的rs
* @param publicKey
* @return
*/
public static bool VerifySm3WithSm2(byte[] msg, byte[] userId, byte[] rs, AsymmetricKeyParameter publicKey)
{
if (rs == null || msg == null || userId == null) return false;
if (rs.Length != RS_LEN * 2) return false;
return VerifySm3WithSm2Asn1Rs(msg, userId, RsPlainByteArrayToAsn1(rs), publicKey);
} /**
*
* @param msg
* @param userId
* @param rs in <b>asn1 format</b>
* @param publicKey
* @return
*/ public static bool VerifySm3WithSm2Asn1Rs(byte[] msg, byte[] userId, byte[] sign, AsymmetricKeyParameter publicKey)
{
try
{
ISigner signer = SignerUtilities.GetSigner("SM3withSM2");
signer.Init(false, new ParametersWithID(publicKey, userId));
signer.BlockUpdate(msg, 0, msg.Length);
return signer.VerifySignature(sign);
}
catch (Exception e)
{
//log.Error("VerifySm3WithSm2Asn1Rs error: " + e.Message, e);
return false;
}
} /**
* bc加解密使用旧标c1||c2||c3,此方法在加密后调用,将结果转化为c1||c3||c2
* @param c1c2c3
* @return
*/
private static byte[] ChangeC1C2C3ToC1C3C2(byte[] c1c2c3)
{
int c1Len = (x9ECParameters.Curve.FieldSize + 7) / 8 * 2 + 1; //sm2p256v1的这个固定65。可看GMNamedCurves、ECCurve代码。
const int c3Len = 32; //new SM3Digest().getDigestSize();
byte[] result = new byte[c1c2c3.Length];
Buffer.BlockCopy(c1c2c3, 0, result, 0, c1Len); //c1
Buffer.BlockCopy(c1c2c3, c1c2c3.Length - c3Len, result, c1Len, c3Len); //c3
Buffer.BlockCopy(c1c2c3, c1Len, result, c1Len + c3Len, c1c2c3.Length - c1Len - c3Len); //c2
return result;
} /**
* bc加解密使用旧标c1||c3||c2,此方法在解密前调用,将密文转化为c1||c2||c3再去解密
* @param c1c3c2
* @return
*/
private static byte[] ChangeC1C3C2ToC1C2C3(byte[] c1c3c2)
{
int c1Len = (x9ECParameters.Curve.FieldSize + 7) / 8 * 2 + 1; //sm2p256v1的这个固定65。可看GMNamedCurves、ECCurve代码。
const int c3Len = 32; //new SM3Digest().GetDigestSize();
byte[] result = new byte[c1c3c2.Length];
Buffer.BlockCopy(c1c3c2, 0, result, 0, c1Len); //c1: 0->65
Buffer.BlockCopy(c1c3c2, c1Len + c3Len, result, c1Len, c1c3c2.Length - c1Len - c3Len); //c2
Buffer.BlockCopy(c1c3c2, c1Len, result, c1c3c2.Length - c3Len, c3Len); //c3
return result;
} /**
* c1||c3||c2
* @param data
* @param key
* @return
*/
public static byte[] Sm2Decrypt(byte[] data, AsymmetricKeyParameter key)
{
return Sm2DecryptOld(ChangeC1C3C2ToC1C2C3(data), key);
} /**
* c1||c3||c2
* @param data
* @param key
* @return
*/ public static byte[] Sm2Encrypt(byte[] data, AsymmetricKeyParameter key)
{
return ChangeC1C2C3ToC1C3C2(Sm2EncryptOld(data, key));
} /**
* c1||c2||c3
* @param data
* @param key
* @return
*/
public static byte[] Sm2EncryptOld(byte[] data, AsymmetricKeyParameter pubkey)
{
try
{
SM2Engine sm2Engine = new SM2Engine();
sm2Engine.Init(true, new ParametersWithRandom(pubkey, new SecureRandom()));
return sm2Engine.ProcessBlock(data, 0, data.Length);
}
catch (Exception e)
{
//log.Error("Sm2EncryptOld error: " + e.Message, e);
return null;
}
} /**
* c1||c2||c3
* @param data
* @param key
* @return
*/
public static byte[] Sm2DecryptOld(byte[] data, AsymmetricKeyParameter key)
{
try
{
SM2Engine sm2Engine = new SM2Engine();
sm2Engine.Init(false, key);
return sm2Engine.ProcessBlock(data, 0, data.Length);
}
catch (Exception e)
{
//log.Error("Sm2DecryptOld error: " + e.Message, e);
return null;
}
} /**
* @param bytes
* @return
*/
public static byte[] Sm3(byte[] bytes)
{
try
{
SM3Digest digest = new SM3Digest();
digest.BlockUpdate(bytes, 0, bytes.Length);
byte[] result = DigestUtilities.DoFinal(digest);
return result;
}
catch (Exception e)
{
//log.Error("Sm3 error: " + e.Message, e);
return null;
}
} private const int RS_LEN = 32; private static byte[] BigIntToFixexLengthBytes(BigInteger rOrS)
{
// for sm2p256v1, n is 00fffffffeffffffffffffffffffffffff7203df6b21c6052b53bbf40939d54123,
// r and s are the result of mod n, so they should be less than n and have length<=32
byte[] rs = rOrS.ToByteArray();
if (rs.Length == RS_LEN) return rs;
else if (rs.Length == RS_LEN + 1 && rs[0] == 0) return Arrays.CopyOfRange(rs, 1, RS_LEN + 1);
else if (rs.Length < RS_LEN)
{
byte[] result = new byte[RS_LEN];
Arrays.Fill(result, (byte)0);
Buffer.BlockCopy(rs, 0, result, RS_LEN - rs.Length, rs.Length);
return result;
}
else
{
throw new ArgumentException("err rs: " + Hex.ToHexString(rs));
}
} /**
* BC的SM3withSM2签名得到的结果的rs是asn1格式的,这个方法转化成直接拼接r||s
* @param rsDer rs in asn1 format
* @return sign result in plain byte array
*/
private static byte[] RsAsn1ToPlainByteArray(byte[] rsDer)
{
Asn1Sequence seq = Asn1Sequence.GetInstance(rsDer);
byte[] r = BigIntToFixexLengthBytes(DerInteger.GetInstance(seq[0]).Value);
byte[] s = BigIntToFixexLengthBytes(DerInteger.GetInstance(seq[1]).Value);
byte[] result = new byte[RS_LEN * 2];
Buffer.BlockCopy(r, 0, result, 0, r.Length);
Buffer.BlockCopy(s, 0, result, RS_LEN, s.Length);
return result;
} /**
* BC的SM3withSM2验签需要的rs是asn1格式的,这个方法将直接拼接r||s的字节数组转化成asn1格式
* @param sign in plain byte array
* @return rs result in asn1 format
*/
private static byte[] RsPlainByteArrayToAsn1(byte[] sign)
{
if (sign.Length != RS_LEN * 2) throw new ArgumentException("err rs. ");
BigInteger r = new BigInteger(1, Arrays.CopyOfRange(sign, 0, RS_LEN));
BigInteger s = new BigInteger(1, Arrays.CopyOfRange(sign, RS_LEN, RS_LEN * 2));
Asn1EncodableVector v = new Asn1EncodableVector();
v.Add(new DerInteger(r));
v.Add(new DerInteger(s));
try
{
return new DerSequence(v).GetEncoded("DER");
}
catch (IOException e)
{
//log.Error("RsPlainByteArrayToAsn1 error: " + e.Message, e);
return null;
}
} public static AsymmetricCipherKeyPair GenerateKeyPair()
{
try
{
ECKeyPairGenerator kpGen = new ECKeyPairGenerator();
kpGen.Init(new ECKeyGenerationParameters(ecDomainParameters, new SecureRandom()));
return kpGen.GenerateKeyPair();
}
catch (Exception e)
{
//log.Error("generateKeyPair error: " + e.Message, e);
return null;
}
} public static ECPrivateKeyParameters GetPrivatekeyFromD(BigInteger d)
{
return new ECPrivateKeyParameters(d, ecDomainParameters);
} public static ECPublicKeyParameters GetPublickeyFromXY(BigInteger x, BigInteger y)
{
return new ECPublicKeyParameters(x9ECParameters.Curve.CreatePoint(x, y), ecDomainParameters);
} public static AsymmetricKeyParameter GetPublickeyFromX509File(FileInfo file)
{ FileStream fileStream = null;
try
{
//file.DirectoryName + "\\" + file.Name
fileStream = new FileStream(file.FullName, FileMode.Open, FileAccess.Read);
X509Certificate certificate = new X509CertificateParser().ReadCertificate(fileStream);
return certificate.GetPublicKey();
}
catch (Exception e)
{
//log.Error(file.Name + "读取失败,异常:" + e);
}
finally
{
if (fileStream != null)
fileStream.Close();
}
return null;
} public class Sm2Cert
{
public AsymmetricKeyParameter privateKey;
public AsymmetricKeyParameter publicKey;
public String certId;
} private static byte[] ToByteArray(int i)
{
byte[] byteArray = new byte[4];
byteArray[0] = (byte)(i >> 24);
byteArray[1] = (byte)((i & 0xFFFFFF) >> 16);
byteArray[2] = (byte)((i & 0xFFFF) >> 8);
byteArray[3] = (byte)(i & 0xFF);
return byteArray;
} /**
* 字节数组拼接
*
* @param params
* @return
*/
private static byte[] Join(params byte[][] byteArrays)
{
List<byte> byteSource = new List<byte>();
for (int i = 0; i < byteArrays.Length; i++)
{
byteSource.AddRange(byteArrays[i]);
}
byte[] data = byteSource.ToArray();
return data;
} /**
* 密钥派生函数
*
* @param Z
* @param klen
* 生成klen字节数长度的密钥
* @return
*/
private static byte[] KDF(byte[] Z, int klen)
{
int ct = 1;
int end = (int)Math.Ceiling(klen * 1.0 / 32);
List<byte> byteSource = new List<byte>();
try
{
for (int i = 1; i < end; i++)
{
byteSource.AddRange(GmUtil.Sm3(Join(Z, ToByteArray(ct))));
ct++;
}
byte[] last = GmUtil.Sm3(Join(Z, ToByteArray(ct)));
if (klen % 32 == 0)
{
byteSource.AddRange(last);
}
else
byteSource.AddRange(Arrays.CopyOfRange(last, 0, klen % 32));
return byteSource.ToArray();
}
catch (Exception e)
{
//log.Error("KDF error: " + e.Message, e);
}
return null;
} public static byte[] Sm4DecryptCBC(byte[] keyBytes, byte[] cipher, byte[] iv, String algo)
{
if (keyBytes.Length != 16) throw new ArgumentException("err key length");
if (cipher.Length % 16 != 0 && algo.Contains("NoPadding")) throw new ArgumentException("err data length"); try
{
KeyParameter key = ParameterUtilities.CreateKeyParameter("SM4", keyBytes);
IBufferedCipher c = CipherUtilities.GetCipher(algo);
if (iv == null) iv = ZeroIv(algo);
c.Init(false, new ParametersWithIV(key, iv));
return c.DoFinal(cipher);
}
catch (Exception e)
{
//log.Error("Sm4DecryptCBC error: " + e.Message, e);
return null;
}
} public static byte[] Sm4EncryptCBC(byte[] keyBytes, byte[] plain, byte[] iv, String algo)
{
if (keyBytes.Length != 16) throw new ArgumentException("err key length");
if (plain.Length % 16 != 0 && algo.Contains("NoPadding")) throw new ArgumentException("err data length"); try
{
KeyParameter key = ParameterUtilities.CreateKeyParameter("SM4", keyBytes);
IBufferedCipher c = CipherUtilities.GetCipher(algo);
if (iv == null) iv = ZeroIv(algo);
c.Init(true, new ParametersWithIV(key, iv));
return c.DoFinal(plain);
}
catch (Exception e)
{
//log.Error("Sm4EncryptCBC error: " + e.Message, e);
return null;
}
} public static byte[] Sm4EncryptECB(byte[] keyBytes, byte[] plain, string algo)
{
if (keyBytes.Length != 16) throw new ArgumentException("err key length");
//NoPadding 的情况下需要校验数据长度是16的倍数.
if (plain.Length % 16 != 0 && algo.Contains("NoPadding")) throw new ArgumentException("err data length"); try
{
KeyParameter key = ParameterUtilities.CreateKeyParameter("SM4", keyBytes);
IBufferedCipher c = CipherUtilities.GetCipher(algo);
c.Init(true, key);
return c.DoFinal(plain);
}
catch (Exception e)
{
//log.Error("Sm4EncryptECB error: " + e.Message, e);
return null;
}
} public static byte[] Sm4DecryptECB(byte[] keyBytes, byte[] cipher, string algo)
{
if (keyBytes.Length != 16) throw new ArgumentException("err key length");
if (cipher.Length % 16 != 0 && algo.Contains("NoPadding")) throw new ArgumentException("err data length"); try
{
KeyParameter key = ParameterUtilities.CreateKeyParameter("SM4", keyBytes);
IBufferedCipher c = CipherUtilities.GetCipher(algo);
c.Init(false, key);
return c.DoFinal(cipher);
}
catch (Exception e)
{
//log.Error("Sm4DecryptECB error: " + e.Message, e);
return null;
}
} public const String SM4_ECB_NOPADDING = "SM4/ECB/NoPadding";
public const String SM4_CBC_NOPADDING = "SM4/CBC/NoPadding";
public const String SM4_CBC_PKCS7PADDING = "SM4/CBC/PKCS7Padding"; /**
* cfca官网CSP沙箱导出的sm2文件
* @param pem 二进制原文
* @param pwd 密码
* @return
*/
public static Sm2Cert readSm2File(byte[] pem, String pwd)
{ Sm2Cert sm2Cert = new Sm2Cert();
try
{
Asn1Sequence asn1Sequence = (Asn1Sequence)Asn1Object.FromByteArray(pem);
// ASN1Integer asn1Integer = (ASN1Integer) asn1Sequence.getObjectAt(0); //version=1
Asn1Sequence priSeq = (Asn1Sequence)asn1Sequence[1];//private key
Asn1Sequence pubSeq = (Asn1Sequence)asn1Sequence[2];//public key and x509 cert // ASN1ObjectIdentifier sm2DataOid = (ASN1ObjectIdentifier) priSeq.getObjectAt(0);
// ASN1ObjectIdentifier sm4AlgOid = (ASN1ObjectIdentifier) priSeq.getObjectAt(1);
Asn1OctetString priKeyAsn1 = (Asn1OctetString)priSeq[2];
byte[] key = KDF(System.Text.Encoding.UTF8.GetBytes(pwd), 32);
byte[] priKeyD = Sm4DecryptCBC(Arrays.CopyOfRange(key, 16, 32),
priKeyAsn1.GetOctets(),
Arrays.CopyOfRange(key, 0, 16), SM4_CBC_PKCS7PADDING);
sm2Cert.privateKey = GetPrivatekeyFromD(new BigInteger(1, priKeyD));
// log.Info(Hex.toHexString(priKeyD)); // ASN1ObjectIdentifier sm2DataOidPub = (ASN1ObjectIdentifier) pubSeq.getObjectAt(0);
Asn1OctetString pubKeyX509 = (Asn1OctetString)pubSeq[1];
X509Certificate x509 = (X509Certificate)new X509CertificateParser().ReadCertificate(pubKeyX509.GetOctets());
sm2Cert.publicKey = x509.GetPublicKey();
sm2Cert.certId = x509.SerialNumber.ToString(10); //这里转10进账,有啥其他进制要求的自己改改
return sm2Cert;
}
catch (Exception e)
{
//log.Error("readSm2File error: " + e.Message, e);
return null;
}
} /**
*
* @param cert
* @return
*/
public static Sm2Cert ReadSm2X509Cert(byte[] cert)
{
Sm2Cert sm2Cert = new Sm2Cert();
try
{ X509Certificate x509 = new X509CertificateParser().ReadCertificate(cert);
sm2Cert.publicKey = x509.GetPublicKey();
sm2Cert.certId = x509.SerialNumber.ToString(10); //这里转10进账,有啥其他进制要求的自己改改
return sm2Cert;
}
catch (Exception e)
{
//log.Error("ReadSm2X509Cert error: " + e.Message, e);
return null;
}
} public static byte[] ZeroIv(String algo)
{ try
{
IBufferedCipher cipher = CipherUtilities.GetCipher(algo);
int blockSize = cipher.GetBlockSize();
byte[] iv = new byte[blockSize];
Arrays.Fill(iv, (byte)0);
return iv;
}
catch (Exception e)
{
//log.Error("ZeroIv error: " + e.Message, e);
return null;
}
} public static void Main2(string[] s)
{ // 随便看看
//log.Info("GMNamedCurves: ");
foreach (string e in GMNamedCurves.Names)
{
//log.Info(e);
}
//log.Info("sm2p256v1 n:" + x9ECParameters.N);
//log.Info("sm2p256v1 nHex:" + Hex.ToHexString(x9ECParameters.N.ToByteArray())); // 生成公私钥对 ---------------------
AsymmetricCipherKeyPair kp = GmUtil.GenerateKeyPair();
//log.Info("private key d: " + ((ECPrivateKeyParameters)kp.Private).D);
//log.Info("public key q:" + ((ECPublicKeyParameters)kp.Public).Q); //{x, y, zs...} //签名验签
byte[] msg = System.Text.Encoding.UTF8.GetBytes("message digest");
byte[] userId = System.Text.Encoding.UTF8.GetBytes("userId");
byte[] sig = SignSm3WithSm2(msg, userId, kp.Private);
//log.Info("testSignSm3WithSm2: " + Hex.ToHexString(sig));
//log.Info("testVerifySm3WithSm2: " + VerifySm3WithSm2(msg, userId, sig, kp.Public)); // 由d生成私钥 ---------------------
BigInteger d = new BigInteger("097b5230ef27c7df0fa768289d13ad4e8a96266f0fcb8de40d5942af4293a54a", 16);
ECPrivateKeyParameters bcecPrivateKey = GetPrivatekeyFromD(d);
//log.Info("testGetFromD: " + bcecPrivateKey.D.ToString(16)); //公钥X坐标PublicKeyXHex: 59cf9940ea0809a97b1cbffbb3e9d96d0fe842c1335418280bfc51dd4e08a5d4
//公钥Y坐标PublicKeyYHex: 9a7f77c578644050e09a9adc4245d1e6eba97554bc8ffd4fe15a78f37f891ff8
AsymmetricKeyParameter publicKey = GetPublickeyFromX509File(new FileInfo("d:/certs/69629141652.cer"));
//log.Info(publicKey);
AsymmetricKeyParameter publicKey1 = GetPublickeyFromXY(new BigInteger("59cf9940ea0809a97b1cbffbb3e9d96d0fe842c1335418280bfc51dd4e08a5d4", 16), new BigInteger("9a7f77c578644050e09a9adc4245d1e6eba97554bc8ffd4fe15a78f37f891ff8", 16));
//log.Info("testReadFromX509File: " + ((ECPublicKeyParameters)publicKey).Q);
//log.Info("testGetFromXY: " + ((ECPublicKeyParameters)publicKey1).Q);
//log.Info("testPubKey: " + publicKey.Equals(publicKey1));
//log.Info("testPubKey: " + ((ECPublicKeyParameters)publicKey).Q.Equals(((ECPublicKeyParameters)publicKey1).Q)); // sm2 encrypt and decrypt test ---------------------
AsymmetricCipherKeyPair kp2 = GenerateKeyPair();
AsymmetricKeyParameter publicKey2 = kp2.Public;
AsymmetricKeyParameter privateKey2 = kp2.Private;
byte[] bs = Sm2Encrypt(System.Text.Encoding.UTF8.GetBytes("s"), publicKey2);
//log.Info("testSm2Enc dec: " + Hex.ToHexString(bs));
bs = Sm2Decrypt(bs, privateKey2);
//log.Info("testSm2Enc dec: " + System.Text.Encoding.UTF8.GetString(bs)); // sm4 encrypt and decrypt test ---------------------
//0123456789abcdeffedcba9876543210 + 0123456789abcdeffedcba9876543210 -> 681edf34d206965e86b3e94f536e4246
byte[] plain = Hex.Decode("0123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba9876543210");
byte[] key = Hex.Decode("0123456789abcdeffedcba9876543210");
byte[] cipher = Hex.Decode("595298c7c6fd271f0402f804c33d3f66");
bs = Sm4EncryptECB(key, plain, GmUtil.SM4_ECB_NOPADDING);
//log.Info("testSm4EncEcb: " + Hex.ToHexString(bs)); ;
bs = Sm4DecryptECB(key, bs, GmUtil.SM4_ECB_NOPADDING);
//log.Info("testSm4DecEcb: " + Hex.ToHexString(bs)); //读.sm2文件
String sm2 = "MIIDHQIBATBHBgoqgRzPVQYBBAIBBgcqgRzPVQFoBDDW5/I9kZhObxXE9Vh1CzHdZhIhxn+3byBU\nUrzmGRKbDRMgI3hJKdvpqWkM5G4LNcIwggLNBgoqgRzPVQYBBAIBBIICvTCCArkwggJdoAMCAQIC\nBRA2QSlgMAwGCCqBHM9VAYN1BQAwXDELMAkGA1UEBhMCQ04xMDAuBgNVBAoMJ0NoaW5hIEZpbmFu\nY2lhbCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEbMBkGA1UEAwwSQ0ZDQSBURVNUIFNNMiBPQ0Ex\nMB4XDTE4MTEyNjEwMTQxNVoXDTIwMTEyNjEwMTQxNVowcjELMAkGA1UEBhMCY24xEjAQBgNVBAoM\nCUNGQ0EgT0NBMTEOMAwGA1UECwwFQ1VQUkExFDASBgNVBAsMC0VudGVycHJpc2VzMSkwJwYDVQQD\nDCAwNDFAWnRlc3RAMDAwMTAwMDA6U0lHTkAwMDAwMDAwMTBZMBMGByqGSM49AgEGCCqBHM9VAYIt\nA0IABDRNKhvnjaMUShsM4MJ330WhyOwpZEHoAGfqxFGX+rcL9x069dyrmiF3+2ezwSNh1/6YqfFZ\nX9koM9zE5RG4USmjgfMwgfAwHwYDVR0jBBgwFoAUa/4Y2o9COqa4bbMuiIM6NKLBMOEwSAYDVR0g\nBEEwPzA9BghggRyG7yoBATAxMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmNmY2EuY29tLmNuL3Vz\nL3VzLTE0Lmh0bTA4BgNVHR8EMTAvMC2gK6AphidodHRwOi8vdWNybC5jZmNhLmNvbS5jbi9TTTIv\nY3JsNDI4NS5jcmwwCwYDVR0PBAQDAgPoMB0GA1UdDgQWBBREhx9VlDdMIdIbhAxKnGhPx8FcHDAd\nBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQwDAYIKoEcz1UBg3UFAANIADBFAiEAgWvQi3h6\niW4jgF4huuXfhWInJmTTYr2EIAdG8V4M8fYCIBixygdmfPL9szcK2pzCYmIb6CBzo5SMv50Odycc\nVfY6";
bs = Convert.FromBase64String(sm2);
String pwd = "cfca1234";
GmUtil.Sm2Cert sm2Cert = GmUtil.readSm2File(bs, pwd);
//log.Info("testReadSm2File, pubkey: " + ((ECPublicKeyParameters)sm2Cert.publicKey).Q.ToString());
//log.Info("testReadSm2File, prikey: " + Hex.ToHexString(((ECPrivateKeyParameters)sm2Cert.privateKey).D.ToByteArray()));
//log.Info("testReadSm2File, certId: " + sm2Cert.certId); bs = Sm2Encrypt(System.Text.Encoding.UTF8.GetBytes("s"), ((ECPublicKeyParameters)sm2Cert.publicKey));
//log.Info("testSm2Enc dec: " + Hex.ToHexString(bs));
bs = Sm2Decrypt(bs, ((ECPrivateKeyParameters)sm2Cert.privateKey));
//log.Info("testSm2Enc dec: " + System.Text.Encoding.UTF8.GetString(bs)); msg = System.Text.Encoding.UTF8.GetBytes("message digest");
userId = System.Text.Encoding.UTF8.GetBytes("userId");
sig = SignSm3WithSm2(msg, userId, ((ECPrivateKeyParameters)sm2Cert.privateKey));
//log.Info("testSignSm3WithSm2: " + Hex.ToHexString(sig));
//log.Info("testVerifySm3WithSm2: " + VerifySm3WithSm2(msg, userId, sig, ((ECPublicKeyParameters)sm2Cert.publicKey)));
} }
}

.NET调用DEMO:

// See https://aka.ms/new-console-template for more information
using CommonUtils;
using Org.BouncyCastle.Utilities.Encoders;
using System.Text; Console.WriteLine("Hello, World!"); try
{
String content = "1234泰酷拉";
String key = "9814548961710661";
byte[] byteKey = Encoding.UTF8.GetBytes(key);
string algo = "SM4/ECB/PKCS7Padding";
byte[] sourceData = Encoding.UTF8.GetBytes(content);
byte[] encryptedData = GmUtil.Sm4EncryptECB(byteKey, sourceData, algo);
string encryptedStr=BitConverter.ToString(encryptedData).Replace("-","").ToLower();
Console.WriteLine("encryptedStr:" + encryptedStr); string javaEncryptedStr = "02d225c9ff6bb99be6a67421aae4f3aa";
Console.WriteLine("JAVA程序加密后的串:" + javaEncryptedStr);
byte[] byJavaEncrypted=Hex.Decode(javaEncryptedStr);
byte[] decryptedData = GmUtil.Sm4DecryptECB(byteKey, byJavaEncrypted, algo);
string sm4DecryptedStr = Encoding.UTF8.GetString(decryptedData);
Console.WriteLine("解密结果:" + sm4DecryptedStr);
}
catch (Exception ex)
{ Console.WriteLine("ex:"+ ex.Message);
} Console.ReadKey();

JAVA代码:

maven需要增加依赖:

<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.1</version>
</dependency> <dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.70</version>
</dependency>

Sm4Util 工具类:

package org.example;

import cn.hutool.crypto.symmetric.SymmetricCrypto;

public class Sm4Util {

    //加密为16进制,也可以加密成base64/字节数组
public static String encryptSm4ECB(String key,String plaintext) {
String _Sm4EcbNoPaddingAlg ="SM4/ECB/PKCS5Padding";
SymmetricCrypto sm4 = new SymmetricCrypto(_Sm4EcbNoPaddingAlg, key.getBytes());
return sm4.encryptHex(plaintext);
} //解密
public static String decryptSm4ECB(String key,String ciphertext) {
String _Sm4EcbNoPaddingAlg ="SM4/ECB/PKCS5Padding";
SymmetricCrypto sm4 = new SymmetricCrypto(_Sm4EcbNoPaddingAlg, key.getBytes());
return sm4.decryptStr(ciphertext);
}
}

JAVA调用DEMO:

package org.example;

public class App
{
public static void main( String[] args )
{
System.out.println( "Hello World!" );
try { String key = "9814548961710661";
String content = "1234泰酷拉";
System.out.println( "待加密字符串:" + content);
String plain = Sm4Util.encryptSm4ECB(key,content);
System.out.println( "加密后:" + plain);
String cipher = Sm4Util.decryptSm4ECB(key,plain);
System.out.println( "解密后:" + cipher); } catch (Exception ex) {
String msg = ex.getMessage();
System.out.println( "解密后:" + msg);
}
}
}

C#.NET 国密SM4对称加解密 与JAVA互通 ver:20230731的更多相关文章

  1. 国密SM4对称算法实现说明(原SMS4无线局域网算法标准)

    国密SM4对称算法实现说明(原SMS4无线局域网算法标准) SM4分组密码算法,原名SMS4,国家密码管理局于2012年3月21日发布:http://www.oscca.gov.cn/News/201 ...

  2. java sm4国密算法加密、解密

      java sm4国密算法加密.解密 CreationTime--2018年7月5日09点20分 Author:Marydon 1.准备工作 所需jar包: bcprov-jdk15on-1.59. ...

  3. 一个关于国密SM4的故事

    一个关于国密SM4的故事 我的名字叫SM4,我还有三位兄长,分别是大哥SM1, 二哥SM2, 和三哥SM3.说起我的名字,故事要回到2006年的时候,我出生的时候并不是叫SM4的,而是叫做SMS4.只 ...

  4. [转帖]一个关于国密SM4的故事

    一个关于国密SM4的故事 https://www.cnblogs.com/ouyida3/p/10053862.html SM1 硬件SM2 非对称加密SM3 hash算法SM4 对称加密 一个关于国 ...

  5. Asp.Net Core 2.0 项目实战(7)MD5加密、AES&DES对称加解密

    本文目录 1. 摘要 2. MD5加密封装 3. AES的加密.解密 4. DES加密/解密 5. 总结 1.  摘要 C#中常用的一些加密和解密方案,如:md5加密.RSA加密与解密和DES加密等, ...

  6. php des 对称加解密类

    <?php header("Content-Type: text/html;charset=utf-8"); /** * des 对称加解密 */ class des { p ...

  7. AES加解密异常java.security.InvalidKeyException: Illegal key size

    AES加解密异常 Java后台AES解密,抛出异常如下:java.security.InvalidKeyException: Illegal key size Illegal key size or ...

  8. AES对称加解密

    简介设计思想加密模式ECB模式(电子密码本模式:Electronic codebook)CBC模式(密码分组链接:Cipher-block chaining)CFB模式(密文反馈:Cipher fee ...

  9. java C# objective-c AES对称加解密

    /** * AES加解密 */ public class AESHelper { final static String AES_KEY = "43hr8fhu34b58123"; ...

  10. rsa互通密钥对生成及互通加解密(c#,java,php)

    摘要 在数据安全上rsa起着非常大的作用,特别是数据网络通讯的安全上.当异构系统在数据网络通讯上对安全性有所要求时,rsa将作为其中的一种选择,此时rsa的互通性就显得尤为重要了. 本文参考网络资料, ...

随机推荐

  1. 驱动开发:通过MDL映射实现多次通信

    在前几篇文章中LyShark通过多种方式实现了驱动程序与应用层之间的通信,这其中就包括了通过运用SystemBuf缓冲区通信,运用ReadFile读写通信,运用PIPE管道通信,以及运用ASYNC反向 ...

  2. 【必知必会的MySQL知识】④DCL语言

    目录 一.概述 二 .授权 2.1 语法格式 2.2 语法说明 2.3 权限类型 2.4 权限级别 三. 回收权限 3.1 语法格式 3.2 语法说明 3.3 注意事项 四 .实践操作 一.概述 数据 ...

  3. KaiOS 2.5.X 使用 WebIDE 安装以及调试第三方应用程序

    本教程将展示使用 Waterfox Classic 安装为 KaiOS 2.5.x 设计的应用,同时我们也非常推荐使用它来进行安装和调试应用. 本教程本身不会对手机产生任何损害,但请注意,你必须信任你 ...

  4. Web进阶LNMP网站部署

    Web进阶LNMP网站部署 目录 Web进阶LNMP网站部署 LNMP架构工作流程 部署LNMP架构 1.安装nginx 2.安装php 3.安装数据库 将Nginx和PHP建立连接 1.修改ngin ...

  5. 2022-12-20:二狗买了一些小兵玩具,和大胖一起玩, 一共有n个小兵,这n个小兵拍成一列, 第i个小兵战斗力为hi,然后他们两个开始对小兵进行排列, 一共进行m次操作,二狗每次操作选择一个数k,

    2022-12-20:二狗买了一些小兵玩具,和大胖一起玩, 一共有n个小兵,这n个小兵拍成一列, 第i个小兵战斗力为hi,然后他们两个开始对小兵进行排列, 一共进行m次操作,二狗每次操作选择一个数k, ...

  6. Python MQTT客户端 paho-mqtt

    Python中MQTT Python有许多优秀的MQTT客户端,比较有代表性的有paho-mqtt.hbmqtt.gmqtt等,各有特色 paho-mqtt 有着最优秀的文档,代码风格易于理解,同时有 ...

  7. django之drf(部分讲解)

    序列化类常用字段和字段参数 drf在Django字段类型的基础上派生了自己的字段类型以及字段参数 序列化器的字段类型用于处理原始值和内部数据类型直接的转换 还可以用于验证输入.以及父对象检索和设置值 ...

  8. linux中使用jenkins自动部署前端工程

    1.去年在自己的服务器上安装了jenkins,说用来自己研究一下jenkins自动化部署前端项目,jenkins安装好了,可是一直没管,最近终于研究了一下使用jenkins自动化部署,以此记录下来. ...

  9. List的拆分的几种方式

    开发中我们可能会遇到一个大的集合,然后我们需要对集合进行拆分,然后再对拆分的集合进行相关的操作.当然我们可以自己写一个拆分的方法,我自己写过用了不少代码,但是感觉还不是很好,最近看了不少工具才发现很多 ...

  10. 20200630 excel365 选中一个单元格,对应的行和列都高亮

    Excel默认只高亮选中单元格的行标和列标,在整理数据时容易眼花,如能把这一行和列都高亮岂不是更好.方法在此: 1 打开"开发工具"菜单 默认这一项是隐藏的.文件-选项-自定义功能 ...