zoukankan      html  css  js  c++  java
  • 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);
        }
    }

    项目文档:点击这里下载

    作者:jillzhang
    出处:http://jillzhang.cnblogs.com/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    Fiddler系列教程3:使用Fiddler录制Jmeter性能测试脚本
    PySide6读取EXCLE文档
    C#实现操作DOS命令的方法
    在PyCharm中调用xlrd模块出现 ModuleNotFoundError: No module named 'xlrd' ,但在sublime却可以正常
    pip安装时出现错误:File "D:Python39Scriptspip.exe\__main__.py", line 4, in <module> ModuleNotFoundError: No module named 'pip'
    /ect/fstab与/etc/mtab的区别
    虚拟机中Ubuntu系统修改分辨率
    关于报错Could not load file or assembly的问题
    关于WinCC归档应该知道的事
    vue + element 表单的简单公用组件,表格的集成写法
  • 原文地址:https://www.cnblogs.com/jillzhang/p/1711355.html
Copyright © 2011-2022 走看看