国密动态令牌java实现(SM3/SM4 OTP)

该代码实现基于国密标准GM/T0021-2012和GB/T38556-2020的动态口令生成,包括SM3和SM4算法。动态口令通过时间因子、事件因子和挑战因子计算,提供了一种安全的身份验证方法。测试类对生成的口令进行验证,确保符合国标数据。
摘要由CSDN通过智能技术生成

密评涉及密改的运维端经常会有动态令牌做身份鉴别,对应的标准为:

GM/T 0021-2012《动态口令密码应用技术规范》

GB/T 38556-2020《信息安全技术 动态口令密码应用技术规范》

写了最基础的SM3/SM4 两种国标口令生成,数据全部验证通过,给小伙伴们抛砖引玉。

package org.liuy.pki;


import org.bouncycastle.util.encoders.Hex;

/**
 * 国密动态令牌实现
 * 参考标准:《GB/38556-2020 信息安全技术动态口令密码应用技术规范》
 * 参考网址:
 *      https://www.wangan.com/docs/2484
 * 
 *      
 * @author liuy
 *
 */
public class GMOTP {
	
	
	/**
     * 左补位
     * @param c 补位的字符
     * @param length 需要的长度
     * @param target
     * @return
     */
    public static String flushLeft(String c, int length, String target) {
        String cs = "";
        if(target.length() < length){
            for(int i = 0; i < length - target.length(); i++){
                cs = c + cs;
            }
            target = cs + target;
        }
        return  target;
    }
    
    /**
         *     字节数组转int 大端模式
     */
   public static int byteArrayToIntBigEndian(byte[] bytes) {
	   
	// byte数组中序号大的在右边
//       long values = 0;
//       for (int i = 0; i < 4; i++) {
//           values <<= Byte.SIZE;
//           values |= (bytes[i] & 0xff);
//       }

	   int res = ((bytes[0] &  0xff) << 24) | ((bytes[1] & 0xff) << 16) |
		          ((bytes[2] & 0xff) << 8)  | (bytes[3] & 0xff);
       return res;
   }

    /**
     * 截位运算
     * OD = Truncate(S)
     * @param sm3Hash
     * @return
     */
    private static String truncate(byte[] sm3Hash){
    	//每组4个字节,32字节长度总共分为8组
    	int g=sm3Hash.length/4;
    	byte[] sByte = new byte[4];
    	long OD_sum=0;
    	for(int i=0;i<g;i++){
    		System.arraycopy(sm3Hash,i*4,sByte,0,4); 
    		long bI=byteArrayToIntBigEndian(sByte);
    		OD_sum+=bI;
    	}
        //转为无符号整形
    	OD_sum=OD_sum & 0xFFFFFFFFL;  	
    	long mod=(long) Math.pow(2,32);    	
    	long OD=OD_sum % mod;
    	String ODStr=String.valueOf(OD);    
    	return ODStr.substring(ODStr.length()-6,ODStr.length());    	
    }
	
    /**
          *  计算 ID
     * @param K
     * @param T
     * @param C
     * @param Q
     * @return
     */
    private static String genID(int T,int C,String Q){
	    	//T : 时间因子 (8字节,整型)
			String T_HEX=Integer.toHexString(T);
			T_HEX=flushLeft("0",16,T_HEX);
			//C : 事件因子 (4字节, 整型)
			String C_HEX=Integer.toHexString(C);
			C_HEX=flushLeft("0",8,C_HEX);	
			//Q : 挑战因子 (最小为4字节,使用ASCII码表示)
			String Q_Hex="";
			for(int i=0;i<Q.length();i++)
			{
				 String hexStr = Integer.toHexString(Q.charAt(i));
				 Q_Hex+=hexStr;
			}
			
			//ID= {T|C|Q}
			String ID=T_HEX+ C_HEX+Q_Hex;
			return ID;
    }
    
	/**
	 * 生成SM3动态口令
	 * @param K   种子密钥 (不少于128位, 16进制)
	 * @param T   时间因子 (8字节,整型)
	 * @param C   事件因子 (4字节, 整型)
	 * @param Q   挑战因子 (最小为4字节,使用ASCII码表示)
	 * @return
	 */
	public static String genSM3GMOTP(String K,int T,int C,String Q){	
		//ID= {T|C|Q}
		String ID=genID(T,C,Q);
		//SM3 S = F(K|ID)
		String S=K+ID;	
		byte[] srcByte=Hex.decode(S);
		byte[] sm3Hash =SM3Tools.encrypt(srcByte);		
		return truncate(sm3Hash);
	}
	
	/**
	 *   生成SM4动态口令
	 * @param K   种子密钥 (不少于128位, 16进制)
	 * @param T   时间因子 (8字节,整型)
	 * @param C   事件因子 (4字节, 整型)
	 * @param Q   挑战因子 (最小为4字节,使用ASCII码表示)
	 * @return
	 */
	public static String genSM4GMOTP(String K,int T,int C,String Q) {	
		//ID= {T|C|Q}
		String ID=genID(T,C,Q);
		//SM4 S = F(K,ID)	
		String encDataHex=SM4Tools.encryptECB(K, ID);
		byte[] sByte = new byte[16];
		System.arraycopy(Hex.decode(encDataHex),0,sByte,0,16); 			
		return truncate(sByte);
	}
}

测试类:

package test;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
import org.liuy.pki.GMOTP;

public class TESTOTP {
	
	public static void testSM3OTP() throws FileNotFoundException {
		//动态令牌相关取值
		String  K;
		int  T;
		int  C;
		String  Q ;
		String  P;
		
		 File myObj = new File("sm3VF.txt");
		 Scanner myReader = new Scanner(myObj);
		 while (myReader.hasNextLine()) {
		    String data = myReader.nextLine();
		    String[]  sList=data.split("\\s+");
		    K=sList[0];
		    T=Integer.valueOf(sList[1]);
		    C=Integer.valueOf(sList[2]);
		    Q=sList[3];
		    P=sList[4];
		    //System.out.println(K+":"+T+":"+C+":"+Q+":"+P);
		    
		    String otp=GMOTP.genSM3GMOTP(K, T, C, Q);
			if(!P.endsWith(otp))
			{
				System.out.println(sList[5]+" 错误口令:"+otp);
				return;
			} 
		  }
		  myReader.close();
		  System.out.println("SM3国标数据验证正确");
	}
	
	public static void testSM4OTP() throws Exception {
		//动态令牌相关取值
		String  K;
		int  T;
		int  C;
		String  Q ;
		String  P;
		
		 File myObj = new File("sm4VF.txt");
		 Scanner myReader = new Scanner(myObj);
		 while (myReader.hasNextLine()) {
		    String data = myReader.nextLine();
		    String[]  sList=data.split("\\s+");
		    K=sList[0];
		    T=Integer.valueOf(sList[1]);
		    C=Integer.valueOf(sList[2]);
		    Q=sList[3];
		    P=sList[4];		    
		    String otp=GMOTP.genSM4GMOTP(K, T, C, Q);
			if(!P.endsWith(otp))
			{
				System.out.println(sList[5]+" 错误口令:"+otp);
				return;
			} 
		  }
		  myReader.close();
		  System.out.println("SM4国标数据验证正确");
	}
	
	public static void main(String[] args) throws Exception {
			testSM3OTP();
			testSM4OTP();
		
	}

}

国标SM3验证数据(sm3VF.txt):

1234567890abcdef1234567890abcdef	1313998979	1234	5678	814095
1234567890abcdefabcdef1234567890	1313998995	5621	3698	959691
1234567890abcdef0987654321abcdef	1313999014	5621	3698	063014
1234567890abcdefabcdef0987654321	1313999047	2053	6984	302593
87524138025adcfe2584376195abfedc	1313999067	2058	3024	657337
87524138025adcfeabfedc2584376195	1313999098	2056	2018	345821
adcfe87524138025abfedc2584376195	1313999131	2358	1036	629660
58ade3698fe280cb6925010dd236caef	1313999155	2547	2058	479821
58ade365201d80cbdd236caef6925010	1313999174	6031	2058	893826
65201d80cb58ade3dd236caef6925010	1313999189	6580	1047	607614

国标SM4验证数据(sm4VF.txt):

1234567890abcdef1234567890abcdef	1340783053	1234	5678	446720
1234567890abcdefabcdef1234567890	1340783416	5621	3698	049845
1234567890abcdef0987654321abcdef	1340783476	2584	2105	717777
87524138025adcfeabfedc2584376195	1340783509	2053	6984	037000
87524138025adcfe2584376195abfedc	1340783588	2058	3024	502206
1234567890abcdefabcdef0987654321	1340783624	2056	2018	692843
adcfe87524138025abfedc2584376195	1340783652	2358	1036	902690
58ade3698fe280cb6925010dd236caef	1340783729	2547	2058	499811
58ade365201d80cbdd236caef6925010	1340783771	6031	2058	565180
65201d80cb58ade3dd236caef6925010	1340783815	6580	1047	724654

参考文献:

 https://www.wangan.com/docs/2484
 https://www.jianshu.com/p/e1722328695e

密码应用安全性评估要点之动态口令技术常见问题探讨-51CTO.COM

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值