密钥派生函数的java实现

一,什么是密钥派生函数

    引用国密规范GM/T 0003.4-2012SM2椭圆曲线公钥密码算法 4部分:公钥加密算法》中5.4.3小节描述,密钥派生函数的作用是从一个共享的秘密比特串中派生出密钥数据。通俗的讲,是将一个输入比特串转换成特定长度的输出比特串,转换过程中使用了密码杂凑函数(也就是摘要函数)。密钥派生函数在椭圆曲线公钥加解密与密钥协商等密码运算场景都有应用。

二、密钥派生函数的定义

   定义: KDF(Z, klen)

   输入: Z,比特串;klen,整数,派生结果比特串的长度

   输出:长度为klen的密钥比特串K

   算法:

         a) 初始化一个32比特的计数器ct = 0x00000001;

         b) i 1    éklen/vù执行:

                  b.1) 计算 Hai = Hv(Z || ct) ;    --Hv() 表示输出长度为vHash函数

                  b.2) ct++;

        c) klen/v 是整数,Ha ! éklen/vù = Ha éklen/vù,否则Ha ! éklen/vù Ha éklen/vù最左边的 (klen-(v*ëklen/vû))比特。  --éklen/vù是顶函数,ëklen/vû是底函数

      d) K=Ha1||Ha2||||Haéklen/vù-1|| Ha ! éklen/vù 

三、JAVA代码实现

 

public static byte[] KDF(byte[] Z, int klen) {

              int sm3_v = 256;

              int hashNum = (int)Math.ceil((double)klen/sm3_v);

              boolean isInt = klen % sm3_v == 0 ? true : false;

 

              SM3Digest sm3 = new SM3Digest();

              int ct = 0x1;

 

              byte[] tempK = new byte[hashNum * 32];

             

              int realByteNum = 0;

              for (int i = 1; i <= hashNum; i++) {

 

                     byte[] ctBytes = Pack.intToBigEndian(ct);

                    

                     sm3.reset();

                     sm3.update(Z, 0, Z.length);

                     sm3.update(ctBytes, 0, ctBytes.length);

 

                     byte[] Ha = new byte[32];

                     sm3.doFinal(Ha, 0);

                    

                     ct++;

                    

                     if (hashNum == i && !isInt) { //最后一个hash,取最左边lastHashBitNum

                            int floor = (int)Math.floor((double)klen/sm3_v);

                            int lastHashBitNum = klen - sm3_v * floor;

                            int maskedByteLen = lastHashBitNum / 8;

                           

                            System.arraycopy(Ha, 0, tempK, (i - 1) * 32, maskedByteLen);

                            realByteNum += maskedByteLen;

                           

                            if (0 != lastHashBitNum % 8) {

                                   int maskedBitLen = 8 - lastHashBitNum % 8;

                                   byte maskByte = (byte)(~((1 << (8 - maskedBitLen)) - 1));

                                   tempK[(i - 1) * 32 + maskedByteLen] = (byte)(maskByte & Ha[maskedByteLen]);

                                   realByteNum += 1;

                            }

                           

                     } else {

                            System.arraycopy(Ha, 0, tempK, (i - 1) * 32, Ha.length);

                            realByteNum += 32;

                     }

              }

 

              byte[] k = new byte[realByteNum];

              System.arraycopy(tempK, 0, k, 0, realByteNum);

              return k;

       }

 

注:由于KDF函数在java实现时返回值k是以字节位单位,所以不能严格以klen长度的比特串返回,所以在做最后一次HASH运算时,如果klen不是字节(8)的整数倍,需要对最后一个字节做掩码运算处理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值