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

    项目文档:点击这里下载

  • 相关阅读:
    分享知识-快乐自己:Shiro 退出登陆清空缓存实现
    分享知识-快乐自己:复选框、全选/反选/获取值
    分享知识-快乐自己:初中级 java 面试题宝典
    分享知识-快乐自己:Liunx 搭建 Dubbo
    分享知识-快乐自己:Liunx 安装 Zookeeper
    分享知识-快乐自己:揭秘HDFS
    计算文件的长度
    fgetc, getchar(), fscanf的问题
    绘制数学函数图像
    C语言遍历一个文件夹下面的所有文件
  • 原文地址:https://www.cnblogs.com/jordan2009/p/1862088.html
Copyright © 2011-2022 走看看