2012-03-08 4 views
2

사용자가있는 MySQL 데이터베이스가 있습니다. 모든 행에는 고유 한 자동 증가 ID (1,2,3 ...)가 있습니다. 이제 ID로 다시 변환 할 수있는 독특하고 무작위로 보이는 일련 번호로 변환해야합니다. 모두 PHP를 사용합니다.자동 증분 ID를 9 자리 임의의 일련 번호로 변환

사용자 ID는 1에서 99999999999까지입니다 (INT (11)).

모든 일련 번호는 최소 9 자리 숫자이어야하며 0으로 시작하지 않아야합니다. 사용자는 작동중인 일련 번호를 쉽게 추측 할 수 없습니다.

감사의 :

+0

무엇 MD5에 대한 ($ userId를 $ 소금.)? – aletzo

+0

ID가 99999999999 인 사용자가있는 경우 11 진수 문자열을 어떻게 9로 변환 할 수 있나요? 다음을 결정해야합니다. 일련 번호가 더 큰 경우 (예 : 11 자리) 또는 X 멤버가없는 경우. –

+0

ID가 9 자리 숫자로 큰 경우 시리얼에 숫자를 추가하는 것이 좋습니다. 몇 가지 간단한 수학 트릭이 그 일을 할 수 있도록 슈퍼 보안이 필요하지 않습니다. – dotmlj

답변

1

간단한 '암호화'를 수행 할 수 있습니다. ('비밀') 프라임 p27407base17 (예 :). 기본 곱셈 p-1, 12897의 곱셈 역함수 inv을 계산합니다. wolframalpha 당신을 위해 그것을 할 수 있습니다.ID

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

이것에 일련 번호 일련

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

이드 exponentiation bysquaring 신속하게 계산 될 수있다. 0에서 27407 사이의 ID 만 사용할 수 있으며 (충분하지 않은 경우 더 큰 소수를 취함) 모두 고유 한 역행 가능 일련 번호가 있습니다.

어둡기를 증가 시키려면 결과를 일부 값으로 XOR 할 수 있습니다.

이것은 실제 암호가 아닙니다, 그냥 바보가 security through obscurity이지만, 대부분의 사람들은 갈라지기 위해 많은 노력을 기울일 것입니다.

+0

감사합니다. 나는 아주 안전 할 필요가 없으며 단지 숫자 일 필요가 있기 때문에 간단한 수학과 함께 갈 것입니다. – dotmlj

1

가장 간단한 대답은

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

당신이 저장해야합니다 있도록 해시 물론 한 방식으로 작동 키로서 사용 비밀 소금 해시 함수를 사용하는 것 주어진 일련 번호에서 ID를 계산할 수 없으므로 DB의 일련 번호도 함께 입력해야합니다.

+0

두 가지 방법으로 변환 할 수 있어야합니다. 그리고 그것은 단지 숫자이어야합니다 (해쉬는 작동하지 않습니다). ID가 크지 않으면 항상 9 자리 숫자 여야합니다. – dotmlj

+0

sha256은 64 문자를 반환합니다. 8 문자를 반환하는'crc32'를 사용해서는 안되며 1 자리 만 추가하면됩니까? –

+0

crc32는 암호 학적으로 강하지 않습니다. 8 문자 만 있으면'substr ($ hash, 0, 8)'을 사용할 수 있습니다. 성능이 중요한 문제가 아니라면 여전히 crc32보다 훨씬 좋습니다. – xato

1

내가하려는 일을하지 않는 것이 좋습니다.

일반적으로 중복 데이터를 피하기 위해 항상 autoincrement을 나타내며 의 가독성을 유지하려면으로 표시됩니다.

대신 해시도 저장하도록 데이터베이스 구조를 업데이트하십시오. 구조는 id, hash, name과 같은 모양 일 수 있습니다. 해시에서

, 당신은

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

해시 하나의 방법으로 암호화하고 그것도 이유 때문에 어떤 논리를 사용할 수 있습니다. 어쨌든, 해시를 확인하기 위해, 당신은 당신이 Y로 X에서 변환 및 X에 Y에서 할 수 있도록하려면, 다시

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

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

저자는 데이터베이스 구조를 업데이트하는 것에 대해 어떤 말을 했습니까? 필자가 읽을 수있는 것은 그가 중간 계층 역할을하는 PHP에서 자동 증가를 암호화/해독하기를 원한다는 것입니다. –

+0

PHP로하는 것이 더 좋고 두 가지 방법이 필요하며 시리얼 번호는 9 자리 숫자 여야합니다 (ID가 큰 경우 제외). 슈퍼 보안 될 필요가 없습니다 ... – dotmlj

+0

@dotmlj, 그럼, $ trimhash = substr ($있다, 0,9) '을 가지고 있습니다. – Starx

0

먼저 Beacuse을 동일한 알고리즘을 수행 할 수 있습니다, 그것은 RANDOM 할 수 없습니다. 할 수있는 일은 다음 단계에 따라 수학을 조작하는 것입니다.

1. ID의 길이를 ID에서 일정한 숫자 또는 숫자로 9로 채우십시오. 알림 : 임의의 숫자는 사용할 수 없습니다! 그렇지 않으면 두 가지 방식으로 작동하지 않습니다.

2. 각 숫자를 1 씩 증가시키는 것처럼 숫자 조작. 이 수학 조치로 숫자 중 하나가 완전히 변경되면 거의 다시 이 될 수 있습니다. 예를 들어, 각 자릿수를 2 씩 증가시키고 다음 자릿수가있는 경우 : "carryover"방법을 사용하지 않으면 문제가 발생합니다. 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 

기본적으로 일련 번호가 최초의 16 진수는 숫자의 나머지 부분에 사용되는 비트 마스크를 결정하는, 진수에 있습니다 여기에 내가 무엇을 최대 온 것입니다. 이렇게하면 ID가> 4294967295 (0xFFFFFF) 일 때를 제외하고는 모든 일련 번호의 길이가 9 자로됩니다.이 경우 직렬에는 첫 번째 자릿수에 따라 마스크 된 4 자리 16 진수가 추가됩니다. 이해가 되니? 다행히도 그것은 당신의 매우 독특한 요구 사항을 충족 시키거나 적어도 이것을 취하여 그것이 필요한 방식으로 작동되게 할 수 있습니다.

코드를 실행의 예 출력 :

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) 
관련 문제