国家商用密码(十)在Apache MINA上实现文本流数据报文的SM4编解码器

同系列文章:

功能描述:

  1. 在Apache MINA上实现二进制流的SM4编解码器
  2. 在Apache MINA上实现文本流的SM4编解码器
  3. 在Apache MINA上实现二进制流数据报文的SM4编解码器
  4. 在Apache MINA上实现文本流数据报文的SM4编解码器
  5. 各个IoSession可独立设置通信密钥

源代码出售:

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

jar包及测试程序下载:

SM4CodecFactory 2015-11-05.zip

源代码:
SM4TextDatagramCodecFactory.java

/* ----------------------------------------------------------
 * 文件名称:SM4TextDatagramCodecFactory.java
 * 
 * 作者:秦建辉
 * 
 * QQ:36748897
 * 
 * 博客:http://www.firstsolver.com/wordpress/
 * 
 * 开发环境:
 *      NetBeans 8.0.2
 *      JDK 8u66
 *      
 * 版本历史:
 *      V1.0    2015年11月05日
 *              在Apache MINA上实现文本流数据报文的SM4编解码器
------------------------------------------------------------ */
package Com.FirstSolver.Security;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFactory;
import org.apache.mina.filter.codec.ProtocolDecoder;
import org.apache.mina.filter.codec.ProtocolEncoder;

public class SM4TextDatagramCodecFactory implements ProtocolCodecFactory {	
	// 编码器
	private final SM4TextDatagramEncoderAdapter mEncoder;

	// 解码器
    private final SM4TextDatagramDecoderAdapter mDecoder;

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

	// 构造函数
	public SM4TextDatagramCodecFactory(CipherMode mode) {
		this(mode, PaddingMode.PKCS7, StandardCharsets.UTF_8);
    }
	
	// 构造函数
	public SM4TextDatagramCodecFactory(CipherMode mode, PaddingMode padding) {
		this(mode, padding, StandardCharsets.UTF_8);
    }
	
	/* 
	功能:构造函数
	参数说明:
		mode:运算模式,支持ECB、CBC、CFB、OFB(默认)、PCBC
		padding:填充模式,支持PKCS7(默认)、ANSIX923、ISO10126、ISO7816、Zeros、None
		charset:字符集编码,默认为UTF-8
	*/
	public SM4TextDatagramCodecFactory(CipherMode mode, PaddingMode padding, Charset charset) {
		if (mode.getValue() > 4) throw new IllegalArgumentException("Unsupported cipher mode!");
		
		mEncoder = new SM4TextDatagramEncoderAdapter(mode, padding, charset);
		mDecoder = new SM4TextDatagramDecoderAdapter(mode, padding, charset);
    }

	// 获取编码器
	@Override
    public ProtocolEncoder getEncoder(IoSession session) {
        return mEncoder;
    }

	// 获取解码器
	@Override
    public ProtocolDecoder getDecoder(IoSession session) {
        return mDecoder;
    }
	
	// 设置编码器加密密钥
    public static void setEncoderKey(IoSession session, String value){
		SM4TextDatagramEncoderAdapter.setSecretKey(session, value);
    }
	
	// 设置解码器解密密钥
    public static void setDecoderKey(IoSession session, String value){
		SM4TextDatagramDecoderAdapter.setSecretKey(session, value);
    }

	// 获取编码器加密密钥
    public static String getEncoderKey(IoSession session) 
	{ 
		return (String)SM4TextDatagramEncoderAdapter.getSecretKey(session); 
	}
	
	// 获取解码器解密密钥
    public static String getDecoderKey(IoSession session) 
	{ 
		return (String)SM4TextDatagramDecoderAdapter.getSecretKey(session);
	}
	
	// 获取编码器字符集编码
	public Charset getEncoderCharset() { return mEncoder.getCharset(); }
	
	// 获取解码器字符集编码
	public Charset getDecoderCharset() { return mDecoder.getCharset(); }
}

SM4TextDatagramEncoderAdapter.java

/* ----------------------------------------------------------
 * 文件名称:SM4TextDatagramEncoderAdapter.java
 * 
 * 作者:秦建辉
 * 
 * QQ:36748897
 * 
 * 博客:http://www.firstsolver.com/wordpress/
 * 
 * 开发环境:
 *      NetBeans 8.0.2
 *      JDK 8u66
 *      
 * 版本历史:
 *      V1.0    2015年11月05日
 *              文本流数据报文的SM4编码器
------------------------------------------------------------ */
package Com.FirstSolver.Security;

import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.AttributeKey;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolEncoder;
import org.apache.mina.filter.codec.ProtocolEncoderOutput;

public class SM4TextDatagramEncoderAdapter implements ProtocolEncoder {		
	// 加密器属性键
	private static final AttributeKey KEY_ENCRYPTOR = new AttributeKey(SM4TextDatagramEncoderAdapter.class, "Encryptor");
	
	// 加密密钥属性键
	private static final AttributeKey KEY_SECRETKEY = new AttributeKey(SM4TextDatagramEncoderAdapter.class, "SecretKey");

	// 块密码工作模式
	protected final CipherMode mMode;
	
	// 消息数据块填充类型
	protected final PaddingMode mPadding;
		
	// 字符集编码
	protected final Charset mCharset;
		
	// 构造函数
	public SM4TextDatagramEncoderAdapter() {
        this(CipherMode.OFB, PaddingMode.PKCS7, StandardCharsets.UTF_8);
    }

	// 构造函数
	public SM4TextDatagramEncoderAdapter(CipherMode mode) {
        this(mode, PaddingMode.PKCS7, StandardCharsets.UTF_8);
    }
	
	// 构造函数
	public SM4TextDatagramEncoderAdapter(CipherMode mode, PaddingMode padding) {
		this(mode, padding, StandardCharsets.UTF_8);
	}
	
	/* 
	功能:构造函数
	参数说明:
		mode:运算模式,支持ECB、CBC、CFB、OFB(默认)、PCBC
		padding:填充模式,支持PKCS7(默认)、ANSIX923、ISO10126、ISO7816、Zeros、None
		charset:字符集编码,默认为UTF-8
	*/
	public SM4TextDatagramEncoderAdapter(CipherMode mode, PaddingMode padding, Charset charset) {
		if (mode.getValue() > 4) throw new IllegalArgumentException("Unsupported cipher mode!");
		
		mMode = mode;
		mPadding = padding;
		mCharset = charset;
    }
	
	@Override
    public void encode(IoSession session, Object message, ProtocolEncoderOutput out) throws Exception {		
		// 对数据进行对称加密
		byte[] Source = message.toString().getBytes(mCharset);
		
		// 获取加密密钥
		String SecretKey = (String)session.getAttribute(KEY_SECRETKEY);
		if (Utils.IsNullOrEmpty(SecretKey))
		{	// 直接发送明文数据			
			IoBuffer Buffer = IoBuffer.allocate(Source.length);
			Buffer.put(Source);
			Buffer.flip();
			out.write(Buffer);			
		}
		else
		{	// 对数据进行对称加密
			SM4 Encryptor = getEncryptor(session, SecretKey);
			byte[] Cipher = Encryptor.TransformFinalBlock(Source, 0, Source.length);
			
			// 发送密文数据
			IoBuffer Buffer = IoBuffer.allocate(Cipher.length);
			Buffer.put(Cipher);
			Buffer.flip();
			out.write(Buffer);
		}
		
		out.flush();	// 刷新缓冲区
    }
	
	// 释放资源
	@Override
	public void dispose(IoSession session) throws Exception
	{	// 释放加密器
		SM4 Encryptor = (SM4)session.getAttribute(KEY_ENCRYPTOR);
		if (Encryptor != null) Encryptor.close();
		
		// 清除属性
		session.removeAttribute(KEY_ENCRYPTOR);
		session.removeAttribute(KEY_SECRETKEY);
	}

	// 获取加密器
	private SM4 getEncryptor(IoSession session, String SecretKey) throws IOException{
		// 获取加密器
		SM4 Encryptor = (SM4)session.getAttribute(KEY_ENCRYPTOR);
		if (Encryptor == null) {
			// 通过密钥派生函数获得对称加密密钥和初始向量
			byte[] DerivedVector = SM3.KDF(SecretKey.getBytes("UTF-8"), 32);

			// SM4加密器
			Encryptor = new SM4(CipherDirection.Encryption, mMode, mPadding);
			Encryptor.Initialize(Arrays.copyOfRange(DerivedVector, 0, 16), Arrays.copyOfRange(DerivedVector, 16, 32));

			// 设置加密器属性
			session.setAttribute(KEY_ENCRYPTOR, Encryptor);
        }
		
		return Encryptor;
	}
	
	// 获取字符集编码
	public Charset getCharset() { return mCharset; }
	
	// 设置加密密钥
    public static void setSecretKey(IoSession session, String value){
		session.setAttribute(KEY_SECRETKEY, value);
    }

	// 获取加密密钥
    public static String getSecretKey(IoSession session) { 
		return (String)session.getAttribute(KEY_SECRETKEY); 
	}
}

SM4TextDatagramDecoderAdapter.java

/* ----------------------------------------------------------
 * 文件名称:SM4TextDatagramDecoderAdapter.java
 * 
 * 作者:秦建辉
 * 
 * QQ:36748897
 * 
 * 博客:http://www.firstsolver.com/wordpress/
 * 
 * 开发环境:
 *      NetBeans 8.0.2
 *      JDK 8u66
 *      
 * 版本历史:
 *      V1.0    2015年11月05日
 *              文本流数据报文的SM4解码器
------------------------------------------------------------ */
package Com.FirstSolver.Security;

import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;
import java.util.Arrays;
import org.apache.mina.core.session.AttributeKey;
import org.apache.mina.filter.codec.ProtocolDecoder;

public class SM4TextDatagramDecoderAdapter implements ProtocolDecoder {
    // 解密器属性键
	private static final AttributeKey KEY_DECRYPTOR = new AttributeKey(SM4TextDatagramDecoderAdapter.class, "Decryptor");
	
	// 解密密钥属性键
	private static final AttributeKey KEY_SECRETKEY = new AttributeKey(SM4TextDatagramDecoderAdapter.class, "SecretKey");

	// 块密码工作模式
	protected final CipherMode mMode;
	
	// 消息数据块填充类型
	protected final PaddingMode mPadding;
		
	// 字符集编码
	protected final Charset mCharset;
		
	// 构造函数
	public SM4TextDatagramDecoderAdapter() {
        this(CipherMode.OFB, PaddingMode.PKCS7, StandardCharsets.UTF_8);
    }

	// 构造函数
	public SM4TextDatagramDecoderAdapter(CipherMode mode) {
        this(mode, PaddingMode.PKCS7, StandardCharsets.UTF_8);
    }
	
	// 构造函数
	public SM4TextDatagramDecoderAdapter(CipherMode mode, PaddingMode padding) {
		this(mode, padding, StandardCharsets.UTF_8);
	}
	
	/* 
	功能:构造函数
	参数说明:
		mode:运算模式,支持ECB、CBC、CFB、OFB(默认)、PCBC
		padding:填充模式,支持PKCS7(默认)、ANSIX923、ISO10126、ISO7816、Zeros、None
		charset:字符集编码,默认为UTF-8
	*/
	public SM4TextDatagramDecoderAdapter(CipherMode mode, PaddingMode padding, Charset charset) {
		if (mode.getValue() > 4) throw new IllegalArgumentException("Unsupported cipher mode!");
		
		mMode = mode;
		mPadding = padding;
		mCharset = charset;
    }
	
	@Override
	public void decode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception {
		int size = in.remaining();
		if (size > 0)
		{	// 获取密文数据
			byte[] Source = new byte[size];
			in.get(Source);

			// 获取解密密钥
			String SecretKey = (String)session.getAttribute(KEY_SECRETKEY);
			if (Utils.IsNullOrEmpty(SecretKey))
			{	// 直接输出明文数据
				out.write(new String(Source, mCharset));
			}
			else
			{	// 输出解密后的数据
				SM4 Decryptor = getDecryptor(session, SecretKey);
				out.write(new String(Decryptor.TransformFinalBlock(Source, 0, Source.length), mCharset));
			}
		}
	}

	@Override
	public void finishDecode(IoSession session, ProtocolDecoderOutput out) throws Exception {
		
	}
	
	// 释放资源
	@Override
	public void dispose(IoSession session) throws Exception {
		SM4 Decryptor = (SM4)session.getAttribute(KEY_DECRYPTOR);
		if (Decryptor != null) Decryptor.close();
		
		session.removeAttribute(KEY_DECRYPTOR);
		session.removeAttribute(KEY_SECRETKEY);
	}
	
	// 获取解密器
	private SM4 getDecryptor(IoSession session, String SecretKey) throws IOException{
		// 获取解密器
		SM4 Decryptor = (SM4)session.getAttribute(KEY_DECRYPTOR);
		if (Decryptor == null) {
			// 通过密钥派生函数获得对称加密私密密钥和初始向量
			byte[] DerivedVector = SM3.KDF(SecretKey.getBytes("UTF-8"), 32);

			// SM4解密器
			Decryptor = new SM4(CipherDirection.Decryption, mMode, mPadding);
			Decryptor.Initialize(Arrays.copyOfRange(DerivedVector, 0, 16), Arrays.copyOfRange(DerivedVector, 16, 32));

			// 设置解密器属性
			session.setAttribute(KEY_DECRYPTOR, Decryptor);
        }
		
		return Decryptor;
	}
	
	// 获取字符集编码
	public Charset getCharset() { return mCharset; }
	
	// 设置解密密钥
    public static void setSecretKey(IoSession session, String value) {
		session.setAttribute(KEY_SECRETKEY, value);
    }

	// 获取解密密钥
    public static String getSecretKey(IoSession session) { 
		return (String)session.getAttribute(KEY_SECRETKEY); 
	}	
}

Comments are closed.