精华内容
下载资源
问答
  • PostgreSQL的MD5加密不重复的方法
    千次阅读
    2015-09-21 16:41:15

    需求:在查用户表时,不同的用户可能会输入相同的密码,怎么使得存储的时变得不同?


    解决:存储用户敏感信息一般会存储加密过的数据,这样可以防止用户的信息泄漏,一般使用的加密方式就是MD5的方式存储,而MD5就是把一个任意长度的字节串变换成一定长的十六进制数字串,固然不同的用户有可能会输入相同的密码,一般用户名都是公开的,假如使用一个用户的密码查库,得到另一个用户的用户名,固然也可以进入到另一个人的账号,所以这样还是有点不安全的,以下介绍最近学到的两种比较安全的加密方式:

    方式1:一般在建表时用户名都是唯一的,固然不会重复,那么何不将用户的用户名与密码放在一起MD5结果存储为密码呢(passwd_store = MD5(username+passwd_input)),这样也就不会重复了,而且实现也比较简单。

    方式2   PostgreSQL 的 pgcrypto 模块实现 

    首先需要创建外部模块pgcrypto : create extension pgcrypto ;

    使用方式:

    insert into crm.test_user(username, password) values ('user', crypt('123456', gen_salt('md5')));  //插入

    select * from crm.test_user where username ='user' and password=crypt('123456',password);  //查询或验证

    相关函数:

    crypt(password text, salt text) returns text

        Calculates a crypt(3)-style hash of password. When storing a new password, you need to use gen_salt() to generate a new salt value. To check a password, pass the stored hash value as salt, and test whether the result matches the stored value.

     crypt() 函数支持的加密算法


    gen_salt(type text [, iter_count integer ]) returns text

    Generates a new random salt string for use in crypt(). The salt string also tells crypt() which algorithm to use.
    The type parameter specifies the hashing algorithm. The accepted types are: des, xdes, md5 and bf.



    更多相关内容
  • giffer-md5-重复 永远不会从相同的 URL 下载 GIF。 但是,如果相同的 GIF 来自不同的 URL(例如,当两个适配器在不同的站点上找到相同的 GIF),则 giffer 将同时下载它们。 giffer-md5-duplicates另外将 md5 哈希...
  • 为什么使用 MD5 存储密码非常危险

    千次阅读 2019-12-29 21:47:00
    很多软件工程师都认为 MD5 是一种加密算法,然而这种观点其实是大错特错并且十分危险的,作为一个 1992 年第一次被公开的算法,到今天为止已经被发现了一些致命的漏洞,我们在生产环境的任...

    很多软件工程师都认为 MD5 是一种加密算法,然而这种观点其实是大错特错并且十分危险的,作为一个 1992 年第一次被公开的算法,到今天为止已经被发现了一些致命的漏洞,我们在生产环境的任何场景都不应该继续使用 MD5 算法,无论是对数据或者文件的内容进行校验还是用于所谓的『加密』。

    这篇文章的主要目的是帮助读者理解 MD5 到底是什么,为什么我们不应该继续使用它,尤其是不应该使用它在数据库中存储密码,作者也希望使用过 MD5 或者明文存储密码的开发者们能够找到更加合理和安全的方式对用户的这些机密信息进行存储(这样也可以间接提高我在各类网站中存储密码的安全性)。

    概述

    与『为什么我们不能使用 MD5 来存储密码?』这一问题相似的其实还有『为什么我们不能使用明文来存储密码?』,使用明文来存储密码是一种看起来就不可行的方案,除非我们能够 100% 保证数据库中的密码字段不会被任何人访问到,不仅包括潜在的攻击者,还包括系统的开发者和管理员。

    不过这是一个非常理想的情况,在实际的生产环境中,我们不能抵御来自黑客的所有攻击,甚至也不能完全阻挡开发者和管理员的访问,因为我们总需要信任并授权一些人或者程序具有当前数据库的所有访问权限,这也就给攻击者留下了可以利用的漏洞,在抵御外部攻击时我们没有办法做到全面,只能尽可能提高攻击者的成本,这也就是使用 MD5 或者其他方式存储密码的原因了。

    很多开发者对于 MD5 的作用和定义都有着非常大的误解,MD5 并不是一种加密算法,而是一种摘要算法,我们也可以叫它哈希函数,哈希函数可以将无限键值空间中的所有键都均匀地映射到一个指定大小的键值空间中;一个好的摘要算法能够帮助我们保证文件的完整性,避免攻击者的恶意篡改,但是加密算法或者加密的功能是 —— 通过某种特定的方式来编码消息或者信息,只有授权方可以访问原始数据,而没有被授权的人无法从密文中获取原文。

    由于加密需要同时保证消息的秘密性和完整性,所以加密的过程使用一系列的算法,MD5 确实可以在加密的过程中作为哈希函数使用来保证消息的完整性,但是我们还需要另一个算法来保证消息的秘密性,所以由于 MD5 哈希的信息无法被还原,只依靠 MD5 是无法完成加密的。

    在任何场景下,我们都应该避免 MD5 的使用,可以选择更好的摘要算法替代 MD5,例如 SHA256、SHA512。

    聊了这么多对于 MD5 的误解,我们重新回到今天最开始的题目,『为什么 MD5 不能用于存储密码』,对于这个问题有一个最简单的答案,也就是MD5 不够安全。当整个系统中的数据库被攻击者入侵之后,存储密码的摘要而不是明文是我们能够对所有用户的最大保护。需要知道的是,不够安全的不只是 MD5,任何摘要算法在存储密码这一场景下都不够安全,我们在这篇文章中就会哈希函数『为什么哈希函数不能用于存储密码』以及其他相关机制的安全性。

    设计

    既然我们已经对哈希函数和加密算法有了一些简单的了解,接下来的这一节中分析使用以下几种不同方式存储密码的安全性:

    • 使用哈希存储密码;

    • 使用哈希加盐存储密码;

    • 使用加密算法存储密码;

    • 使用 bcrypt 存储密码;

    在分析的过程中可能会涉及到一些简单的密码学知识,也会谈到一些密码学历史上的一些事件,不过这对于理解不同方式的安全性不会造成太大的障碍。

    哈希

    在今天,如果我们直接使用哈希来存储密码,那其实跟存储明文没有太多的区别,所有的攻击者在今天都已经掌握了彩虹表这个工具,我们可以将彩虹表理解成一张预计算的大表,其中存储着一些常见密码的哈希,当攻击者通过入侵拿到某些网站的数据库之后就可以通过预计算表中存储的映射来查找原始密码。

    攻击者只需要将一些常见密码提前计算一些哈希就可以找到数据库中很多用于存储的密码,Wikipedia 上有一份关于最常见密码的 列表,在 2016 年的统计中发现使用情况最多的前 25 个密码占了调查总数的 10%,虽然这不能排除统计本身的不准确因素,但是也足以说明仅仅使用哈希的方式存储密码是不够安全的。

    哈希加盐

    仅仅使用哈希来存储密码无法抵御来自彩虹表的攻击,在上世纪 70 到 80 年代,早期版本的 Unix 系统就在/etc/passwrd中存储加盐的哈希密码,密码加盐后的哈希与盐会被一起存储在/etc/passwd文件中,今天哈希加盐的策略与几十年前的也没有太多的不同,差异可能在于盐的生成和选择:

    md5(salt, password), salt
    

    加盐的方式主要还是为了增加攻击者的计算成本,当攻击者顺利拿到数据库中的数据时,由于每个密码都使用了随机的盐进行哈希,所以预先计算的彩虹表就没有办法立刻破译出哈希之前的原始数据,攻击者对每一个哈希都需要单独进行计算,这样能够增加了攻击者的成本,减少原始密码被大范围破译的可能性。

    在这种情况下,攻击者破解一个用户密码的成本其实就等于发现哈希碰撞的概率,因为攻击者其实不需要知道用户的密码是什么,他只需要找到一个值value,这个值加盐后的哈希与密码加盐后的哈希完全一致就能登录用户的账号:

    hash(salt, value) = hash(salt, password)
    

    这种情况在密码学中叫做哈希碰撞,也就是两个不同值对应哈希相同,一个哈希函数或者摘要算法被找到哈希碰撞的概率决定了该算法的安全性,早在几十年前,我们就在 MD5 的设计中发现了缺陷并且在随后的发展中找到了低成本快速制造哈希碰撞的方法。

    1. 1996 年 The Status of MD5 After a Recent Attack —— 发现了 MD5 设计中的缺陷,但是并没有被认为是致命的缺点,密码学专家开始推荐使用其他的摘要算法;

    2. 2004 年 How to Break MD5 and Other Hash Functions ——  发现了 MD5 摘要算法不能抵抗哈希碰撞,我们不能在数字安全领域使用 MD5 算法;

    3. 2006 年 A Study of the MD5 Attacks: Insights and Improvements —— 创建一组具有相同 MD5 摘要的文件;

    4. 2008 年 MD5 considered harmful today —— 创建伪造的 SSL 证书;

    5. 2010 年 MD5 vulnerable to collision attacks —— CMU 软件工程机构认为 MD5 摘要算法已经在密码学上被破译并且不适合使用;

    6. 2012 年 Flame ——  恶意软件利用了 MD5 的漏洞并伪造了微软的数字签名;

    从过往的历史来看,为了保证用户敏感信息的安全,我们不应该使用 MD5 加盐的方式来存储用户的密码,那么我们是否可以使用更加安全的摘要算法呢?不可以,哈希函数并不是专门用来设计存储用户密码的,所以它的计算可能相对来说还是比较快,攻击者今天可以通过 GPU 每秒执行上亿次的计算来破解用户的密码,所以不能使用这种方式存储用户的密码,感兴趣的读者可以了解一下用于恢复密码的工具 Hashcat。

    加密

    既然今天的硬件已经能够很快地帮助攻击者破解用户的密码,那么我们能否通过其他的方式来取代哈希函数来存储密码呢?有些工程师想到使用加密算法来替代哈希函数,这样能够从源头上避免哈希碰撞的的发生,这种方式看起来非常美好,但是有一个致命的缺点,就是我们如何存储用于加密密码的秘钥

    既然存储密码的仓库能被泄露,那么用于存储秘钥的服务也可能会被攻击,我们永远都没有办法保证我们的数据库和服务器是安全的,一旦秘钥被攻击者获取,他们就可以轻而易举地恢复用户的密码,因为核对用户密码的过程需要在内存对密码进行解密,这时明文的密码就可能暴露在内存中,依然有导致用户密码泄露的风险。

    使用加密的方式存储密码相比于哈希加盐的方式,在一些安全意识和能力较差的公司和网站反而更容易导致密码的泄露和安全事故。

    bcrypt

    哈希加盐的方式确实能够增加攻击者的成本,但是今天来看还远远不够,我们需要一种更加安全的方式来存储用户的密码,这也就是今天被广泛使用的bcrypt,使用bcrypt相比于直接使用哈希加盐是一种更加安全的方式,也是我们目前推荐使用的方法,为了增加攻击者的成本,bcrypt引入了计算成本这一可以调节的参数,能够调节执行bcrypt函数的成本。

    当我们将验证用户密码的成本提高几个数量级时,攻击者的成本其实也相应的提升了几个数量级,只要我们让攻击者的攻击成本大于硬件的限制,同时保证正常请求的耗时在合理范围内,我们就能够保证用户密码的相对安全。

    "bcryptwas designed for password hashing hence it is a slow algorithm. This is good for password hashing as it reduces the number of passwords by second an attacker could hash when crafting a dictionary attack. "

    bcrypt这一算法就是为哈希密码而专门设计的,所以它是一个执行相对较慢的算法,这也就能够减少攻击者每秒能够处理的密码数量,从而避免攻击者的字典攻击。

    func main() {
        for cost := 10; cost <= 15; cost++ {
            startedAt := time.Now()
            bcrypt.GenerateFromPassword([]byte("password"), cost)
            duration := time.Since(startedAt)
            fmt.Printf("cost: %d, duration: %v\n", cost, duration)
        }
    }
    
    $ go run bcrypt.go
    cost: 10, duration: 51.483401ms
    cost: 11, duration: 100.639251ms
    cost: 12, duration: 202.788492ms
    cost: 13, duration: 399.552731ms
    cost: 14, duration: 801.041128ms
    cost: 15, duration: 1.579692689s
    

    运行上述 代码片段 时就能发现cost和运行时间的关系,算法运行的成本每+1,当前算法最终的耗时就会翻一倍,这与bcrypt算法的实现原理有关,你可以在 Wikipedia 上找到算法执行过程的伪代码,这可以帮助我们快速理解算法背后的设计。

    如果硬件的发展使攻击者能够对使用bcrypt存储的密码进行攻击时,我们就可以直接提升bcrypt算法的cost参数以增加攻击者的成本,这也是bcrypt设计上的精妙之处,所以使用bcrypt是一种在存储用户密码时比较安全的方式。

    总结

    这篇文章分析的问题其实是 —— 当数据库被攻击者获取时,我们怎么能够保证用户的密码很难被攻击者『破译』,作为保护用户机密信息的最后手段,选择安全并且合适的方法至关重要。攻击者能否破解用户的密码一般取决于两个条件:

    • 使用的加密算法是否足够安全,使用暴力破解的方式时间成本极高;

    • 足够好的硬件支持,能够支持大规模地高速计算哈希;

    抵御攻击者的攻击的方式其实就是提高单次算法运行的成本,当我们将用户的验证耗时从0.1ms提升到了500ms,攻击者的计算成本也就提升了 5000 倍,这种结果就是之前需要几小时破解的密码现在需要几年的时间。

    不论如何,使用 MD5、MD5 加盐或者其他哈希的方式来存储密码都是不安全的,希望各位工程师能够避免在这样的场景下使用 MD5,在其他必须使用哈希函数的场景下也建议使用其他算法代替,例如 SHA-512 等。

    当然,如何保证用户机密信息的安全不只是一个密码学问题,它还是一个工程问题,任何工程开发商的疏漏都可能导致安全事故,所以我们作为开发者在与用于敏感信息打交道时也应该小心谨慎、怀有敬畏之心。到最后,我们还是来看一些比较开放的相关问题,有兴趣的读者可以仔细思考一下下面的问题:

    1. 使用 GPU 每秒可以计算多少 MD5 哈希(数量级)?能够在多长时间破解使用 MD5 加盐存储的密码?

    2. 假设计算一次哈希耗时500ms,破解bcrypt算法生成的哈希需要多长时间?

    3. MD5 哈希23cdc18507b52418db7740cbb5543e54对应的原文可能是?谈谈你使用的工具和破译的过程。

    如果对文章中的内容有疑问或者想要了解更多软件工程上一些设计决策背后的原因,可以在博客下面留言,作者会及时回复本文相关的疑问并选择其中合适的主题作为后续的内容。

    Reference

    • Is salted MD5 or salted SHA considered secure?

    • How to securely hash passwords?

    • Rainbow table

    • The MD5 Message-Digest Algorithm · RFC1321

    • Collision (computer science)

    • Why You Should Use Bcrypt to Hash Stored Passwords

    • How can bcrypt have built-in salts?

    • bcrypt

    猜你喜欢

    1、Delta Lake 0.5.0 正式发布,支持包括 Hive/Presto 等多种查询引擎

    2、当小内存遇上大量数据,你该怎么解决这个问题?

    3、从 Hive 大规模迁移作业到 Spark 在有赞的实践

    4、Docker 核心技术与实现原理

    过往记忆大数据微信群,请添加微信:fangzhen0219,备注【进群】

    展开全文
  • 而且只要是文件不一样,MD5码肯定不一样,这个是不会重复的,那么到底如何获取文件的MD5码呢?下面就使用C#代码进行讲解。 代码如下://———————————————————————–using System;using System...
  • 为什么MD5是不可逆的? 先说大白话版本的,因为MD5算法里面有很多不可逆的运算。比如移位,假设:10010001 左移两位后是:01000100,你有什么办法把它移回来吗?移出去的已经找不回了哦. MD5是一种散列函数,使用的...

    为什么MD5是不可逆的?

    先说大白话版本的,因为MD5算法里面有很多不可逆的运算。比如移位,假设:10010001 左移两位后是:01000100,你有什么办法把它移回来吗?移出去的已经找不回了哦.  

    MD5是一种散列函数,使用的是hash算法,不可逆的原因是在计算过程中原文的部分信息是丢失了的. 一个MD5理论上的确是可能对应无数多个原文的,因为MD5是有限多个的而原文可以是无数多个。比如主流使用的MD5将任意长度的“字节串映射为一个128bit的大整数。也就是一共有2^128种可能,大概是3.4*10^38,这个数字是有限多个的,而但是世界上可以被用来加密的原文则会有无数的可能性。以无限 <--> 有限, 所以想通过有限还原无限是不可能的.

    下面两个二进制串

    d131dd02c5e6eec4693d9a0698aff95c 2fcab58712467eab4004583eb8fb7f89 
    55ad340609f4b30283e488832571415a 085125e8f7cdc99fd91dbdf280373c5b 
    d8823e3156348f5bae6dacd436c919c6 dd53e2b487da03fd02396306d248cda0 
    e99f33420f577ee8ce54b67080a80d1e c69821bcb6a8839396f9652b6ff72a70
    

    and

    d131dd02c5e6eec4693d9a0698aff95c 2fcab50712467eab4004583eb8fb7f89 
    55ad340609f4b30283e4888325f1415a 085125e8f7cdc99fd91dbd7280373c5b 
    d8823e3156348f5bae6dacd436c919c6 dd53e23487da03fd02396306d248cda0 
    e99f33420f577ee8ce54b67080280d1e c69821bcb6a8839396f965ab6ff72a70 

    有完全相同的 MD5:79054025255fb1a26e4bc422aef54eb4

    不过需要注意的一点是,尽管这是一个理论上的有限对无限,不过问题是这个无限在现实生活中并不完全成立,因为一方面现实中原文的长度往往是有限的(以常用的密码为例,一般人都在20位以内),另一方面目前想要发现两段原文对应同一个MD5(专业的说这叫杂凑冲撞)值非常困难,因此某种意义上来说,在一定范围内想构建MD5值与原文的一一对应关系是完全有可能的。所以对于MD5目前最有效的攻击方式就是彩虹表,下面在说什么是彩虹表。


    在说彩虹表之前,先说说已经存在的几种破解类似md5这种哈希散列算法方法

    方法一:暴力破解

    我们假设有一个明文123456通过md5加密后得到密文 E10ADC3949BA59ABBE56E057F20F883E,那么我们有了这段密文如何反推他的明文呢?我们假设我们知道他的明文是一个6位数的明文,暴力破解就是不停的算,先用111111进行md5看看得到多少,然后和密文比,发现不一样,然后用111112进行md5再和密文比,还是不一样,就这样一直循环,直到找到一个数n的密文也是 E10ADC3949BA59ABBE56E057F20F883E,那么就说明他的明文可能就是n.为什么说是可能呢?因为对于不同的数进行md5运算后可能会得到同样的密文。很明显这种方式的效率是十分低下的,每一个数我们都要进行一次md5运算然后再把结果和密文进行对比,众所周知,运算是需要时间的,尽管md5运算很快,但任然需要消耗计算机一定的性能。那么我们能不能先把所有可能的密文都算出来,然后放在一张表里,然后直接用我们需要找的密文去这张表里找呢?其实是可得,这种方式其实就是下面要说的查表法。

    方法二:查表法

    把所有可能的密文都算出来,然后放在一张表里,表的数据结构类似如下

    明文

    密文

    1

    C4CA4238A0B923820DCC509A6F75849B

    2

    C81E728D9D4C2F636F067F89CC14862C

    3

    ECCBC87E4B5CE2FE28308FD9F2A7BAF3

    4

    A87FF679A2F3E71D9181A67B7542122C

    .......

    ...........

    然后我们要找某个密文对应的明文的时候,直接用这个明文去表里查询就完了。这个方式省略了每次都进行md5运算这个耗时的操作,确实会比较快,但相比你也已经想到了,我这个表的数据得多大才能涵盖所有的字母+数字+特殊符号的组合?的确如此,这种方式所得到的表数据量是非常惊人的,我们来看一组数据

    对于14位的大小写加数字(先不算特殊字符了)组成的密码的集合有多大?自然就是(26*2+10)^14 = 62^14 = 1.24*10^25,这个就约等于12亿亿亿,即使我们每纳秒可以校验一个p(一秒钟10亿次,目前PC做不到),暴力破解法也大概需要4亿年;如果我们采用查表法,假定Hash的结果是128Bit即16字节的,光存放Hash(不存放明文P)就需要10^26字节的存储空间。什么?现在硬盘很便宜?没错现在 1GB硬盘大概是五毛钱,那么按这个来算光存储这个Hash大概需要5亿亿人民币来买硬盘。

    实际生活中大多数人的密码并不会有14位这么长,所以采用暴力破解法或者查表法具有一定的可行性,但对于强密码的破解,显而易见这两种方式都有点捉颈见肘,局限性很大。那么有没有更好的办法呢?彩虹表的出现就是为了解决这一问题。

    方法三:彩虹表

    先构建一张表

    我们对于一个明文P,进行HASH算法H后得到了一个密文Q,可以进行表示  Q=H(P)

    然后我们额外构建一个函数R(Reduce)。这个函数是Hash的伪逆运算,也就是:R函数的参数是Hash码,得到的是一个位数不定的密码,之所以说伪是因为得到的密码并不是最初的密码。那么表示为 P=R(Q)

    这之后,就要开始一堆骚操作了

    我们先给定任意明文P1,先进性一次H运算,得到Q1,即Q1=H(P1)。然后对Q1进行R运算得到P2,即P2=R(Q1),再对P2进行H运算得到Q2,即Q2=H(P2)。......如此循环下去。假设循环得到n步长,我们就得到一条链,如下:

    然后我们存储P1和Pn,其他的p都不存储,那么这就得到了一个类似于查表法的一张表,只不过他的数据量很明显要少了很多,少了n-2这么多。
    那么有了这个P1和Pn之后,我们如何进行破解呢?

    破解过程

    比如我们拿到一个Hash码,我们先对hash做一次R运算得到一个P,P=R(hash码)

    将这个P跟存储Pn比较,如果P与Pn不相等,那么我们就对P做一次H-R运算,表示为如下

    hash码2 = H(P)
    P2 = R(hash码2)

    然后用P2继续和Pn比较,如果相等的话,因为我们这里只做了一次H-R的运算,说明这个明文就是倒数第二个P,也就是P(n-1),因为

    P(n-1)-H-Q(n-1)-R-Pn

    知道了他是P(n-1),而又因为我们存储了P1的值,那么我们从头开始计算一次, 就可以通过P1得到P(n-1).也就得到了明文了。

    当然还有可能就是,这个hash码做了所有的H-R运算,依然不等于Pn. 那就说明我们这条HASH链并不能破解这个密文,那么就要转而去找其他的HASH链。所以从这里也可以看出,彩虹表破解成功率其实也并不是100%。但只要库的hash链的数据样本足够多,那么破解成功的概率应该是无限接近100%的。

    彩虹表的根本原理就是组合了暴力法和查表法,并在这两者之中取得一个折中,用我们可以承受的时间和存储空间进行破解。当然这里只是讲述了最粗浅的原理,仔细想一下还有很多的问题,例如R的选择,Hash冲突的处理,如何选择p0来实现足够的覆盖,如何在有限资源下生成彩虹表等等。

    所以:严格来说,以上的这种算法并不能叫彩虹表,他被称为预计算的哈希链集.

    哈哈,是不是很失望,我都看到这里了你告诉这个不是彩虹表?别急,其实这个离彩虹表已经很近了,彩虹表也是基于这个做出了改进

    R的问题

    在构造哈希链的时候,一个优秀的函数R功不可没。首先R需要能将值域限定在固定的范围——例如给定的长度范围、给定的字符取值范围等等——之内,否则的话,哈希链中大量的计算结果并不在可接受的取值范围内,一条链条无法对应多个明文,链条就失去了意义;其次R必须同哈希函数一样,尽量保证输出值在值域中的均匀分布,减少碰撞的概率。

    然而实际上,很难找到能满足这些需求的完美的R函数。当计算中发生碰撞时,就会出现如下的情况:

    图中加粗的部分,所涉及到的明文是完全重复的,因此这两条哈希链能解密的明文数量就远小于理论上的明文数2×k。不幸的是,由于集合只保存链条的首末节点,因此这样的重复链条并不能被迅速地发现。随着碰撞的增加,这样的重复链条会逐渐造成严重的冗余和浪费。

    改进

    对于这个问题,2003年提出的彩虹表算法进行了针对性的改进。它在各步的运算中,并不使用统一的R函数,而是分别使用R1…Rk共k个不同的R函数(下划线表示下标)。这样生成的哈希链集即被称为彩虹表。(在不同的运算位置使用不同的R函数,就像彩虹由内而外的不同位置上显示出不同的颜色一样。)这样一来,如果发生碰撞,通常会是下图的情况:

    不难发现,当两个链条发生碰撞的位置并非相同的序列位置时,后续的R函数的不一致使得链条的后续部分也不相同,从而最大程度地减小了链条中的重复节点,保证了链条的有效性。

    同时,如果在极端情况下,两个链条有1/k的概率在同一序列位置上发生碰撞,导致后续链条完全一致,这样的链条也会因为末节点相同而检测出来,可以丢弃其中一条而不浪费存储空间。

    彩虹表的使用比哈希链集稍微麻烦一些。首先,假设要破解的密文位于任一链条的k-1位置处,对其进行Rk运算,看是否能够在末节点中找到对应的值。如果找到,则可以如前所述,使用起节点验证其正确性。否则,需要继续假设密文位于k-2位置处,这时就需要进行Rk-1、H、Rk两步运算,然后在末节点中查找结果。如是反复,最不利条件下需要将密文进行完整的R1、H、…Rk运算后,才能得知密文是否存在于彩虹表之中。

    彩虹表的防御

    了解了彩虹表的原理,那么知道怎么防御彩虹表破解就简单了,很明显的是,如果我们的密码足够的复杂,比如我20位的密码以至于40位的密码,即时使用彩虹表也很难破解,但大多数人并不会采用这么长的密码,那么我们可以在密码后面加盐(salt)以增加密码的长度。

    saltedhash(password) = hash(password+salt)

    如果将用户密码后添加一段随机字符串,然后将随机字符串和散列后的哈希值存储在密码数据库中。彩虹表讲不得不计算出盐化后的密码,而盐化后的密码会大大增加散列前的长度,从而使密码集合过大而变的不可能生成的彩虹表。

    展开全文
  • Md5加密中为什么要 & 0xff

    千次阅读 2017-03-19 12:13:49
    Md5加密中为什么要 & 0xff》 这里首先要搞明白一个代理(自己设想的):  * byte有8位,假如全部都是 11111111 那么对应的int(10进制)类型就是 255  * 虽然255(十进制)和11111111(二进制)都表示同一个数,但...

    《Md5加密中为什么要 & 0xff》

    这里首先要搞明白一个代理(自己设想的):
     *  byte有8位,假如全部都是 11111111 那么对应的int(10进制)类型就是 255
     *  虽然255(十进制)和11111111(二进制)都表示同一个数,但作为String类型存储255作为String类型存储长度为3,而11111111作为string类型存储长度为8
     *  【关键点一:】MessageDigest.getInstance("MD5").digest("需要加密的字符".getBytes()) 计算出来的结果返回的byte[]长度始终为16位。
     *  所以说,真正的密文 是由java别人大神写的算法计算出来的。已经保证16位的固定长度的byte
     *  【关键点二:】要记住我们计算出来的md5(32位)最后都都是固定长度32的字符串
     *  那么问题出现了:byte[16]这个数组要是直接转化为int类型在存储为字符。而byte的取值范围为-128~127.那么作为0-99转化为总长度为16的字符串没有问题,
     *  但,100~128和-10~-128这些数字转换为总长度为16的字符串就不一定了。
     *  因为一个byte数可以是-10(转换为String长度为3)那么这样的16个byte总长度就变成了3*16=48
     *  注意:-128~127一共有256个数字。
     *  即:{1~127}有127个
     *  {-1~-128}有128个
     *  0 有 1个
     *  得:127+128+1=256
     *  那么就需要单独用一个字符位表示256个数字就需要用到256进制。
     *  【常规一:】十进制 一个字符位可以表示10个字符{0,1,2,3,4,5,6,7,8,9}
     *  如果不想将md5生成的密文(byte & 0xff)二直接保存为16个定长度的字符。那么就需要256进制的数字来形容
     *  【注意:】应为负数转为字符串会占用2个长度,应为符号占用一个长度。所以最精简的方法就是用256进制表示,刚好可以满足byte的取值范围将其一一对应。



     *  【总结一:】直接将byte[16]转换为一个长度为16的字符需要【256】进制的数来做直接替换。
     *  那么现在问题来了,字符串中单个字符就能代表到255的符号需要怎么来表示?
     *  当然这是数学家的问题,我们只是苦逼的程序员。即使你想出来了,也没有权威,别人也不会用。
     *  【常规二:】java虚拟机有16精制的数。并且能用1个字符表示{0~15}即{0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f}。
     *      对应的JAVA方法为Integer.toHexString(k),k为int类型的数。
     *   那么一个16精制的正数最大为 f---->(十进制)15
     *   两个16进制的正数最大为 ff---->(十进制)15*16+15=255
     *   那么对于从0 到ff一个有多少个数为:
     *   0---》1个
     *   1~ff--》256个
     *   刚好和byte的取值范围{-128~127}共256个数字可以一一对应。

     *      对应的JAVA方法为Integer.toHexString(k),k为int类型的数。
     *   那么一个16精制的正数最大为 f---->(十进制)15
     *   两个16进制的正数最大为 ff---->(十进制)15*16+15=255
     *   那么对于从0 到ff一个有多少个数为:
     *   0---》1个
     *   1~ff--》256个
     *   刚好和byte的取值范围{-128~127}共256个数字可以一一对应。
     *   【总结二:】如果用16进制的2位数来表示一个byte字节的值,在保证不出现负数的情况下刚好可以完全替换。
     *   只不过对于0-f(15)这样的一个长度的字符串转换为字符串时。为了保证和两位数的16进制保持一致都占用两个长度的字符串,
     *   需要将不足长度的在前面用0补齐。
     *  【总结三:】将byte[16]全部转换为正数的16进制字符串刚好是32位。
     *   即Md5生成的byte[16]固定长度的规律可以得到固定转换为16精制的数表示为固定长度为32的字符串。
     *   当然,你如果觉得用负数替换,保证固定长度。不足的位数用你自己定义的符号去替换当然可以使用.
     *   (解密也需要用你自己定义的符号去计算解密,挨个找出原来的byte[16]个字节)
     *   只不过,在md5算出来的密文中,大家都约定束城了用什么样的字符去替换。
     *  【总结四:】那么在byte[16]转换为16进制的固定长度32的字符串。并不是为了什么,就是为了保证我们可以直观看到的密文都是固定长度的。
     *  延续了在byte[16]这个固定长度的特点。提高了md5的加密的高大上。那么对于每一个byte[16]中的单个byte转换到对应16进制的的二位数
     *  只需要保证都是唯一,一一对应的就行了(保证可逆)(md5算出来的密文byte[16]是不可逆的)。
     *   那么 对于需要加密的密文 "xxxx"-----(不可逆)-->Md5(byte[16])<-----可逆---->16进制的32个长度的字符串。
     *   就可以简化为 "xxxx"------(不可逆)---->16进制的32个长度的字符串。
     *   想想上面这段推理大家都看得懂。
     *   那么对于通用Md5加密后生产32个长度固定的字符串java逻辑为:
     *  

    	/**
    	 * 获取md5密文
    	 * @param pwd 未加密的密码
    	 * @return
    	 */
    	private static String getmd5(String pwd) {
    		StringBuffer str=new StringBuffer();
    		try {
    			MessageDigest md = MessageDigest.getInstance("MD5");
    			byte[] digest = md.digest(pwd.getBytes());
    			for(int i=0;i<digest.length;i++){
    				int k=digest[i] & 0xff;
    				String gdy = Integer.toHexString(k);
    				if(gdy.length()<2){
    					gdy="0"+gdy;
    				}
    				str.append(gdy);
    			}
    		} catch (NoSuchAlgorithmException e) {
    			e.printStackTrace();
    		}
    		System.out.println(str.toString());
    		System.out.println(str.length());
    		return str.toString();
    	}



     *  在了解这么多后我们可以回归到之前的问题了。
     *   【问题:】为什么md5加密中需要将 byte[16] 的每一个数先 & 0xff后再计算呢?
     *   当然,上面已经解释了,这样并不是为了保证两个数据相等,而是为了保正生成的Md5字符串为固定长度32,
     *      并且可以将固定长度32的字符串每两个可逆为原有的byte[16]中的相应字节。至于转换后的相对应的实际值是否相当这个没有必要。
     * 下面我们来看一组数据 你看了下面的一组数据就 明白了。

     *  
     *  【发现规律】
     *  这里我们可以发现 无论byte转int后再转16进制,还是byte & 0xff后再转16进制。在输出的数据中最后两位的结果都是保持一致的
     *  而我们在用md5算法加密时,md5加密后的结果有32位和16位的 上面这种就是转为32位固定长度。
     *  所有在md5(32)位 加密中需要将不足2位的前面补0 
     *   【规律一:】其实如果将byte直接转16进制后将不足2位前面补0,比2位多的前面全部去掉。结果和byte & 0xff生成的32位密文是一样的。
     *  其实还有一个规律:

     *   对于byte类型 强制转换为int10(进制)类型后(无论正负)存储在int(38位)类型里面的最后8位和byte的8位是一样的
     *   对于byte类型 强制转换为16进制后(无论正负)存储在最后的8位也是一样的
     *   【规律二:】byte转int10进制或者转16精制 最后的byte(8位)数字都没有变化
     *  【原理推理证明】
     * 对于计算机而言:一个byte在内存存储占用8个字节 即 00000000---->11111111
     * 对于计算机而言可以用 {11111111---->01111111} 的二进制去完整的表示byte的取值范围 {-128~127}【具体计算规则请百度参考原码,反码,补码。去转10精制,这里不多介绍】
     * 这也就是byte的取值范围为什么是{-128~127}的原因。
     * 【发现规律:】对于byte8位二进制的每一位用0和1的不同组合可以完全对应{-128~127}
     *  而对于int类型来说(去除负数,完全用正数匹配)不考虑二精制转换后数字实际值是否一致的问题,让其一一对应,达到可以逆的目的。
     *  那么int最小的数为:
     *   计算机内部补码:
     *   最小: 00000000 00000000 00000000 00000000 ---》0
     *   最大: 00000000 00000000 00000000 11111111 ---》255(十进制)
     *   而再java中进行  byte[i] & 0xff时有一个默认规律
     *   先将byte[i]转换为int类型存储
     *   在将0xff转换为int类型存储
     *   再运算 (byte[i] & 0xff) 
     *   【知识点:】0xff表示的是一个数,一个16进制的数,转换为十进制后为255
     *   其实(byte[i] & 0xff)就是运算 (byte[i] & 255)两个得到的结果都是一样的
     *   至于为什么要把0xff来替代255个人想法大概就是当初第一次用这个替换法的人觉得这样高大上把。。其实没什么不同。结果都一样。
     *   那么假如 byte[i]内部存储的补码为:11010111
     *   转为int存储后的补码为: 11111111 11111110 11111110 11010111
     *   而0xff转为int存储的补码为: 00000000 00000000 00000000 11111111 ----》即255
     *   那么做&运算结果为: 00000000 00000000 00000000 11010111
     *   由于第一位是0 所有计算后的所有结果都为一个int类型的整数,不会出现负数。
     *   那么这样就把byte[16]完全的用int类型的整数一一对应了。(不考虑前后的实际值,只需要一一对应就行。至于为什么具体原因见【总结四】)
     *   即:{-128 ~ 127} 可以由{0-255}去一一对应。
     *   由于需要将byte[16]转换为固定长度为32的string类型。我们直接用得到的int是不可能的。原因请参考【总结一】的推理
     *   在文章前已经说明了,要想转换为固定长度32的字符串,可以用16进制的数做替换。这样就可以保证从{0-255} 一一对应 {0x00-0xff}(0x表示这个数为16进制)
     *   那么这样就就出现了如下结果:
     *   {-128~127}<----可逆---->{0~255}<--- 可逆--->{0x00~0xff}<---可逆--->长度为32的16进制字符串
     *   即:{-125~127}<-----可逆---->{0x00~0xff}<---可逆--->长度为32的16进制字符串
     *   而md5生成的byte[16]每个可以 & 0xff结算结果得到唯一的一个16进制数,并且不会重复。
     *   那么md5生成的byte[16]就可以客观的用String长度为32的十六进制字符串替代。并且都是唯一对应。
     *  这样就显示可见,方便我们操作。
     *   【重点:】至于Md5(32)生成的密文为什么要有上面的java代码的逻辑生成字符串,其实就是一种将不可逆的byte[16]转换为唯一对应的字符串吧了。
     *  而那种方法已经成为了公认的方法。只不过大家都习惯了用这种转换。如果你能保证将每一个byte[16]转换为唯一的一个字符串,并且可逆,
     *  那么这个算法,也可用。并不一定需要按照上面的方式转换。这样就可以设计自己的密文了。并且这种密文是很难破解的。因为对应关系只有你一个知道。







    展开全文
  • python3 hashlib.md5使用总结

    千次阅读 2021-12-04 21:15:39
    python3中第三方库hashlib.md5摘要算法的使用,以及python3自带hash()函数的比较。
  • MD5加盐,实现一人一密

    千次阅读 2017-11-01 15:18:44
    理论上md5是不可逆的,而且MD5本来也不是作加密使用,而是用来校验...但实际上,真正要破解MD5的人,不会选择逆向逆的明文,都是用hash碰撞。把一些明文密码MD5 hash一遍之后对比哪个MD5值与你的一样。那你的明文就知
  • 什么MD5加密算法? MD5信息摘要算法(英语:MD5 Message-Digest Algorithm),一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致。 MD5加密算法的...
  • 不同字符串的MD5加密后的值可能相同。假如‘123’和‘456’的MD5加密后的值相同。如果我的密码是123,那么我输入456在实际中是不通过的?那么是不是还有其他机制决定?
  • 什么MD5MD5(Message Digest Algorithm,信息摘要算法),一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致。它后面这个数字 5 是因为它是...
  • 破解md5加密的方法

    千次阅读 2015-04-22 15:56:40
    我们知道md5加密是不可逆转的,但是要破解md5的加密也很简单。 网上也有很多在线的破解。既然是不可逆转的,那么网上的那些破解是怎么来的呢? 原因很简单,就是使用穷举法来进行破解。 如:我们计算出键盘上所有...
  • 关于org.apache.commons.codec.digest.DigestUtils的这个类,对一个输入流连续的进行两次加密,输出的MD5码不同,如果多次连续加密,则除过第一次得到的MD5码都一致 前一段儿时间在公司写接口的项目,webservice的...
  • hashCode,MD5,SHA-1的区别和碰撞量级

    千次阅读 2019-11-19 14:46:23
    在java中,默认使用hashCode生成对象...hashcode,md5,SHA-1都是散列加密算法,其中hashcode长度32位,md5为128位,sha-1160位。位数越大,这个数据的数据量就越大,重复的几率越小,但是运算起来越复杂,消耗...
  • MD5是一种HASH函数,又称杂凑函数,由32位16进制组成,在信息安全范畴有广泛和首要运用的暗码算法,它有类似于指纹的运用。在网络安全协议中,杂凑函数用来处理电子签名,将冗长的签名文件紧缩一段一起的数字信息...
  • C++ MD5

    千次阅读 2017-11-11 20:55:39
    因为我实在没办法去证明通过一系列的运算,累加a,b,c,d还能够有唯一性,因为就逆向去看加法,那是有无数解的,MD5也只能说在概率上是不会重复的吧。所以说那个幻数,还有里面的那些数据,是不能
  • java中16位或32位MD5加密

    万次阅读 2016-05-23 17:54:47
    import java.security.... * @Description:MD5加解密工具 * @author:liuyc * @time:2016年5月23日 上午11:11:16 */ public class MD5Helper { /** * @Description:加密-32位小写 * @author:liuyc * @tim
  • UUID和MD5解析

    千次阅读 2018-06-26 17:45:28
    比如,在UNIX下有很多软件在下载的时候都有一个文件名相同,文件扩展名.md5的文件,在这个文件中通常只有一行文本,大致结构如: MD5 (tanajiya.tar.gz) = 0ca175b9c0f726a831d895e269332461 这就是tanajiya.tar...
  • 接口调用方根据签名算法生成签名sign值: sign = MD5(timestamp + appId + appSecret + nonce + version) ,其中 version接口提供方API接口的统一版本号,version默认值固定1.0 。 接口提供方根据签名算法验证...
  • 头条怎么发伪原创视频 修改视频md5不会被 那么,如何改善这两点呢?。 视频自媒体最主要的就是素材,如果你的视频素材对了,标题起的不要太烂,播放量是差不到哪里去的。如果您没有专业团队来做,请相信...
  • MD5 和秒传

    2019-10-17 10:24:52
    MD5:不可逆加密算法,任何文件的输入调用一个MD5的哈希函数,算出来一个32或64位的字符串,算法能够保证只要输入的内容不一样,算出的MD5值一定不会重复。一般密码会存MD5的码 秒传:算本地的MD5值传给服务器,...
  • 关于fbx转化为md5

    千次阅读 2015-12-22 14:23:48
    2者都是模型格式,不要问我为什么要这么转,也不要问我为什么不走插件,有些情况我也说不清楚 Fbx转化为md5 简述: fbx和md5都是3d模型格式就不多作介绍了,直接进入主题;我们的目标是把fbx转化为md5md5的mesh和...
  • 火山小视频消重复技巧 怎么看视频md5 那么在抖音投放广告的费用需要多少呢?A5抖音广告平台提示您:抖音广告费用通常按照达人的粉丝数量、获赞数量,视频播放数量,以及行业类型来做评估,价格通常几千元起步到数...
  • 两个不同的字符串用MD5加密后有没有可能相同md5最长能加多长的字符串,有没有可能超过100位数就会自动截断呢1 你说的两个不同的字符串用MD5计算产生相同结果(散列冲突)是极小概率事件,基本上可以认为不会发生。...
  • api接口签名验证(MD5)

    千次阅读 2018-12-17 10:34:01
    上述的Sign签名的方式能够在一定程度上防止信息被篡改和伪造,保障通信的安全,这里使用的是MD5进行加密,当然实际使用中大家可以根据实际需求进行自定义签名算法,比如:RSA,SHA等。 No Excuse~
  • 【iOS】MD5(加密)/AES/Base64加密和解密

    千次阅读 2016-06-27 20:53:05
    Message Digest Algorithm MD5(中文名消息摘要算法第五版)计算机安全领域广泛使用的一种散列函数,用以提供消息的完整性保护。MD5的典型应用是对一段信息(Message)产生信息摘要(Message-Digest),以防止被...
  • Hash(哈希)算法及MD5的C语言实现

    千次阅读 2019-06-03 10:23:35
    什么是哈希算法? 哈希算法又叫散列算法,是将任意长度的二进制值映射较短的固定长度的二进制值,这个小的二进制值称为哈希值。它的原理其实很简单,就是把一段交易信息转换成一个固定长度的字符串。 这串字符...
  • MD5初探及简单应用

    千次阅读 2016-05-27 21:34:20
    信息安全的一次小作业,图片都没有了,不影响阅读,欢迎讨论 MD5初探及简单应用 ...网站经常说:我们不会保存您的密码,请放心,那么问题来了,不保存密码他怎么验证呢?...一、MD5什么: Mes
  • 使用场景,在接口开发过程中,我们通常不能暴露一个接口给第三方随便调用,要对第三方发来参数进行校验,看是不是具有访问权限,在微信支付接口中也是这个道理...注意:MD5验签有两个作用 1. 保证数据在传输过程中...
  • 走近消息摘要--Md5产生重复的概率

    千次阅读 2006-09-20 10:45:00
    问题:假设有十万个不同的文件,每个文件对应于一个MD5。这十万个MD5中,存在两个相同的MD5的概率是多大? 答:MD5是128位hash码(4个整数,每个整数4个字节)。我们假设它的计算结果是足够随机和足够分散的。因此,...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 53,765
精华内容 21,506
关键字:

为什么md5不会重复