文章目录
- 前言
- 对方接口签名要求
- 我方对接思路
-
- [1.RSA 加密](#1.RSA 加密)
- 2.AES256加密
- 完整的加密帮助类
前言
提示:这里可以添加本文要记录的大概内容:
在我们对接其他公司接口的时候,时常会出现对方使用的开发语言和我方使用的开发语言不同的情况,因为每个语言之间都会有些许差别,在进行加密签名中就会出现签名一直对接不上的问题,下面我就来和各位分享一下我所遇到的问题以及解决方案。
对方接口签名要求
- 报文发送方自行产生随机密钥,然后再使用接收方公钥对随机秘钥进行RSA 非对称加密,生成 encrypted。
- 按照报文规范生成报文原文,然后对报文原文(JSON 格式字符串)使用 对称密钥字节数组进行 AES256 算法加密,再进行 Base64 编码,生成msg
- 再对报文原文进行签名,得到签名结果(十六进制字符串),签名算法采用"SHA1withRSA",生成 signature
可以看到上面这一堆文字,看似字很少,实则却使用到了很多种加密方式
可以梳理出会用到的加密有:RSA加密,AES256加密,Base64加密,SHA1加密
我方对接思路
1.RSA 加密
由于对方时使用的java,java密钥的key格式和我们C#这边RSA加密使用的key格式不一样,需要进行格式处理也就是下面的"RSAPrivateKeyJava2DotNet"方法。
csharp
public class RSAUtils
{
/// <summary>
/// 生成私钥
/// </summary>
/// <returns></returns>
public static string CreatePrivateKey()
{
string str = Guid.NewGuid().ToString("N");
Byte[] bytes = Encoding.GetEncoding("utf-8").GetBytes(str);
byte[] aesKey = new byte[16];
for (int i = 0; i < 16; i++)
{
aesKey[i] = bytes[i];
}
return Convert.ToBase64String(aesKey);
}
/// <summary>
/// 生成密钥
/// <param name="privateKey">私钥</param>
/// <param name="publicKey">公钥</param>
/// <param name="keySize">密钥长度:512,1024,2048,4096,8192</param>
/// </summary>
public static void Generator(out string privateKey, out string publicKey, int keySize = 1024)
{
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(keySize);
privateKey = rsa.ToXmlString(true); //将RSA算法的私钥导出到字符串PrivateKey中 参数为true表示导出私钥 true 表示同时包含 RSA 公钥和私钥;false 表示仅包含公钥。
publicKey = rsa.ToXmlString(false); //将RSA算法的公钥导出到字符串PublicKey中 参数为false表示不导出私钥 true 表示同时包含 RSA 公钥和私钥;false 表示仅包含公钥。
}
/// <summary>
/// RSA加密 将公钥导入到RSA对象中,准备加密
/// </summary>
/// <param name="publicKey">公钥</param>
/// <param name="encryptstring">待加密的字符串</param>
public static string RsaEncrypt(string publicKey, string encryptstring)
{
using (var rsaProvider = new RSACryptoServiceProvider())
{
string key = RSAPublicKeyJava2DotNet(publicKey);
var inputBytes = Encoding.UTF8.GetBytes(encryptstring);//有含义的字符串转化为字节流
rsaProvider.FromXmlString(key);//载入公钥
int bufferSize = (rsaProvider.KeySize / 8) - 11;//单块最大长度
var buffer = new byte[bufferSize];
using (MemoryStream inputStream = new MemoryStream(inputBytes), outputStream = new MemoryStream())
{
while (true)
{ //分段加密
int readSize = inputStream.Read(buffer, 0, bufferSize);
if (readSize <= 0)
{
break;
}
var temp = new byte[readSize];
Array.Copy(buffer, 0, temp, 0, readSize);
var encryptedBytes = rsaProvider.Encrypt(temp, false);
outputStream.Write(encryptedBytes, 0, encryptedBytes.Length);
}
return Convert.ToBase64String(outputStream.ToArray());//转化为字节流方便传输
}
}
}
/// <summary>
/// Java转.net格式
/// </summary>
/// <param name="JavaPublicKey">Java格式公钥</param>
/// <returns></returns>
public static string RSAPublicKeyJava2DotNet(string JavaPublicKey)
{
RsaKeyParameters publicKeyParam = (RsaKeyParameters)PublicKeyFactory.CreateKey(Convert.FromBase64String(JavaPublicKey));
return string.Format("<RSAKeyValue><Modulus>{0}</Modulus><Exponent>{1}</Exponent></RSAKeyValue>",
Convert.ToBase64String(publicKeyParam.Modulus.ToByteArrayUnsigned()),
Convert.ToBase64String(publicKeyParam.Exponent.ToByteArrayUnsigned()));
}
/// <summary>
/// .NET格式转Java格式
/// </summary>
/// <param name="cPublicKey">c#的.net格式公钥</param>
/// <returns></returns>
public static string RSAPublicKeyDotNet2Java(string cPublicKey)
{
XmlDocument doc = new XmlDocument(); doc.LoadXml(cPublicKey);
BigInteger m = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Modulus")[0].InnerText));
BigInteger p = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Exponent")[0].InnerText));
RsaKeyParameters pub = new RsaKeyParameters(false, m, p);
SubjectPublicKeyInfo publicKeyInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(pub);
byte[] serializedPublicBytes = publicKeyInfo.ToAsn1Object().GetDerEncoded();
return Convert.ToBase64String(serializedPublicBytes);
}
/// <summary>
/// .java格式密钥转c#使用的.net格式密钥
/// </summary>
/// <param name="JavaPrivateKey">.java密钥</param>
/// <returns></returns>
public static string RSAPrivateKeyJava2DotNet(string JavaPrivateKey)
{
RsaPrivateCrtKeyParameters privateKeyParam = (RsaPrivateCrtKeyParameters)PrivateKeyFactory.CreateKey(Convert.FromBase64String(JavaPrivateKey));
return string.Format("<RSAKeyValue><Modulus>{0}</Modulus><Exponent>{1}</Exponent><P>{2}</P><Q>{3}</Q><DP>{4}</DP><DQ>{5}</DQ><InverseQ>{6}</InverseQ><D>{7}</D></RSAKeyValue>",
Convert.ToBase64String(privateKeyParam.Modulus.ToByteArrayUnsigned()),
Convert.ToBase64String(privateKeyParam.PublicExponent.ToByteArrayUnsigned()),
Convert.ToBase64String(privateKeyParam.P.ToByteArrayUnsigned()),
Convert.ToBase64String(privateKeyParam.Q.ToByteArrayUnsigned()),
Convert.ToBase64String(privateKeyParam.DP.ToByteArrayUnsigned()),
Convert.ToBase64String(privateKeyParam.DQ.ToByteArrayUnsigned()),
Convert.ToBase64String(privateKeyParam.QInv.ToByteArrayUnsigned()),
Convert.ToBase64String(privateKeyParam.Exponent.ToByteArrayUnsigned()));
}
/// <summary>
/// c#使用的.net格式密钥转换成.Java格式密钥
/// </summary>
/// <param name="cPrivateKey">.net格式密钥</param>
/// <returns></returns>
public static string RSAPrivateKeyDotNet2Java(string cPrivateKey)
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(cPrivateKey);
BigInteger m = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Modulus")[0].InnerText));
BigInteger exp = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Exponent")[0].InnerText));
BigInteger d = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("D")[0].InnerText));
BigInteger p = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("P")[0].InnerText));
BigInteger q = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Q")[0].InnerText));
BigInteger dp = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("DP")[0].InnerText));
BigInteger dq = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("DQ")[0].InnerText));
BigInteger qinv = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("InverseQ")[0].InnerText));
RsaPrivateCrtKeyParameters privateKeyParam = new RsaPrivateCrtKeyParameters(m, exp, d, p, q, dp, dq, qinv);
PrivateKeyInfo privateKeyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(privateKeyParam);
byte[] serializedPrivateBytes = privateKeyInfo.ToAsn1Object().GetEncoded();
return Convert.ToBase64String(serializedPrivateBytes);
}
/// <summary>
/// RSA解密 载入私钥,解密数据
/// </summary>
/// <param name="privateKey">私钥</param>
/// <param name="decryptstring">待解密的字符串</param>
public static string RsaDecrypt(string privateKey, string decryptstring)
{
using (var rsaProvider = new RSACryptoServiceProvider())
{
string key = RSAPrivateKeyJava2DotNet(privateKey);
rsaProvider.FromXmlString(key); //载入私钥
var encryptedBytes = Convert.FromBase64String(decryptstring); //将传入的字符串转化为字节流
//var outputStream = new MemoryStream(encryptedBytes);
var bufferSize = rsaProvider.KeySize / 8;
var buffer = new byte[bufferSize];
using (MemoryStream inputStream = new MemoryStream(encryptedBytes), outputStream = new MemoryStream())
{
while (true)
{
int readSize = inputStream.Read(buffer, 0, bufferSize);
if (readSize <= 0)
{
break;
}
var temp = new byte[readSize];
Array.Copy(buffer, 0, temp, 0, readSize);
var decryptedBytes = rsaProvider.Decrypt(temp, false);
outputStream.Write(decryptedBytes, 0, decryptedBytes.Length);
}
return Encoding.UTF8.GetString(outputStream.ToArray()); //转化为字符串
}
}
}
/// <summary>
/// RSA私钥加密
/// </summary>
/// <param name="privateKey">私钥</param>
/// <param name="encryptstring">待加密的字符串</param>
public static string RsaPrivateEncrypt(string privateKey, string encryptstring)
{
var rsaProvider = new RSACryptoServiceProvider();
rsaProvider.FromXmlString(privateKey);//载入私钥
var inputBytes = Convert.FromBase64String(encryptstring);//有含义的字符串转化为字节流
int bufferSize = (rsaProvider.KeySize / 8) - 11;//单块最大长度
var buffer = new byte[bufferSize];
using (MemoryStream inputStream = new MemoryStream(inputBytes), outputStream = new MemoryStream())
{
while (true)
{
//分段加密
int readSize = inputStream.Read(buffer, 0, bufferSize);
if (readSize <= 0)
{
break;
}
var temp = new byte[readSize];
Array.Copy(buffer, 0, temp, 0, readSize);
var encryptedBytes = RsaPrivateEncrypt(privateKey, temp);
outputStream.Write(encryptedBytes, 0, encryptedBytes.Length);
}
return Convert.ToBase64String(outputStream.ToArray());//转化为字节流方便传输
}
}
/// <summary>
/// RSA公钥解密
/// </summary>
/// <param name="publicKey">公钥</param>
/// <param name="decryptstring">待解密的字符串</param>
public static string RsaPublicDecrypt(string publicKey, string decryptstring)
{
var rsaProvider = new RSACryptoServiceProvider();
rsaProvider.FromXmlString(publicKey); //载入私钥
var encryptedBytes = Convert.FromBase64String(decryptstring); //将传入的字符串转化为字节流
var bufferSize = rsaProvider.KeySize / 8;
var buffer = new byte[bufferSize];
using (MemoryStream inputStream = new MemoryStream(encryptedBytes), outputStream = new MemoryStream())
{
while (true)
{
int readSize = inputStream.Read(buffer, 0, bufferSize);
if (readSize <= 0)
{
break;
}
var temp = new byte[readSize];
Array.Copy(buffer, 0, temp, 0, readSize);
var decryptedBytes = decryptByPublicKey(publicKey, temp);
outputStream.Write(decryptedBytes, 0, decryptedBytes.Length);
}
return Convert.ToBase64String(outputStream.ToArray());
}
}
/// <summary>
/// SHA1 加密,返回大写字符串
/// </summary>
/// <param name="content">需要加密字符串</param>
/// <returns>返回40位UTF8 大写</returns>
public static string SHA1(string content)
{
return SHA1(content, Encoding.UTF8);
}
/// <summary>
/// SHA1 加密,返回大写字符串
/// </summary>
/// <param name="content">需要加密字符串</param>
/// <param name="encode">指定加密编码</param>
/// <returns>返回40位大写字符串</returns>
private static string SHA1(string content, Encoding encode)
{
try
{
SHA1 sha1 = new SHA1CryptoServiceProvider();
byte[] bytes_in = encode.GetBytes(content);
byte[] bytes_out = sha1.ComputeHash(bytes_in);
sha1.Dispose();
string result = BitConverter.ToString(bytes_out);
result = result.Replace("-", "");
return result;
}
catch (Exception ex)
{
throw new Exception("SHA1加密出错:" + ex.Message);
}
}
/// <summary>
/// 私钥加密
/// 这个方法只能加密 私钥长度/8 -11 个字符,分段加密的代码要自己处理了。
/// </summary>
/// <param name="privateKey">密钥</param>
/// <param name="data">要加密的数据</param>
/// <returns></returns>
public static byte[] RsaPrivateEncrypt(string privateKey, byte[] data)
{
string xmlPrivateKey = privateKey;
//加载私钥
RSACryptoServiceProvider privateRsa = new RSACryptoServiceProvider();
privateRsa.FromXmlString(xmlPrivateKey);
//转换密钥
AsymmetricCipherKeyPair keyPair = DotNetUtilities.GetKeyPair(privateRsa);
//IBufferedCipher c = CipherUtilities.GetCipher("RSA/ECB/PKCS1Padding");// 参数与Java中加密解密的参数一致
IBufferedCipher c = CipherUtilities.GetCipher("RSA");
c.Init(true, keyPair.Private); //第一个参数为true表示加密,为false表示解密;第二个参数表示密钥
byte[] DataToEncrypt = data;
byte[] outBytes = c.DoFinal(DataToEncrypt);//加密
return outBytes;
}
/// <summary>
/// 用公钥解密
/// 这个方法只能加密 私钥长度/8 -11 个字符,分段加密的代码要自己处理了。
/// </summary>
/// <param name="data"></param>
/// <param name="key"></param>
/// <returns></returns>
public static byte[] decryptByPublicKey(string publicKey, byte[] data)
{
string xmlPublicKey = publicKey;
RSACryptoServiceProvider publicRsa = new RSACryptoServiceProvider();
publicRsa.FromXmlString(xmlPublicKey);
AsymmetricKeyParameter keyPair = DotNetUtilities.GetRsaPublicKey(publicRsa);
//转换密钥
// AsymmetricCipherKeyPair keyPair = DotNetUtilities.GetRsaKeyPair(publicRsa);
//IBufferedCipher c = CipherUtilities.GetCipher("RSA/ECB/PKCS1Padding");// 参数与Java中加密解密的参数一致
IBufferedCipher c = CipherUtilities.GetCipher("RSA");
c.Init(false, keyPair); //第一个参数为true表示加密,为false表示解密;第二个参数表示密钥
byte[] DataToEncrypt = data;
byte[] outBytes = c.DoFinal(DataToEncrypt);//解密
return outBytes;
}
}
调用方法
csharp
string pkey= RSAUtils.CreatePrivateKey();
encrypt.data.encrypted = RSAUtils.RsaEncrypt(publicKey, pkey);
其中publicKey 是对方公司(JAVA)给我们的公钥,
这里我们生成的KEY是:Q2THHWOD1H4L81DO
加密出来的值是:rZdVr8ksB4EyJ0L6GGjcgHR+XYKwRnxxs+94Hyd/Y52SgqaROFva3DLACjYrzyAHetmGrMpPLKf4TRq0V8F5eDrjZRhOQelA5ogSWRoLwzpN4KZirBc1HCHyrfaEvHDtoJeNabZzKFTDHvNZ94NRQfpHXqABlS7TzOXJKLK1Z/BiQjGuyOGL3xohwhyZ+vgjqNFjpTYU7gqobno5kBK6zoG8B2wilsDP+4hkF7IAn6dAlw8scBMpuULZF6ceBCEakkgWrBYn4E5DiC5c1tz2x3yViBNO+2XV0YdZIrBVkWKZGCWBYVkq53ovyPavuMMyK16HF7CnKlE3RdMc2WvT6g==
这一步我们加密后对方公司的java是能解密出正确明文的。
2.AES256加密
这里问题就来了
下面是错误方法:
csharp
/// <summary>
/// AES加密
/// </summary>
/// <param name="encryptStr">明文</param>
/// <param name="key">密钥</param>
/// <returns></returns>
public static string Encrypt(string encryptStr,string key)
{
byte[] keyArray = UTF8Encoding.UTF8.GetBytes(key);
byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(encryptStr);
RijndaelManaged rDel = new RijndaelManaged();
rDel.Key = keyArray;
rDel.Mode = CipherMode.ECB;
rDel.Padding = PaddingMode.PKCS7;
ICryptoTransform cTransform = rDel.CreateEncryptor();
byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
return Convert.ToBase64String(resultArray, 0, resultArray.Length);
}
/// <summary>
/// AES解密
/// </summary>
/// <param name="decryptStr">密文</param>
/// <param name="key">密钥</param>
/// <returns></returns>
public static string Decrypt(string decryptStr,string key)
{
byte[] keyArray = UTF8Encoding.UTF8.GetBytes(key);
byte[] toEncryptArray = Convert.FromBase64String(decryptStr);
RijndaelManaged rDel = new RijndaelManaged();
rDel.Key = keyArray;
rDel.Mode = CipherMode.ECB;
rDel.Padding = PaddingMode.PKCS7;
ICryptoTransform cTransform = rDel.CreateDecryptor();
byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
return UTF8Encoding.UTF8.GetString(resultArray);
}
这种方式加密在网上的在线解密工具都解密不了,只有我们C#写的解密方法能解密,估计是因为填充类型或者其他什么地方有问题。在这里我也困惑了很久
下面是正确方法:
csharp
public class AESUtils
{
/// <summary>
/// AES256加密
/// </summary>
/// <param name="content">明文</param>
/// <param name="passphase">密钥</param>
/// <returns></returns>
public static string Encrypt(string content, string passphase)
{
byte[] bytes = Encoding.UTF8.GetBytes(content);
byte[] key, iv, salt = new byte[8];
using (var rng = new RNGCryptoServiceProvider())
{
rng.GetBytes(salt);
}
using (var md5 = new MD5CryptoServiceProvider())
{
var preHash = Encoding.UTF8.GetBytes(passphase).Concat(salt).ToArray();
var bs1 = md5.ComputeHash(preHash);
var bs2 = md5.ComputeHash(bs1.Concat(preHash).ToArray());
var bs3 = md5.ComputeHash(bs2.Concat(preHash).ToArray());
key = bs1.Concat(bs2).ToArray();
iv = bs3;
}
using (var aes = new AesCryptoServiceProvider() { Key = key, IV = iv })
using (var encryptor = aes.CreateEncryptor())
{
var encryptedBytes = encryptor.TransformFinalBlock(bytes, 0, bytes.Length);
var concated = Encoding.UTF8.GetBytes("Salted__").Concat(salt).Concat(encryptedBytes);
return Convert.ToBase64String(concated.ToArray());
}
}
/// <summary>
/// AES256解密
/// </summary>
/// <param name="content">密文</param>
/// <param name="passphase">密钥</param>
/// <returns></returns>
public static string Decrypt(string content, string passphase)
{
// openssl aes-256-cbc -k 123456789 -md md5 -e -base64
//
byte[] bytes = Convert.FromBase64String(content);
byte[] key, iv, salt = new byte[8], encryptedBytes = new byte[bytes.Length - 8 - 8];
//提取 salt
Array.ConstrainedCopy
(
sourceArray: bytes,
sourceIndex: 8, //剔除开头的 "Salted__"
destinationArray: salt,
destinationIndex: 0,
length: salt.Length
);
//提取 encryptedBytes
Array.ConstrainedCopy
(
sourceArray: bytes,
sourceIndex: 8 + 8, //并剔除开头的 salt
destinationArray: encryptedBytes,
destinationIndex: 0,
length: encryptedBytes.Length
);
using (var md5 = new MD5CryptoServiceProvider())
{
var preHash = Encoding.UTF8.GetBytes(passphase).Concat(salt).ToArray();
var bs1 = md5.ComputeHash(preHash);
var bs2 = md5.ComputeHash(bs1.Concat(preHash).ToArray());
var bs3 = md5.ComputeHash(bs2.Concat(preHash).ToArray());
key = bs1.Concat(bs2).ToArray();
iv = bs3;
}
using (var aes = new AesCryptoServiceProvider() { Key = key, IV = iv })
using (var decryptor = aes.CreateDecryptor())
{
byte[] decryptedBytes = decryptor.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length);
return Encoding.UTF8.GetString(decryptedBytes);
}
}
/// <summary>
/// 加密 (新的思路)
/// </summary>
/// <param name="content">明文</param>
/// <param name="passphase">密码(固定32位)</param>
/// <returns>密文(base64)</returns>
static string CryptoJsEncrypt_New(string content, string passphase )
{
byte[] bytes = Encoding.UTF8.GetBytes(content);
byte[] key = Encoding.UTF8.GetBytes(passphase); //32位的key
byte[] iv = new byte[16];
using (var rng = new RNGCryptoServiceProvider())
rng.GetBytes(iv); // 产生16个字节的随机iv
using (var aes = new AesCryptoServiceProvider() { Key = key, IV = iv })
using (var encryptor = aes.CreateEncryptor())
{
var encryptedBytes = encryptor.TransformFinalBlock(bytes, 0, bytes.Length);
var concated = iv.Concat(encryptedBytes);
return "aes256:" + Convert.ToBase64String(concated.ToArray());
}
}
/// <summary>
/// 解密 (新的思路)
/// </summary>
/// <param name="content">密文(base64)</param>
/// <param name="passphase">密码(固定32位)</param>
/// <returns>明文</returns>
static string CryptoJsDecrypt_New(string content, string passphase )
{
byte[] bytes = Convert.FromBase64String(content.Substring(7)); //剔除开头的 "aes256:"
byte[] key = Encoding.UTF8.GetBytes(passphase); //32位的key
byte[] iv = new byte[16];
byte[] encryptedBytes = new byte[bytes.Length - 16];
//提取 iv
Array.ConstrainedCopy
(
sourceArray: bytes,
sourceIndex: 0,
destinationArray: iv,
destinationIndex: 0,
length: iv.Length
);
//提取 加密结果
Array.ConstrainedCopy
(
sourceArray: bytes,
sourceIndex: 16, //并剔除开头的 iv
destinationArray: encryptedBytes,
destinationIndex: 0,
length: encryptedBytes.Length
);
using (var aes = new AesCryptoServiceProvider() { Key = key, IV = iv })
using (var decryptor = aes.CreateDecryptor())
{
byte[] decryptedBytes = decryptor.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length);
return Encoding.UTF8.GetString(decryptedBytes);
}
}
}
调用方法
csharp
AESUtils.Encrypt(datastr, pkey);
加密前明文字符串:
{"storeId":"1788431406828474370","merchantId":"1788027169854296065","tradeNo":"123456","phone":"13366237305","tradeAmount":"5.0","notifyUrl":"http://wx.wjy99.com/onlinemtorder/yunxin/orderMsg","callbackUrl":"http://wx.wjy99.com/onlinemtorder/yunxin/orderMsg","remark":"测试请求"}
加密后密文:
U2FsdGVkX1+FSSnYrXRRcvfDoSeLLPcaA2LEN0/ix7Z41jXIYRdCdIm3DMob+xwvVdMnFwv4iq7LhFxAZcetRHbS3hxhbjObhNvkQrvd79+AnZdEMoM/BGTx66U/c8xtdMheqxrRWoXoIIpfRf++UQCGZBuU5upwMjTmuU3vJKQX/2r5qUHkjH05qkR+ioLb6bvi1FKI6vp3Bs4sKPEKtq+5M26aBdOfo5RmmrSJ023GkvC4DGxlyVn7ac97bBj3X/8h2yfpT1E6zW6FwZIBK+aVPlPFVeKVeXBZwdX5tgpgB+4e6duHPAjArQ1XYRfx2ugNn38IDxwtap7ocBi3GnPB8U4iTXPCz+/7uFutDzIQi0hRVEMpVRqaaaw2Ri2fFV84QYgotJC+qXkKRwyx9g==
这种加密方式,网上的解密都能解开了。
完整的加密帮助类
csharp
/// <summary>
/// RSA
/// </summary>
public class RSAUtils
{
/// <summary>
/// 生成私钥
/// </summary>
/// <returns></returns>
public static string CreatePrivateKey()
{
string str = Guid.NewGuid().ToString("N");
Byte[] bytes = Encoding.GetEncoding("utf-8").GetBytes(str);
byte[] aesKey = new byte[16];
for (int i = 0; i < 16; i++)
{
aesKey[i] = bytes[i];
}
return Convert.ToBase64String(aesKey);
}
/// <summary>
/// 生成密钥
/// <param name="privateKey">私钥</param>
/// <param name="publicKey">公钥</param>
/// <param name="keySize">密钥长度:512,1024,2048,4096,8192</param>
/// </summary>
public static void Generator(out string privateKey, out string publicKey, int keySize = 1024)
{
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(keySize);
privateKey = rsa.ToXmlString(true); //将RSA算法的私钥导出到字符串PrivateKey中 参数为true表示导出私钥 true 表示同时包含 RSA 公钥和私钥;false 表示仅包含公钥。
publicKey = rsa.ToXmlString(false); //将RSA算法的公钥导出到字符串PublicKey中 参数为false表示不导出私钥 true 表示同时包含 RSA 公钥和私钥;false 表示仅包含公钥。
}
/// <summary>
/// RSA加密 将公钥导入到RSA对象中,准备加密
/// </summary>
/// <param name="publicKey">公钥</param>
/// <param name="encryptstring">待加密的字符串</param>
public static string RsaEncrypt(string publicKey, string encryptstring)
{
using (var rsaProvider = new RSACryptoServiceProvider())
{
string key = RSAPublicKeyJava2DotNet(publicKey);
var inputBytes = Encoding.UTF8.GetBytes(encryptstring);//有含义的字符串转化为字节流
rsaProvider.FromXmlString(key);//载入公钥
int bufferSize = (rsaProvider.KeySize / 8) - 11;//单块最大长度
var buffer = new byte[bufferSize];
using (MemoryStream inputStream = new MemoryStream(inputBytes), outputStream = new MemoryStream())
{
while (true)
{ //分段加密
int readSize = inputStream.Read(buffer, 0, bufferSize);
if (readSize <= 0)
{
break;
}
var temp = new byte[readSize];
Array.Copy(buffer, 0, temp, 0, readSize);
var encryptedBytes = rsaProvider.Encrypt(temp, false);
outputStream.Write(encryptedBytes, 0, encryptedBytes.Length);
}
return Convert.ToBase64String(outputStream.ToArray());//转化为字节流方便传输
}
}
}
/// <summary>
/// Java转.net格式
/// </summary>
/// <param name="JavaPublicKey">Java格式公钥</param>
/// <returns></returns>
public static string RSAPublicKeyJava2DotNet(string JavaPublicKey)
{
RsaKeyParameters publicKeyParam = (RsaKeyParameters)PublicKeyFactory.CreateKey(Convert.FromBase64String(JavaPublicKey));
return string.Format("<RSAKeyValue><Modulus>{0}</Modulus><Exponent>{1}</Exponent></RSAKeyValue>",
Convert.ToBase64String(publicKeyParam.Modulus.ToByteArrayUnsigned()),
Convert.ToBase64String(publicKeyParam.Exponent.ToByteArrayUnsigned()));
}
/// <summary>
/// .NET格式转Java格式
/// </summary>
/// <param name="cPublicKey">c#的.net格式公钥</param>
/// <returns></returns>
public static string RSAPublicKeyDotNet2Java(string cPublicKey)
{
XmlDocument doc = new XmlDocument(); doc.LoadXml(cPublicKey);
BigInteger m = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Modulus")[0].InnerText));
BigInteger p = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Exponent")[0].InnerText));
RsaKeyParameters pub = new RsaKeyParameters(false, m, p);
SubjectPublicKeyInfo publicKeyInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(pub);
byte[] serializedPublicBytes = publicKeyInfo.ToAsn1Object().GetDerEncoded();
return Convert.ToBase64String(serializedPublicBytes);
}
/// <summary>
/// .java格式密钥转c#使用的.net格式密钥
/// </summary>
/// <param name="JavaPrivateKey">.java密钥</param>
/// <returns></returns>
public static string RSAPrivateKeyJava2DotNet(string JavaPrivateKey)
{
RsaPrivateCrtKeyParameters privateKeyParam = (RsaPrivateCrtKeyParameters)PrivateKeyFactory.CreateKey(Convert.FromBase64String(JavaPrivateKey));
return string.Format("<RSAKeyValue><Modulus>{0}</Modulus><Exponent>{1}</Exponent><P>{2}</P><Q>{3}</Q><DP>{4}</DP><DQ>{5}</DQ><InverseQ>{6}</InverseQ><D>{7}</D></RSAKeyValue>",
Convert.ToBase64String(privateKeyParam.Modulus.ToByteArrayUnsigned()),
Convert.ToBase64String(privateKeyParam.PublicExponent.ToByteArrayUnsigned()),
Convert.ToBase64String(privateKeyParam.P.ToByteArrayUnsigned()),
Convert.ToBase64String(privateKeyParam.Q.ToByteArrayUnsigned()),
Convert.ToBase64String(privateKeyParam.DP.ToByteArrayUnsigned()),
Convert.ToBase64String(privateKeyParam.DQ.ToByteArrayUnsigned()),
Convert.ToBase64String(privateKeyParam.QInv.ToByteArrayUnsigned()),
Convert.ToBase64String(privateKeyParam.Exponent.ToByteArrayUnsigned()));
}
/// <summary>
/// c#使用的.net格式密钥转换成.Java格式密钥
/// </summary>
/// <param name="cPrivateKey">.net格式密钥</param>
/// <returns></returns>
public static string RSAPrivateKeyDotNet2Java(string cPrivateKey)
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(cPrivateKey);
BigInteger m = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Modulus")[0].InnerText));
BigInteger exp = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Exponent")[0].InnerText));
BigInteger d = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("D")[0].InnerText));
BigInteger p = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("P")[0].InnerText));
BigInteger q = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Q")[0].InnerText));
BigInteger dp = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("DP")[0].InnerText));
BigInteger dq = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("DQ")[0].InnerText));
BigInteger qinv = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("InverseQ")[0].InnerText));
RsaPrivateCrtKeyParameters privateKeyParam = new RsaPrivateCrtKeyParameters(m, exp, d, p, q, dp, dq, qinv);
PrivateKeyInfo privateKeyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(privateKeyParam);
byte[] serializedPrivateBytes = privateKeyInfo.ToAsn1Object().GetEncoded();
return Convert.ToBase64String(serializedPrivateBytes);
}
/// <summary>
/// RSA解密 载入私钥,解密数据
/// </summary>
/// <param name="privateKey">私钥</param>
/// <param name="decryptstring">待解密的字符串</param>
public static string RsaDecrypt(string privateKey, string decryptstring)
{
using (var rsaProvider = new RSACryptoServiceProvider())
{
string key = RSAPrivateKeyJava2DotNet(privateKey);
rsaProvider.FromXmlString(key); //载入私钥
var encryptedBytes = Convert.FromBase64String(decryptstring); //将传入的字符串转化为字节流
//var outputStream = new MemoryStream(encryptedBytes);
var bufferSize = rsaProvider.KeySize / 8;
var buffer = new byte[bufferSize];
using (MemoryStream inputStream = new MemoryStream(encryptedBytes), outputStream = new MemoryStream())
{
while (true)
{
int readSize = inputStream.Read(buffer, 0, bufferSize);
if (readSize <= 0)
{
break;
}
var temp = new byte[readSize];
Array.Copy(buffer, 0, temp, 0, readSize);
var decryptedBytes = rsaProvider.Decrypt(temp, false);
outputStream.Write(decryptedBytes, 0, decryptedBytes.Length);
}
return Encoding.UTF8.GetString(outputStream.ToArray()); //转化为字符串
}
}
}
/// <summary>
/// RSA私钥加密
/// </summary>
/// <param name="privateKey">私钥</param>
/// <param name="encryptstring">待加密的字符串</param>
public static string RsaPrivateEncrypt(string privateKey, string encryptstring)
{
var rsaProvider = new RSACryptoServiceProvider();
rsaProvider.FromXmlString(privateKey);//载入私钥
var inputBytes = Convert.FromBase64String(encryptstring);//有含义的字符串转化为字节流
int bufferSize = (rsaProvider.KeySize / 8) - 11;//单块最大长度
var buffer = new byte[bufferSize];
using (MemoryStream inputStream = new MemoryStream(inputBytes), outputStream = new MemoryStream())
{
while (true)
{
//分段加密
int readSize = inputStream.Read(buffer, 0, bufferSize);
if (readSize <= 0)
{
break;
}
var temp = new byte[readSize];
Array.Copy(buffer, 0, temp, 0, readSize);
var encryptedBytes = RsaPrivateEncrypt(privateKey, temp);
outputStream.Write(encryptedBytes, 0, encryptedBytes.Length);
}
return Convert.ToBase64String(outputStream.ToArray());//转化为字节流方便传输
}
}
/// <summary>
/// RSA公钥解密
/// </summary>
/// <param name="publicKey">公钥</param>
/// <param name="decryptstring">待解密的字符串</param>
public static string RsaPublicDecrypt(string publicKey, string decryptstring)
{
var rsaProvider = new RSACryptoServiceProvider();
rsaProvider.FromXmlString(publicKey); //载入私钥
var encryptedBytes = Convert.FromBase64String(decryptstring); //将传入的字符串转化为字节流
var bufferSize = rsaProvider.KeySize / 8;
var buffer = new byte[bufferSize];
using (MemoryStream inputStream = new MemoryStream(encryptedBytes), outputStream = new MemoryStream())
{
while (true)
{
int readSize = inputStream.Read(buffer, 0, bufferSize);
if (readSize <= 0)
{
break;
}
var temp = new byte[readSize];
Array.Copy(buffer, 0, temp, 0, readSize);
var decryptedBytes = decryptByPublicKey(publicKey, temp);
outputStream.Write(decryptedBytes, 0, decryptedBytes.Length);
}
return Convert.ToBase64String(outputStream.ToArray());
}
}
/// <summary>
/// SHA1 加密,返回大写字符串
/// </summary>
/// <param name="content">需要加密字符串</param>
/// <returns>返回40位UTF8 大写</returns>
public static string SHA1(string content)
{
return SHA1(content, Encoding.UTF8);
}
/// <summary>
/// SHA1 加密,返回大写字符串
/// </summary>
/// <param name="content">需要加密字符串</param>
/// <param name="encode">指定加密编码</param>
/// <returns>返回40位大写字符串</returns>
private static string SHA1(string content, Encoding encode)
{
try
{
SHA1 sha1 = new SHA1CryptoServiceProvider();
byte[] bytes_in = encode.GetBytes(content);
byte[] bytes_out = sha1.ComputeHash(bytes_in);
sha1.Dispose();
string result = BitConverter.ToString(bytes_out);
result = result.Replace("-", "");
return result;
}
catch (Exception ex)
{
throw new Exception("SHA1加密出错:" + ex.Message);
}
}
/// <summary>
/// 私钥加密
/// 这个方法只能加密 私钥长度/8 -11 个字符,分段加密的代码要自己处理了。
/// </summary>
/// <param name="privateKey">密钥</param>
/// <param name="data">要加密的数据</param>
/// <returns></returns>
public static byte[] RsaPrivateEncrypt(string privateKey, byte[] data)
{
string xmlPrivateKey = privateKey;
//加载私钥
RSACryptoServiceProvider privateRsa = new RSACryptoServiceProvider();
privateRsa.FromXmlString(xmlPrivateKey);
//转换密钥
AsymmetricCipherKeyPair keyPair = DotNetUtilities.GetKeyPair(privateRsa);
//IBufferedCipher c = CipherUtilities.GetCipher("RSA/ECB/PKCS1Padding");// 参数与Java中加密解密的参数一致
IBufferedCipher c = CipherUtilities.GetCipher("RSA");
c.Init(true, keyPair.Private); //第一个参数为true表示加密,为false表示解密;第二个参数表示密钥
byte[] DataToEncrypt = data;
byte[] outBytes = c.DoFinal(DataToEncrypt);//加密
return outBytes;
}
/// <summary>
/// 用公钥解密
/// 这个方法只能加密 私钥长度/8 -11 个字符,分段加密的代码要自己处理了。
/// </summary>
/// <param name="data"></param>
/// <param name="key"></param>
/// <returns></returns>
public static byte[] decryptByPublicKey(string publicKey, byte[] data)
{
string xmlPublicKey = publicKey;
RSACryptoServiceProvider publicRsa = new RSACryptoServiceProvider();
publicRsa.FromXmlString(xmlPublicKey);
AsymmetricKeyParameter keyPair = DotNetUtilities.GetRsaPublicKey(publicRsa);
//转换密钥
// AsymmetricCipherKeyPair keyPair = DotNetUtilities.GetRsaKeyPair(publicRsa);
//IBufferedCipher c = CipherUtilities.GetCipher("RSA/ECB/PKCS1Padding");// 参数与Java中加密解密的参数一致
IBufferedCipher c = CipherUtilities.GetCipher("RSA");
c.Init(false, keyPair); //第一个参数为true表示加密,为false表示解密;第二个参数表示密钥
byte[] DataToEncrypt = data;
byte[] outBytes = c.DoFinal(DataToEncrypt);//解密
return outBytes;
}
}
/// <summary>
/// AES
/// </summary>
public class AESUtils
{
/// <summary>
/// AES256加密
/// </summary>
/// <param name="content">明文</param>
/// <param name="passphase">密钥</param>
/// <returns></returns>
public static string Encrypt(string content, string passphase)
{
byte[] bytes = Encoding.UTF8.GetBytes(content);
byte[] key, iv, salt = new byte[8];
using (var rng = new RNGCryptoServiceProvider())
{
rng.GetBytes(salt);
}
using (var md5 = new MD5CryptoServiceProvider())
{
var preHash = Encoding.UTF8.GetBytes(passphase).Concat(salt).ToArray();
var bs1 = md5.ComputeHash(preHash);
var bs2 = md5.ComputeHash(bs1.Concat(preHash).ToArray());
var bs3 = md5.ComputeHash(bs2.Concat(preHash).ToArray());
key = bs1.Concat(bs2).ToArray();
iv = bs3;
}
using (var aes = new AesCryptoServiceProvider() { Key = key, IV = iv })
using (var encryptor = aes.CreateEncryptor())
{
var encryptedBytes = encryptor.TransformFinalBlock(bytes, 0, bytes.Length);
var concated = Encoding.UTF8.GetBytes("Salted__").Concat(salt).Concat(encryptedBytes);
return Convert.ToBase64String(concated.ToArray());
}
}
/// <summary>
/// AES256解密
/// </summary>
/// <param name="content">密文</param>
/// <param name="passphase">密钥</param>
/// <returns></returns>
public static string Decrypt(string content, string passphase)
{
// openssl aes-256-cbc -k 123456789 -md md5 -e -base64
//
byte[] bytes = Convert.FromBase64String(content);
byte[] key, iv, salt = new byte[8], encryptedBytes = new byte[bytes.Length - 8 - 8];
//提取 salt
Array.ConstrainedCopy
(
sourceArray: bytes,
sourceIndex: 8, //剔除开头的 "Salted__"
destinationArray: salt,
destinationIndex: 0,
length: salt.Length
);
//提取 encryptedBytes
Array.ConstrainedCopy
(
sourceArray: bytes,
sourceIndex: 8 + 8, //并剔除开头的 salt
destinationArray: encryptedBytes,
destinationIndex: 0,
length: encryptedBytes.Length
);
using (var md5 = new MD5CryptoServiceProvider())
{
var preHash = Encoding.UTF8.GetBytes(passphase).Concat(salt).ToArray();
var bs1 = md5.ComputeHash(preHash);
var bs2 = md5.ComputeHash(bs1.Concat(preHash).ToArray());
var bs3 = md5.ComputeHash(bs2.Concat(preHash).ToArray());
key = bs1.Concat(bs2).ToArray();
iv = bs3;
}
using (var aes = new AesCryptoServiceProvider() { Key = key, IV = iv })
using (var decryptor = aes.CreateDecryptor())
{
byte[] decryptedBytes = decryptor.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length);
return Encoding.UTF8.GetString(decryptedBytes);
}
}
/// <summary>
/// 加密 (新的思路)
/// </summary>
/// <param name="content">明文</param>
/// <param name="passphase">密码(固定32位)</param>
/// <returns>密文(base64)</returns>
static string CryptoJsEncrypt_New(string content, string passphase )
{
byte[] bytes = Encoding.UTF8.GetBytes(content);
byte[] key = Encoding.UTF8.GetBytes(passphase); //32位的key
byte[] iv = new byte[16];
using (var rng = new RNGCryptoServiceProvider())
rng.GetBytes(iv); // 产生16个字节的随机iv
using (var aes = new AesCryptoServiceProvider() { Key = key, IV = iv })
using (var encryptor = aes.CreateEncryptor())
{
var encryptedBytes = encryptor.TransformFinalBlock(bytes, 0, bytes.Length);
var concated = iv.Concat(encryptedBytes);
return "aes256:" + Convert.ToBase64String(concated.ToArray());
}
}
/// <summary>
/// 解密 (新的思路)
/// </summary>
/// <param name="content">密文(base64)</param>
/// <param name="passphase">密码(固定32位)</param>
/// <returns>明文</returns>
static string CryptoJsDecrypt_New(string content, string passphase )
{
byte[] bytes = Convert.FromBase64String(content.Substring(7)); //剔除开头的 "aes256:"
byte[] key = Encoding.UTF8.GetBytes(passphase); //32位的key
byte[] iv = new byte[16];
byte[] encryptedBytes = new byte[bytes.Length - 16];
//提取 iv
Array.ConstrainedCopy
(
sourceArray: bytes,
sourceIndex: 0,
destinationArray: iv,
destinationIndex: 0,
length: iv.Length
);
//提取 加密结果
Array.ConstrainedCopy
(
sourceArray: bytes,
sourceIndex: 16, //并剔除开头的 iv
destinationArray: encryptedBytes,
destinationIndex: 0,
length: encryptedBytes.Length
);
using (var aes = new AesCryptoServiceProvider() { Key = key, IV = iv })
using (var decryptor = aes.CreateDecryptor())
{
byte[] decryptedBytes = decryptor.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length);
return Encoding.UTF8.GetString(decryptedBytes);
}
}
}