哈希算法及其拓展

本篇是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逆向開發的另外一篇----應用簽名和重簽名。

相關文章
相關標籤/搜索