mirror of https://github.com/postgres/postgres
salt generation code. He also urged using better random source and making possible to choose using bcrypt and xdes rounds more easily. So, here's patch: * For all salt generation, use Solar Designer's own code. This is mostly due fact that his code is more fit for get_random_bytes() style interface. * New function: gen_salt(type, rounds). This lets specify iteration count for algorithm. * random.c: px_get_random_bytes() function. Supported randomness soure: /dev/urandom, OpenSSL PRNG, libc random() Default: /dev/urandom. * Draft description of C API for pgcrypto functions. New files: API, crypt-gensalt.c, random.c Marko KreenREL7_2_STABLE
parent
b75814aee3
commit
ab56022864
@ -0,0 +1,163 @@ |
||||
|
||||
C API for pgcrypto |
||||
================== |
||||
|
||||
|
||||
UN*X crypt() |
||||
============ |
||||
|
||||
#include <px-crypt.h> |
||||
|
||||
char * |
||||
px_crypt(const char *psw, const char *salt, char *buf, unsigned buflen); |
||||
|
||||
returns buf or NULL for error. |
||||
|
||||
unsigned px_gen_salt(const char *salt_type, char *dst, int rounds); |
||||
|
||||
returns salt size. dst should be PX_MAX_SALT_LEN bytes. |
||||
'rounds' is algorithm specific. 0 means default for |
||||
that algorithm. |
||||
|
||||
Random |
||||
====== |
||||
|
||||
int px_rand_get_bytes(uint8 *dst, int num) |
||||
|
||||
|
||||
Crypto "objects" |
||||
================ |
||||
|
||||
PX_MD - Message digest |
||||
PX_HMAC - HMAC (Hash MAC) |
||||
PX_Cipher - cipher+mode: provided by libs |
||||
PX_Combo - higher-level encryption -> padding, [MD] |
||||
|
||||
Objects are activated with following functions: |
||||
|
||||
int px_find_digest(const char *name, PX_MD **res); |
||||
int px_find_hmac(const char *name, PX_HMAC **res); |
||||
int px_find_cipher(const char *name, PX_Cipher **res); |
||||
int px_find_combo(const char *name, PX_Combo **res); |
||||
|
||||
returns 0 on success, < 0 on error. If successful, |
||||
*res contains pointer to new object. |
||||
|
||||
Message Digest |
||||
============== |
||||
|
||||
uint px_md_result_size(PX_MD *md) |
||||
|
||||
returns final result size in bytes |
||||
|
||||
void px_md_reset(PX_MD *md) |
||||
|
||||
resets md to clean state |
||||
|
||||
uint px_md_block_size(PX_MD *md) |
||||
|
||||
return algorithm block size in bytes |
||||
|
||||
void px_md_update(PX_MD *md, const uint8 *data, uint dlen) |
||||
|
||||
updates hash state with new data |
||||
|
||||
void px_md_finish(PX_MD *md, uint8 *buf) |
||||
|
||||
puts final hash state into buf. buf should have room |
||||
for px_md_result_size() bytes. |
||||
|
||||
void px_md_free(PX_MD *md) |
||||
|
||||
frees resources. |
||||
|
||||
HMAC (Hash Message Authentication Code) |
||||
======================================= |
||||
|
||||
int px_hmac_init(PX_HMAC *hmac, const uint8 *key, uint klen) |
||||
|
||||
initalized hmac state with key. |
||||
|
||||
uint px_hmac_result_size(PX_HMAC *md) |
||||
|
||||
returns final result size in bytes |
||||
|
||||
void px_hmac_reset(PX_HMAC *md) |
||||
|
||||
resets md to state after _init() |
||||
|
||||
uint px_hmac_block_size(PX_HMAC *md) |
||||
|
||||
return algorithm block size in bytes |
||||
|
||||
void px_hmac_update(PX_HMAC *md, const uint8 *data, uint dlen) |
||||
|
||||
updates hash state with new data |
||||
|
||||
void px_hmac_finish(PX_HMAC *md, uint8 *buf) |
||||
|
||||
puts final hash state into buf. buf should have room |
||||
for px_hmac_result_size() bytes. |
||||
|
||||
void px_hmac_free(PX_HMAC *md) |
||||
|
||||
frees resources. |
||||
|
||||
|
||||
Cipher |
||||
====== |
||||
|
||||
uint px_cipher_key_size(PX_Cipher *c) |
||||
|
||||
returns max key size in bytes |
||||
|
||||
uint px_cipher_block_size(PX_Cipher *c) |
||||
|
||||
returns cipher+mode block size in bytes. So blowfish |
||||
in CFB mode should return 1. |
||||
|
||||
uint px_cipher_iv_size(PX_Cipher *c) |
||||
|
||||
returns IV size in bytes. |
||||
|
||||
int px_cipher_init(PX_Cipher *c, uint8 *key, uint klen, uint8 *iv) |
||||
|
||||
initializes cipher with supplied key and iv. |
||||
|
||||
int px_cipher_encrypt(PX_Cipher *c, uint8 *data, uint dlen, uint8 *res) |
||||
|
||||
encrypts data. res must have room for dlen bytes. |
||||
data must be multiple of px_cipher_block_size(). |
||||
|
||||
int px_cipher_decrypt(PX_Cipher *c, uint8 *data, uint dlen, uint8 *res) |
||||
|
||||
decrypts data. res must have room for dlen bytes. |
||||
|
||||
void px_cipher_free(PX_Cipher *c) |
||||
|
||||
frees resources assiocated. |
||||
|
||||
PX_Combo |
||||
======== |
||||
|
||||
uint px_combo_encrypt_len(PX_Combo *c, uint dlen) |
||||
|
||||
calculates max result length for dlen of data. |
||||
|
||||
uint px_combo_decrypt_len(PX_Combo *c, uint dlen) |
||||
|
||||
calculates result length for dlen of data. |
||||
|
||||
int px_combo_init(PX_Combo *c, uint8 *key, uint klen, uint8 *iv, uint ivlen) |
||||
|
||||
initializes c with key and iv. If cipher uses fixed length keys, |
||||
key will be padded with zeroes to needed length. |
||||
|
||||
int px_combo_encrypt(PX_Combo *c, uint8 *data, uint dlen, uint8 *res, uint rlen) |
||||
|
||||
int px_combo_decrypt(PX_Combo *c, uint8 *data, uint dlen, uint8 *res, uint rlen) |
||||
|
||||
void px_combo_free(PX_Combo *c) |
||||
|
||||
frees resources assiocated. |
||||
|
@ -0,0 +1,181 @@ |
||||
/*
|
||||
* Written by Solar Designer and placed in the public domain. |
||||
* See crypt_blowfish.c for more information. |
||||
* |
||||
* This file contains salt generation functions for the traditional and |
||||
* other common crypt(3) algorithms, except for bcrypt which is defined |
||||
* entirely in crypt_blowfish.c. |
||||
* |
||||
* Put bcrypt generator also here as crypt-blowfish.c |
||||
* may not be compiled always. -- marko |
||||
*/ |
||||
|
||||
#include <postgres.h> |
||||
#include "px-crypt.h" |
||||
|
||||
#include <errno.h> |
||||
#ifndef __set_errno |
||||
#define __set_errno(val) errno = (val) |
||||
#endif |
||||
|
||||
#undef __CONST |
||||
#ifdef __GNUC__ |
||||
#define __CONST __const |
||||
#else |
||||
#define __CONST |
||||
#endif |
||||
|
||||
typedef unsigned int BF_word; |
||||
|
||||
unsigned char _crypt_itoa64[64 + 1] = |
||||
"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; |
||||
|
||||
char *_crypt_gensalt_traditional_rn(unsigned long count, |
||||
__CONST char *input, int size, char *output, int output_size) |
||||
{ |
||||
if (size < 2 || output_size < 2 + 1 || (count && count != 25)) { |
||||
if (output_size > 0) output[0] = '\0'; |
||||
__set_errno((output_size < 2 + 1) ? ERANGE : EINVAL); |
||||
return NULL; |
||||
} |
||||
|
||||
output[0] = _crypt_itoa64[(unsigned int)input[0] & 0x3f]; |
||||
output[1] = _crypt_itoa64[(unsigned int)input[1] & 0x3f]; |
||||
output[2] = '\0'; |
||||
|
||||
return output; |
||||
} |
||||
|
||||
char *_crypt_gensalt_extended_rn(unsigned long count, |
||||
__CONST char *input, int size, char *output, int output_size) |
||||
{ |
||||
unsigned long value; |
||||
|
||||
/* Even iteration counts make it easier to detect weak DES keys from a look
|
||||
* at the hash, so they should be avoided */ |
||||
if (size < 3 || output_size < 1 + 4 + 4 + 1 || |
||||
(count && (count > 0xffffff || !(count & 1)))) { |
||||
if (output_size > 0) output[0] = '\0'; |
||||
__set_errno((output_size < 1 + 4 + 4 + 1) ? ERANGE : EINVAL); |
||||
return NULL; |
||||
} |
||||
|
||||
if (!count) count = 725; |
||||
|
||||
output[0] = '_'; |
||||
output[1] = _crypt_itoa64[count & 0x3f]; |
||||
output[2] = _crypt_itoa64[(count >> 6) & 0x3f]; |
||||
output[3] = _crypt_itoa64[(count >> 12) & 0x3f]; |
||||
output[4] = _crypt_itoa64[(count >> 18) & 0x3f]; |
||||
value = (unsigned long)input[0] | |
||||
((unsigned long)input[1] << 8) | |
||||
((unsigned long)input[2] << 16); |
||||
output[5] = _crypt_itoa64[value & 0x3f]; |
||||
output[6] = _crypt_itoa64[(value >> 6) & 0x3f]; |
||||
output[7] = _crypt_itoa64[(value >> 12) & 0x3f]; |
||||
output[8] = _crypt_itoa64[(value >> 18) & 0x3f]; |
||||
output[9] = '\0'; |
||||
|
||||
return output; |
||||
} |
||||
|
||||
char *_crypt_gensalt_md5_rn(unsigned long count, |
||||
__CONST char *input, int size, char *output, int output_size) |
||||
{ |
||||
unsigned long value; |
||||
|
||||
if (size < 3 || output_size < 3 + 4 + 1 || (count && count != 1000)) { |
||||
if (output_size > 0) output[0] = '\0'; |
||||
__set_errno((output_size < 3 + 4 + 1) ? ERANGE : EINVAL); |
||||
return NULL; |
||||
} |
||||
|
||||
output[0] = '$'; |
||||
output[1] = '1'; |
||||
output[2] = '$'; |
||||
value = (unsigned long)input[0] | |
||||
((unsigned long)input[1] << 8) | |
||||
((unsigned long)input[2] << 16); |
||||
output[3] = _crypt_itoa64[value & 0x3f]; |
||||
output[4] = _crypt_itoa64[(value >> 6) & 0x3f]; |
||||
output[5] = _crypt_itoa64[(value >> 12) & 0x3f]; |
||||
output[6] = _crypt_itoa64[(value >> 18) & 0x3f]; |
||||
output[7] = '\0'; |
||||
|
||||
if (size >= 6 && output_size >= 3 + 4 + 4 + 1) { |
||||
value = (unsigned long)input[3] | |
||||
((unsigned long)input[4] << 8) | |
||||
((unsigned long)input[5] << 16); |
||||
output[7] = _crypt_itoa64[value & 0x3f]; |
||||
output[8] = _crypt_itoa64[(value >> 6) & 0x3f]; |
||||
output[9] = _crypt_itoa64[(value >> 12) & 0x3f]; |
||||
output[10] = _crypt_itoa64[(value >> 18) & 0x3f]; |
||||
output[11] = '\0'; |
||||
} |
||||
|
||||
return output; |
||||
} |
||||
|
||||
|
||||
|
||||
static unsigned char BF_itoa64[64 + 1] = |
||||
"./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; |
||||
|
||||
static void BF_encode(char *dst, __CONST BF_word *src, int size) |
||||
{ |
||||
unsigned char *sptr = (unsigned char *)src; |
||||
unsigned char *end = sptr + size; |
||||
unsigned char *dptr = (unsigned char *)dst; |
||||
unsigned int c1, c2; |
||||
|
||||
do { |
||||
c1 = *sptr++; |
||||
*dptr++ = BF_itoa64[c1 >> 2]; |
||||
c1 = (c1 & 0x03) << 4; |
||||
if (sptr >= end) { |
||||
*dptr++ = BF_itoa64[c1]; |
||||
break; |
||||
} |
||||
|
||||
c2 = *sptr++; |
||||
c1 |= c2 >> 4; |
||||
*dptr++ = BF_itoa64[c1]; |
||||
c1 = (c2 & 0x0f) << 2; |
||||
if (sptr >= end) { |
||||
*dptr++ = BF_itoa64[c1]; |
||||
break; |
||||
} |
||||
|
||||
c2 = *sptr++; |
||||
c1 |= c2 >> 6; |
||||
*dptr++ = BF_itoa64[c1]; |
||||
*dptr++ = BF_itoa64[c2 & 0x3f]; |
||||
} while (sptr < end); |
||||
} |
||||
|
||||
char *_crypt_gensalt_blowfish_rn(unsigned long count, |
||||
__CONST char *input, int size, char *output, int output_size) |
||||
{ |
||||
if (size < 16 || output_size < 7 + 22 + 1 || |
||||
(count && (count < 4 || count > 31))) { |
||||
if (output_size > 0) output[0] = '\0'; |
||||
__set_errno((output_size < 7 + 22 + 1) ? ERANGE : EINVAL); |
||||
return NULL; |
||||
} |
||||
|
||||
if (!count) count = 5; |
||||
|
||||
output[0] = '$'; |
||||
output[1] = '2'; |
||||
output[2] = 'a'; |
||||
output[3] = '$'; |
||||
output[4] = '0' + count / 10; |
||||
output[5] = '0' + count % 10; |
||||
output[6] = '$'; |
||||
|
||||
BF_encode(&output[7], (BF_word *)input, 16); |
||||
output[7 + 22] = '\0'; |
||||
|
||||
return output; |
||||
} |
||||
|
@ -0,0 +1,127 @@ |
||||
/*
|
||||
* random.c |
||||
* Random functions. |
||||
* |
||||
* Copyright (c) 2001 Marko Kreen |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions |
||||
* are met: |
||||
* 1. Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* 2. Redistributions in binary form must reproduce the above copyright |
||||
* notice, this list of conditions and the following disclaimer in the |
||||
* documentation and/or other materials provided with the distribution. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
||||
* SUCH DAMAGE. |
||||
* |
||||
* $Id: random.c,v 1.1 2001/09/23 04:12:44 momjian Exp $ |
||||
*/ |
||||
|
||||
|
||||
#include <postgres.h> |
||||
|
||||
#include "px.h" |
||||
|
||||
|
||||
#ifdef RAND_DEV |
||||
|
||||
#include <errno.h> |
||||
#include <fcntl.h> |
||||
#include <unistd.h> |
||||
|
||||
static int |
||||
safe_read(int fd, void *buf, size_t count) |
||||
{ |
||||
int done = 0; |
||||
char *p = buf; |
||||
int res; |
||||
|
||||
while (count) { |
||||
res = read(fd, p, count); |
||||
if (res <= 0) { |
||||
if (errno == EINTR) |
||||
continue; |
||||
return -1; |
||||
} |
||||
p += res; |
||||
done += res; |
||||
count -= res; |
||||
} |
||||
return done; |
||||
} |
||||
|
||||
int |
||||
px_get_random_bytes(uint8 *dst, unsigned count) |
||||
{ |
||||
int fd; |
||||
int res; |
||||
|
||||
fd = open(RAND_DEV, O_RDONLY); |
||||
if (fd == -1) |
||||
return -1; |
||||
res = safe_read(fd, dst, count); |
||||
close(fd); |
||||
return res; |
||||
} |
||||
|
||||
#endif /* RAND_DEV */ |
||||
|
||||
#ifdef RAND_SILLY |
||||
|
||||
int px_get_random_bytes(char *dst, unsigned count) |
||||
{ |
||||
int i; |
||||
for (i = 0; i < count; i++) { |
||||
*dst++ = random(); |
||||
} |
||||
return i; |
||||
} |
||||
|
||||
#endif /* RAND_SILLY */ |
||||
|
||||
#ifdef RAND_OPENSSL |
||||
|
||||
#include <openssl/evp.h> |
||||
#include <openssl/blowfish.h> |
||||
#include <openssl/rand.h> |
||||
#include <openssl/err.h> |
||||
|
||||
static int openssl_random_init = 0; |
||||
|
||||
int px_get_random_bytes(uint8 *dst, unsigned count) |
||||
{ |
||||
int res; |
||||
|
||||
if (!openssl_random_init) { |
||||
if (RAND_get_rand_method() == NULL) { |
||||
RAND_set_rand_method(RAND_SSLeay()); |
||||
} |
||||
openssl_random_init = 1; |
||||
} |
||||
|
||||
/*
|
||||
* OpenSSL random should re-feeded occasionally. |
||||
* From /dev/urandom preferrably. |
||||
*/ |
||||
|
||||
res = RAND_bytes(dst, count); |
||||
if (res > 0) |
||||
return count; |
||||
|
||||
return -1; |
||||
} |
||||
|
||||
#endif /* RAND_OPENSSL */ |
||||
|
Loading…
Reference in new issue