2016-06-10 1 views
1

알파벳을 사용하여 이진 데이터 b1, b2, ... bn을 인코딩합니다. 그러나 b의 이진 표현은 다소 순차적이므로 비트를 문자로 간단히 매핑하면 문자열이 매우 유사합니다. 예 :알파벳으로 바이트 배열을 인코딩하면 출력이 임의로 분포해야합니다.

encode(b1) => "QXpB4IBsu0" 
encode(b2) => "QXpB36Bsu0" 
... 

나는 출력 문자열을 볼 때 입력 b을 추측하기 어려운 의미보다 "임의의"출력을 만들 수있는 방법을 찾고 있어요.

일부 요구 사항 :

  • differenent b S의 경우는, 출력 문자열 달라야합니다. 동일한 b을 여러 번 인코딩해도 반드시 동일한 결과가 나올 필요는 없습니다. 다른 입력 b의 출력 문자열 사이에 충돌이 없으면 모든 것이 좋습니다.
  • 중요성이있는 경우 : b은 ~ 50-60 비트 정도입니다. 알파벳은 64자를 포함합니다. 각 b에 대한
  • 기능 방금 ​​위의 값 주어진 알파벳 (의 문자에 b의의 비트에서 간단한 매핑을 사용하여 얻는 것보다 더 큰 출력 문자열을 생성하지해야하는 인코딩, 이것이 의미 ~ 10 자). SHA와 같은 해시 함수를 사용하는 것은 옵션이 아닙니다.

이 문제의 가능한 해결책은 "암호 학적으로 안전"일 필요는 없습니다. 누군가가 바이너리 데이터를 재구성하기에 충분한 시간과 노력을 투자한다면 그렇게 될 것입니다. 그러나 목표는 가능한 한 어렵게 만드는 것입니다. 어쨌든 디코딩 기능이 필요하지 않을 수도 있습니다. 내가 지금 뭐하는 거지

:

  1. 는 이진 데이터에서 다음 4 개 비트를 취할

    는 이제 xxxx
  2. 앞에 추가 2 랜덤 비트 rrrxxxx
  3. 을 얻을 가정 해 봅시다에서 해당 문자를 조회 알파벳 : val char = alphabet[rrxxxx] 그리고 결과에 추가하십시오 (알파벳 크기가 64이기 때문에 작동합니다)
  4. 1 단계로 계속하십시오.

이 장치는 출력 문자열에 약간의 노이즈를 추가하지만, 임의의 비트로 인해 문자열의 크기가 50 % 증가합니다. 난 더 많은 임의의 비트 (rrrxxx 또는 심지어 rrrrxx)를 추가하여 더 많은 노이즈를 추가 할 수 있지만 출력이 커지고 커질 것입니다. 위에서 언급 한 요구 사항 중 하나는 출력 문자열의 크기를 늘리는 것이 아닙니다. 현재 더 나은 아이디어가 없기 때문에 현재이 접근 방식을 사용하고 있습니다.

대체 절차로 알파벳을 적용하기 전에 입력의 비트를 바꿔 넣을 생각이었습니다. b 그러나 서로 다른 문자열이 결과가 다르다는 것을 보장해야하므로 셔플 함수는 완전히 무작위가 아닌 결정론 (아마 비밀 번호를 인수로 사용)을 사용해야합니다. 나는 그런 기능을 할 수 없었다.

더 좋은 방법이 있다면 궁금합니다. 힌트를 얻으실 수 있습니다.

답변

0

기본적으로 가능한 50 비트 값에서 다른 50 비트 값으로 가역 의사 랜덤 매핑이 필요합니다. 뒤집을 수있는 Linear Congruential Generator (일부 의사 난수 생성기에 사용되는 종류)을 사용하여이를 수행 할 수 있습니다.

인코딩 할 때 순방향으로 숫자에 LCG를 적용한 다음 base64로 인코딩하십시오. 해독해야하는 경우 base64에서 디코딩 한 다음 반대 방향으로 LCG를 적용하여 원래 번호를 되 찾습니다.

This answer에는 가역 LCG 용 코드가 포함되어 있습니다. 기간은 2 입니다. LCG를 정의하는 데 사용되는 상수는 귀하의 비밀 번호입니다.

0

multiplicative inverse을 사용하려고합니다. 그러면 순차 키를 가져와 비 순차적 숫자로 변환합니다. 키와 결과 간에는 일대일 관계가 있습니다. 따라서 두 개의 숫자가 동일한 비 순차 키를 생성하지 않으며 프로세스는 되돌릴 수 있습니다.

C#으로 작성된 작은 예제가 나와 있습니다.

private void DoIt() 
{ 
    const long m = 101; 
    const long x = 387420489; // must be coprime to m 

    var multInv = MultiplicativeInverse(x, m); 

    var nums = new HashSet<long>(); 
    for (long i = 0; i < 100; ++i) 
    { 
     var encoded = i*x%m; 
     var decoded = encoded*multInv%m; 
     Console.WriteLine("{0} => {1} => {2}", i, encoded, decoded); 
     if (!nums.Add(encoded)) 
     { 
      Console.WriteLine("Duplicate"); 
     } 
    } 
} 

private long MultiplicativeInverse(long x, long modulus) 
{ 
    return ExtendedEuclideanDivision(x, modulus).Item1%modulus; 
} 

private static Tuple<long, long> ExtendedEuclideanDivision(long a, long b) 
{ 
    if (a < 0) 
    { 
     var result = ExtendedEuclideanDivision(-a, b); 
     return Tuple.Create(-result.Item1, result.Item2); 
    } 
    if (b < 0) 
    { 
     var result = ExtendedEuclideanDivision(a, -b); 
     return Tuple.Create(result.Item1, -result.Item2); 
    } 
    if (b == 0) 
    { 
     return Tuple.Create(1L, 0L); 
    } 
    var q = a/b; 
    var r = a%b; 
    var rslt = ExtendedEuclideanDivision(b, r); 
    var s = rslt.Item1; 
    var t = rslt.Item2; 
    return Tuple.Create(t, s - q*t); 
} 

상기 언급 된 코드 및 보조 재료로부터 입힌 코드.

그런 다음 순차 번호를 가져 와서 역수를 계산 한 다음 64 진수로 인코딩해야합니다. 프로세스를 되돌리려면 base-64가 주어진 값을 디코드 한 다음 역 계산을 통해 실행하고 원래 번호가 있어야합니다.

관련 문제