国家商用密码(13)在DotNetty 0.4.5上实现文本流的SM4编解码器

同系列文章:

源代码出售:

sell
价格:壹仟元人民币
微信:splashcn

源代码:
SM4TextToMessageCodec.cs

/* ----------------------------------------------------------
 * 文件名称:SM4TextToMessageCodec.cs
 *
 * 作者:秦建辉
 *
 * 微信:splashcn
 *
 * 博客:http://www.firstsolver.com/wordpress/
 *
 * 开发环境:
 *      Visual Studio V2017
 *      .NET Framework 4.5.2
 *      DotNetty 0.4.5
 *
 * 版本历史:
 *	    V1.0    2017年06月28日
 *			    基于DotNetty框架的SM4文本编解码器
 *
 * 参考资料:
 *      https://github.com/Azure/DotNetty
 * ------------------------------------------------------------ */
using Com.FirstSolver.Security;
using DotNetty.Buffers;
using DotNetty.Common.Utilities;
using DotNetty.Transport.Channels;
using System;
using System.Text;
using System.Threading.Tasks;

namespace Com.FirstSolver.Netty
{
    /// <summary>
    /// SM4文本编解码器
    /// </summary>
    public class SM4TextToMessageCodec : ChannelHandlerAdapter
    {
        /// <summary>
        /// 属性键:加密器
        /// </summary>
        private static readonly AttributeKey<SM4> KEY_ENCRYPTOR = AttributeKey<SM4>.ValueOf(typeof(SM4TextToMessageCodec), "Encryptor");

        /// <summary>
        /// 属性键:解密器
        /// </summary>
        private static readonly AttributeKey<SM4> KEY_DECRYPTOR = AttributeKey<SM4>.ValueOf(typeof(SM4TextToMessageCodec), "Decryptor");

        /// <summary>
        /// 属性键:通信密钥
        /// </summary>
        private static readonly AttributeKey<string> KEY_SECRETKEY = AttributeKey<string>.ValueOf(typeof(SM4TextToMessageCodec), "SecretKey");

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="mode">运算模式,支持ECB、CBC、CFB、OFB(默认)、PCBC</param>
        /// <param name="padding">填充模式,支持PKCS7(默认)、ANSIX923、ISO10126、ISO7816、Zeros、None</param>
        /// <param name="codepage">字符集代码页,默认为UTF-8字符集</param>
        public SM4TextToMessageCodec(CipherMode mode = CipherMode.OFB, PaddingMode padding = PaddingMode.PKCS7, int codepage = 65001)
        {
            if ((int)mode > 4) throw new ArgumentOutOfRangeException("Unsupported cipher mode!");

            Mode = mode;
            Padding = padding;
            Codepage = codepage;
            mEncoding = Encoding.GetEncoding(codepage);
        }

        public override bool IsSharable => true;

        public virtual bool AcceptOutboundMessage(object message) => message is string;

        public virtual bool AcceptInboundMessage(object message) => message is IByteBuffer;

        /// <summary>
        /// 异步写操作
        /// </summary>
        /// <param name="context">通道处理器上下文</param>
        /// <param name="message">要发送的文本字符串</param>
        /// <returns>异步操作</returns>
        public override Task WriteAsync(IChannelHandlerContext context, object message)
        {
            if (AcceptOutboundMessage(message))
            {   // 将字符串转换为字节数组
                byte[] Source = mEncoding.GetBytes((string)message);

                // 获取加密密钥
                string SecretKey = context.GetAttribute<string>(KEY_SECRETKEY).Get();
                if (!string.IsNullOrEmpty(SecretKey))
                {   // 对数据进行对称加密
                    SM4 Encryptor = GetEncryptor(context, SecretKey);
                    Source = Encryptor.TransformFinalBlock(Source, 0, Source.Length);
                }

                IByteBuffer Buffer = context.Allocator.Buffer(4 + Source.Length);
                Buffer.WriteInt(Source.Length); // 按BigEndian字节序写入长度信息
                Buffer.WriteBytes(Source);
                return context.WriteAsync(Buffer);
            }
            else
            {
                return context.WriteAsync(message);
            }
        }

        /// <summary>
        /// 通道读操作
        /// </summary>
        /// <param name="context">通道处理器上下文</param>
        /// <param name="message">要处理的消息对象</param>
        public override void ChannelRead(IChannelHandlerContext context, object message)
        {
            if (AcceptInboundMessage(message))
            {
                IByteBuffer Buffer = (IByteBuffer)message;
                if (Buffer.ReadableBytes > 4)
                {
                    Buffer.MarkReaderIndex();
                    int Size = Buffer.ReadInt();
                    if (Buffer.ReadableBytes >= Size)
                    {
                        byte[] Source = new byte[Size];
                        Buffer.ReadBytes(Source);

                        // 获取解密密钥
                        String SecretKey = context.GetAttribute<string>(KEY_SECRETKEY).Get();
                        if (string.IsNullOrEmpty(SecretKey))
                        {   // 直接输出明文数据
                            context.FireChannelRead(mEncoding.GetString(Source));
                        }
                        else
                        {   // 输出解密后的数据
                            SM4 Decryptor = GetDecryptor(context, SecretKey);
                            context.FireChannelRead(mEncoding.GetString(Decryptor.TransformFinalBlock(Source, 0, Size)));
                        }
                    }
                    else
                    {   // 回到标记位置
                        Buffer.ResetReaderIndex();
                    }
                }
            }
            else
            {
                context.FireChannelRead(message);
            }
        }

        /// <summary>
        /// 通道处理器关闭异步处理
        /// </summary>
        /// <param name="context">通道处理器上下文</param>
        /// <returns>通道处理器关闭异步任务</returns>
        public override Task CloseAsync(IChannelHandlerContext context)
        {
            // 释放加密器
            SM4 Encryptor = context.GetAttribute<SM4>(KEY_ENCRYPTOR).Get();
            if (Encryptor != null) Encryptor.Dispose();

            // 释放解密器
            SM4 Decryptor = context.GetAttribute<SM4>(KEY_DECRYPTOR).Get();
            if (Decryptor != null) Decryptor.Dispose();

            return base.CloseAsync(context);
        }

        /// <summary>
        /// 获取加密器
        /// </summary>
        /// <param name="context">通道处理器上下文内容</param>
        /// <param name="secretKey">通信密钥</param>
        /// <returns>加密器</returns>
        private SM4 GetEncryptor(IChannelHandlerContext context, string secretKey)
        {
            SM4 Encryptor = context.GetAttribute<SM4>(KEY_ENCRYPTOR).Get();
            if (Encryptor == null)
            {
                Encryptor = new SM4(CipherDirection.Encryption, Mode, Padding);
                byte[] DerivedVector = SM3.KDF(Encoding.UTF8.GetBytes(secretKey), 32);

                // 对称加密私密密钥
                byte[] Key = new byte[16];
                Array.Copy(DerivedVector, 0, Key, 0, 16);

                // 对称加密初始向量
                byte[] IV = new byte[16];
                Array.Copy(DerivedVector, 16, IV, 0, 16);

                // 初始化加密器和解密器
                Encryptor.Initialize(Key, IV);
                context.GetAttribute<SM4>(KEY_ENCRYPTOR).Set(Encryptor);
            }
            return Encryptor;
        }

        /// <summary>
        /// 获取解密器
        /// </summary>
        /// <param name="context">通道处理器上下文内容</param>
        /// <param name="secretKey">通信密钥</param>
        /// <returns>解密器</returns>
        private SM4 GetDecryptor(IChannelHandlerContext context, string secretKey)
        {
            SM4 Decryptor = context.GetAttribute<SM4>(KEY_DECRYPTOR).Get();
            if (Decryptor == null)
            {
                Decryptor = new SM4(CipherDirection.Decryption, Mode, Padding);
                byte[] DerivedVector = SM3.KDF(Encoding.UTF8.GetBytes(secretKey), 32);

                // 对称加密私密密钥
                byte[] Key = new byte[16];
                Array.Copy(DerivedVector, 0, Key, 0, 16);

                // 对称加密初始向量
                byte[] IV = new byte[16];
                Array.Copy(DerivedVector, 16, IV, 0, 16);

                // 初始化加密器和解密器
                Decryptor.Initialize(Key, IV);
                context.GetAttribute<SM4>(KEY_DECRYPTOR).Set(Decryptor);
            }
            return Decryptor;
        }

        /// <summary>
        /// 获取通信密钥
        /// </summary>
        /// <param name="context">通道处理器上下文内容</param>
        /// <returns>通信密钥</returns>
        public static string GetSecretKey(IChannelHandlerContext context)
        {
            return context.GetAttribute<string>(KEY_SECRETKEY).Get();
        }

        /// <summary>
        /// 设置通信密钥
        /// </summary>
        /// <param name="context">通道处理器上下文内容</param>
        /// <param name="key">通信密钥</param>
        public static void SetSecretKey(IChannelHandlerContext context, string key)
        {
            context.GetAttribute<string>(KEY_SECRETKEY).Set(key);
        }

        /// <summary>
        /// 运算模式,支持ECB、CBC、CFB、OFB(默认)、PCBC
        /// </summary>
        public readonly CipherMode Mode;

        /// <summary>
        /// 填充模式,支持PKCS7(默认)、ANSIX923、ISO10126、ISO7816、Zeros、None
        /// </summary>
        public readonly PaddingMode Padding;

        /// <summary>
        /// 字符集代码页,默认为65001(UTF-8)
        /// </summary>
        public readonly int Codepage;

        /// <summary>
        /// 字符编码
        /// </summary>
        private readonly Encoding mEncoding;
    }
}

例子程序:

Comments are closed.