mirror of
				https://github.com/michaelrsweet/pdfio.git
				synced 2025-10-31 02:15:48 +01:00 
			
		
		
		
	Add random number generation support.
This commit is contained in:
		
							
								
								
									
										182
									
								
								pdfio-crypto.c
									
									
									
									
									
								
							
							
						
						
									
										182
									
								
								pdfio-crypto.c
									
									
									
									
									
								
							| @@ -12,6 +12,188 @@ | ||||
| // | ||||
|  | ||||
| #include "pdfio-private.h" | ||||
| #if !_WIN32 | ||||
| #  include <sys/time.h> | ||||
| #endif // !_WIN32 | ||||
| #ifdef __has_include | ||||
| #  if __has_include(<sys/random.h>) | ||||
| #    define HAVE_GETRANDOM 1 | ||||
| #    include <sys/random.h> | ||||
| #  endif // __has_include(<sys/random.h>) | ||||
| #endif // __has_include | ||||
|  | ||||
|  | ||||
| // | ||||
| // '_pdfioCryptoMakeRandom()' - Fill a buffer with good random numbers. | ||||
| // | ||||
|  | ||||
| void | ||||
| _pdfioCryptoMakeRandom(uint8_t *buffer,	// I - Buffer | ||||
|                        size_t  bytes)	// I - Number of bytes | ||||
| { | ||||
| #ifdef __APPLE__ | ||||
|   // macOS/iOS provide the arc4random function which is seeded with entropy | ||||
|   // from the system... | ||||
|   while (bytes > 0) | ||||
|   { | ||||
|     // Just collect 8 bits from each call to fill the buffer... | ||||
|     *buffer++ = (uint8_t)arc4random(); | ||||
|     bytes --; | ||||
|   } | ||||
|  | ||||
| #else | ||||
| #  if _WIN32 | ||||
|   // Windows provides the CryptGenRandom function... | ||||
|   HCRYPTPROV	prov;			// Cryptographic provider | ||||
|  | ||||
|   if (CryptAcquireContextA(&prov, NULL, NULL, PROV_RSA_FULL, 0)) | ||||
|   { | ||||
|     // Got the default crypto provider, try to get random data... | ||||
|     BOOL success = CryptGenRandom(prov, (DWORD)bytes, buffer); | ||||
|  | ||||
|     // Release the crypto provider and return on success... | ||||
|     CryptReleaseContext(prov, 0); | ||||
|  | ||||
|     if (success) | ||||
|       return; | ||||
|   } | ||||
|  | ||||
| #  elif HAVE_GETRANDOM | ||||
|   // Linux provides a system call called getrandom that uses system entropy ... | ||||
|   ssize_t	rbytes;			// Bytes read | ||||
|  | ||||
|   while (bytes > 0) | ||||
|   { | ||||
|     if ((rbytes = getrandom(buffer, bytes, 0)) < 0) | ||||
|     { | ||||
|       if (errno != EINTR && errno != EAGAIN) | ||||
| 	break; | ||||
|     } | ||||
|     bytes -= (size_t)rbytes; | ||||
|     buffer += rbytes; | ||||
|   } | ||||
|  | ||||
|   if (bytes == 0) | ||||
|     return; | ||||
|  | ||||
| #  else | ||||
|   // Other UNIX-y systems have /dev/urandom... | ||||
|   int		fd;			// Random number file | ||||
|   ssize_t	rbytes;			// Bytes read | ||||
|  | ||||
|  | ||||
|   // Fall back on /dev/urandom... | ||||
|   if ((fd = open("/dev/urandom", O_RDONLY)) >= 0) | ||||
|   { | ||||
|     while (bytes > 0) | ||||
|     { | ||||
|       if ((rbytes = read(fd, buffer, bytes)) < 0) | ||||
|       { | ||||
|         if (errno != EINTR && errno != EAGAIN) | ||||
|           break; | ||||
|       } | ||||
|       bytes -= (size_t)rbytes; | ||||
|       buffer += rbytes; | ||||
|     } | ||||
|  | ||||
|     close(fd); | ||||
|  | ||||
|     if (bytes == 0) | ||||
|       return; | ||||
|   } | ||||
| #  endif // _WIN32 | ||||
|  | ||||
|   // If we get here then we were unable to get enough random data or the local | ||||
|   // system doesn't have enough entropy.  Make some up... | ||||
|   uint32_t	i,			// Looping var | ||||
| 		mt_state[624],		// Mersenne twister state | ||||
| 		mt_index,		// Mersenne twister index | ||||
| 		temp;			// Temporary value | ||||
| #  if _WIN32 | ||||
|   struct _timeb curtime;		// Current time | ||||
|  | ||||
|   _ftime(&curtime); | ||||
|   mt_state[0] = (uint32_t)(curtime.time + curtime.millitm); | ||||
|  | ||||
| #  else | ||||
|   struct timeval curtime;		// Current time | ||||
|  | ||||
|   gettimeofday(&curtime, NULL); | ||||
|   mt_state[0] = (uint32_t)(curtime.tv_sec + curtime.tv_usec); | ||||
| #  endif // _WIN32 | ||||
|  | ||||
|   // Seed the random number state... | ||||
|   mt_index = 0; | ||||
|  | ||||
|   for (i = 1; i < 624; i ++) | ||||
|     mt_state[i] = (uint32_t)((1812433253 * (mt_state[i - 1] ^ (mt_state[i - 1] >> 30))) + i); | ||||
|  | ||||
|   // Fill the buffer with random numbers... | ||||
|   while (bytes > 0) | ||||
|   { | ||||
|     if (mt_index == 0) | ||||
|     { | ||||
|       // Generate a sequence of random numbers... | ||||
|       uint32_t i1 = 1, i397 = 397;	// Looping vars | ||||
|  | ||||
|       for (i = 0; i < 624; i ++) | ||||
|       { | ||||
| 	temp        = (mt_state[i] & 0x80000000) + (mt_state[i1] & 0x7fffffff); | ||||
| 	mt_state[i] = mt_state[i397] ^ (temp >> 1); | ||||
|  | ||||
| 	if (temp & 1) | ||||
| 	  mt_state[i] ^= 2567483615u; | ||||
|  | ||||
| 	i1 ++; | ||||
| 	i397 ++; | ||||
|  | ||||
| 	if (i1 == 624) | ||||
| 	  i1 = 0; | ||||
|  | ||||
| 	if (i397 == 624) | ||||
| 	  i397 = 0; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     // Pull 32-bits of random data... | ||||
|     temp = mt_state[mt_index ++]; | ||||
|     temp ^= temp >> 11; | ||||
|     temp ^= (temp << 7) & 2636928640u; | ||||
|     temp ^= (temp << 15) & 4022730752u; | ||||
|     temp ^= temp >> 18; | ||||
|  | ||||
|     if (mt_index == 624) | ||||
|       mt_index = 0; | ||||
|  | ||||
|     // Copy to the buffer... | ||||
|     switch (bytes) | ||||
|     { | ||||
|       case 1 : | ||||
|           *buffer++ = (uint8_t)(temp >> 24); | ||||
|           bytes --; | ||||
|           break; | ||||
|       case 2 : | ||||
|           *buffer++ = (uint8_t)(temp >> 24); | ||||
|           *buffer++ = (uint8_t)(temp >> 16); | ||||
|           bytes -= 2; | ||||
|           break; | ||||
|       case 3 : | ||||
|           *buffer++ = (uint8_t)(temp >> 24); | ||||
|           *buffer++ = (uint8_t)(temp >> 16); | ||||
|           *buffer++ = (uint8_t)(temp >> 8); | ||||
|           bytes -= 3; | ||||
|           break; | ||||
|       default : | ||||
|           *buffer++ = (uint8_t)(temp >> 24); | ||||
|           *buffer++ = (uint8_t)(temp >> 16); | ||||
|           *buffer++ = (uint8_t)(temp >> 8); | ||||
|           *buffer++ = (uint8_t)temp; | ||||
|           bytes -= 4; | ||||
|           break; | ||||
|     } | ||||
|   } | ||||
| #endif // __APPLE__ | ||||
| } | ||||
|  | ||||
|  | ||||
| // | ||||
|   | ||||
| @@ -339,6 +339,7 @@ extern bool		_pdfioArrayWrite(pdfio_array_t *a) _PDFIO_INTERNAL; | ||||
| extern void		_pdfioCryptoAESInit(_pdfio_aes_t *ctx, const uint8_t *key, size_t keylen, const uint8_t *iv) _PDFIO_INTERNAL; | ||||
| extern void		_pdfioCryptoAESDecrypt(_pdfio_aes_t *ctx, uint8_t *buffer, size_t len) _PDFIO_INTERNAL; | ||||
| extern void		_pdfioCryptoAESEncrypt(_pdfio_aes_t *ctx, uint8_t *buffer, size_t len) _PDFIO_INTERNAL; | ||||
| extern void		_pdfioCryptoMakeRandom(uint8_t *buffer, size_t bytes) _PDFIO_INTERNAL; | ||||
| extern _pdfio_crypto_cb_t _pdfioCryptoMakeReader(pdfio_file_t *pdf, pdfio_obj_t *obj, _pdfio_crypto_ctx_t *ctx, uint8_t *iv, size_t *ivlen) _PDFIO_INTERNAL; | ||||
| extern _pdfio_crypto_cb_t _pdfioCryptoMakeWriter(pdfio_file_t *pdf, pdfio_obj_t *obj, _pdfio_crypto_ctx_t *ctx, uint8_t *iv, size_t *ivlen) _PDFIO_INTERNAL; | ||||
| extern void		_pdfioCryptoMD5Append(_pdfio_md5_t *pms, const uint8_t *data, size_t nbytes) _PDFIO_INTERNAL; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user