mirror of https://github.com/postgres/postgres
Big thanks to Solar Designer who pointed out a bug in bcrypt
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 Kreen
This commit is contained in:
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.
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# $Header: /cvsroot/pgsql/contrib/pgcrypto/Makefile,v 1.6 2001/09/16 16:11:09 petere Exp $
|
||||
# $Header: /cvsroot/pgsql/contrib/pgcrypto/Makefile,v 1.7 2001/09/23 04:12:44 momjian Exp $
|
||||
#
|
||||
|
||||
subdir = contrib/pgcrypto
|
||||
|
@ -12,6 +12,18 @@ cryptolib = builtin
|
|||
# either 'builtin', 'system'
|
||||
cryptsrc = builtin
|
||||
|
||||
# Random source, preferred order:
|
||||
# 'dev' - read from random device
|
||||
#
|
||||
# 'openssl' - use openssl PRNG.
|
||||
# Note that currently pgcrypto does not do any
|
||||
# entropy feeding to it
|
||||
# This works ofcouse only with cryptolib = openssl
|
||||
#
|
||||
# 'silly' - use libc random() - very weak
|
||||
random = dev
|
||||
random_dev = \"/dev/urandom\"
|
||||
|
||||
##########################
|
||||
|
||||
ifeq ($(cryptolib), builtin)
|
||||
|
@ -38,8 +50,19 @@ else
|
|||
CRYPTO_CFLAGS += -DPX_SYSTEM_CRYPT
|
||||
endif
|
||||
|
||||
ifeq ($(random), dev)
|
||||
CRYPTO_CFLAGS += -DRAND_DEV=$(random_dev)
|
||||
endif
|
||||
ifeq ($(random), openssl)
|
||||
CRYPTO_CFLAGS += -DRAND_OPENSSL
|
||||
endif
|
||||
ifeq ($(random), silly)
|
||||
CRYPTO_CFLAGS += -DRAND_SILLY
|
||||
endif
|
||||
|
||||
NAME := pgcrypto
|
||||
SRCS += pgcrypto.c px.c px-hmac.c px-crypt.c misc.c
|
||||
SRCS += pgcrypto.c px.c px-hmac.c px-crypt.c misc.c \
|
||||
crypt-gensalt.c random.c
|
||||
OBJS := $(SRCS:.c=.o)
|
||||
SHLIB_LINK := $(CRYPTO_LDFLAGS)
|
||||
SO_MAJOR_VERSION = 0
|
||||
|
|
|
@ -9,6 +9,13 @@ INSTALLATION
|
|||
|
||||
Edit makefile, if you want to use any external library.
|
||||
|
||||
NB! Default randomness source is /dev/urandom device. If you
|
||||
do not have it, you also need to edit Makefile to let pgcrypto
|
||||
use either OpenSSL PRNG or libc random() PRNG. Using libc random()
|
||||
is discouraged.
|
||||
|
||||
After editing Makefile:
|
||||
|
||||
make
|
||||
make install
|
||||
|
||||
|
@ -73,6 +80,27 @@ gen_salt(type::text)::text
|
|||
When you use --enable-system-crypt then note that system
|
||||
libcrypt may not support them all.
|
||||
|
||||
gen_salt(type::text, rounds::int4)::text
|
||||
|
||||
same as above, but lets user specify iteration count
|
||||
for algorithm. Number is algotithm specific:
|
||||
|
||||
type default min max
|
||||
---------------------------------
|
||||
xdes 725 1 16777215
|
||||
bf 6 4 31
|
||||
|
||||
In case of xdes there is a additional limitation that the
|
||||
count must be a odd number.
|
||||
|
||||
The higher the count, the more time it takes to calculate
|
||||
crypt and therefore the more time to break it. But beware!
|
||||
With too high count it takes a _very_long_ time to
|
||||
calculate it.
|
||||
|
||||
For maximum security, you should choose the 'bf' crypt
|
||||
and use maximum number of rounds you can still tolerate.
|
||||
|
||||
encrypt(data::bytea, key::bytea, type::text)::bytea
|
||||
decrypt(data::bytea, key::bytea, type::text)::bytea
|
||||
encrypt_iv(data::bytea, key::bytea, iv::bytea, type::text)::bytea
|
||||
|
|
|
@ -705,28 +705,3 @@ char *_crypt_blowfish_rn(__CONST char *key, __CONST char *setting,
|
|||
return output;
|
||||
}
|
||||
|
||||
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,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;
|
||||
}
|
||||
|
|
@ -26,7 +26,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: openssl.c,v 1.4 2001/08/21 00:42:41 momjian Exp $
|
||||
* $Id: openssl.c,v 1.5 2001/09/23 04:12:44 momjian Exp $
|
||||
*/
|
||||
|
||||
#include <postgres.h>
|
||||
|
@ -35,7 +35,6 @@
|
|||
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/blowfish.h>
|
||||
/*#include <openssl/crypto.h>*/
|
||||
|
||||
static uint
|
||||
digest_result_size(PX_MD * h)
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: pgcrypto.c,v 1.8 2001/08/21 00:42:41 momjian Exp $
|
||||
* $Id: pgcrypto.c,v 1.9 2001/09/23 04:12:44 momjian Exp $
|
||||
*/
|
||||
|
||||
#include <postgres.h>
|
||||
|
@ -200,7 +200,7 @@ pg_gen_salt(PG_FUNCTION_ARGS)
|
|||
len = len > PX_MAX_SALT_LEN ? PX_MAX_SALT_LEN : len;
|
||||
memcpy(buf, VARDATA(arg0), len);
|
||||
buf[len] = 0;
|
||||
len = px_gen_salt(buf, buf);
|
||||
len = px_gen_salt(buf, buf, 0);
|
||||
if (len == 0)
|
||||
elog(ERROR, "No such crypt algorithm");
|
||||
|
||||
|
@ -213,6 +213,41 @@ pg_gen_salt(PG_FUNCTION_ARGS)
|
|||
PG_RETURN_TEXT_P(res);
|
||||
}
|
||||
|
||||
/* SQL function: pg_gen_salt(text, int4) returns text */
|
||||
PG_FUNCTION_INFO_V1(pg_gen_salt_rounds);
|
||||
|
||||
Datum
|
||||
pg_gen_salt_rounds(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *arg0;
|
||||
int rounds;
|
||||
uint len;
|
||||
text *res;
|
||||
char buf[PX_MAX_SALT_LEN + 1];
|
||||
|
||||
if (PG_ARGISNULL(0) || PG_ARGISNULL(1))
|
||||
PG_RETURN_NULL();
|
||||
|
||||
arg0 = PG_GETARG_TEXT_P(0);
|
||||
rounds = PG_GETARG_INT32(1);
|
||||
|
||||
len = VARSIZE(arg0) - VARHDRSZ;
|
||||
len = len > PX_MAX_SALT_LEN ? PX_MAX_SALT_LEN : len;
|
||||
memcpy(buf, VARDATA(arg0), len);
|
||||
buf[len] = 0;
|
||||
len = px_gen_salt(buf, buf, rounds);
|
||||
if (len == 0)
|
||||
elog(ERROR, "No such crypt algorithm or bad number of rounds");
|
||||
|
||||
res = (text *) palloc(len + VARHDRSZ);
|
||||
VARATT_SIZEP(res) = len + VARHDRSZ;
|
||||
memcpy(VARDATA(res), buf, len);
|
||||
|
||||
PG_FREE_IF_COPY(arg0, 0);
|
||||
|
||||
PG_RETURN_TEXT_P(res);
|
||||
}
|
||||
|
||||
/* SQL function: pg_crypt(psw:text, salt:text) returns text */
|
||||
PG_FUNCTION_INFO_V1(pg_crypt);
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: pgcrypto.h,v 1.4 2001/08/21 00:42:41 momjian Exp $
|
||||
* $Id: pgcrypto.h,v 1.5 2001/09/23 04:12:44 momjian Exp $
|
||||
*/
|
||||
|
||||
#ifndef _PG_CRYPTO_H
|
||||
|
@ -38,6 +38,7 @@ Datum pg_digest_exists(PG_FUNCTION_ARGS);
|
|||
Datum pg_hmac(PG_FUNCTION_ARGS);
|
||||
Datum pg_hmac_exists(PG_FUNCTION_ARGS);
|
||||
Datum pg_gen_salt(PG_FUNCTION_ARGS);
|
||||
Datum pg_gen_salt_rounds(PG_FUNCTION_ARGS);
|
||||
Datum pg_crypt(PG_FUNCTION_ARGS);
|
||||
Datum pg_encrypt(PG_FUNCTION_ARGS);
|
||||
Datum pg_decrypt(PG_FUNCTION_ARGS);
|
||||
|
|
|
@ -5,10 +5,12 @@
|
|||
-- drop function hmac_exists(text);
|
||||
-- drop function crypt(text, text);
|
||||
-- drop function gen_salt(text);
|
||||
-- drop function gen_salt(text, int4);
|
||||
-- drop function encrypt(bytea, bytea, text);
|
||||
-- drop function decrypt(bytea, bytea, text);
|
||||
-- drop function encrypt_iv(bytea, bytea, bytea, text);
|
||||
-- drop function decrypt_iv(bytea, bytea, bytea, text);
|
||||
-- drop function cipher_exists(text);
|
||||
|
||||
|
||||
|
||||
|
@ -36,6 +38,10 @@ CREATE FUNCTION gen_salt(text) RETURNS text
|
|||
AS '@MODULE_FILENAME@',
|
||||
'pg_gen_salt' LANGUAGE 'C';
|
||||
|
||||
CREATE FUNCTION gen_salt(text, int4) RETURNS text
|
||||
AS '@MODULE_FILENAME@',
|
||||
'pg_gen_salt_rounds' LANGUAGE 'C';
|
||||
|
||||
CREATE FUNCTION encrypt(bytea, bytea, text) RETURNS bytea
|
||||
AS '@MODULE_FILENAME@',
|
||||
'pg_encrypt' LANGUAGE 'C';
|
||||
|
|
|
@ -26,10 +26,11 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: px-crypt.c,v 1.1 2001/08/21 01:32:01 momjian Exp $
|
||||
* $Id: px-crypt.c,v 1.2 2001/09/23 04:12:44 momjian Exp $
|
||||
*/
|
||||
|
||||
#include <postgres.h>
|
||||
#include "px.h"
|
||||
#include "px-crypt.h"
|
||||
|
||||
|
||||
|
@ -62,12 +63,8 @@ run_crypt_bf(const char *psw, const char *salt,
|
|||
char *buf, unsigned len)
|
||||
{
|
||||
char *res;
|
||||
|
||||
res = _crypt_blowfish_rn(psw, salt, buf, len);
|
||||
if (!res)
|
||||
return NULL;
|
||||
strcpy(buf, res);
|
||||
return buf;
|
||||
return res;
|
||||
}
|
||||
|
||||
static struct
|
||||
|
@ -128,106 +125,53 @@ px_crypt(const char *psw, const char *salt,
|
|||
* salt generators
|
||||
*/
|
||||
|
||||
static int my_rand64()
|
||||
{
|
||||
return random() % 64;
|
||||
}
|
||||
|
||||
static uint
|
||||
gen_des_salt(char *buf)
|
||||
{
|
||||
buf[0] = px_crypt_a64[my_rand64()];
|
||||
buf[1] = px_crypt_a64[my_rand64()];
|
||||
buf[2] = 0;
|
||||
|
||||
return 2;
|
||||
}
|
||||
|
||||
static uint
|
||||
gen_xdes_salt(char *buf)
|
||||
{
|
||||
strcpy(buf, "_12345678");
|
||||
|
||||
px_crypt_to64(buf+1, (long)PX_XDES_ROUNDS, 4);
|
||||
px_crypt_to64(buf+5, random(), 4);
|
||||
|
||||
return 9;
|
||||
}
|
||||
|
||||
static uint
|
||||
gen_md5_salt(char *buf)
|
||||
{
|
||||
int i;
|
||||
strcpy(buf, "$1$12345678$");
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
buf[3 + i] = px_crypt_a64[my_rand64()];
|
||||
|
||||
return 12;
|
||||
}
|
||||
|
||||
static uint
|
||||
gen_bf_salt(char *buf)
|
||||
{
|
||||
int i, count;
|
||||
char *s;
|
||||
char saltbuf[16+3];
|
||||
unsigned slen = 16;
|
||||
uint32 *v;
|
||||
|
||||
for (i = 0; i < slen; i++)
|
||||
saltbuf[i] = random() & 255;
|
||||
saltbuf[16] = 0;
|
||||
saltbuf[17] = 0;
|
||||
saltbuf[18] = 0;
|
||||
|
||||
strcpy(buf, "$2a$00$0123456789012345678901");
|
||||
|
||||
count = PX_BF_ROUNDS;
|
||||
buf[4] = '0' + count / 10;
|
||||
buf[5] = '0' + count % 10;
|
||||
|
||||
s = buf + 7;
|
||||
for (i = 0; i < slen; )
|
||||
{
|
||||
v = (uint32 *)&saltbuf[i];
|
||||
if (i + 3 <= slen)
|
||||
px_crypt_to64(s, *v, 4);
|
||||
else
|
||||
/* slen-i could be 1,2 make it 2,3 */
|
||||
px_crypt_to64(s, *v, slen-i+1);
|
||||
s += 4;
|
||||
i += 3;
|
||||
}
|
||||
|
||||
s = buf;
|
||||
/*s = _crypt_gensalt_blowfish_rn(count, saltbuf, 16, buf, PX_MAX_CRYPT);*/
|
||||
|
||||
return s ? strlen(s) : 0;
|
||||
}
|
||||
|
||||
struct generator {
|
||||
char *name;
|
||||
uint (*gen)(char *buf);
|
||||
char *(*gen)(unsigned long count, const char *input, int size,
|
||||
char *output, int output_size);
|
||||
int input_len;
|
||||
int def_rounds;
|
||||
int min_rounds;
|
||||
int max_rounds;
|
||||
};
|
||||
|
||||
static struct generator gen_list [] = {
|
||||
{ "des", gen_des_salt },
|
||||
{ "md5", gen_md5_salt },
|
||||
{ "xdes", gen_xdes_salt },
|
||||
{ "bf", gen_bf_salt },
|
||||
{ NULL, NULL }
|
||||
{ "des", _crypt_gensalt_traditional_rn, 2, 0, 0, 0 },
|
||||
{ "md5", _crypt_gensalt_md5_rn, 6, 0, 0, 0 },
|
||||
{ "xdes", _crypt_gensalt_extended_rn, 3, PX_XDES_ROUNDS, 1, 0xFFFFFF },
|
||||
{ "bf", _crypt_gensalt_blowfish_rn, 16, PX_BF_ROUNDS, 4, 31 },
|
||||
{ NULL, NULL, 0, 0, 0 }
|
||||
};
|
||||
|
||||
uint
|
||||
px_gen_salt(const char *salt_type, char *buf)
|
||||
px_gen_salt(const char *salt_type, char *buf, int rounds)
|
||||
{
|
||||
int i;
|
||||
int i, res;
|
||||
struct generator *g;
|
||||
char *p;
|
||||
char rbuf[16];
|
||||
|
||||
for (i = 0; gen_list[i].name; i++) {
|
||||
g = &gen_list[i];
|
||||
if (!strcasecmp(g->name, salt_type))
|
||||
return g->gen(buf);
|
||||
if (strcasecmp(g->name, salt_type) != 0)
|
||||
continue;
|
||||
|
||||
if (g->def_rounds) {
|
||||
if (rounds == 0)
|
||||
rounds = g->def_rounds;
|
||||
|
||||
if (rounds < g->min_rounds || rounds > g->max_rounds)
|
||||
return 0;
|
||||
}
|
||||
|
||||
res = px_get_random_bytes(rbuf, g->input_len);
|
||||
if (res != g->input_len)
|
||||
return 0;
|
||||
|
||||
p = g->gen(rounds, rbuf, g->input_len, buf, PX_MAX_SALT_LEN);
|
||||
memset(rbuf, 0, sizeof(rbuf));
|
||||
|
||||
return p != NULL ? strlen(p) : 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: px-crypt.h,v 1.1 2001/08/21 01:32:01 momjian Exp $
|
||||
* $Id: px-crypt.h,v 1.2 2001/09/23 04:12:44 momjian Exp $
|
||||
*/
|
||||
|
||||
#ifndef _PX_CRYPT_H
|
||||
|
@ -38,19 +38,22 @@
|
|||
/* max salt returned by gen_salt() */
|
||||
#define PX_MAX_SALT_LEN 128
|
||||
|
||||
/* rounds for xdes salt */
|
||||
/* default rounds for xdes salt */
|
||||
/* NetBSD bin/passwd/local_passwd.c has (29 * 25)*/
|
||||
#define PX_XDES_ROUNDS (29 * 25)
|
||||
|
||||
/* rounds for blowfish salt */
|
||||
/* default for blowfish salt */
|
||||
#define PX_BF_ROUNDS 6
|
||||
|
||||
/*
|
||||
* main interface
|
||||
*/
|
||||
char *px_crypt(const char *psw, const char *salt, char *buf, unsigned buflen);
|
||||
unsigned px_gen_salt(const char *salt_type, char *dst);
|
||||
unsigned px_gen_salt(const char *salt_type, char *dst, int rounds);
|
||||
|
||||
/*
|
||||
* internal functions
|
||||
*/
|
||||
|
||||
/* misc.c */
|
||||
extern void px_crypt_to64(char *s, unsigned long v, int n);
|
||||
|
@ -59,6 +62,15 @@ extern char px_crypt_a64[];
|
|||
#define _crypt_to64 px_crypt_to64
|
||||
#define _crypt_a64 px_crypt_a64
|
||||
|
||||
/* crypt-gensalt.c */
|
||||
char *_crypt_gensalt_traditional_rn(unsigned long count,
|
||||
const char *input, int size, char *output, int output_size);
|
||||
char *_crypt_gensalt_extended_rn(unsigned long count,
|
||||
const char *input, int size, char *output, int output_size);
|
||||
char *_crypt_gensalt_md5_rn(unsigned long count,
|
||||
const char *input, int size, char *output, int output_size);
|
||||
char *_crypt_gensalt_blowfish_rn(unsigned long count,
|
||||
const char *input, int size, char *output, int output_size);
|
||||
|
||||
#ifndef PX_SYSTEM_CRYPT
|
||||
|
||||
|
@ -66,9 +78,6 @@ extern char px_crypt_a64[];
|
|||
/* #define DISABLE_XDES */
|
||||
|
||||
/* crypt-blowfish.c */
|
||||
char *_crypt_gensalt_blowfish_rn(unsigned long count,
|
||||
const char *input, int size,
|
||||
char *output, int output_size);
|
||||
char *_crypt_blowfish_rn(const char *key, const char *setting,
|
||||
char *output, int size);
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: px.h,v 1.1 2001/08/21 01:32:01 momjian Exp $
|
||||
* $Id: px.h,v 1.2 2001/09/23 04:12:44 momjian Exp $
|
||||
*/
|
||||
|
||||
#ifndef __PX_H
|
||||
|
@ -133,6 +133,8 @@ 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);
|
||||
|
||||
int px_get_random_bytes(uint8 *dst, unsigned count);
|
||||
|
||||
const char *px_resolve_alias(const PX_Alias *aliases, const char *name);
|
||||
|
||||
#define px_md_result_size(md) (md)->result_size(md)
|
||||
|
|
|
@ -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