2012-03-08 77 views
2

我有一個MySQL數據庫與用戶。每行都有一個唯一的自動增量ID(1,2,3 ...)。現在我需要將它轉換爲唯一的隨機序列號,我可以將其轉換回ID - 全部使用PHP。將自動增量ID轉換爲9位隨機序列號

用戶ID從1到99999999999(INT(11))。

所有序列號應至少有9位數字,從不以0開始。 用戶不應該輕易地找出如何猜測工作序列號。

感謝的:)

+0

什麼關於MD5($用戶id $鹽。)? – aletzo 2012-03-08 11:01:15

+0

我不認爲這是可能的,因爲如果有一個ID爲99999999999的用戶,如何將11位數字字符串轉換爲9? 您必須決定:擁有更大的序列號(例如11位數字)或不超過X個成員。 – 2012-03-08 11:11:26

+0

如果ID爲9位數字的大,則可以向串行添加數字。不必超級安全,所以一些簡單的數學技巧可能會完成這項工作。 – dotmlj 2012-03-08 11:15:17

回答

1

你可以做一些簡單的'加密'。以('祕密')素數p27407base17(例如)。計算基數mod p-112897的乘法逆invwolframalpha可以爲你做到這一點。

ID來序號

serial = id^base mod p 
serial = 42^17 % 27407 = 24978 

串口ID

id = serial^inv mod p 
id = 24978^12897 % 27407 = 42 

這可以快速exponentiation bysquaring計算。只能使用0到27407之間的id(如果沒有足夠大的素數),並且都有唯一的可逆序列號。

要提高默認值,您可以將結果與一些值異或。

這不是真正的密碼學,只是愚蠢的security through obscurity,但將採取大部分人類相當一些努力來破解。

+0

謝謝。我會用一些簡單的數學,因爲我不必非常安全,只需要一個數字。 – dotmlj 2012-03-12 09:05:17

1

最簡單的回答是使用散列函數作爲關鍵

$secretKey = 'oh no nobody will guess this'; 
$userId = 312; 
$serialNumber = hash('sha256', $secretKey . $userId); 

散列作品當然是單向的,所以你必須要存儲一個祕密鹽也是DB中的序列號,因爲您無法從給定的序列號計算ID。

+0

我需要能夠轉換兩種方式。它只能是一個數字(哈希不起作用)。除非ID很大,否則它應該始終爲9位數字。 – dotmlj 2012-03-08 11:08:37

+0

sha256將返回64個字符,他不應該使用'crc32'返回8個字符,然後只加1個數字? – 2012-03-08 11:09:07

+0

crc32在密碼學上並不強大。如果你只需要8個字符,你可以使用'substr($ hash,0,8)'。這仍然比crc32好很多(除非性能是一個主要問題)。 – xato 2012-03-08 11:10:33

1

我不會推薦做你正在做的事情。

您會看到,autoincrement通常用於表示不斷地避免冗餘數據,並仍然保持可讀性

因此,改爲更新數據庫結構以存儲散列。該結構可能像id,hash,name等等。

在哈希,你可以用任何邏輯

$hash = sha1("secretanswer".$userid); 
$trimmedhash = substr($has,0,9); //get a 9 digit random hash 

哈希是一個單向加密,它是如此的一個原因也。不管怎麼說,爲了驗證哈希,你可以做同樣的算法再次

$userid = "getthissomehow"; 
    $hash = sha1("secretanswer".$userid); 
    $trimmedhash = substr($has,0,9); 

    $prevhash = "asfaf23rfs"; //get previously stored hash somehow 
    if($trimmedhash == $prevhash) { 
    //valid 
    } 
+0

作者怎麼說更新數據庫結構?我所能讀到的只是他想要在PHP中對自動增量進行加密/解密,這顯然是作爲中間層的。 – 2012-03-08 11:09:42

+0

寧願用PHP來做,需要雙向訪問,串行必須是9位數字(除非ID很大)。不必超級安全...... – dotmlj 2012-03-08 11:13:27

+0

@dotmlj,然後修剪下來,'$ trimhash = substr($ has,0,9)'。查看更新 – Starx 2012-03-08 11:14:49

0

首先,怎麼一回事,因爲你希望能夠從X將其轉換成Y和從Y到X,它不能是隨機的。可以做的只是數學操作,遵循以下步驟:

1.將ID的長度用ID本身的常數或數字填充到9。 只是提醒一下:你不能使用隨機數字!否則,它不會同時工作。

2.做數學操作,就像每個數字增加1一樣。 注意,如果這個數學操作完全改變了其中一個數字,它幾乎是 無法取回它。 例如,如果您將每位數字增加2,並且有下一個數字:8,9 除非使用「結轉」方法,否則將會遇到麻煩。 所以我會建議增加每個數字X,但如果DIGIT + X> 10,則將其保留爲DIGIT。

3.如何將其轉換回來?簡而言之,請按照這些步驟後退

0

這是一個非常有趣的問題。希望我明白你在找什麼。以下是我想出了:

$test_limit = 25; 
$test_ids = array(1, 99999999999); 
for($i=0; $i<($test_limit-2); $i++) $test_ids[] = mt_rand(1, 99999999999); 

foreach($test_ids as $tii=>$ti) 
{ 
    $serial = getSerialUsingId($ti); 
    $id = getIdUsingSerial($serial); 
    if($id!=$ti) echo 'Test '.($tii+1).' (id: '.$ti.') FAILED! (serial: '.$serial.")\n"; 
    else echo 'Test '.($tii+1).' (id: '.$ti.') was a success! (serial: '.$serial.")\n"; 
} 


function getMask($index, $places=8) 
{ 
    $masks = array 
    (
    0xac976f4, 
    0x1c70f81, 
    0x441f67f, 
    0x5fb0b87, 
    0xf1542d2, 
    0xfa28851, 
    0x91bbd8c, 
    0x30a5448, 
    0x46a2708, 
    0x5856fbf, 
    0x65fa462, 
    0xf24337b, 
    0xea2c390, 
    0x8561da4, 
    0x9f77b25 
); 

    if($places==4) return $masks[$index] & 0x0000FFFF; 
    else return $masks[$index]; 

}// getMask 


function getSerialUsingId($id) 
{ 

    $prepend = ''; 
    $mask_index = mt_rand(0, 14); 

    // 8 hex places can only handle up to 4294967295 
    // If the number is greater than than that then get the additional bytes and treat separate 
    if($id>0xffffffff) 
    { 
    $packed = pack('d', $id); 
    $hex_pack = unpack('H*', $packed); 
    $hex_string = substr($hex_pack[1],4); 
    $bytes = array_reverse(explode("\n", chunk_split($hex_string, 2, "\n"))); 
    foreach($bytes as $bi=>$b) if(!$b) unset($bytes[$bi]); 
    $truncated_bytes = array_splice($bytes,0,count($bytes)-4); 
    $truncated = implode('', $truncated_bytes); 
    $prepend = dechex(hexdec($truncated)^getMask($mask_index, 4)); 
    } 

    $serial = dechex($mask_index+1).$prepend.str_pad(dechex($id^getMask($mask_index)), 8, '0', STR_PAD_LEFT); 

    return $serial; 

}// getSerialUsingId 


function getIdUsingSerial($serial) 
{ 
    $mask_index = hexdec($serial[0])-1; 
    $serial = substr($serial, 1); 
    $prepended = false; 
    if(strlen($serial)>9) 
    { 
    $prepended = substr($serial, 0, 4); 
    $serial = substr($serial, 4); 
    } 
    $id = hexdec($serial)^getMask($mask_index); 
    if($prepended) 
    { 
    $unmasked_prepended = dechex(hexdec($prepended)^getMask($mask_index, 4)); 
    $bytes = array_reverse(array_merge 
    (
     explode("\n", chunk_split($unmasked_prepended, 2, "\n")), 
     explode("\n", chunk_split(dechex($id), 2, "\n")), 
     array('00','00') 
    )); 
    foreach($bytes as $bi=>$b) if(!$b) unset($bytes[$bi]); 
    $packed = pack('H*', implode('', $bytes)); 
    $unpacked = unpack('d', $packed); 
    $id = $unpacked[1]; 
    } 

    return $id; 

}// getIdUsingSerial 

基本上,序列號是十六進制,第一個十六進制數字確定上的數字,其餘使用的位掩碼。這使得所有串行長度都爲9個字符,除非ID大於4294967295(0xFFFFFF),在這種情況下串行將有4個附加的十六進制數字,這些數字也會根據第一個數字被屏蔽。合理?希望它能滿足你非常特殊的要求,或者你至少可以採取這種做法,並使其能夠滿足你的需求。

運行代碼的示例輸出:

Test 1 (id: 1) was a success! (serial: 60fa28850) 
Test 2 (id: 99999999999) was a success! (serial: 24db649b1e87e) 
Test 3 (id: 487808132) was a success! (serial: 31952aafb) 
Test 4 (id: 227726272) was a success! (serial: 40869d847) 
Test 5 (id: 836896236) was a success! (serial: 53ef7473e) 
Test 6 (id: 958345007) was a success! (serial: 93d750827) 
Test 7 (id: 164308905) was a success! (serial: 30d8ad1d6) 
Test 8 (id: 715018588) was a success! (serial: 1205727a8) 
Test 9 (id: 1127737044) was a success! (serial: 8403db29c) 
Test 10 (id: 409934489) was a success! (serial: 81b654ed1) 
Test 11 (id: 907129123) was a success! (serial: f3fe6ca06) 
Test 12 (id: 720453497) was a success! (serial: b2cae9b1b) 
Test 13 (id: 500526447) was a success! (serial: 1171c1b9b) 
Test 14 (id: 322340582) was a success! (serial: 119fff012) 
Test 15 (id: 1176988677) was a success! (serial: b4078c867) 
Test 16 (id: 698755861) was a success! (serial: 92dcc0c1d) 
Test 17 (id: 555569451) was a success! (serial: 52e0813f9) 
Test 18 (id: 227332917) was a success! (serial: a0809bc8a) 
Test 19 (id: 819326158) was a success! (serial: 334941ab1) 
Test 20 (id: 659803411) was a success! (serial: d29f10e83) 
Test 21 (id: 895574245) was a success! (serial: d3bc3a375) 
Test 22 (id: 539979792) was a success! (serial: 425d47b97) 
Test 23 (id: 933093554) was a success! (serial: 83497b4fa) 
Test 24 (id: 959556569) was a success! (serial: 93d5b8cd1) 
Test 25 (id: 668064949) was a success! (serial: 22616d334)