国家商用密码(八)在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

源代码:
SM4TextCodecFactory.java

/* ----------------------------------------------------------
 * 文件名称:SM4TextCodecFactory.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 SM4TextCodecFactory implements ProtocolCodecFactory {
	// 编码器
	private final SM4TextEncoderAdapter mEncoder;

	// 解码器
    private final SM4TextCumulativeDecoder mDecoder;

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

	// 构造函数
	public SM4TextCodecFactory(CipherMode mode) {
		this(mode, PaddingMode.PKCS7, StandardCharsets.UTF_8);
    }
	
	// 构造函数
	public SM4TextCodecFactory(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 SM4TextCodecFactory(CipherMode mode, PaddingMode padding, Charset charset) {
		if (mode.getValue() > 4) throw new IllegalArgumentException("Unsupported cipher mode!");
		
		mEncoder = new SM4TextEncoderAdapter(mode, padding, charset);
		mDecoder = new SM4TextCumulativeDecoder(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){
		SM4TextEncoderAdapter.setSecretKey(session, value);
    }
	
	// 设置解码器解密密钥
    public static void setDecoderKey(IoSession session, String value){
		SM4TextCumulativeDecoder.setSecretKey(session, value);
    }

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

SM4TextEncoderAdapter.java

/* ----------------------------------------------------------
 * 文件名称:SM4TextEncoderAdapter.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.ByteOrder;
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 SM4TextEncoderAdapter implements ProtocolEncoder {
	// 编码器属性键
	private static final AttributeKey KEY_ENCRYPTOR = new AttributeKey(SM4TextEncoderAdapter.class, "Encryptor");
	
	// 加密密钥属性键
	private static final AttributeKey KEY_SECRETKEY = new AttributeKey(SM4TextEncoderAdapter.class, "SecretKey");

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

	// 构造函数
	public SM4TextEncoderAdapter(CipherMode mode) {
        this(mode, PaddingMode.PKCS7, StandardCharsets.UTF_8);
    }
	
	// 构造函数
	public SM4TextEncoderAdapter(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 SM4TextEncoderAdapter(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 + 4);
			Buffer.put(Utils.GetBytes(Source.length, ByteOrder.BIG_ENDIAN));
			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 + 4);
			Buffer.put(Utils.GetBytes(Cipher.length, ByteOrder.BIG_ENDIAN));
			Buffer.put(Cipher);
			Buffer.flip();
			out.write(Buffer);
		}
    }
	
	// 释放资源
	@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); 
	}
}

SM4TextCumulativeDecoder.java

/* ----------------------------------------------------------
 * 文件名称:SM4TextCumulativeDecoder.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.ByteOrder;
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.CumulativeProtocolDecoder;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;

public class SM4TextCumulativeDecoder extends CumulativeProtocolDecoder {
	// 解码器属性键
	private static final AttributeKey KEY_DECRYPTOR = new AttributeKey(SM4TextCumulativeDecoder.class, "Decryptor");
	
	// 解密密钥属性键
	private static final AttributeKey KEY_SECRETKEY = new AttributeKey(SM4TextCumulativeDecoder.class, "SecretKey");

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

	// 构造函数
	public SM4TextCumulativeDecoder(CipherMode mode) {
        this(mode, PaddingMode.PKCS7, StandardCharsets.UTF_8);
    }
	
	// 构造函数
	public SM4TextCumulativeDecoder(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 SM4TextCumulativeDecoder(CipherMode mode, PaddingMode padding, Charset charset) {
		if (mode.getValue() > 4) throw new IllegalArgumentException("Unsupported cipher mode!");
		
		mMode = mode;
		mPadding = padding;
		mCharset = charset;
    }

	@Override
	protected boolean doDecode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception {
		if (in.remaining() > 4) {			
			in.mark();	// 标记当前位置	
			byte[] sizeByteArray = new byte[4];
			in.get(sizeByteArray);			
			int size = Utils.ToInt32(sizeByteArray, 0, ByteOrder.BIG_ENDIAN);
			
			if(in.remaining() >= size)
			{
				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, size), mCharset));
				}
				
				if (in.hasRemaining()) return true;
			}
			else
			{	// 回到标记位置
				in.reset();
			}
		}
		
		return false;
	}
	
	// 释放资源
	@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);		

		super.dispose(session);
	}
	
	// 获取解密器
	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.