1 摘要
目前服务和服务之间通过Rpc方式进行数据交互,但数据在传输的时候为明文,对于整个平台而言可能存在数据被拦截、篡改、破坏等风险。因为需要提出一种共同遵守的约定,保证数据传输的安全性。
2 方案
主要是通过对传输前加密,数据接收后解密的方式实现传输安全保护。
2.1 方案一 对称加密
原理
1、发送端和接收端持有相同的密钥,发送端将需要发送的数据用密钥key加密,接收端用密钥Key解密得到数据。
优点
1、安全随着密钥的复杂度加大,被破解的难度急剧上升,保证了数据的安全;
2、速度快
3、实现简单
缺点
密钥需要提前约定,如果任意一方泄漏key那么整个服务集群的数据传输将变得不安全。
算法
DES、3DES、AES、RC5、RC6
2.2 方案二 公钥加密
原理
1、 发送端用接收端的公钥加密数据;
2、 接收端用自身的私钥解密密文获得数据。
优点
相对对于对称加密算法,在传输过程中就算数据被窃取也不会有什么问题,因为只有公钥对应的私钥才能解密密文
缺点
1、 对比堆成加密来说,运行速度慢很多
2、 有实现难度
算法
RSA
2.3 方案三 对称加密、公钥加密混合模式
原理
- 发送端向接收方申请连接;
- 接收方发送自身公钥;
- 发送方将自身的公钥用接收方的公钥加密并发送非接收方;
- 接收方将发送方的密文解密后得到发送方的公钥,并将对称加密的key加密后发给发送方;
- 发送方收到消息验证消息的正确性,如果正确则认为接收方是可信的,并在之后的发送消息活动中都用这个key进行数据加密。
利用公钥加密方式动态获取对称加密的密钥,用于对称加密,第二步、第三步够让发送方确认接收方是正确的,而不是冒牌的。
优点
结合了公钥加密和对称加密算法的优点,并且增加了公钥的拥有者的身份鉴别,安全、高效
缺点
实现复杂
算法
RSA+ DES(或3DES、AES、RC5、RC6)
3 实验
实验一 DES和RSA性能对比
对比项 | 加密 | 解密 | 加密 | 解密 |
---|---|---|---|---|
执行次数\算法\消耗(ms) | DES | RSA | DES | RSA |
1 | 0 | 1 | 2 | 1 |
10 | 5 | 5 | 7 | 10 |
100 | 54 | 59 | 56 | 101 |
1000 | 574 | 577 | 499 | 943 |
10000 | 4971 | 5109 | 4789 | 9341 |
100000 | 48591 | 53417 | 53876 | 93848 |
1000000 | 485881 | 510226 | 480218 | 930679 |
分析
DES和RSA加密性能相差不大,RSA慢一点可忽略不计,而解密相差很大,DES比RSA快一倍。
4 总结
对性能有较高要求采取对称加密,从安全的角度会选择公钥加密算法,而时间的充裕程度对安全和性能都有较高要求,则建议采取第三个方案,混合式加密技术,既保证通信的安全性也能有很好的性能表现。
附录
测试代码
1. DESCryption.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using static System.Text.Encoding;
using Convert = System.Convert;
namespace ConsoleApp.Encryption
{
public class DESCryption
{
private const string KEY_64 = "";//必须是8位无符号字符串
private const string IV_64 = "";
/// <summary>
/// DSE加密
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public static string Encode(string str)
{
byte[] byKey = UTF8.GetBytes(KEY_64);
byte[] byIV = UTF8.GetBytes(IV_64);
DESCryptoServiceProvider cryptoProvider = new DESCryptoServiceProvider();
int i = cryptoProvider.KeySize;
MemoryStream ms = new MemoryStream();
CryptoStream cst = new CryptoStream(ms, cryptoProvider.CreateEncryptor(byKey, byIV), CryptoStreamMode.Write);
StreamWriter sw = new StreamWriter(cst);
sw.Write(str);
sw.Flush();
cst.FlushFinalBlock();
sw.Flush();
return Convert.ToBase64String(ms.GetBuffer(), 0, (int)ms.Length);
}
/// <summary>
/// DSE解密
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public static string Decode(string str)
{
byte[] byKey = UTF8.GetBytes(KEY_64);
byte[] byIV = UTF8.GetBytes(IV_64);
byte[] byEnc;
try
{
byEnc = Convert.FromBase64String(str);
}
catch
{
return null;
}
DESCryptoServiceProvider cryptoProvider = new DESCryptoServiceProvider();
MemoryStream ms = new MemoryStream(byEnc);
CryptoStream cst = new CryptoStream(ms, cryptoProvider.CreateDecryptor(byKey, byIV), CryptoStreamMode.Read);
StreamReader sr = new StreamReader(cst);
return sr.ReadToEnd();
}
}
}
2. RSACryption.cs
using Consul;
using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
namespace ConsoleApp.Encryption
{
public class RSACryption
{
/// <summary>
/// 生成一对公钥和私钥
/// </summary>
/// <returns></returns>
public static KeyValuePair<string, string> GetKeyPairCspBlob()
{
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
string public_Key = Convert.ToBase64String(RSA.ExportCspBlob(false));
string private_Key = Convert.ToBase64String(RSA.ExportCspBlob(true));
return new KeyValuePair<string, string>(public_Key, private_Key);
}
/// <summary>
/// 生成一对公钥和私钥
/// </summary>
/// <returns></returns>
public static KeyValuePair<string, string> GetKeyPairXmlString()
{
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
string public_Key = RSA.ToXmlString(false);
string private_Key = RSA.ToXmlString(true);
return new KeyValuePair<string, string>(public_Key, private_Key);
}
/// <summary>
/// DSE加密
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public static string EncodeXmlString(string str,string publicKey)
{
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
byte[] cipherbytes;
rsa.FromXmlString(publicKey);
cipherbytes = rsa.Encrypt(Encoding.UTF8.GetBytes(str), false);
return Convert.ToBase64String(cipherbytes);
}
/// <summary>
/// DSE解密
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public static string DecodeXmlString(string str,string privateKey)
{
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
byte[] cipherbytes;
rsa.FromXmlString(privateKey);
cipherbytes = rsa.Decrypt(Convert.FromBase64String(str), false);
return Encoding.UTF8.GetString(cipherbytes);
}
}
}
3. Program.cs
using ConsoleApp.Encryption;
using System;
using System.Diagnostics;
using System.Threading;
namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
Stopwatch stopwatch = new Stopwatch();
var RSAKeyPiar = RSACryption.GetKeyPairXmlString();
var RSAPublicKey = RSAKeyPiar.Key;
var RSAPrivateKey = RSAKeyPiar.Value;
string plainText = Newtonsoft.Json.JsonConvert.SerializeObject(new { Name="admin",Sex = 1,BirthDay = DateTime.Now.AddYears(-20),Address="广东省深圳市" });
string DesCiphertext = DESCryption.Encode(plainText);
string RSACliphertext = RSACryption.EncodeXmlString(plainText, RSAPublicKey);
int runNumber = 1000000;
Console.WriteLine($"执行{runNumber}次,消耗时间单位-毫秒");
stopwatch.Start();
for (int i = 0; i < runNumber; i++)
{
var desCiphertextTemp = DESCryption.Encode(plainText);
}
stopwatch.Stop();
Console.WriteLine("DES加密消耗:"+stopwatch.ElapsedMilliseconds);
stopwatch.Reset();
stopwatch.Start();
for (int i = 0; i < runNumber; i++)
{
var desCiphertextTemp = RSACryption.EncodeXmlString(plainText, RSAPublicKey);
}
stopwatch.Stop();
Console.WriteLine("RSA加密消耗:" + stopwatch.ElapsedMilliseconds);
Console.WriteLine("------------------------------");
stopwatch.Reset();
stopwatch.Start();
for (int i = 0; i < runNumber; i++)
{
var desCiphertextTemp = DESCryption.Decode(DesCiphertext);
}
stopwatch.Stop();
Console.WriteLine("DES解密消耗:" + stopwatch.ElapsedMilliseconds);
stopwatch.Reset();
stopwatch.Start();
for (int i = 0; i < runNumber; i++)
{
var desCiphertextTemp = RSACryption.DecodeXmlString(RSACliphertext, RSAPrivateKey);
}
stopwatch.Stop();
Console.WriteLine("RSA解密消耗:" + stopwatch.ElapsedMilliseconds);
Console.ReadKey();
}
}
}