pos终端mac国密(sm4)算法(java实现)

概念理解

mac算法是(Message Authentication Codes 消息认证码算法),是含有密钥散列函数算法。主要通过异或运算,再配合其他加密算法实现mac值的运算,用于校验。

Demo项目下载地址 :https://github.com/Cats-eat-fish/-sm4-MAC-

实现过程


  1. 将需要加密计算的字符串转换为16进制字符串

    例如:
    密钥:"12345678901234567890123456789012"
    待加密数据(字符串形式):
    6000112018111411003020170930101010120171025000755000000005553

    转化为16进制:
    36303030 31313230 31383131 31343131 30303330 32303137 30393330 31303130 31303132 30313731 30323530 30303735 35303030 30303030 30353535 33

  2. 将转换过的16字符串进行补位分组

    部位后的数据(部位规则:字符长度%32!=0补位)
    36303030 31313230 31383131 31343131 30303330 32303137 30393330 31303130 31303132 30313731 30323530 30303735 35303030 30303030 30353535 33000000

    分组后的数据
    第 0组明文:36303030 31313230 31383131 31343131
    第 1组明文:30303330 32303137 30393330 31303130
    第 2组明文:31303132 30313731 30323530 30303735
    第 3组明文:35303030 30303030 30353535 33000000

  3. 将分组过的字符串数组逐步进行异或运算

    异或流程
    第 0组明文: 36303030 31313230 31383131 31343131
    第 1组明文: 30303330 32303137 30393330 31303130
    第 1组异或结果:06000300 03010307 01010201 00040001
    第 2组明文:31303132 30313731 30323530 30303735
    第 2组异或结果:37303232 33303436 31333731 30343734
    第3组明文:35303030 30303030 30353535 33000000
    与第2组密文异或:02000202 03000406 01060204 03343734

  4. 将最后异或结果转化为16进制字符串

    转换为16进制
    30323030 30323032 30333030 30343036 30313036 30323034 30333334 33373334

  5. 取前16位和后16位,前16位进行sm4加密,加密结果与后16位异或后再加密

    前16位
    30323030 30323032 30333030 30343036

    后16位
    30313036 30323034 30333334 33373334

    前16位加密结果
    B038A2B2 F3FFE3C8 AC60B377 C70C2DB1

    与后16位异或结果
    80099284 C3CDD3FC 9C538043 F43B1E85

    再加密结果
    1E80F373 40B0FEE6 2C81F356 AFB20BF1

  6. 取前16个字符作为mac值

    mac值:1E80F37340B0FEE6


具体实现过程

准备工作

  1. 数据转换工具类 TransferUtils.java

    • 字符串转换为16进制字符串
    public static String StringToHexString(String str) {
        String data = bytesToHexString(str.getBytes(), 32);
        return data;
    } 
    
    • 字节数组转换为16进制字符串
    /**
     * 字节数组转化为十六进制字符串 并按照len的倍数进行补"0"
     * @param bytes 字节数据
     * @param len   部位原则  不够len倍数补"0"
     * @return
     */
    public static String bytesToHexString(byte[] bytes, int len) {
        StringBuffer hexStr = new StringBuffer();
        for (byte b : bytes) {
            hexStr.append(String.format("%02x", new Integer(b & 0xff)));
        }
        //长度不满32的整数倍 在后边添加 "0"
        while (hexStr.length() % len != 0) {
            hexStr.append("0");
        }
    
        return hexStr.toString();
    }
    
  • 将字符串str 按照长度len 进行分组
    /**
     * 将字符串str 按照长度len 进行分组
     * @param str 字符串
     * @param len 每组字符长度
     * @return
     */
    public static String[] dataGrouping(String str, int len) {
        int lenth = str.length() % len == 0 ? str.length() / len : str.length() / len + 1;
        String[] data = new String[lenth];
        for (int i = 0; i < lenth; i++) {
            data[i] = str.substring(i * len, i * len + len);
        }
        return data;
    }
    
  • 将字符串数组进行异或运算
    public static String handleXOrStringArr(String[] strs){
        String result = "";
        for (int i = 1;i < strs.length;i++){
            if (i == 1){
                result = xOr(strs[0],strs[1]);
            }else {
                result = xOr(strs[i],result);
            }
        }
        return result;
    }
    
  • 异或运算
    /**
     * 异或运算
     * @param s1
     * @param s2
     * @return
     */
    public static String xOr(String s1, String s2) {
        String data = IntArr2String(xOr(String2IntArr(s1),String2IntArr(s2)));
        return data;
    }
    public static int [] xOr(int[] i1,int[] i2){
        int[] xor = new int[i1.length];
        for (int i = 0;i < i1.length & i < i2.length;i++){
            xor[i] = i1[i]^i2[i];
        }
        return xor;
    }
    
  1. 加密工具类
    • sm4加密
  public static byte[] encodeSMS4(byte[] plaintext, byte[] key) {
      byte[] ciphertext = new byte[plaintext.length];

      int k = 0;
      int plainLen = plaintext.length;
      while (k + 16 <= plainLen) {
          byte[] cellPlain = new byte[16];
          for (int i = 0; i < 16; i++) {
              cellPlain[i] = plaintext[k + i];
          }
          byte[] cellCipher = encode16(cellPlain, key);
          for (int i = 0; i < cellCipher.length; i++) {
              ciphertext[k + i] = cellCipher[i];
          }

          k += 16;
      }

      return ciphertext;
  }

调用过程

  1. 将密钥转换为字节数组,将需要加密计算的字符串转换为16进制字符串并补位

    例如:
    密钥:"12345678901234567890123456789012"
    待加密数据(字符串形式):
    6000112018111411003020170930101010120171025000755000000005553

    //将key转换为字节数组
    byte[] keys = TransformUtils.HexStringToByteArr(key);
    //将加密数据转换为16进制字符串
    String hexData = TransformUtils.StringToHexString(data);
    
  2. 将转换过的16字符串进行分组

    //将数据分组 32位为一组
    String[] dataGroup = TransformUtils.dataGrouping(hexData, 32);
    
  3. 将分组过的字符串数组逐步进行异或运算

    //进行异或运算
    String xorData = TransformUtils.handleXOrStringArr(dataGroup);
    
  4. 将最后异或结果转化为16进制字符串

    //将异或结果转化为16进制字符串
    String hexOxrData = TransformUtils.StringToHexString(xorData);
    
  5. 取前16字节和后16字节,前16字节进行sm4加密,加密结果与后16字节异或后再加密

    //取前16字节和后16字节  两个16进制位表示一个字节
    String start32Bit = hexOxrData.substring(0,32);
    String end32Bit = hexOxrData.substring(hexOxrData.length() - 32,hexOxrData.length());
    //前16位进行首次加密
    byte[] encodeSMS4_1 = SMS4.encodeSMS4(TransformUtils.HexStringToByteArr(start32Bit), keys);
    //加密结果与后16位进行异或
    String xOrEnd = TransformUtils.xOr(TransformUtils.bytesToHexString(encodeSMS4_1, 16), end32Bit);
    //异或结果转成字节数组
    byte[] bytes = TransformUtils.HexStringToByteArr(xOrEnd);
    //进行二次加密
    byte[] resultByte = SMS4.encodeSMS4(bytes, keys);
    //将加密结果转换成16进制字符串 并取前八个字符作为mac值返回
    String result = TransformUtils.bytesToHexString(resultByte, 16);
    
  6. 取前16个字符作为mac值

    //取前8字节作为mac值返回
    result = result.substring(0,16);
    

后记

  此处是pos终端mac国密(sm4)算法,之前还有一个pos终端mac国际算法(双倍长 3des),两者的区别在于 分组的时候分组长度不太一样,国际是16个16进制字符(8字节)分组,国密是32个16进制字符(16字节)分组,再有不同的地方就是加密算法不同,国密是sm4加密算法,国际是双倍长3des加密算法,其他基本都是一样的,这个加密算法也是根据需求可以进行更改的 ,比如改为RSA 或AES也是可以的,这个就需要双方沟通了 统一加密算法就可以了

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342

推荐阅读更多精彩内容

  • 前言 最先接触编程的知识是在大学里面,大学里面学了一些基础的知识,c语言,java语言,单片机的汇编语言等;大学毕...
    oceanfive阅读 3,040评论 0 7
  • 后来,我终于在摸爬滚打之中渐渐的懂得了某些以前自己不曾领悟到的东西;是生活所迫,还是被逼无奈的选择,但是我无论怎么...
    就是很帅htx阅读 173评论 0 0
  • 姓名:邓平云 深圳蔚蓝时代商业管理有限公司南京分公司 【日精进打卡第214天】 【知~学习】 《六项精进大纲 》1...
    邓平云阅读 130评论 0 0
  • 1、切记:质量比数量重要。 2、按照计划,一步步走。 3、他人的关注,只是一时的兴趣。坦然享受就好了,千万不能在意...
    知柬阅读 163评论 0 0
  • 2018年10月20 星期六 天气晴 今天礼拜六儿子上托辅,不用起那么早,6点30起床,给儿子做了西红柿...
    HelloFox_447c阅读 127评论 0 1