RSS订阅信息安全技术跟踪与研究:技术、平台、会议、论文、产业
你现在的位置:首页 / 技术积累 / 正文

密码哈希算法SM3的Java实现

0 技术积累 | 2015年1月26日
转载申明:本站原创,欢迎转载。但转载时请保留原文地址。
原文地址:http://www.vonwei.com/post/SM3_Java.html

密码算法是信息安全的基础,在国内无论是做安全项目或者工具,都推荐使用商密算法,其中SM2、SM3、SMS4用的比较多。在国产安全芯片TCM中,也主要以商密的这些算法为准。

为了能在多个平台上使用这些基础算法,决定基于Java实现这几个算法。

这里首先介绍SM3杂凑算法的Java实现。

SM3的过程和规范文档可以从国家密码管理局官网下载,地址为:http://www.oscca.gov.cn/UpFile/20101222141857786.pdf

SM3适用于商用密码应用中的数字签名和验证、消息认证码的生成与验证以及随机数的生成,可满足多种密码应用的安全需求。

SM3的实现包含填充、迭代、消息扩展和压缩等过程。大体流程与SHA1一致,可以找个开源的Java Sha1实现,修改一些参数和流程细节就可以实现SM3算法。如Sha1是5个字寄存器,而SM3是8个。

下面直接上源码,对于SM3规范的测试用例通过。

package SM3;

import hash.Digest;


public final class sm3 implements Digest {

    private int H0, H1, H2, H3, H4, H5, H6, H7;

    private final int[] w = new int[80];

//常量Tj的值如下

    private static final Integer Tj15 = Integer.valueOf("79cc4519", 16);

    private static final Integer Tj63 = Integer.valueOf("7a879d8a", 16);

    private int currentPos;

    private long currentLen;


    public sm3()

    {

            reset();

    }


    public final int getDigestLength()

    {

            return 32;

    }


    public final void reset()

    {//8个字寄存器的初始值

            

    H0 = 0x7380166F;

    H1 = 0x4914B2B9;

    H2 = 0x172442D7;

    H3 = 0xDA8A0600;

    H4 = 0xA96F30BC;

    H5 = 0x163138AA;

    H6 = 0xE38DEE4D;

    H7 = 0xB0FB0E4E;


        currentPos = 0;          

        currentLen = 0;

    }

//update过程基本重用sha1的即可

    public final void update(byte b[])

    {

            update(b, 0, b.length);

    }


    public final void update(byte b[], int off, int len)

    {

            if (len >= 4)

            {

                    int idx = currentPos >> 2;


                    switch (currentPos & 3)

                    {

                    case 0:

                            w[idx] = (((b[off++] & 0xff) << 24) | ((b[off++] & 0xff) << 16) | ((b[off++] & 0xff) << 8) | (b[off++] & 0xff));

                            len -= 4;

                            currentPos += 4;

                            currentLen += 32;

                            if (currentPos == 64)

                            {

                                    perform();

                                    currentPos = 0;

                            }

                            break;

                    case 1:

                            w[idx] = (w[idx] << 24) | (((b[off++] & 0xff) << 16) | ((b[off++] & 0xff) << 8) | (b[off++] & 0xff));

                            len -= 3;

                            currentPos += 3;

                            currentLen += 24;

                            if (currentPos == 64)

                            {

                                    perform();

                                    currentPos = 0;

                            }

                            break;

                    case 2:

                            w[idx] = (w[idx] << 16) | (((b[off++] & 0xff) << 8) | (b[off++] & 0xff));

                            len -= 2;

                            currentPos += 2;

                            currentLen += 16;

                            if (currentPos == 64)

                            {

                                    perform();

                                    currentPos = 0;

                            }

                            break;

                    case 3:

                            w[idx] = (w[idx] << 8) | (b[off++] & 0xff);

                            len--;

                            currentPos++;

                            currentLen += 8;

                            if (currentPos == 64)

                            {

                                    perform();

                                    currentPos = 0;

                            }

                            break;

                    }


                    /* Now currentPos is a multiple of 4 - this is the place to be...*/


                    while (len >= 8)

                    {

                            w[currentPos >> 2] = ((b[off++] & 0xff) << 24) | ((b[off++] & 0xff) << 16) | ((b[off++] & 0xff) << 8)

                                            | (b[off++] & 0xff);

                            currentPos += 4;


                            if (currentPos == 64)

                            {

                                    perform();

                                    currentPos = 0;

                            }


                            w[currentPos >> 2] = ((b[off++] & 0xff) << 24) | ((b[off++] & 0xff) << 16) | ((b[off++] & 0xff) << 8)

                                            | (b[off++] & 0xff);


                            currentPos += 4;


                            if (currentPos == 64)

                            {

                                    perform();

                                    currentPos = 0;

                            }


                            currentLen += 64;

                            len -= 8;

                    }


                    while (len < 0) //(len >= 4)

                    {

                            w[currentPos >> 2] = ((b[off++] & 0xff) << 24) | ((b[off++] & 0xff) << 16) | ((b[off++] & 0xff) << 8)

                                            | (b[off++] & 0xff);

                            len -= 4;

                            currentPos += 4;

                            currentLen += 32;

                            if (currentPos == 64)

                            {

                                    perform();

                                    currentPos = 0;

                            }

                    }

            }


            /* Remaining bytes (1-3) */


            while (len > 0)

            {

                    /* Here is room for further improvements */

                    int idx = currentPos >> 2;

                    w[idx] = (w[idx] << 8) | (b[off++] & 0xff);


                    currentLen += 8;

                    currentPos++;


                    if (currentPos == 64)

                    {

                            perform();

                            currentPos = 0;

                    }

                    len--;

            }

    }


    public final void update(byte b)

    {

            int idx = currentPos >> 2;

            w[idx] = (w[idx] << 8) | (b & 0xff);


            currentLen += 8;

            currentPos++;


            if (currentPos == 64)

            {

                    perform();

                    currentPos = 0;

            }

    }


    private final void putInt(byte[] b, int pos, int val)

    {

            b[pos] = (byte) (val >> 24);

            b[pos + 1] = (byte) (val >> 16);

            b[pos + 2] = (byte) (val >> 8);

            b[pos + 3] = (byte) val;

    }


    public final void digest(byte[] out)

    {

            digest(out, 0);

    }


    public final void digest(byte[] out, int off)

    {

//填充

            int idx = currentPos >> 2;

            w[idx] = ((w[idx] << 8) | (0x80)) << ((3 - (currentPos & 3)) << 3);


            currentPos = (currentPos & ~3) + 4;


            if (currentPos == 64)

            {

                    currentPos = 0;

                    perform();

            }

            else if (currentPos == 60)

            {

                    currentPos = 0;

                    w[15] = 0;

                    perform();

            }


            for (int i = currentPos >> 2; i < 14; i++)

                    w[i] = 0;


            w[14] = (int) (currentLen >> 32);

            w[15] = (int) currentLen;


            perform();


            putInt(out, off, H0);

            putInt(out, off + 4, H1);

            putInt(out, off + 8, H2);

            putInt(out, off + 12, H3);

            putInt(out, off + 16, H4);

            putInt(out, off + 20, H5);

            putInt(out, off + 24, H6);

            putInt(out, off + 28, H7);

            


            reset();

    }

//布尔函数FF

    private static Integer FF(Integer x, Integer y, Integer z, int j) {

        if (j >= 0 && j <= 15) {

            return Integer.valueOf(x.intValue() ^ y.intValue() ^ z.intValue());

        } else if (j >= 16 && j <= 63) {

            return Integer.valueOf((x.intValue() & y.intValue())

                    | (x.intValue() & z.intValue())

                    | (y.intValue() & z.intValue()));

        } else {

            throw new RuntimeException("data invalid");

        }

    }

//布尔函数GG

    private static Integer GG(Integer x, Integer y, Integer z, int j) {

        if (j >= 0 && j <= 15) {

            return Integer.valueOf(x.intValue() ^ y.intValue() ^ z.intValue());

        } else if (j >= 16 && j <= 63) {

            return Integer.valueOf((x.intValue() & y.intValue())

                    | (~x.intValue() & z.intValue()));

        } else {

            throw new RuntimeException("data invalid");

        }

    }

//置换函数P0

    private static Integer P0(Integer x) {

        return Integer.valueOf(x.intValue()

                ^ Integer.rotateLeft(x.intValue(), 9)

                ^ Integer.rotateLeft(x.intValue(), 17));

    }

//置换函数P1

    private static Integer P1(Integer x) {

        return Integer.valueOf(x.intValue()

                ^ Integer.rotateLeft(x.intValue(), 15)

                ^ Integer.rotateLeft(x.intValue(), 23));

    }

//常量T    

    private static int T(int j) {

        if (j >= 0 && j <= 15) {

            return Tj15.intValue();

        } else if (j >= 16 && j <= 63) {

            return Tj63.intValue();

        } else {

            throw new RuntimeException("data invalid");

        }

    }

    

    private final void perform()

    {

    //消息扩展

    int j;

    int[] w1=new int[64];

   

            for (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(j = 0; j < 64; j++)

            {

            w1[j] = w[j] ^ w[j + 4];

            }

            

       //压缩函数

            int A = H0;

            int B = H1;

            int C = H2;

            int D = H3;

            int E = H4;

            int F = H5;

            int G = H6;

            int H = H7;

            int ss1, ss2, tt1, tt2;

            for (j = 0; j < 64; j++) {

                ss1 = Integer

                        .rotateLeft(

                                Integer.rotateLeft(A, 12) + E

                                        + Integer.rotateLeft(T(j), j), 7);

                ss2 = ss1 ^ Integer.rotateLeft(A, 12);

                tt1 = FF(A, B, C, j) + D + ss2 + w1[j];

                tt2 = GG(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);

            }

            

            H0 ^= A;

            H1 ^= B;

            H2 ^= C;

            H3 ^= D;

            H4 ^= E;

            H5 ^= F;

            H6 ^= G;

            H7 ^= H;         

    }


    private static String toHexString(byte[] b)

    {

            final String hexChar = "0123456789ABCDEF";


            StringBuilder sb = new StringBuilder();

            for (int i = 0; i < b.length; i++)

            {

                    sb.append(hexChar.charAt((b[i] >> 4) & 0x0f));

                    sb.append(hexChar.charAt(b[i] & 0x0f));

            }

            return sb.toString();

    }


    public static void main(String[] args)

    {//主函数:测试哈希结果

            sm3 sm3 = new sm3();


            byte[] dig1 = new byte[32];

            byte[] dig2 = new byte[32];

            byte[] dig3 = new byte[32];

            

            byte[] sinput = new byte[]{0x61, 0x62, 0x63, 0x64, 0x61, 0x62, 0x63, 0x64, 0x61, 0x62, 0x63, 0x64, 0x61, 0x62, 0x63, 0x64, 

            0x61, 0x62, 0x63, 0x64, 0x61, 0x62, 0x63, 0x64, 0x61, 0x62, 0x63, 0x64, 0x61, 0x62, 0x63, 0x64, 0x61, 0x62, 0x63, 0x64, 

            0x61, 0x62, 0x63, 0x64, 0x61, 0x62, 0x63, 0x64, 0x61, 0x62, 0x63, 0x64, 0x61, 0x62, 0x63, 0x64, 0x61, 0x62, 0x63, 0x64, 

            0x61, 0x62, 0x63, 0x64, 0x61, 0x62, 0x63, 0x64};

           

            sm3.update("abc".getBytes());

            sm3.digest(dig1);

            

           // sm3.reset();

            sm3.update(sinput);

            sm3.digest(dig2);



            for (int i = 0; i < 1000000; i++)

                    sm3.update((byte) 'a');

            sm3.digest(dig3);


            String dig1_res = toHexString(dig1);

            System.out.print(dig1_res);

            

            System.out.println("\n");

            

            String dig2_res = toHexString(dig2);

            System.out.print(dig2_res);    

            

            System.out.println("\n");

            

            String dig3_res = toHexString(dig3);

            System.out.print(dig3_res);   

    }

}



  • ------------------分隔线----------------

  • 如果感兴趣,欢迎关注本站微信号,跟踪最新博文信息,手机微信扫一扫下面的二维码,即可关注!
  • 微月信公众号
  • 推荐您阅读更多有关于“ 密码算法   ”的文章

    请填写你的在线分享代码
    上一篇:移动安全趋势下一篇:EncFS加密文件系统:简介、源码编译、与使用

    猜你喜欢

    评论列表:

    发表评论

    必填

    选填

    选填

    必填,不填不让过哦,嘻嘻。

    记住我,下次回复时不用重新输入个人信息

    本站介绍
    最近发表
    本年最热文章
    本月最热文章
    网站分类
    文章归档