加入收藏 | 设为首页 | 会员中心 | 我要投稿 揭阳站长网 (https://www.0663zz.cn/)- 机器学习、行业智能、决策智能、云计算、AI应用!
当前位置: 首页 > 站长学院 > PHP教程 > 正文

用PHP实现自己的sha-256哈希算法!

发布时间:2022-08-10 11:20:40 所属栏目:PHP教程 来源:互联网
导读:哈希 又称作 散列,它接收任何一组任意长度的输入信息,通过 哈希 算法变换成固定长度的数据指纹,该指纹就是 哈希值。总体而言,哈希 可理解为一种消息摘要。 在 PHP 中有这个函数 hash(),可以计算字符串的哈希值,出于好奇我 Google 了一下哈希计算的具体
  哈希 又称作 “散列”,它接收任何一组任意长度的输入信息,通过 哈希 算法变换成固定长度的数据指纹,该指纹就是 哈希值。总体而言,哈希 可理解为一种消息摘要。
  在 PHP 中有这个函数 hash(),可以计算字符串的哈希值,出于好奇我 Google 了一下哈希计算的具体步骤,并使用 PHP 编写了一套计算 sha-256 哈希值的代码。当然除了 sha-256 以外还有一些别的哈希算法,只是目前 sha-256 用的多一些。下面是目前 美国国家标准与技术研究院 发布哈希算法:
 
  哈希算法 输入大小(bits) 分块大小(bits) 行大小(bits) 生成二进制长度(bits) 生成十六进制长度(chars)
  sha1 < 2^64 512 32 160 40
  sha-224 < 2^64 512 32 224 56
  sha-256 < 2^64 512 32 256 64
  sha-384 < 2^128 1024 64 384 96
  sha-512 < 2^128 1024 64 512 128
  sha-512/224 < 2^128 1024 64 224 56
  sha-512/256 < 2^128 1024 64 256 64
  在编写过程中我主要参考了以下文档和站点:
 
 
 
 
  Lane Wagner - How SHA-256 Works Step-By-Step:https://blog.boot.dev/cryptography/how-sha-2-works-step-by-step-sha-256/
 
  Secure Hash Standard (SHS) - FIPS 180-4(官方文档):https://csrc.nist.gov/publications/detail/fips/180/4/final
 
  ASCII Table:https://www.asciitable.com/
 
  本文内容较多,主要分为下面这几个部分,读者阅读时可以先跳过 准备二:助手方法 直接进入 步骤 部分,在阅读 步骤 部分需要用到指定方法时再回过头来查阅 准备二:助手方法 中的函数。
 
  准备一:代码主体
 
  准备二:助手方法(阅读时可先跳过)
 
  步骤一:字符串转二进制
 
  步骤二:追加数字 1
 
  步骤三:填充至 512 的倍数
 
  步骤四:追加原始长度信息
 
  步骤五:切分区块并填充至 2048 位
 
  步骤六:区块数据修改
 
  步骤七:压缩
 
  准备一:代码主体
  我们创建一个类 Algorithm 来存放我们计算哈希所需要用到的方法和属性。这个类中只有一个 public 的方法 sha256(),此方法传入一个字符串参数,输出此字符串的 sha-256 哈希值。要完成我们的哈希计算,总共需要经过七个步骤,我们先把这七个步骤的调用写到 sha256() 的函数体中。
 
 
 
  <?php
 
  declare(strict_types=1);
 
  class Algorithm
 
  {
 
      public function sha256(string $str): string
 
      {
 
          // 步骤一:将字符串转化为二进制
 
          $this->step1_convert_str_to_bits($str);
 
          // 步骤二:在最后面追加一个1
 
          $this->step2_append_1();
 
          // 步骤三:在数据末尾添加0,确保二进制的个数是512的倍数,最后预留64位用于存储原始长度信息
 
          $this->step3_extend_to_multiple_of_512();
 
          // 步骤四:把原始字符串位长度,填充到预留在最后的64位(8个字节的长整型)中
 
          $this->step4_append_origin_length();
 
          // 步骤五:每一个512位切分区块,在区块末尾填充0,使得每个区块位数为2048位,需要增加48行(32位一行)
 
          $this->step5_split_blocks_and_append_48_lines();
 
          // 步骤六:针对每一个2048位区块处理:以32位为一行,总共有64行,修改【16-63】行的数据
 
          $this->step6_modify_blocks_appended_48_lines();
 
          // 步骤七:压缩数据,生成最终的哈希值
 
          return $this->step7_compress_to_final_hash();
 
      }
 
  }
 
  除了 sha256() 这个函数外, 我们要需要几个成员属性来保存计算过程中产生的数据。
 
  $originLen 属性用于记录字符串被转化为二进制之后的原始长度,这个长度值后续会追加到数据中去。
 
 
 
  /** @var int 原始数据的二进制长度  */
 
  private int $originLen = 0;
 
  $bits 属性用于储存字符串转化后得到的二进制数据。
 
 
 
  /** @var array 存储二进制数组 */
 
  private array $bits;
 
  $blocks 存放分块后的二进制数据。
 
 
 
  /** @var array 二进制区块 */
 
  private array $blocks;
 
  H 哈希计所需的常量,hash-256 的 8 个哈希常量是质数 2、3、5、7、11、13、17、19 各自平方根取二进制小数部分前 32 位所得。
 
 
 
  /** @var array 质数平方根常量 */
 
  private const H = [
 
      0x6a09e667, // 质数2的平方根取二进制小数部分前32位
 
      0xbb67ae85, // 质数3的平方根取二进制小数部分前32位
 
      0x3c6ef372, // 质数5的平方根取二进制小数部分前32位
 
      0xa54ff53a, // 质数7的平方根取二进制小数部分前32位
 
      0x510e527f, // 质数11的平方根取二进制小数部分前32位
 
      0x9b05688c, // 质数13的平方根取二进制小数部分前32位
 
      0x1f83d9ab, // 质数17的平方根取二进制小数部分前32位
 
      0x5be0cd19, // 质数19的平方根取二进制小数部分前32位
 
  ];
 
  对于上面这几个常量,感兴趣的同学也可以自己计算得到,我这里只提供一个简单的计算示例,以质数 2 为例,我们先通过计算器得到它的平方根:1.4142135623730950488016887242097 然后只取小数部分:0.4142135623730950488016887242097,接着将这个十进制的小数转为二进制,转为流程如下:
 
 
 
  小数转二进制
 
                              0.
 
  0.4142135623730950488016887242097 x 2 => 0
 
  0.8284271247461900976033774484194 x 2 => 1
 
  0.6568542494923801952067548968388 x 2 => 1
 
  0.3137084989847603904135097936776 x 2 => 0
 
  0.6274169979695207808270195873552 x 2 => 1
 
  0.2548339959390415616540391747104 x 2 => 0
 
  0.~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ x 2 => 1
 
  0.~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ x 2 => 0
 
  0.~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ x 2 => 0
 
  0.~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ x 2 => 0
 
  0.~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ x 2 => 0
 
  0.~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ x 2 => 0
 
  0.~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ x 2 => 1
 
  0.~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ x 2 => 0
 
  0.~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ x 2 => 0
 
  0.~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ x 2 => 1
 
  0.~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ x 2 => 1
 
  0.~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ x 2 => 1
 
  0.~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ x 2 => 1
 
  0.~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ x 2 => 0
 
  0.~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ x 2 => 0
 
  . . .
 
  上面计算得到的小数部分二进制,取前 32 位:01101010 00001001 11100110 01100111,转为十六进制表示:0x6a09e667,其他几个质数的计算也是类似。当然由于是常量,值是固定不变的,所以我们只要知道其计算原理即可。
 
  和上面的平方根常量类似,hash-256 的另外 64 个常量是质数 2、3、5、…、311 各自立方根取二进制小数部分前 32 位。

(编辑:揭阳站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    热点阅读