SM3算法实现

/// sm3.h 头文件
#pragma once
#include <cstdint>

namespace sm3
{
/// interface funcName of SM3
extern void SM3Hash(const unsigned char* m, const int ml, unsigned char r[32]);
}
/// sm3.cpp实现文件
#include "sm3.h"
#include <memory>
#include <cstring>

namespace sm3
{
static unsigned char IV[256 / 8] = { 0x73,0x80,0x16,0x6f,0x49,0x14,0xb2,0xb9,0x17,0x24,0x42,0xd7,0xda,0x8a,0x06,0x00,
                                     0xa9,0x6f,0x30,0xbc,0x16,0x31,0x38,0xaa,0xe3,0x8d,0xee,0x4d,0xb0,0xfb,0x0e,0x4e
                                   };

/// 循环左移
static uint32_t SL(uint32_t X, int n)
{
  uint64_t x = X;
  x <<= (n % 32);
  uint32_t l = (uint32_t)(x >> 32);
  return x | l;
}

static uint32_t Tj(int j)
{
  return (j <= 15) ? 0x79cc4519 : 0x7a879d8a;
}

static uint32_t FFj(int j, uint32_t X, uint32_t Y, uint32_t Z)
{
  return (j <= 15)? (X ^ Y ^ Z) : ((X & Y) | (X & Z) | (Y & Z));
}

static uint32_t GGj(int j, uint32_t X, uint32_t Y, uint32_t Z)
{
  return (j <= 15) ? (X ^ Y ^ Z) :  ((X & Y) | (~X & Z));
}

static uint32_t P0(uint32_t X)
{
  return X ^ SL(X, 9) ^ SL(X, 17);
}

static uint32_t P1(uint32_t X)
{
  return X ^ SL(X, 15) ^ SL(X, 23);
}

/// 扩展
static void EB(const unsigned char Bi[512 / 8], uint32_t W[68], uint32_t W1[64])
{
  /// Bi 分为W0~W15
  for (size_t i = 0; i < 16; ++i)
  {
    W[i] = Bi[i * 4] << 24 | Bi[i * 4 + 1] << 16 | Bi[i * 4 + 2] << 8 | Bi[i * 4 + 3];
  }

  size_t j;
  for (j = 16; j < 68; ++j)
  {
    W[j] = P1(W[j - 16] ^ W[j - 9] ^ SL(W[j - 3], 15)) ^ SL(W[j - 13], 7) ^ W[j - 6];
  }

  for (j = 0; j < 64; ++j)
  {
    W1[j] = W[j] ^ W[j + 4];
  }
}

// 压缩函数
static void CF(const unsigned char Vi[256 / 8], const unsigned char Bi[512 / 8], unsigned char Vi1[256 / 8])
{
  /// Bi 扩展为132个字
  uint32_t W[68] = { 0 };
  uint32_t W1[64] = { 0 };

  EB(Bi, W, W1);

  /// 串联 ABCDEFGH = Vi
  uint32_t R[8] = { 0 };
  for (size_t i = 0; i < 8; ++i)
  {
    R[i] = ((uint32_t)Vi[i * 4]) << 24 | ((uint32_t)Vi[i * 4 + 1]) << 16 | ((uint32_t)Vi[i * 4 + 2]) << 8 | ((uint32_t)Vi[i * 4 + 3]);
  }

  uint32_t A = R[0], B = R[1], C = R[2], D = R[3], E = R[4], F = R[5], G = R[6], H = R[7];

  uint32_t SS1, SS2, TT1, TT2;
  for (int j = 0; j < 64; ++j)
  {
    SS1 = SL(SL(A, 12) + E + SL(Tj(j), j), 7);
    SS2 = SS1 ^ SL(A, 12);
    TT1 = FFj(j, A, B, C) + D + SS2 + W1[j];
    TT2 = GGj(j, E, F, G) + H + SS1 + W[j];
    D = C;
    C = SL(B, 9);
    B = A;
    A = TT1;
    H = G;
    G = SL(F, 19);
    F = E;
    E = P0(TT2);
  }

  /// Vi1 = ABCDEFGH 串联
  R[0] = A, R[1] = B, R[2] = C, R[3] = D, R[4] = E, R[5] = F, R[6] = G, R[7] = H;
  for (size_t i = 0; i < 8; ++i)
  {
    Vi1[i * 4] = (R[i] >> 24) & 0xFF;
    Vi1[i * 4 + 1] = (R[i] >> 16) & 0xFF;
    Vi1[i * 4 + 2] = (R[i] >> 8) & 0xFF;
    Vi1[i * 4 + 3] = (R[i]) & 0xFF;
  }
  /// Vi1 = ABCDEFGH ^ Vi
  for (size_t i = 0; i < 256 / 8; ++i)
  {
    Vi1[i] ^= Vi[i];
  }
}

void SM3Hash(const unsigned char* m, const int ml, unsigned char r[32])
{
  const int l = ml * 8;
  int k = (448 - 1) - (l % 512);/// 添加k个0,k 是满足 l + 1 + k ≡ 448mod512 的最小的非负整数
  if (k <= 0)
  {
    k += 512;
  }

  const int n = (l + k + 65) / 512; /// 多少个64Bytes的块

//  const int m1l = n * (512 / 8); /// 填充后的字节长度,512位的倍数

  /// calculate the final 64Bytes data for later usage
  unsigned char finalBlk[512 / 8] = {0};
  const int leftOver = ml % 64;
  const int startPos = ml - leftOver;
  memcpy(finalBlk, m + startPos, leftOver);
  finalBlk[leftOver] = 0x80; /// 消息后补1

  /// 再添加一个64位比特串,该比特串是长度l的二进制表示
  uint32_t l1 = l;
  for (int i = 0; i < (64 / 8) && l1 > 0; ++i)
  {
    finalBlk[64 - 1 - i] = l1 & 0xFF;
    l1 >>= 8;
  }


  /// 将填充后的消息m′按512比特进行分组:m′ = B(0)B(1)· · · B(n-1),其中n=(l+k+65)/512
  unsigned char V0_[256 / 8];
  unsigned char V1_[256 / 8] = {0};
  /// 初始化 V0 <=== IV
  memcpy(V0_, IV, 256/8);

  /// 压缩函数,V 与扩展的B
  unsigned char* pi_ = V0_;
  unsigned char* pj_ = V1_;
  const unsigned char* BPtr = m; /// 初始指向数组首地址
  /// 最前面的n-1个块的update处理逻辑
  for (int i = 0; i < n - 1; ++i)
  {
    CF(pi_, BPtr, pj_);
    BPtr += 64; /// adjust ptr advancing one block(64bytes) for the next loop
    /// swap two pointers for the next loop
    unsigned char* tmp = pi_;
    pi_ = pj_;
    pj_ = tmp;
  }
  /// 上面循环执行完毕后, pi_将保存最终的结果值, pi_是结果
  /// 最后一个填充块的final处理逻辑
  CF(pi_, finalBlk, pj_);
  /// 得到最终结果
  memcpy(r, pj_, 32);
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值