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

源代码:
SM4BinaryCodecFactory.java

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

	// 解码器
    private final SM4BinaryCumulativeDecoder mDecoder;

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

	// 构造函数
	public SM4BinaryCodecFactory(CipherMode mode) {
		this(mode, PaddingMode.PKCS7);
    }
	
	/* 
	功能:构造函数
	参数说明:
		mode:运算模式,支持ECB、CBC、CFB、OFB(默认)、PCBC
		padding:填充模式,支持PKCS7(默认)、ANSIX923、ISO10126、ISO7816、Zeros、None
	*/
	public SM4BinaryCodecFactory(CipherMode mode, PaddingMode padding) {
		if (mode.getValue() > 4) throw new IllegalArgumentException("Unsupported cipher mode!");
		
		mEncoder = new SM4BinaryEncoderAdapter(mode, padding);
		mDecoder = new SM4BinaryCumulativeDecoder(mode, padding);
    }

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

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

	// 获取编码器加密密钥
    public static String getEncoderKey(IoSession session) 
	{ 
		return (String)SM4BinaryEncoderAdapter.getSecretKey(session); 
	}
	
	// 获取解码器解密密钥
    public static String getDecoderKey(IoSession session) 
	{ 
		return (String)SM4BinaryCumulativeDecoder.getSecretKey(session);
	}
}

SM4BinaryEncoderAdapter.java

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

	// 块密码工作模式
	protected final CipherMode mMode;
	
	// 消息数据块填充类型
	protected final PaddingMode mPadding;
		
	// 构造函数
	public SM4BinaryEncoderAdapter() {
        this(CipherMode.OFB, PaddingMode.PKCS7);
    }

	// 构造函数
	public SM4BinaryEncoderAdapter(CipherMode mode) {
        this(mode, PaddingMode.PKCS7);
    }
	
	/* 
	功能:构造函数
	参数说明:
		mode:运算模式,支持ECB、CBC、CFB、OFB(默认)、PCBC
		padding:填充模式,支持PKCS7(默认)、ANSIX923、ISO10126、ISO7816、Zeros、None
	*/
	public SM4BinaryEncoderAdapter(CipherMode mode, PaddingMode padding) {
		if (mode.getValue() > 4) throw new IllegalArgumentException("Unsupported cipher mode!");
		
		mMode = mode;
		mPadding = padding;
    }
	
	@Override
    public void encode(IoSession session, Object message, ProtocolEncoderOutput out) throws Exception {		
		// 获取明文数据
		byte[] Source = (byte[])message;

		// 获取加密密钥
		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 static void setSecretKey(IoSession session, String value){
		session.setAttribute(KEY_SECRETKEY, value);
    }

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

SM4BinaryCumulativeDecoder.java

/* ----------------------------------------------------------
 * 文件名称:SM4BinaryCumulativeDecoder.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 org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.CumulativeProtocolDecoder;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;
import java.util.Arrays;
import org.apache.mina.core.session.AttributeKey;

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

	// 块密码工作模式
	protected final CipherMode mMode;
	
	// 消息数据块填充类型
	protected final PaddingMode mPadding;
		
	// 构造函数
	public SM4BinaryCumulativeDecoder() {
        this(CipherMode.OFB, PaddingMode.PKCS7);
    }

	// 构造函数
	public SM4BinaryCumulativeDecoder(CipherMode mode) {
        this(mode, PaddingMode.PKCS7);
    }
	
	/* 
	功能:构造函数
	参数说明:
		mode:运算模式,支持ECB、CBC、CFB、OFB(默认)、PCBC
		padding:填充模式,支持PKCS7(默认)、ANSIX923、ISO10126、ISO7816、Zeros、None
	*/
	public SM4BinaryCumulativeDecoder(CipherMode mode, PaddingMode padding) {
		if (mode.getValue() > 4) throw new IllegalArgumentException("Unsupported cipher mode!");
		
		mMode = mode;
		mPadding = padding;
    }

	@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(Source);
				}
				else
				{	// 输出解密后的数据
					SM4 Decryptor = getDecryptor(session, SecretKey);
					out.write(Decryptor.TransformFinalBlock(Source, 0, size));
				}
				
				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 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.