2016-03-08 50 views
1

爲了Ø能夠創建我用我發現這裏的代碼中的6個字符大小寫不敏感可逆灰:http://web.archive.org/web/20130727034425/http://blog.kevburnsjr.com/php-unique-hash其使用Base64工作並將其轉化與base36工作。無法解密

不過,我不能哈希逆轉到其原始值的原始代碼類的base64一樣。

編輯: 爲了迴應我在這裏得到的反饋,我明白我沒有使用正確的術語。我很清楚散列意味着什麼,加密是什麼,但我只是用它,因爲它是如何在我用於此目的的原始代碼中呈現的。 我沒有花時間來更好地解釋我真正想要的,但我的目標是要1轉換任何整數讓說10.000.000爲6或8個字節的唯一字符串。

編輯:張貼我的解決方案下面作爲答案。

class PseudoCrypt { 

    /* Key: Next prime greater than 36^n/1.618033988749894848 */ 
    /* Value: modular multiplicative inverse */ 
    private static $golden_primes = array(
     '1'     => '1', 
     '41'     => '59', 
     '2377'    => '1677', 
     '147299'    => '187507', 
     '9132313'   => '5952585', 
     '5662'   => '643566407', 
     '35104476161'  => '22071637057', 
     '2176477521929'  => '294289236153', 
     '134941606358731' => '88879354792675', 
     '8366379594239857' => '7275288500431249', 
     '518715534842869223' => '280042546585394647' 
    ); 

    /* Ascii :     0 9,   A Z,   a z  */ 
    /* $chars = array_merge(range(48,57), range(65,90), range(97,122)) */ 
    private static $chars36 = array(
     0=>48, 
     1=>49, 
     2=>50, 
     3=>51, 
     4=>52, 
     5=>53, 
     6=>54, 
     7=>55, 
     8=>56, 
     9=>57, 
     10=>65, 
     11=>66, 
     12=>67, 
     13=>68, 
     14=>69, 
     15=>70, 
     16=>71, 
     17=>72, 
     18=>73, 
     19=>74, 
     20=>75, 
     21=>76, 
     22=>77, 
     23=>78, 
     24=>79, 
     25=>80, 
     26=>81, 
     27=>82, 
     28=>83, 
     29=>84, 
     30=>85, 
     31=>86, 
     32=>87, 
     33=>88, 
     34=>89, 
     35=>90 
    ); 


    public static function base36($int) { 
     $key = ''; 
     while($int > 0) { 
     $mod = $int-(floor($int/36)*36); 
     $key .= chr(self::$chars36[$mod]); 
     $int = floor($int/36); 
     } 
     return strrev($key); 
    } 

    public static function hash($num, $len = 5) { 
     $ceil = bcpow(36, $len); 
     $primes = array_keys(self::$golden_primes); 
     $prime = $primes[$len]; 
     $dec = bcmod(bcmul($num, $prime), $ceil); 
     $hash = self::base36($dec); 
     return str_pad($hash, $len, "0", STR_PAD_LEFT); 
    } 

    public static function unbase36($key) { 
     $int = 0; 
     foreach(str_split(strrev($key)) as $i => $char) { 
      $dec = array_search(ord($char), self::$chars36); 
      $int = bcadd(bcmul($dec, bcpow(36, $i)), $int); 
     } 
     return $int; 
    } 

    public static function unhash36($num, $len = 5) { 
     $ceil = pow(36, $len); 
     $prime = self::$golden_primes[$len]; 
     $dec = ($num * $prime)-floor($num * $prime/$ceil)*$ceil; 
     $hash = self::base36($dec); 
     return str_pad($hash, $len, 「0″, STR_PAD_LEFT); 
    } 

} 

echo "<pre>"; 

foreach(range(1, 100000) as $n) { 
    echo $n." - "; 
    $hash = PseudoCrypt::hash($n, 8); 
    echo $hash." - "; 
    echo PseudoCrypt::unhash36($hash)."<br/>"; 
} 
+1

術語挑剔:一個散列不(容易)可逆的。如果你認爲你可以很容易地扭轉這個「散列」,那麼它不是一個散列,而是完全不同。 –

+1

這也不是加密,它是編碼。 @BeoWulf如果你想了解它們,這些術語在這裏解釋(https://paragonie.com/blog/2015/08/you-wouldnt-base64-a-password-cryptography-decoded)。 –

+0

我知道我沒有使用正確的術語。我很清楚散列意味着什麼,加密是什麼,但我只是用它,因爲它是如何在我用於此目的的原始代碼中呈現的。我沒有花時間更好地解釋我真正想要的,但是我的目標是將任何從1到1的整數轉換成10或000個字節的單個字符串。 – BeoWulf

回答

0

難道你不想在下面的代碼,而不是base36(..)unbase36(..)

public static function unhash36($num, $len = 5) { 
    $ceil = pow(36, $len); 
    $prime = self::$golden_primes[$len]; 
    $dec = ($num * $prime)-floor($num * $prime/$ceil)*$ceil; 
    $hash = self::base36($dec);        <=== problem 
    return str_pad($hash, $len, 「0″, STR_PAD_LEFT); 
} 
0

爲了Ø能夠創建一個6個字符,不區分大小寫可逆灰我用我發現這裏的代碼:

Hashes是不可逆的,通過定義。

但是,我無法將散列翻轉爲原始值,因爲帶有base64的類的原始代碼確實如此。

Base64不是散列,它是a method of encoding arbitrary data

你想不區分大小寫的編碼解決什麼樣的問題?這是否適用於子域名?


編輯 - 回答評論:

我真正想要的,但我的目標是到任何整數從1轉換爲可以說10.000.000爲6或8個字節的唯一字符串。

這種描述聽起來危險地接近encrypting URL parameters,這是一個反模式,將不可避免地導致嚴重的痛苦在未來的一些開發商。

除此之外,該解決方案是非常簡單的:

$string = base_convert($integer, 10, 36); 

然後做相反:

$integer = base_convert($string, 36, 10); 
+0

感謝您的反饋。 我想你忘了添加鏈接到你的第一段。 我知道我沒有使用正確的術語。我很清楚散列意味着什麼,加密是什麼,但我只是用它,因爲它是如何在我用於此目的的原始代碼中呈現的。我沒有花時間更好地解釋我真正想要的,但是我的目標是將任何從1到1的整數轉換成10或000個字節的單個字符串。 – BeoWulf

+0

@BeoWulf更新回答問題 –

+0

你的更新並沒有真正實現我想要做的。不管怎麼說,還是要謝謝你。 如果您可以分享您在第一段中提到的解決方案的鏈接,那麼您會說:「創建一個6個字符不區分大小寫的可逆灰,我使用了我在此處找到的代碼:」。 – BeoWulf

1

我開發的解決方案我自己,所以我在這裏分享代碼。

這個問題在我的問題的代碼是在$ golden_primes陣列需要有不同的值,以匹配基於36個字符的素數,而不是62

它可以完美運行生成唯一的字符串(大寫字母和數字),用1到99,999,999,999,999(最多9個可逆「散列」字符)進行測試,沒有發生任何衝突。

代碼:

<?php 

class PseudoCrypt { 

    /* Key: Next prime greater than 36^n/1.618033988749894848 */ 
    /* Value: modular multiplicative inverse */ 
    private static $golden_primes = array(
     '1' =>'1', 
     '23' =>'11', 
     '809' =>'809', 
     '28837' => '29485', 
     '1038073' =>'179017', 
     '37370153' => '47534873' , 
     '1345325473' => '264202849', 
     '48431716939' => '19727015779', 
     '1743541808839' =>'1532265214711', 
     '62767505117101' =>'67935388019749' 
    ); 

    /* Ascii :     0 9,   A Z,   a z  */ 
    /* $chars = array_merge(range(48,57), range(65,90), range(97,122)) */ 
    private static $chars36 = array(0=>48, 1=>49, 2=>50, 3=>51, 4=>52, 5=>53, 6=>54, 7=>55, 8=>56, 9=>57,10=>65,11=>66,12=>67,13=>68,14=>69,15=>70,16=>71,17=>72,18=>73,19=>74,20=>75,21=>76,22=>77,23=>78,24=>79,25=>80,26=>81,27=>82,28=>83,29=>84,30=>85,31=>86,32=>87,33=>88,34=>89,35=>90); 

    public static function base36($int) { 
     $key = ""; 
     while($int > 0) { 
     $mod = $int-(floor($int/36)*36); 
     $key .= chr(self::$chars36[$mod]); 
     $int = floor($int/36); 
     } 
     return strrev($key); 
    } 

    public static function unbase36($key) { 
     $int = 0; 
     foreach(str_split(strrev($key)) as $i => $char) { 
      $dec = array_search(ord($char), self::$chars36); 
      $int = bcadd(bcmul($dec, bcpow(36, $i)), $int); 
     } 
     return $int; 
    } 

    public static function hash($num, $len = 5) { 
     $ceil = bcpow(36, $len); 
     $primes = array_keys(self::$golden_primes); 
     $prime = $primes[$len]; 
     $dec = bcmod(bcmul($num, $prime), $ceil); 
     $hash = self::base36($dec); 
     return str_pad($hash, $len, "0", STR_PAD_LEFT); 
    } 

    public static function unhash($hash) { 
     $len = strlen($hash); 
     $ceil = bcpow(36, $len); 
     $mmiprimes = array_values(self::$golden_primes); 
     $mmi = $mmiprimes[$len]; 
     $num = self::unbase36($hash); 
     $dec = bcmod(bcmul($num, $mmi), $ceil); 
    return $dec; 
} 

} 
/// Test 
echo "<pre>"; 

foreach(range(99999999990000, 99999999999999) as $n) { 
    echo $n." - "; 
    $hash = PseudoCrypt::hash($n, 9); 
    echo $hash." - Reversed: "; 
    echo PseudoCrypt::unhash($hash)."<br/>"; 
} 
+0

如果在沒有這種情況下沒有將編碼稱爲「可逆」散列「,那麼這將是一個可選擇的答案。這是一種編碼。 – zaph