哈希算法及其拓展

本篇是iOS逆向开发的递进篇-关于哈希算法、数字签名及对称加密等,下面咱们着重讲解此内容,但愿对你们有所帮助!!!html

 

 1、哈希

1.1 基本内容

哈希表也称为散列表(Hash table),是根据关键码值(key,value),直接进行访问的数据结构。经过把关键码映射到表中的一个位置来进行访问记录,用来加快查找速度。映射函数也称之为散列函数,存放记录数组称为散列表。算法

假设没有内存限制,直接能够将键做为数组的索引,那么全部的查找仅仅须要一次便可完成。可是这种理想的状况也不会一直出现,由于牵扯到内存问题。从另外一个角度来讲,若是没有时间来限制,咱们也可使用无序数组并进行顺序查找,这样也会使用较少的内存。数据库

使用哈希查找算法分为两个步骤:数组

  1. 使用Hash函数将被要查找的键转化为数组中的一个索引。理想状况下,不一样的键均可以转为不一样的索引值。但这仅仅是理想状况下,在实际的开发运算中,咱们仍是要处理两个或者多个键值散列到同个索引值的状况。
  2. 要处理碰撞冲突的过程。

目前本人博客关于讲述哈希思想查找元素的博客有:http://www.javashuo.com/article/p-krvbdrbk-br.html,还会持续更新此类算法思想有关的题目。安全

 

1.2 哈希函数的两种解决碰撞的方式

1.2.1 拉链法(separate chaining)

 拉链法简单说就是链表+数组。将键来经过Hash函数映射为大小为M的数组下标索引,数组的每一个元素指向链表,链表的每一个节点存储着哈希出来的索引值为节点下标的键对值。服务器

举一个例子:数据结构

给定一组数据为{45,27,55,24,10,53,32,14,23,01,42,20},假设散列表长度为13,用拉链法解决构造的哈希表。拉链法表示以下:函数

上面就是拉链法的图示,下面咱们讲解拉链法的代码实现:this

public class SeparateChainingHashST<Key, Value> {
    //SequetialSearchST
    private int N;//键值对总数
    private int M;//散列表的大小
    private SequentialSearchST<Key, Value>[] st;//存放链表对象的数组
    public SeparateChainingHashST() {//默认的构造函数会使用997条链表
        this(997);
    }
    public SeparateChainingHashST(int M) {
        //建立M条链表
        this.M = M;
        //创造一个(SequentialSearchST<Key, Value>[])类型的,长度为M的数组
        st = (SequentialSearchST<Key, Value>[]) new SequentialSearchST[M];
        for(int i = 0; i < M; i++) {
            //为每个数组元素申请一个空间
            st[i] = new SequentialSearchST();
        }
    }
    private int hash(Key key) {
        return (key.hashCode() & 0x7fffffff) % M;
    }
    public Value get(Key key) {
        return (Value)st[hash(key)].get(key);
    }
    public void put(Key key, Value val) {
        st[hash(key)].put(key, val);
    }
    public void delete(Key key) {
        st[hash(key)].delete(key);
    }
    public Iterable<Key> keys(){
        Queue<Key> queue = new Queue<Key>();
        for(int i = 0; i < M; i++) {
            System.out.println("" + i +"个元素的链表");
            for(Key key : st[i].keys()) {
                queue.enqueue(key);
                System.out.print(key + " " + get(key) + " ,");
            }
            System.out.println();
        }
        return queue;
    }
    public static void main(String[] args) {
        SeparateChainingHashST<String, Integer> st = new SeparateChainingHashST<String, Integer>(5);
        for (int i = 0; i < 13; i++) {
            String key = StdIn.readString();
            st.put(key, i);
        }
        for (String s : st.keys())
            StdOut.println(s + " " + st.get(s));
        st.delete("M");
        StdOut.println("*************************************");
        for (String s : st.keys()) {
             StdOut.println(s + " " + st.get(s));
        }
    }
}

上面就是拉链表的基本内容,若是想进一步了解,能够查看数据结构相关书籍。搜索引擎

 

1.2.2 开放定址法

开放定址法包括线性探测法和平方探测法。

开放定址法是由关键码获得的哈希地址一旦发生了冲突,假如已经存在了元素,就会去寻找下一个空的哈希地址,只须要哈希表足够的大,空的哈希地址总能找到,并将元素存入进去。

 

1.3 哈希的特色

  • 算法是公开的
  • 对相同的数据运算,获得的结果是同样的
  • 对不一样的数据运算,如用MD5获得的结果默认为128位,32个字符(16进制)
  • 这玩意没办法进行逆运算
  • 信息摘要,信息的指纹,都是用来数据识别的

 

1.4 哈希用途加密方式

1.4.1 用户密码的加密

1.4.1.1 直接使用MD5加密
//密码
    NSString * pwd = @"123456";
    
    //MD5 直接加密 e10adc3949ba59abbe56e057f20f883e
    //不足:不够安全了。能够反查询!
  pwd = pwd.md5String;

咱们也能够经过终端,经过输入md5 -s "内容",以下获得md5,32个字符

1.4.1.2 加盐
//足够复杂!
static NSString * salt = @"(*(*(DS*YFHIUYF(*&DSFHUS(*AD&";
pwd = [pwd stringByAppendingString:salt].md5String;

运用加盐方式弊端: 盐都是是固定的,把它写死在程序里面,一旦泄露就会不安全了!

1.4.1.3 HMAC
/** HMAC
     *  使用一个密钥加密,而且作两次散列!
     *  在实际开发中,密钥(KEY)来自于服务器(动态的)!
     *  一个帐号,对应一个KEY,并且还能够跟新!
     */
    pwd = [pwd hmacMD5StringWithKey:@"hank"];

在咱们平常开发中,若是一个是有很是好的后台开发素质,会在登陆注册接口返回来一个时间戳,对于这个时间戳能够很好地运用到HMAC中

经过上面:

假如将时间戳运用到里面中,和HMAC哈希值拼接此时的时间戳(直到分,不到秒)发给服务器,而后服务器根据客户端发来的字符,进行解析;若是此时这个过程到了下一分钟(201812032050 58s发,服务器收到已经201812032051 20s ),服务器会作一个分钟-1进行验证

 

1.4.2 搜索引擎

咱们在搜索几个词语时,假如在数据库检索“国孩”,“真的”,“很帅”,对于咱们搜索其中的任何一个词,均可以经过哈希检索出来,哈希内部是怎么作到的呢?

下面是三个词在md5下的32位字符值:

 哈希经过将“国孩”,“真的”,“很帅”的哈希值进行想加,获得了也是一个32位字符串

 

1.4.3 版权

对于不少源文件上传至某个平台上时,该平台会给源文件设置惟一一个哈希值,若是有盗版上传至该平台,会被拒绝

 

2、数字签名

数字签名是对原始数据的HASH值,用非对称RSA加密

明文数据和HASH值若是经过直接传递就会有篡改的风险,所以咱们要对数据加密。可是明文数据是比较大的,不太适合运用RSA非对称加密,那么数据的HASH值是比较小,这个数据若是用来校验,这样就彻底可使用RSA进行加密。当咱们在数据传递的时候,能够经过将明文数据+RSA加密的校验数据一块儿发送给对方,RSA加密的校验数据,称之为签名。

 

下面咱们来说述一下数字签名验证的过程:当对方拿到数据以后,如何验证呢?

  • 首先传递数据时会将原始的数据和数字签名共同发送
  • 对方拿到数据以后,先进行校验,拿到了原始数据,通过一样的HASH算法获得数据的HASH值
  • 紧接着经过非对称加密,将数字签名中的校验HASH解密出来
  • 对比两个HASH值是不是一致的,这样就能够很好地判断数据是否被人篡改啦

上面是过程,下面有一份图解:

 

3、对称加密

对称加密就是明文经过密钥获得密文,而后密文经过密钥解密获得明文。

常见算法:

  • DES:数据加密的标准(用的比较少)
  • 3DES:(数据三次DES加密,强度加强了)
  • AES:(高级密码标准)--钥匙串访问用到了

应用模式以下图解:

总结,上面就是关于哈希的基本内容和拓展,但愿对你们对关于理解哈希有更深的感触!!!下一篇咱们将继续讲述iOS逆向开发的另外一篇----应用签名和重签名。

相关文章
相关标签/搜索