2011-09-15 2 views
5

암호화 유틸리티의 단위 테스트를 위해 OpenSSL의 암호화 난수 생성기 (모두 RAND_bytesRAND_pseudo_bytes)가 예측 가능하고 반복 가능한 바이트 시퀀스를 강제로 반환 할 수있게하여 다양한 암호문은 차례대로 예측 가능하며 테스트 벡터로 구울 수 있습니다. (다른 모든 주요 자료는 저의 통제하에 있습니다.)openssl의 RNG가 반복 가능한 바이트 시퀀스를 반환하도록합니다.

나는 이것이 보안을 완전히 상실한 것을 알고 있습니다. 이것은 단위 테스트에만 사용됩니다. /dev/urandom에서 자동으로

(나타나는) 때문에 단순히 각 시험 전에 고정 씨앗을 RAND_seed를 호출 할 수있는 RNG 씨앗 자체가 내가 그것을 원하거나하지, 어쨌든 RAND_seed는를 재설정하지 않습니다 여부 RNG는 엔트로피 풀에 시드 만 추가합니다.

이렇게 할 방법이 있습니까? (극단적으로, 나는 내 자신의 PRNG 엔진을 작성할 수있는 것처럼 보이지만, 더 간단한 옵션이 있다고 생각하고 싶다.)

+0

PRNG가 필요하지 않습니다. 예측 가능한 값의 흐름 만 있으면됩니다. 카운터조차 할 것이다. –

답변

5

런타임시 강제로 FIPS ANSI X9.31 RNG를 테스트 모드로 설정할 수 있지만 SSLeay RNG는 기본값이 아닙니다. -DPREDICT으로 OpenSSL을 다시 컴파일하면 기본 RNG가 예측 가능한 일련의 숫자를 출력하지만 아주 편리하지는 않습니다.

RAND_pseudo_bytes 함수는 예측 가능한 일련의 숫자를 생성합니다. 즉, 자동으로 RAND_bytes과 같은 엔트로피를 추가하지 않습니다. 그러나 당신이 알았 듯이, 시드에 엔트로피를 추가하는 것만 가능합니다. 명시 적으로 시드를 제공하지 않습니다. 따라서 프로그램을 실행하는 동안 다른 숫자를 얻을 수 있습니다. 또한 도움이되지 않습니다.

그러나 예측 가능한 RNG 엔진을 작성하는 것은 어렵지 않습니다. 사실, 나는 그것의 핵심은 다음 stdlib의 rand()와 랜드 엔진을 만들어 그것을 통해 당신을 데려 갈 것이다 :

#include <cstdio> 
#include <cstdlib> 
#include <cassert> 
#include <openssl/rand.h> 

// These don't need to do anything if you don't have anything for them to do. 
static void stdlib_rand_cleanup() {} 
static void stdlib_rand_add(const void *buf, int num, double add_entropy) {} 
static int stdlib_rand_status() { return 1; } 

// Seed the RNG. srand() takes an unsigned int, so we just use the first 
// sizeof(unsigned int) bytes in the buffer to seed the RNG. 
static void stdlib_rand_seed(const void *buf, int num) 
{ 
     assert(num >= sizeof(unsigned int)); 
     srand(*((unsigned int *) buf)); 
} 

// Fill the buffer with random bytes. For each byte in the buffer, we generate 
// a random number and clamp it to the range of a byte, 0-255. 
static int stdlib_rand_bytes(unsigned char *buf, int num) 
{ 
     for(int index = 0; index < num; ++index) 
     { 
       buf[index] = rand() % 256; 
     } 
     return 1; 
} 

// Create the table that will link OpenSSL's rand API to our functions. 
RAND_METHOD stdlib_rand_meth = { 
     stdlib_rand_seed, 
     stdlib_rand_bytes, 
     stdlib_rand_cleanup, 
     stdlib_rand_add, 
     stdlib_rand_bytes, 
     stdlib_rand_status 
}; 

// This is a public-scope accessor method for our table. 
RAND_METHOD *RAND_stdlib() { return &stdlib_rand_meth; } 

int main() 
{ 
     // If we're in test mode, tell OpenSSL to use our special RNG. If we 
     // don't call this function, OpenSSL uses the SSLeay RNG. 
     int test_mode = 1; 
     if(test_mode) 
     { 
       RAND_set_rand_method(RAND_stdlib()); 
     } 

     unsigned int seed = 0x00beef00; 
     unsigned int rnum[5]; 

     RAND_seed(&seed, sizeof(seed)); 
     RAND_bytes((unsigned char *)&rnum[0], sizeof(rnum)); 
     printf("%u %u %u %u %u\n", rnum[0], rnum[1], rnum[2], rnum[3], rnum[4]); 

     return 0; 
} 

당신이 그것을 씨앗 같은 번호 srand()이 프로그램을 실행할 때마다 때문에 당신 같은 순서를 제공합니다 매번 난수의.

corruptor:scratch indiv$ g++ rand.cpp -o r -lcrypto -g 
corruptor:scratch indiv$ ./r 
1547399009 981369121 2368920148 925292993 788088604 
corruptor:scratch indiv$ ./r 
1547399009 981369121 2368920148 925292993 788088604 
corruptor:scratch indiv$ 
+0

감사! OpenSSL 문서는 내부 RNG를 무시하는 것이 그보다 훨씬 어려웠다는 인상을주었습니다. 그래서 나는 그렇게하기를 꺼 렸습니다. – zwol

+0

설명서는 또한 RAND_METHOD가 아니라 ENGINE에서이 작업을 수행해야한다는 것을 강하게 암시하지만 내 엔진을 구현하는 방법을 알 수는 없습니다. 당신은 그것에 대해 논평 할 수 있습니까? – zwol

+0

@Zack : ENGINE는 컨테이너이며, 알고리즘 구현을 동적으로로드 및 해제하기위한 인터페이스를 공개합니다. 그게 전부 야. 따라서 RNG 엔진을 ENGINE 개체로 구현하려면 먼저 위에서 설명한 내용을 구현 한 다음 ENGINE 인터페이스의 모든 이점을 얻기 위해 ENGINE 래퍼를 구현해야합니다. 알고리즘 인터페이스는 변경되지 않습니다 ('RAND_ *'함수와'RAND_METHOD' 테이블). ENGINE을 구현한다면 여전히 테이블 접근자를 제공하여'-DOPENSSL_NO_ENGINE'으로 컴파일 된 OpenSSL 사용자를 지원해야합니다. – indiv

1

라이브러리 주위에 랩퍼를 작성한다. 그런 다음 시험 시간에 당신의 마법의 가치를 돌려주는 자신의 모의로 대체하십시오.

단위 테스트에서는 OpenSSL을 테스트하지 않는 것을 기억하십시오. 코드를 테스트하려고합니다.

+0

OpenSSL 용으로 내 자신의 PRNG 엔진을 작성하는 것만 큼 어려울 것입니다. OpenSSL의 PRNG를 통해 내가 원하는 것을 쉽게 할 수있게되었습니다. – zwol

+0

좋아, 그럼 테스트 프로젝트의 링커를 속여. 소스 모듈에서 자신의 RAND_bytes() 및 RAND_pseudo_bytes()를 구현하면 모든 라이브러리가 가져 오기 전에 링크됩니다. –

+0

"자신의 [암호화 PRNG] 구현"은 내 엔진 작성만큼 어렵습니다. 문제의 핵심은 그것이 피할 수 있다면 그렇게 할 필요가 없다는 것입니다. – zwol

관련 문제