WCF 进阶: 对称加密传输
大家使用WCF的时候,会不会觉得使用SSL通道传输太麻烦,使用明文传输又觉得不安全呢? 特别是当传递的消息中带有比较敏感,机密的身份信息的时候更是如此呢?我们在上文实现了压缩编码传输,详见WCF进阶:将编码后的字节流压缩传输,本文照葫芦画瓢,实现一个可能大家更为需要的功能,将数据对称加密后传输,好处就是加密速度嗷嗷快,使用起来嗷嗷方便。
工作原理和压缩传输一致所以本文不做赘述,详细的实现机理会单开一篇详细去谈,本文重点看看实现代码和实现效果。要实现对称机密传输的功能,我们主要要实现的有如下几个类:CryptEncodingBindingElement,CryptEncoderFactory,CryptEncoder,DESCryption,前面三项都是WCF扩展所必须的,后面是工具类,主要是用于DES加解密和生成密钥和IV。
CryptEncodingBindingElement
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Xml; using System.ServiceModel.Channels; namespace RobinLib { public class CryptEncodingBindingElement: MessageEncodingBindingElement { private XmlDictionaryReaderQuotas readerQuotas; private MessageEncodingBindingElement innerMessageEncodingBindingElement; string key; string iv; public MessageEncodingBindingElement InnerMessageEncodingBindingElement { get { return innerMessageEncodingBindingElement; } } public string Key { get { return key; } } public string IV { get { return iv; } } public CryptEncodingBindingElement(MessageEncodingBindingElement innerMessageEncodingBindingElement, string key,string iv) { this.readerQuotas = new XmlDictionaryReaderQuotas(); this.key = key; this.iv = iv; this.innerMessageEncodingBindingElement = innerMessageEncodingBindingElement; } public override IChannelFactory<TChannel> BuildChannelFactory<TChannel>(BindingContext context) { context.BindingParameters.Add(this); return context.BuildInnerChannelFactory<TChannel>(); } public override IChannelListener<TChannel> BuildChannelListener<TChannel>(BindingContext context) { context.BindingParameters.Add(this); return context.BuildInnerChannelListener<TChannel>(); } public override bool CanBuildChannelFactory<TChannel>(BindingContext context) { context.BindingParameters.Add(this); return context.CanBuildInnerChannelFactory<TChannel>(); } public override bool CanBuildChannelListener<TChannel>(BindingContext context) { context.BindingParameters.Add(this); return context.CanBuildInnerChannelListener<TChannel>(); } public override MessageEncoderFactory CreateMessageEncoderFactory() { return new CryptEncoderFactory(innerMessageEncodingBindingElement,key,iv); } public override T GetProperty<T>(BindingContext context) { if (typeof(T) == typeof(XmlDictionaryReaderQuotas)) { return this.readerQuotas as T; } return base.GetProperty<T>(context); } public override MessageVersion MessageVersion { get { return innerMessageEncodingBindingElement.MessageVersion; } set { innerMessageEncodingBindingElement.MessageVersion = value; } } public override BindingElement Clone() { return new CryptEncodingBindingElement(innerMessageEncodingBindingElement,key,iv); } } }
CryptEncoderFactory
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel.Channels; namespace RobinLib { public class CryptEncoderFactory : MessageEncoderFactory { private MessageEncodingBindingElement innerMessageEncodingBindingElement; CryptEncoder messageEncoder; string key; string iv; public CryptEncoderFactory(MessageEncodingBindingElement innerMessageEncodingBindingElement, string key,string iv) { this.innerMessageEncodingBindingElement = innerMessageEncodingBindingElement; this.key = key; this.iv = iv; messageEncoder = new CryptEncoder(this,key, iv); } public override MessageEncoder CreateSessionEncoder() { return base.CreateSessionEncoder(); } public override MessageEncoder Encoder { get { return messageEncoder; } } public override MessageVersion MessageVersion { get { return innerMessageEncodingBindingElement.MessageVersion; } } public MessageEncodingBindingElement InnerMessageEncodingBindingElement { get { return innerMessageEncodingBindingElement; } } } }
CryptEncoder
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel.Channels; using System.IO; namespace RobinLib { public class CryptEncoder : MessageEncoder { CryptEncoderFactory factory; MessageEncoder innserEncoder; string key; string iv; public CryptEncoder(CryptEncoderFactory encoderFactory,string key,string iv) { factory = encoderFactory; this.key = key; this.iv = iv; innserEncoder = factory.InnerMessageEncodingBindingElement.CreateMessageEncoderFactory().Encoder; } public override string ContentType { get { return innserEncoder.ContentType; } } public override string MediaType { get { return innserEncoder.MediaType; } } public override MessageVersion MessageVersion { get { return innserEncoder.MessageVersion; } } public override bool IsContentTypeSupported(string contentType) { return innserEncoder.IsContentTypeSupported(contentType); } public override T GetProperty<T>() { return innserEncoder.GetProperty<T>(); } public override Message ReadMessage(ArraySegment<byte> buffer, BufferManager bufferManager, string contentType) { ArraySegment<byte> bytes = new DESCryption(key,iv).Decrypt(buffer); int totalLength = bytes.Count; byte[] totalBytes = bufferManager.TakeBuffer(totalLength); Array.Copy(bytes.Array, 0, totalBytes, 0, bytes.Count); ArraySegment<byte> byteArray = new ArraySegment<byte>(totalBytes, 0, bytes.Count); bufferManager.ReturnBuffer(byteArray.Array); Message msg = innserEncoder.ReadMessage(byteArray, bufferManager, contentType); return msg; } public override Message ReadMessage(System.IO.Stream stream, int maxSizeOfHeaders, string contentType) { //读取消息的时候,二进制流为加密的,需要解压 Stream ms = new DESCryption(key,iv).Decrypt(stream); Message msg = innserEncoder.ReadMessage(ms, maxSizeOfHeaders, contentType); return msg; } public override ArraySegment<byte> WriteMessage(Message message, int maxMessageSize, BufferManager bufferManager, int messageOffset) { ArraySegment<byte> bytes = innserEncoder.WriteMessage(message, maxMessageSize, bufferManager); ArraySegment<byte> buffer = new DESCryption(key,iv).Encrypt(bytes); int totalLength = buffer.Count + messageOffset; byte[] totalBytes = bufferManager.TakeBuffer(totalLength); Array.Copy(buffer.Array, 0, totalBytes, messageOffset, buffer.Count); ArraySegment<byte> byteArray = new ArraySegment<byte>(totalBytes, messageOffset, buffer.Count); Console.WriteLine(",原来字节流大小:"+bytes.Count+",压缩后字节流大小:"+byteArray.Count); return byteArray; } public override void WriteMessage(Message message, System.IO.Stream stream) { System.IO.MemoryStream ms = new System.IO.MemoryStream(); innserEncoder.WriteMessage(message, ms); stream = new DESCryption(key,iv).Encrypt(ms); } } }
DESCryption
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Security.Cryptography; using System.IO; namespace RobinLib { public class DESCryption : IDisposable { DESCryptoServiceProvider des; Encoding encoding = new UnicodeEncoding(); public DESCryption() { } public DESCryption(string key, string iv) { des = new DESCryptoServiceProvider(); des.Key = Convert.FromBase64String(key); des.IV = Convert.FromBase64String(iv); } public void Dispose() { des.Clear(); } public void GenerateKey(out string key, out string iv) { key = ""; iv = ""; using (DESCryptoServiceProvider des_o = new DESCryptoServiceProvider()) { des_o.GenerateIV(); des_o.GenerateKey(); iv = Convert.ToBase64String(des_o.IV); key = Convert.ToBase64String(des_o.Key); } } #region ========加密======== /// <summary> /// 加密数据 /// </summary> /// <param name="Text"></param> /// <param name="sKey"></param> /// <returns></returns> public string Encrypt(string Text) { MemoryStream ms = new MemoryStream(); CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write); StreamWriter sw = new StreamWriter(cs); sw.Write(Text); sw.Close(); cs.Close(); byte[] buffer = ms.ToArray(); ms.Close(); return Convert.ToBase64String(buffer); } public ArraySegment<byte> Encrypt(ArraySegment<byte> buffers) { MemoryStream ms = new MemoryStream(); CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write); cs.Write(buffers.Array, 0, buffers.Count); cs.Close(); byte[] buffer = ms.ToArray(); ms.Close(); ArraySegment<byte> bytes = new ArraySegment<byte>(buffer); return bytes; } public Stream Encrypt(Stream stream) { MemoryStream ms = new MemoryStream(); CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write); byte[] buffer = new byte[stream.Length]; stream.Read(buffer, 0, buffer.Length); cs.Write(buffer, 0, buffer.Length); cs.Close(); return ms; } #endregion #region ========解密======== /// <summary> /// 解密数据 /// </summary> /// <param name="Text"></param> /// <param name="sKey"></param> /// <returns></returns> public string Decrypt(string Text) { byte[] inputByteArray = Convert.FromBase64String(Text); System.IO.MemoryStream ms = new System.IO.MemoryStream(inputByteArray); CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Read); StreamReader sr = new StreamReader(cs); string val = sr.ReadLine(); cs.Close(); ms.Close(); des.Clear(); return val; } public ArraySegment<byte> Decrypt(ArraySegment<byte> buffers) { MemoryStream ms = new MemoryStream(); ms.Write(buffers.Array, 0, buffers.Count); ms.Seek(0, SeekOrigin.Begin); CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Read); byte[] buffer = RetrieveBytesFromStream(cs, 1024); ms.Close(); ArraySegment<byte> bytes = new ArraySegment<byte>(buffer); return bytes; } public Stream Decrypt(Stream stream) { stream.Seek(0, SeekOrigin.Begin); MemoryStream ms = new MemoryStream(); Stream compressStream = new CryptoStream(stream, des.CreateDecryptor(), CryptoStreamMode.Read); byte[] newByteArray = RetrieveBytesFromStream(compressStream, 1); compressStream.Close(); return new MemoryStream(newByteArray); } public static byte[] RetrieveBytesFromStream(Stream stream, int bytesblock) { List<byte> lst = new List<byte>(); byte[] data = new byte[1024]; int totalCount = 0; while (true) { int bytesRead = stream.Read(data, 0, data.Length); if (bytesRead == 0) { break; } byte[] buffers = new byte[bytesRead]; Array.Copy(data, buffers, bytesRead); lst.AddRange(buffers); totalCount += bytesRead; } return lst.ToArray(); } #endregion #region IDisposable 成员 void IDisposable.Dispose() { if (des != null) { des.Clear(); } } #endregion } }
宿主
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel; using Robin_Wcf_CustomMessageEncoder_SvcLib; using System.ServiceModel.Channels; using RobinLib; namespace Robin_Wcf_CustomMessageEncoder_Host { class Program { static void Main(string[] args) { //服务地址 Uri baseAddress = new Uri("http://127.0.0.1:8081/Robin_Wcf_Formatter"); ServiceHost host = new ServiceHost(typeof(Service1), new Uri[] { baseAddress }); //服务绑定 ICollection<BindingElement> bindingElements = new List<BindingElement>(); HttpTransportBindingElement httpBindingElement = new HttpTransportBindingElement(); string key = "JggkieIw7JM="; string iv = "XdTkT85fZ0U="; CryptEncodingBindingElement textBindingElement = new CryptEncodingBindingElement(new BinaryMessageEncodingBindingElement(), key,iv); bindingElements.Add(textBindingElement); bindingElements.Add(httpBindingElement); CustomBinding bind = new CustomBinding(bindingElements); host.AddServiceEndpoint(typeof(IService1), bind, ""); if (host.Description.Behaviors.Find<System.ServiceModel.Description.ServiceMetadataBehavior>() == null) { System.ServiceModel.Description.ServiceMetadataBehavior svcMetaBehavior = new System.ServiceModel.Description.ServiceMetadataBehavior(); svcMetaBehavior.HttpGetEnabled = true; svcMetaBehavior.HttpGetUrl = new Uri("http://127.0.0.1:8001/Mex"); host.Description.Behaviors.Add(svcMetaBehavior); } host.Opened += new EventHandler(delegate(object obj, EventArgs e) { Console.WriteLine("服务已经启动!"); }); host.Open(); Console.Read(); } } }
客户端
using System; using System.Collections.Generic; using System.Linq; using System.Text; using RobinLib; using System.ServiceModel.Channels; using Robin_Wcf_CustomMessageEncoder_ClientApp.ServiceReference1; namespace Robin_Wcf_CustomMessageEncoder_ClientApp { class Program { static void Main(string[] args) { System.Threading.Thread.Sleep(5300); ICollection<BindingElement> bindingElements = new List<BindingElement>(); HttpTransportBindingElement httpBindingElement = new HttpTransportBindingElement(); string key = "JggkieIw7JM="; string iv = "XdTkT85fZ0U="; CryptEncodingBindingElement textBindingElement = new CryptEncodingBindingElement(new BinaryMessageEncodingBindingElement(), key, iv); bindingElements.Add(textBindingElement); bindingElements.Add(httpBindingElement); CustomBinding bind = new CustomBinding(bindingElements); ServiceReference1.IService1 svc = new ServiceReference1.Service1Client(bind, new System.ServiceModel.EndpointAddress("http://127.0.0.1:8081/Robin_Wcf_Formatter")); string pres = svc.GetData(10); Console.WriteLine(pres); CompositeType ct = svc.GetDataUsingDataContract(new CompositeType()); System.IO.MemoryStream ms = new System.IO.MemoryStream(); for (int i = 0; i < 1000000; i++) { byte[] buffer = BitConverter.GetBytes(i); ms.Write(buffer, 0, buffer.Length); } System.IO.Stream stream = svc.GetStream(ms); Console.Read(); } } }
运行效果图:
生成key和iv的方法为:
public void GenerateKey(out string key, out string iv) { key = ""; iv = ""; using (DESCryptoServiceProvider des_o = new DESCryptoServiceProvider()) { des_o.GenerateIV(); des_o.GenerateKey(); iv = Convert.ToBase64String(des_o.IV); key = Convert.ToBase64String(des_o.Key); } }
项目文档:点击这里下载
作者:jillzhang
出处:http://jillzhang.cnblogs.com/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
出处:http://jillzhang.cnblogs.com/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。