国家商用密码(11)在Netty 5.0.X上实现文本流的SM4编解码器

同系列文章:

源代码出售:

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

源代码:
SM4TextToMessageCodec.java

/* ----------------------------------------------------------
 * 文件名称:SM4TextToMessageCodec.java
 *
 * 作者:秦建辉
 *
 * QQ:36748897
 *
 * 博客:http://www.firstsolver.com/wordpress/
 *
 * 开发环境:
 *      NetBeans 8.1
 *      JDK 8u66
 *
 * 版本历史:
 *	V1.0    2016年02月02日
 *              在Netty 5.0.X上实现文本流的SM4编解码器
 * ------------------------------------------------------------ */
package Com.FirstSolver.Security;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.handler.codec.ByteToMessageCodec;
import io.netty.util.AttributeKey;
import java.io.IOException;
import java.nio.ByteOrder;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;

public class SM4TextToMessageCodec extends ByteToMessageCodec<String> {    
    // 编码器
    private static final AttributeKey<SM4> KEY_ENCRYPTOR = AttributeKey.valueOf(SM4TextToMessageCodec.class, "Encryptor");
    
    // 解码器
    private static final AttributeKey<SM4> KEY_DECRYPTOR = AttributeKey.valueOf(SM4TextToMessageCodec.class, "Decryptor"); 
    
    // 通信密钥
    private static final AttributeKey<String> KEY_SECRETKEY = AttributeKey.valueOf(SM4TextToMessageCodec.class, "SecretKey");    

    // 构造函数
    public SM4TextToMessageCodec() 
    {
        this(CipherMode.OFB, PaddingMode.PKCS7, StandardCharsets.UTF_8);
    }

    // 构造函数
    public SM4TextToMessageCodec(CipherMode mode) 
    {
        this(mode, PaddingMode.PKCS7, StandardCharsets.UTF_8);
    }
	
    // 构造函数
    public SM4TextToMessageCodec(CipherMode mode, PaddingMode padding) 
    {
        this(mode, padding, StandardCharsets.UTF_8);
    }
    
    /*
    功能:构造函数
    参数说明:
        mode:运算模式,支持ECB、CBC、CFB、OFB(默认)、PCBC
        padding:填充模式,支持PKCS7(默认)、ANSIX923、ISO10126、ISO7816、Zeros、None
        charset:字符集编码
    */
    public SM4TextToMessageCodec(CipherMode mode, PaddingMode padding, Charset charset) 
    {
        if (mode.getValue() > 4) throw new IllegalArgumentException("Unsupported cipher mode!");
        
        mMode = mode;
        mPadding = padding;
        mCharset = charset;
    }
    
    /*
    功能:构造函数
    参数说明:
        mode:运算模式,支持ECB、CBC、CFB、OFB(默认)、PCBC
        padding:填充模式,支持PKCS7(默认)、ANSIX923、ISO10126、ISO7816、Zeros、None
        charset:字符集名称
    */
    public SM4TextToMessageCodec(CipherMode mode, PaddingMode padding, String charset)
    { 
        this(mode, padding, Charset.forName(charset));
    }
    
    // 编码
    @Override
    protected void encode(io.netty.channel.ChannelHandlerContext ctx, String msg, io.netty.buffer.ByteBuf out) throws Exception
    {   // 将字符串转换为字节数组
        byte[] Source = msg.getBytes(mCharset);
        
        // 获取加密密钥
        String SecretKey = ctx.attr(KEY_SECRETKEY).get();
        if (!Utils.IsNullOrEmpty(SecretKey))
        {   // 对数据进行对称加密
            SM4 Encryptor = getEncryptor(ctx, SecretKey);
            Source = Encryptor.TransformFinalBlock(Source, 0, Source.length);   
        }
        
        out.writeBytes(Utils.GetBytes(Source.length, ByteOrder.BIG_ENDIAN));
        out.writeBytes(Source);
        ctx.flush();
    }

    // 解码
    @Override
    protected void decode(io.netty.channel.ChannelHandlerContext ctx, io.netty.buffer.ByteBuf in, List<Object> out) throws Exception
    {
        if (in.readableBytes() > 4)
        {
            in.markReaderIndex();
            int Size = in.readInt();  
            if(in.readableBytes() >= Size)
            {
                byte[] Source = new byte[Size];
                in.readBytes(Source);

                // 获取解密密钥
                String SecretKey = ctx.attr(KEY_SECRETKEY).get();
                if (Utils.IsNullOrEmpty(SecretKey)) 
                {   // 直接输出明文数据
                    out.add(new String(Source, mCharset));
                }
                else
                {   // 输出解密后的数据
                    SM4 Decryptor = getDecryptor(ctx, SecretKey);
                    out.add(new String(Decryptor.TransformFinalBlock(Source, 0, Size), mCharset));
                }
            }
            else
            {	// 回到标记位置
                in.resetReaderIndex();
            }
        }
    }
    
    // 释放资源
    @Override
    public void close(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception
    {   // 释放加密器
        SM4 Encryptor = ctx.attr(KEY_ENCRYPTOR).get();
        if (Encryptor != null) Encryptor.close();
        
        // 释放解密器
        SM4 Decryptor = ctx.attr(KEY_DECRYPTOR).get();
        if (Decryptor != null) Decryptor.close();
        
        // 移去属性键
        ctx.attr(KEY_ENCRYPTOR).remove();
        ctx.attr(KEY_DECRYPTOR).remove();
        ctx.attr(KEY_SECRETKEY).remove();
    }
    
    // 获取加密器
    private SM4 getEncryptor(io.netty.channel.ChannelHandlerContext ctx, String SecretKey) throws IOException 
    {
        SM4 Encryptor = ctx.attr(KEY_ENCRYPTOR).get();
        if (Encryptor == null)
        {
            Encryptor = new SM4(CipherDirection.Encryption, mMode, mPadding);
            byte[] DerivedVector = SM3.KDF(SecretKey.getBytes("UTF-8"), 32);
            Encryptor.Initialize(Arrays.copyOfRange(DerivedVector, 0, 16), Arrays.copyOfRange(DerivedVector, 16, 32));
            ctx.attr(KEY_ENCRYPTOR).set(Encryptor);
        }
        
        return Encryptor;
    }
    
    // 获取解密器
    private SM4 getDecryptor(io.netty.channel.ChannelHandlerContext ctx, String SecretKey) throws IOException 
    {
        SM4 Decryptor = ctx.attr(KEY_DECRYPTOR).get();
        if (Decryptor == null)
        {
            Decryptor = new SM4(CipherDirection.Decryption, mMode, mPadding);
            byte[] DerivedVector = SM3.KDF(SecretKey.getBytes("UTF-8"), 32);
            Decryptor.Initialize(Arrays.copyOfRange(DerivedVector, 0, 16), Arrays.copyOfRange(DerivedVector, 16, 32));
            ctx.attr(KEY_DECRYPTOR).set(Decryptor);
        }
        
        return Decryptor;
    }

    // 获取字符集编码
    public Charset getCharset() { return mCharset; }
	
    // 设置加密密钥
    public static void setSecretKey(io.netty.channel.ChannelHandlerContext ctx, String key)
    {
        ctx.attr(KEY_SECRETKEY).set(key);
    }

    // 获取加密密钥
    public static String getSecretKey(io.netty.channel.ChannelHandlerContext ctx)
    { 
        return ctx.attr(KEY_SECRETKEY).get();
    }
    
    // 运算模式,支持ECB、CBC、CFB、OFB(默认)、PCBC
    private CipherMode mMode;
    
    // 填充模式,支持PKCS7(默认)、ANSIX923、ISO10126、ISO7816、Zeros、None
    private PaddingMode mPadding;
    
    // 字符集编码,默认为UTF-8
    private final Charset mCharset;
}

Comments are closed.