前端哈希算法大揭秘

关注我们 文末有福利

作者简介

陈龙

转转平台运营部前端负责人,9年前端经验,含3年技术管理,平时喜欢研究一些技术方案,写写文章,做做分享。

背景

前端做流量AB测

AB测应该注意什么?

  • 保证流量分配尽量准确

  • 命中某项规则的用户,下次访问依旧是命中相同规则

  • 每个AB测相互独立

有同学说了:让server做不就行了

那我想问:前端不能做么?

于是我就打算在前端实现。

怎么做分流

通常第一时间会想到:哈希算法

然后再将生成的hash值转换成0-99间的数字,再按比例分配就可以了

另外,误差要尽可能的小

比如:10W个hash值,转换后落在每个区间[0-9] [10-19] ..., [90-99] 各10%

当hash算法是现成的,直接拿过来用就行了

那问题来了,为什么hash能做到?

hash在数据结构中的含义和密码学中的含义并不相同,所以在这两种不同的领域里,算法的设计侧重点也不同

什么是hash算法

Hash算法也被称为散列算法,就是把任意长度的字符串,通过散列算法,变换成固定长度的输出,而输出值没有任何规律,这就是散列值

虽然被称为算法,但实际上它更像是一种思想

Hash算法没有一个固定的公式,只要符合散列思想的算法都可以被称为是Hash算法

什么是散列思想?

对于每一个值,都可以唯一地映射到散列表中的一个位置,而且让位置分配尽可能的均匀

hash算法的特点

它是一种压缩映射,散列值的空间远远小于输入空间,不同的输入可能会有相同的输出。

  • 抗碰撞能力:对于任意两个不同的数据块,其hash值相同的可能性极小;对于一个给定的数据块,找到和它hash值相同的数据块极为困难。

  • 抗篡改能力:对于一个数据块,哪怕只改动其一个比特位,其hash值的改动也会非常大。

  • 固定输出长度:无论多长的输入,输出一定是固定长度

  • 单向唯一:它是一种单向密码体制,即它是一个从明文到密文的不可逆的映射,只有加密过程,没有解密过程

  • 相同输入相同输出:同样的输入,每次都有同样的输出

以MD算法为例:

MD5("version1") = "966634ebf2fc135707d6753692bf4b1e";
MD5("version2") = "2e0e95285f08a07dea17e7ee111b21c8";

使用类型

在数据结构中

hash出来的key,只要保证value大致均匀的放在不同的桶里就可以了

比如hashmap,hash值(key)存在的目的是加速键值对的查找,key的作用是为了将元素适当地放在各个桶里,对于抗碰撞的要求没有那么高。

在密码学中

hash算法的作用主要是用于消息摘要和签名,换句话说,它主要用于对整个消息的完整性进行校验。

比如存储用户的账户密码信息,数据库里是不会存储明文的,通常是存储加密后的md5值,后台会把用户输入的账户和密码做md5,然后和库里存储的md5值做比对。

常见的hash算法

MD4

MD4(RFC 1320)是 MIT 的Ronald L. Rivest在 1990 年设计的,MD 是 Message Digest(消息摘要) 的缩写。它适用在32位字长的处理器上用高速软件实现——它是基于 32位操作数的位操作来实现的。

MD5

MD5(RFC 1321)是 Rivest 于1991年对MD4的改进版本。它对输入仍以512位分组,其输出是4个32位字的级联,与 MD4 相同。MD5比MD4来得复杂,并且速度较之要慢一点,但更安全,在抗分析和抗差分方面表现更好。

SHA-1

SHA1是由NIST NSA设计的,SHA1对任意长度明文的预处理和MD5的过程是一样的,即预处理完后的明文长度是512位的整数倍,但是有一点不同,那就是SHA1的原始报文长度不能超过2的64次方,然后SHA1生成160位的报文摘要。SHA1算法简单而且紧凑,容易在计算机上实现。

因为我用到的是sha-1算法,所以本次分享是基于sha-1算法的分析

SHA-1算法

算法介绍

SHA-1(英语:Secure Hash Algorithm 1,中文名:安全散列算法1)是一种密码散列函数,美国国家安全局设计,并由美国国家标准技术研究所(NIST)发布为联邦数据处理标准(FIPS)。SHA-1可以生成一个被称为消息摘要的160位(20字节)散列值,散列值通常的呈现形式为40个十六进制数。(来自百度)

SHA1的算法已被破解,出于安全考虑官方推荐用SHA2代替,

但作为不涉及安全性的功能(如AB测分流)依旧不失为一种选择

本次算法分析主要是跟大家一起了解Hash算法世界,并非要破解

里面会用到大量的位运算,如果不熟悉的同学,可以参看前面的文章《JavaScript位运算最强指南》

算法思路

  1. 对任意长度的明文字符串,转换成数字(32位二进制),并进行初始化分组,

  2. 将初始分组后的数组每16个元素分为一组,不足16个元素部分会补齐

  3. 申请5个32位的计算因子,记为A、B、C、D、E。

  4. 每个分组进行80次复杂混合运算,每个分组计算完成后,得出新的A、B、C、D、E

  5. 将新的A、B、C、D、E和老的A、B、C、D、E分别进行求和运算,得出新的计算因子,并重复(4 到 5)的操作,得出最终的A、B、C、D、E

  6. 将最终得出的A、B、C、D、E每个元素进行8次混合运算,得出40位16进制hash码

js-sha1算法

var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode    */
function hex_sha1(s) {
  return binb2hex(core_sha1(str2binb(s), s.length * chrsz));
}

/*
 * Convert an 8-bit or 16-bit string to an array of big-endian words
 * In 8-bit function, characters >255 have their hi-byte silently ignored.
 */
function str2binb(str) {
  var bin = Array();
  var mask = (1 << chrsz) - 1;
  for (var i = 0; i < str.length * chrsz; i += chrsz)
    bin[i >> 5] |= (str.charCodeAt(i / chrsz) & mask) << (24 - i % 32);
  return bin;
}

/*
 * Bitwise rotate a 32-bit number to the left.
 */
function rol(num, cnt) {
  return (num << cnt) | (num >>> (32 - cnt));
}

/*
 * Calculate the SHA-1 of an array of big-endian words, and a bit length
 */
function core_sha1(x, len) {
  /* append padding */
  x[len >> 5] |= 0x80 << (24 - len % 32);
  x[((len + 64 >> 9) << 4) + 15] = len;
  var w = Array(80);
  var a = 1732584193;
  var b = -271733879;
  var c = -1732584194;
  var d = 271733878;
  var e = -1009589776;
  for (var i = 0; i < x.length; i += 16) {
    var olda = a;
    var oldb = b;
    var oldc = c;
    var oldd = d;
    var olde = e;
    for (var j = 0; j < 80; j++) {
      if (j < 16) w[j] = x[i + j];
      else w[j] = rol(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1);
      var t = safe_add(safe_add(rol(a, 5), sha1_ft(j, b, c, d)), safe_add(safe_add(e, w[j]), sha1_kt(j)));
      e = d;
      d = c;
      c = rol(b, 30);
      b = a;
      a = t;
    }
    a = safe_add(a, olda);
    b = safe_add(b, oldb);
    c = safe_add(c, oldc);
    d = safe_add(d, oldd);
    e = safe_add(e, olde);
  }
  return Array(a, b, c, d, e);
}

/*
 * Add integers, wrapping at 2^32. This uses 16-bit operations internally
 * to work around bugs in some JS interpreters.
 */
funct
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值