[algorithm] ID 난독 화

정수 ID를 다른 정수로 암호화 / 난독 화하는 방법을 찾고 있습니다. 더 정확하게는 함수가 필요 int F(int x)하므로

  • x <-> F (x)는 일대일 대응입니다 (x! = y, F (x)! = F (y)).
  • F (x)가 주어지면 x를 쉽게 찾을 수 있으므로 F는 해시 함수가 아닙니다.
  • x와 F (x)가 주어지면 F (y)를 찾는 것이 어렵거나 불가능 x ^ 0x1234합니다.

명확성을 위해 강력한 암호화 솔루션을 찾는 것이 아니라 난독 화일뿐입니다. 같은 URL을 웹 응용 프로그램을 상상해 example.com/profile/1, example.com/profile/2자신이 비밀이없는 등 프로파일,하지만 난 같은 뒤에 숨길 오히려 것, 그래서 모든 프로필을 잇달아 가져 오기 /보기로 캐주얼 관음증을 방지하고자 example.com/profile/23423, example.com/profile/80980234등이 있지만 데이터베이스에 저장된 토큰은이 작업을 매우 쉽게 수행 할 수 있습니다. 이에 대한 간단한 수학이 있는지 궁금합니다.

내가 약을 취소하지 않은 한 가지 중요한 요구 사항은 결과, 시퀀스 제공되는 “임의”모양해야한다는 것입니다 x,x+1,...,x+n, F(x),F(x+1)...F(x+n)어떤 종류의 진행을 형성해서는 안된다.



답변

2 개 또는 3 개의 간단한 방법을 조합하여 난독 화합니다.

  • XOR
  • 개별 비트를 섞다
  • 모듈 표현으로 변환 (D.Knuth, Vol. 2, Chapter 4.3.2)
  • 32 개 (또는 64 개)의 겹치는 비트 서브 세트와 각 서브 세트에서 XOR 비트 (서브 세트의 패리티 비트)를 선택합니다.
  • 가변 길이 숫자 체계로 표현하고 숫자를 섞습니다.
  • 홀수 정수의 쌍을 선택 x하고 y, 서로 (모듈로 2 곱셈 역수임을 32 ) 후, 승산함으로써 x난독과 곱셈에 의해 y복원하기 위해서, 모든 승산은 모듈 (2)이다 (32) (출처 : 에릭 “곱셈 역수의 실용화” 리퍼 트 )

가변 길이 숫자 체계 방법은 자체적으로 “진행”요구 사항을 따르지 않습니다. 항상 짧은 산술 진행을 생성합니다. 그러나 다른 방법과 함께 사용하면 좋은 결과를 얻을 수 있습니다.

모듈 식 표현 방법도 마찬가지입니다.

다음은 이러한 메서드 중 3 가지에 대한 C ++ 코드 예제입니다. 셔플 비트 예제는 예측 불가능한 일부 다른 마스크 및 거리를 사용할 수 있습니다. 다른 두 가지 예는 작은 숫자에 적합합니다 (아이디어를 제공하기 위해). 모든 정수 값을 적절하게 난독 화하려면 확장해야합니다.

// *** Numberic system base: (4, 3, 5) -> (5, 3, 4)
// In real life all the bases multiplied should be near 2^32
unsigned y = x/15 + ((x/5)%3)*4 + (x%5)*12; // obfuscate
unsigned z = y/12 + ((y/4)%3)*5 + (y%4)*15; // restore

// *** Shuffle bits (method used here is described in D.Knuth's vol.4a chapter 7.1.3)
const unsigned mask1 = 0x00550055; const unsigned d1 = 7;
const unsigned mask2 = 0x0000cccc; const unsigned d2 = 14;

// Obfuscate
unsigned t = (x ^ (x >> d1)) & mask1;
unsigned u = x ^ t ^ (t << d1);
t = (u ^ (u  >> d2)) & mask2;
y = u ^ t ^ (t << d2);

// Restore
t = (y ^ (y >> d2)) & mask2;
u = y ^ t ^ (t << d2);
t = (u ^ (u >> d1)) & mask1;
z = u ^ t ^ (t << d1);

// *** Subset parity
t = (x ^ (x >> 1)) & 0x44444444;
u = (x ^ (x << 2)) & 0xcccccccc;
y = ((x & 0x88888888) >> 3) | (t >> 1) | u; // obfuscate

t = ((y & 0x11111111) << 3) | (((y & 0x11111111) << 2) ^ ((y & 0x22222222) << 1));
z = t | ((t >> 2) ^ ((y >> 2) & 0x33333333)); // restore


답변

변환이 되돌릴 수 있고 명확하지 않기를 원합니다. 이는 주어진 범위에서 숫자를 가져와 동일한 범위에서 다른 숫자를 생성하는 암호화처럼 들립니다. 범위가 64 비트 숫자이면 DES를 사용하십시오. 범위가 128 비트 숫자이면 AES를 사용하십시오. 다른 범위를 원할 경우 가장 좋은 방법은 100,000에서 999,999와 같이 블록에 깔끔하게 맞지 않는 여러 블록 크기 및 숫자 범위에 대처하도록 설계된 Hasty Pudding cipher 일 것입니다.


답변

난독 화는 보안 측면에서 실제로 충분하지 않습니다.

그러나 캐주얼 구경꾼을 방해하려는 경우 두 가지 방법을 조합하는 것이 좋습니다.

  • 함께 xor’ing하여 id와 결합하는 개인 키
  • 키 적용 전후에 일정한 양만큼 비트 회전

다음은 의사 코드를 사용하는 예입니다.

  def F(x)
    x = x XOR 31415927       # XOR x with a secret key
    x = rotl(x, 5)           # rotate the bits left 5 times
    x = x XOR 31415927       # XOR x with a secret key again
    x = rotr(x, 5)           # rotate the bits right 5 times
    x = x XOR 31415927       # XOR x with a secret key again
    return x                 # return the value
  end

나는 그것을 테스트하지 않았지만 이것은 되돌릴 수 있고 빠르며 방법을 알아내는 것이 너무 쉽지 않다고 생각합니다.


답변

이 특정 Python / PHP 코드가 매우 유용하다는 것을 알았습니다.

https://github.com/marekweb/opaque-id


답변

이 스레드의 일부 아이디어를 사용하여 JS 코드를 작성했습니다.

const BITS = 32n;
const MAX = 4294967295n;
const COPRIME = 65521n;
const INVERSE = 2166657316n;
const ROT = 6n;
const XOR1 = 10296065n;
const XOR2 = 2426476569n;


function rotRight(n, bits, size) {
    const mask = (1n << bits) - 1n;
    // console.log('mask',mask.toString(2).padStart(Number(size),'0'));
    const left = n & mask;
    const right = n >> bits;
    return (left << (size - bits)) | right;
}

const pipe = fns => fns.reduce((f, g) => (...args) => g(f(...args)));

function build(...fns) {
    const enc = fns.map(f => Array.isArray(f) ? f[0] : f);
    const dec = fns.map(f => Array.isArray(f) ? f[1] : f).reverse();

    return [
        pipe(enc),
        pipe(dec),
    ]
}

[exports.encode, exports.decode] = build(
    [BigInt, Number],
    [i => (i * COPRIME) % MAX, i => (i * INVERSE) % MAX],
    x => x ^ XOR1,
    [x => rotRight(x, ROT, BITS), x => rotRight(x, BITS-ROT, BITS)],
    x => x ^ XOR2,
);

다음과 같은 멋진 결과가 생성됩니다.

1 1352888202n 1 'mdh37u'
2 480471946n 2 '7y26iy'
3 3634587530n 3 '1o3xtoq'
4 2225300362n 4 '10svwqy'
5 1084456843n 5 'hxno97'
6 212040587n 6 '3i8rkb'
7 3366156171n 7 '1jo4eq3'
8 3030610827n 8 '1e4cia3'
9 1889750920n 9 'v93x54'
10 1017334664n 10 'gtp0g8'
11 4171450248n 11 '1wzknm0'
12 2762163080n 12 '19oiqo8'
13 1621319561n 13 'qtai6h'
14 748903305n 14 'cdvlhl'
15 3903018889n 15 '1sjr8nd'
16 3567473545n 16 '1mzzc7d'
17 2426613641n 17 '144qr2h'
18 1554197390n 18 'ppbudq'
19 413345678n 19 '6u3fke'
20 3299025806n 20 '1ik5klq'
21 2158182286n 21 'zoxc3y'
22 1285766031n 22 'l9iff3'
23 144914319n 23 '2ea0lr'
24 4104336271n 24 '1vvm64v'
25 2963476367n 25 '1d0dkzz'
26 2091060108n 26 'ykyob0'
27 950208396n 27 'fpq9ho'
28 3835888524n 28 '1rfsej0'
29 2695045004n 29 '18kk618'
30 1822628749n 30 'u559cd'
31 681777037n 31 'b9wuj1'
32 346231693n 32 '5q4y31'

테스트 대상 :

  const {encode,decode} = require('./obfuscate')

  for(let i = 1; i <= 1000; ++i) {
        const j = encode(i);
        const k = decode(j);
        console.log(i, j, k, j.toString(36));
   }

XOR1XOR20 사이의 무작위 숫자입니다 MAX. MAX이다 2**32-1; 가장 높은 ID가 될 것이라고 생각하는 값으로 설정해야합니다.

COPRIME는 coprime w / MAX입니다. 나는 소수 그 자체가 다른 모든 수 (자신의 배수를 제외하고)와 공통점 이라고 생각 합니다.

INVERSE알아 내기가 까다로운 것입니다. 이 블로그 게시물은 정확한 답변을 제공하지 않지만 WolframAlpha가 알아낼 수 있습니다 . 기본적으로, 단지 방정식 해결하기 (COPRIME * x) % MAX = 1위한이 x.

build함수는 이러한 인코딩 / 디코딩 파이프 라인을 더 쉽게 만들 수 있도록 제가 만든 것입니다. [encode, decode]쌍으로 원하는만큼 작업을 공급할 수 있습니다 . 이러한 기능은 동일하고 반대 여야합니다. XOR당신이 한 쌍의가 필요하지 않도록 기능은 자신의 칭찬이다.


또 다른 재미있는 혁신이 있습니다 .

function mixHalves(n) {
    const mask = 2n**12n-1n;
    const right = n & mask;
    const left = n >> 12n;
    const mix = left ^ right;
    return (mix << 12n) | right;
}

(24 비트 정수 가정-다른 크기의 숫자 만 변경)


답변

그들을 파괴하지 않을 ID의 비트로 무엇이든하십시오. 예를 들면 :

  • 값을 회전
  • 검색을 사용하여 값의 특정 부분을 바꿉니다.
  • 어떤 값을 가진 xor
  • 스왑 비트
  • 스왑 바이트
  • 전체 가치를 반영
  • 가치의 일부를 미러링
  • … 상상력을 발휘 해봐

암호 해독의 경우 모든 작업을 역순으로 수행하십시오.

흥미로운 값을 ‘암호화’하는 프로그램을 만들어 검사 할 수있는 테이블에 저장하십시오. 동일한 프로그램이 시스템에 포함하려는 모든 값 세트로 암호화 / 복호화 루틴을 테스트하도록하십시오.

당신의 숫자가 당신에게 적절하게 엉망이 될 때까지 위의 목록에있는 것들을 루틴에 추가하십시오.

그 밖의 경우에는 The Book을 받으십시오 .


답변

나는 블록 암호를 사용한 보안 순열 에 대한 기사를 썼는데 , 이는 명시된대로 요구 사항을 충족해야합니다.

하지만 추측하기 어려운 식별자를 원할 경우 처음에 식별자를 사용하는 것이 좋습니다. UUID를 생성하고이를 처음부터 레코드의 기본 키로 사용합니다. 그럴 필요가 없습니다. ‘실제’ID로 /에서 변환합니다.