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();

        }

    }

}

运行效果图:

image

image

 

生成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);

    }

}

项目文档:点击这里下载

你可能感兴趣的:(对称加密)