ID 난독 화


85

정수 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)어떤 종류의 진행을 형성해서는 안된다.


int F (int x)는 요구 사항입니까, 아니면 int [2] F (int x) 일 수 있습니까?
Eugen Rieck 2011

@Eugen RIECK는, 이상적으로, 나는 숫자 범위로 x와 F (x)를하고 싶습니다
게오르그

@ toon81, 그래 기능이 유지됩니다 비밀
게오르그

토큰없이 가고 싶다고 하셨는데 어떤 종류의 룩업 테이블도 피하고 싶다는 뜻인가요?
Daniel Mošmondor 2011

16
이 질문은 완벽하게 설명되어 있고 정확히 제가 찾고있는 것입니다. 좋은 작업.
Snekse

답변:


39

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

답변 주셔서 감사합니다. 의사 코드 예제를 제공 할 수 있다면 좋을 것입니다.
georg

3
@ thg435 의사 코드 대신 C ++를 사용했습니다. 테스트되지 않은 예제를 제공하고 싶지 않았습니다.
Evgeny Kluev 2011

1
위의 숫자 시스템 기본 코드를 x = 99로 시도하면 z = 44가됩니다.
Harvey

@Harvey : 가역적 난독기를 얻으려면 모든 염기의 곱이 난독화할 수보다 커야합니다. 이 예에서는 3 * 4 * 5 = 60이므로 더 큰 숫자 (예 : 99)가 반드시 동일한 값으로 복원되는 것은 아닙니다.
Evgeny Kluev 2013-06-21

1
@Harvey : 또한 모든 염기의 곱을 더 작지만 2 ^ 32에 매우 가까운 곱을 얻은 다음 작은 테이블을 사용하여 나머지 값을 난독 화하는 것도 가능합니다. 이 경우 모든 것이 32 비트 숫자로 유지됩니다.
예브게니 Kluev

8

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


흥미로운 일이지만 1) 잘 테스트되지 않았고 2) 이해하기가 너무 어렵 기 때문에 잘 테스트되지 않은 암호를 구현해달라고 누군가에게 요청하는 것이 약간 어려울 수 있습니다. :)
Maarten Bodewes

감사! 그래도 가능한 한 간단하게 유지하려고합니다.
georg

Hasty Pudding 구현을 찾을 수없는 경우 (허용 된 크기 중 하나만 필요) 간단한 4 라운드 Feistel 암호 ( en.wikipedia.org/wiki/Feistel_cipher )를 균일 한 블록 크기로 쉽게 구현할 수 있습니다 . Hasty Pudding과 마찬가지로 출력이 올바른 범위에있을 때까지 암호화를 계속하십시오. 안전하지는 않지만 난독 화하기에 충분합니다.
rossum

NSA는 이제 32 비트 및 48 비트 블록 크기를 포함하는 버전을 포함 하는 Speck 암호를 출시했습니다 . 또한 해당 크기로 숫자를 난독 화하는 데 유용 할 수 있습니다. 특히 32 비트 버전이 유용 할 것입니다.
rossum

5

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

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

  • 함께 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

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


또한 상수 모드 2 ^ 32가 추가되었습니다 (비트 회전이 모두가 좋아하는 사소하게 되돌릴 수있는 기능인 rot13을 상기 시켰기 때문입니다).
ccoakley

정말 return x XOR rotr(31415927, 5)그래도 그렇죠? 마지막 xor는 첫 번째 작업을 실행 취소하고 회전 작업은 서로 실행 취소합니다. 물론 모든 가역 작업 체인도 되돌릴 수 있으므로 해당 조건을 충족합니다.
harold

몇 가지 간단한 테스트를 실행했고 결과가 예상대로 만족 스러웠습니다. ccoakley가 언급했듯이 rot13은 rot5 대신 사용할 수 있으며 모든 회전이 작동하며 (caveat : 0> rot> integer-size) 다른 키로 간주 될 수 있습니다. 그가 제안한 모듈러스와 같이 여기에 던질 수있는 다른 것들이 있으며, 해롤드가 언급 한대로 되돌릴 수있는 한.
IAmNaN 2011

1
죄송합니다. @harold는 대부분 정확합니다. 전체 함수는 x = x XOR F(0), 또는 x = x XOR 3087989491, 또는 과 같습니다 x = x XOR rotr(31415927, 5). 첫 xor와 마지막 xor는 서로를 부정하므로 키를 사용하여 비트 시프트 된 입력을 xoring하거나 비트 시프트 된 키로 입력을 xoring하는 것입니다. 각 단계에 다른 키를 사용한 경우에도 마찬가지입니다. 모든 키를 일반 텍스트로 xored 할 수있는 단일 키로 합성 할 수 있습니다.
Nick Johnson

2
더 나쁜 것은 일정한 오프셋에 의한 모든 회전 체인과 상수가있는 xors가 하나의 회전과 하나의 xor로 압축 될 수 있다는 것을 증명하는 것이 매우 쉽습니다. 서로 결합 된 후 두 개의 회전 (오프셋 추가), 서로 결합 된 두 개의 xor (두 상수의 xor와 xor), xor / rot 쌍은 동일한 회전을 적용하여 rot / xor로 교체 할 수 있습니다. xor의 상수.
해롤드


3

이 스레드의 일부 아이디어를 사용하여 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 비트 정수 가정-다른 크기의 숫자 만 변경)


1
좋아요, 공유해 주셔서 감사합니다! BTW "32n"은 무엇입니까? 전에는 본 적이 없습니다.
georg

1
nBigInts 의 숫자 접미사입니다 . 정말 큰 숫자를 처리 할 수있는 새로운 JS 기능입니다. 중간 값 중 하나를 일시적으로 초과 Number.MAX_SAFE_INTEGER하여 정밀도를 잃을 수있는 정말 큰 숫자를 곱하기 때문에 사용해야했습니다 .
mpen 2019-04-05

2

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

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

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

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

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

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


설명하는 것은 블록 암호의 구성 요소입니다. 자신의 것을 발명하는 것보다 기존의 것을 사용하는 것이 더 합리적입니다.
Nick Johnson

@NickJohnson 내 게시물의 마지막 줄에있는 링크를 클릭 했습니까?
Daniel Mošmondor

나는 충분히 "무작위"로 보이는 결과를주는 rotl / xor 조합을 모으지 못했습니다 (업데이트 참조). 포인터가 있습니까?
georg

@ DanielMošmondor 나는 당신이 무엇을 연결하고 있는지 알고 있습니다.하지만 그것은 당신이 처음에 그가 직접 무언가를 만들 것을 제안한다는 사실을 바꾸지 않습니다.
Nick Johnson

@NickJohnson은 분명히 OP는 새로운 API를 배우고 싶거나 배우고 싶지 않기 때문에 기존 암호화를 사용하고 싶지 않습니다. 나는 그것에 전적으로 공감할 수 있습니다.
Daniel Mošmondor 2011

2

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

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


2
@ thg435이 접근 방식에 관심이 있다면 유용한 검색 용어는 "형식 보존 암호화"입니다. 위키 백과 페이지는 Nick의 기사에 언급 된 Black / Rogaway 논문과 최신 개발 사항을 다룹니다. 나는 당신이하고있는 것과 비슷한 것을 위해 FPE를 성공적으로 사용했습니다. 내 경우에는 가벼운 유효성 검사에 사용한 ID 외에 몇 가지 비트를 추가했지만.
Paul Du Bois

1

얼마나 "어려움"이 필요한지, 얼마나 빠른지 또는 얼마나 적은 메모리를 사용해야하는지 확실하지 않습니다. 메모리 제약이 없다면 모든 정수의 목록을 만들고 섞은 다음 그 목록을 매핑으로 사용할 수 있습니다. 그러나 4 바이트 정수의 경우에도 많은 메모리가 필요합니다.

그러나 이것은 더 작게 만들 수 있으므로 모든 정수를 매핑하는 대신 2 (또는 최악의 경우 1) 바이트 만 매핑하고이를 정수의 각 그룹에 적용합니다. 따라서 2 바이트를 사용하면 정수는 (group1) (group2) 가됩니다. 무작위 맵을 통해 각 그룹을 매핑합니다. 그러나 이는 group2 만 변경하면 group1의 매핑이 동일하게 유지됨을 의미합니다. 이것은 각 그룹에 다른 비트를 매핑함으로써 "고정"될 수 있습니다.

따라서 * (group2)는 (bit 14,12,10,8,6,4,2,0)이 될 수 있으므로 1을 추가하면 group1group2가 모두 변경 됩니다.

그래도 이것은 모호한 보안 일 뿐이며 함수에 숫자를 입력 할 수있는 사람 (함수를 비밀로 유지하더라도) 누구나 쉽게 알아낼 수 있습니다.


시스템의 제약에 따라 이것은 아마도 작동하지 않을 것입니다. 임의의 y.
templatetypedef

@templatetypedef 내가 말했듯이 이것은 모호함에 의한 보안 일뿐입니다. 순열을 알아야하지만 순열을 "키"로 볼 수 있습니다. 여기서 가장 큰 문제는 OP가 암호화 된 메시지가 동일한 세트에 들어가야하는 하나의 세트 (작은 세트)에있는 모든 메시지를 암호화 할 수 있기를 원하고 이는 세트의 모든 메시지에 대해 유효해야한다는 것입니다.
Roger Lindsjö 2011

감사. 룩업 테이블을 피하려고합니다.
georg

1

애플리케이션에서 사용할 개인 대칭 키를 생성하고이를 사용하여 정수를 암호화합니다. 이것은 가장 어려운 # 3을 포함하여 세 가지 요구 사항을 모두 충족합니다. 계획을 깨기 위해 키를 추측해야합니다.


thg435는 정수 대 정수를 요청했습니다 (그리고 내가 이해하는 한 모든 정수에서 작동해야 함). 이러한 속성을 가질 수있는 개인 키 알고리즘을 제안 할 수 있습니까?
Roger Lindsjö 2011

1

여기서 설명하는 것은 단방향 함수의 반대 인 것 같습니다. 반전하기는 쉽지만 적용하기는 매우 어렵습니다. 한 가지 옵션은 비밀을 유지하는 (비밀, 임의로 선택한) 공개 키와 세상과 공유하는 개인 키를 수정하는 표준 기성 공개 키 암호화 알고리즘을 사용하는 것입니다. 이런 식으로 함수 F (x)는 공개 키를 사용하여 x를 암호화합니다. 그런 다음 개인 암호 해독 키를 사용하여 F (x)를 x로 쉽게 해독 할 수 있습니다. 여기서는 공개 키와 개인 키의 역할이 반대로되어 있습니다. 모든 사람에게 개인 키를 제공하여 기능을 해독 할 수 있지만 공개 키는 서버에서 비밀로 유지합니다. 그런 식으로:

  1. 이 기능은 bijection이므로 뒤집을 수 있습니다.
  2. F (x)가 주어지면 x는 효율적으로 계산할 수 있습니다.
  3. x와 F (x)가 주어지면 공개 키가 없으면 (암호화 적으로 강력한 암호화 체계를 사용한다고 가정 할 때) 데이터를 암호화 할 수있는 실행 가능한 방법이 없기 때문에 y에서 F (y)를 계산하기가 매우 어렵습니다. 암호 해독 키가 알려져 있습니다.

이것은 많은 장점이 있습니다. 첫째, RSA와 같이 잘 확립 된 알고리즘을 사용하면 우발적 인 불안정에 대해 걱정할 필요가 없기 때문에 암호화 시스템이 안전하다는 것을 확신 할 수 있습니다. 둘째,이 작업을 수행 할 라이브러리가 이미 있으므로 많은 코드를 작성할 필요가 없으며 부 채널 공격에 면역이 될 수 있습니다. 마지막으로, 누구든지 실제로 F (x)를 계산할 수없는 상태에서 누구든지 F (x)를 반전 할 수 있습니다.

한 가지 세부 사항-여기서 표준 int 유형을 사용해서는 안됩니다. 64 비트 정수를 사용하더라도 공격자가 키가 없더라도 일부 y에 대한 암호화 F (y)를 찾을 때까지 모든 것을 무차별 대입 할 수있는 조합이 거의 없습니다. 공상 과학 공격조차도 이것을 무차별 대입 할 수 없기 때문에 512 비트 값과 같은 것을 사용하는 것이 좋습니다.

도움이 되었기를 바랍니다!


그러나 thg435는 작은 메시지 세트 (4 바이트 메시지)를 동일한 메시지 세트로 암호화 할 수있는 암호화를 요구하는 것으로 보이며 암호화는 모든 메시지에 대해 작동해야합니다.
Roger Lindsjö 2011

답변 주셔서 감사합니다. 완전한 암호화 프레임 워크를 사용하는 것이 아마도이를 수행하는 가장 좋은 방법 일 수 있지만 내 요구에 비해 너무 "무겁습니다".
georg

1

경우는 xor모든 것을 허용하지만, 추론 F(y)부여 x하고 F(x)나는 당신이와 그렇게 할 수 있다고 생각 소금 . 먼저 비밀 단방향 기능을 선택하십시오. 예를 들면 S(s) = MD5(secret ^ s). 그러면 F(x) = (s, S(s) ^ x)여기서, s무작위로 선택된다. 나는 그것을 튜플로 썼지 만 두 부분을 정수로 결합 할 수 있습니다 F(x) = 10000 * s + S(s) ^ x. 해독은 소금을 s다시 추출하고 F'(F(x)) = S(extract s) ^ (extract S(s)^x). 주어 x지고 (약간 난독 화되었지만) F(x)s수 있으며 추론 할 수 S(s)있지만 y다른 임의의 솔트를 가진 다른 사용자의 t경우 사용자 F(x)가 찾을 수 없습니다 S(t).


덕분에, 그러나 이것은 (업데이트 참조) 나를 위해 임의 충분히 보이지 않는
게오르그

솔트는 무작위로 선택되며 해시 S(s)도 무작위로 표시되므로 F(x)어떤 종류의 진행도 발생하지 않습니다.
Ben Jackson
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.