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