前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >[ffffffff0x] 安全工具系列 :SM3国密算法模块学习

[ffffffff0x] 安全工具系列 :SM3国密算法模块学习

原创
作者头像
r0fus0d
修改2020-12-25 17:49:54
1.5K0
修改2020-12-25 17:49:54
举报
文章被收录于专栏:ffffffff0x

前言

国密即国家密码局认定的国产密码算法.主要有 SM1,SM2,SM3,SM4.密钥长度和分组长度均为 128 位.

SM3是我国采用的的一种密码散列函数标准,由国家密码管理局于2010年12月17日发布。相关标准为“GM/T 0004-2012 《SM3密码杂凑算法》”。

SM3密码杂凑算法采用Merkle-Damgard结构,消息分组长度为512b,摘要长度256b。压缩函数状态256b,共64步操作步骤。

在商用密码体系中,SM3主要用于数字签名及验证、消息认证码生成及验证、随机数生成等,其算法公开。据国家密码管理局表示,其安全性及效率与SHA-256相当。

密码散列函数(Cryptographic hash function)

密码散列函数又称为加密散列函数,是散列函数的一种,被认为是一种单向函数,很难由刺中函数输出的结果反推出输入的数据。此类散列函数的输入数据,通常被称为消息(message)。而它的输出结果,通常被称为消息摘要(message digest)或摘要(digest)。

散列函数在密码学中具有重要的地位,它们通常被认为需要满足三个基本特性:

  • 原像稳固性
  • 第二原像稳固性
  • 碰撞稳固性

原像稳固性

对于所有预设输出,从计算角度应无法找到任何符合输入哈希的输出。例如,给定y,使得很难找到满足h(x) = y的x。这样的散列函数我们称之为原像稳定。

第二原像抗性

从计算角度无法找到任何与特定输入值有着相同输出的二次输入值。例如,给定x,使得很难找到满足h(x) = h(x′)的次原像x′ ≠ x。

碰撞稳固性

很难找到满足h(x)=h(x’)的二元组(x,x’)。

满足以上三个特性的散列函数可以认为是安全的散列函数,按照美国国家标准与技术研究院(NIST)的标准,MD5已经是不安全的散列函数了,不推荐使用SHA-1,推荐使用SHA-2与SHA-3。

SM3密码摘要算法适用于商用密码应用中的数字签名和验证,是在SHA-256基础上改进并实现的一种算法。SM3算法采用Merkle-Damgard结构,消息分组长度为512位,摘要值长度为256位。

SM3算法的压缩函数与SHA-256的压缩函数具有相似的结构,但是SM3算法的设计更加复杂,比如压缩函数的每一轮都使用2个消息字。

至今为止,SM3算法的安全性相对而言比较高。

SM3算法描述

SM3散列函数会对输入消息做填充,迭代压缩,输出256比特的杂凑值这三项操作,而迭代压缩中又分:迭代过程、消息扩展、压缩函数。

填充

假设消息M的长度为l比特,则首先将比特“1”添加到消息的末尾,在添加k个“0”,k是满足l+1+k===448(mod512)的最小非负整数。然后在添加一个64位比特串,该比特串是长度l的二进制表示。填充后的消息M1的比特长度为512的倍数。

迭代过程

将填充后的消息M1按512比特进行分组。

代码语言:txt
复制
M1 = C^0 C^1...k^N-1
其中n=(l+k+65)/512

对M1按以下方式迭代:

代码语言:txt
复制
FOR I=0 TO N-1
V^I+1 = CF(V^I,B^I)
ENDFOR
其中CF是压缩函数,V^0为256比特初始值IV,B^i为填充后的消息分组,得带压缩的结果为V^n

消息扩展

将消息分组 B^i按以下方法扩展生成132个消息字用于压缩函数CF;

压缩函数

令A,B,C,D,E,F,G,H为字寄存器,SS1,SS2,TT1,TT2为中间变量,压缩函数V^i+1=CF(V^I,B^I),0<=i<=n-1

杂凑值

ABCDEFGH <- V^n

输出256比特的杂凑值y=ABCDEFGH。

JAVA算法实现

具体的代码实现需要弄清楚加密原理,下面是使用JAVA实现的SM3加密代码:

首先是填充,迭代与消息扩展。

代码语言:txt
复制
    private static byte[] CF(byte[] vi, byte[] bi) throws IOException {
        int a, b, c, d, e, f, g, h;
        a = toInteger(vi, 0);
        b = toInteger(vi, 1);
        c = toInteger(vi, 2);
        d = toInteger(vi, 3);
        e = toInteger(vi, 4);
        f = toInteger(vi, 5);
        g = toInteger(vi, 6);
        h = toInteger(vi, 7);
        int[] w = new int[68];
        int[] w1 = new int[64];
        for (int i = 0; i < 16; i++) {
            w[i] = toInteger(bi, i);
        }
        for (int j = 16; j < 68; j++) {
            w[j] = P1(w[j - 16] ^ w[j - 9] ^ Integer.rotateLeft(w[j - 3], 15))
                    ^ Integer.rotateLeft(w[j - 13], 7) ^ w[j - 6];
        }
        for (int j = 0; j < 64; j++) {
            w1[j] = w[j] ^ w[j + 4];
        }
        int ss1, ss2, tt1, tt2;
        for (int j = 0; j < 64; j++) {
            ss1 = Integer.rotateLeft(Integer.rotateLeft(a, 12) + e + Integer.rotateLeft(TJT(j), j), 7);
            ss2 = ss1 ^ Integer.rotateLeft(a, 12);
            tt1 = FJF(a, b, c, j) + d + ss2 + w1[j];
            tt2 = GJG(e, f, g, j) + h + ss1 + w[j];
            d = c;
            c = Integer.rotateLeft(b, 9);
            b = a;
            a = tt1;
            h = g;
            g = Integer.rotateLeft(f, 19);
            f = e;
            e = P0(tt2);
        }
        byte[] v = toByteArray(a, b, c, d, e, f, g, h);
        for (int i = 0; i < v.length; i++) {
            v[i] = (byte) (v[i] ^ vi[i]);
        }
        return v;
    }

然后是压缩函数。

代码语言:txt
复制
        private static int TJT(int j) {
        if (j >= 0 && j <= 15) {
            return Tj11;
        } else if (j >= 16 && j <= 63) {
            return Tj61;
        } else {
            throw new RuntimeException("DI");
        }
    }
    private static Integer FJF(Integer x, Integer y, Integer z, int j) {
        if (j >= 0 && j <= 15) {
            return x ^ y ^ z;
        } else if (j >= 16 && j <= 63) {
            return (x & y)|(x & z)|(y & z);
        } else {
            throw new RuntimeException("DI");
        }
    }
    private static Integer GJG(Integer x, Integer y, Integer z, int j) {
        if (j >= 0 && j <= 15) {
            return x ^ y ^ z;
        } else if (j >= 16 && j <= 63) {
            return (x & y)|(~x & z);
        } else {
            throw new RuntimeException("DI");
        }
    }

最后将压缩完的杂凑值输出,结合图形化显示效果如下:

结语

在越来越多国际通用散列算法被攻击、破解的今日,我国自研的SM3散列函数使用更复杂的压缩函数,因此具有更高的安全性,为金融、政企类网站保驾护航,守护信息安全。


本文作者 r0fus0d、RyuZU

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 密码散列函数(Cryptographic hash function)
    • 原像稳固性
      • 第二原像抗性
        • 碰撞稳固性
        • SM3算法描述
          • 填充
            • 迭代过程
              • 消息扩展
                • 压缩函数
                  • 杂凑值
                  • JAVA算法实现
                  • 结语
                  相关产品与服务
                  文件存储
                  文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档