Stefan reported me that prcrypto regression test fails on solaris 10 with openssl support. I investigated this problem and the result is that Solaris 10 delivers only support for short keys up to 128. Strong crypto (SUNWcry and SUNWcryr packages) is available on web download pages. (It is result of US crypto export policy.)

However, on default installation (which is commonly used) it is a problem. Regression test cannot be fixed because it tests strong ciphers, but there two very strange issue:


1) First issue is blowfish cipher. Because pgcrypto uses old interface instead new "evp" it calls bf_set_key function which does not return any output and cut key if it is too long. See http://src.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/common/openssl/crypto/bf/bf_skey.c
line 84.

If user installs strong crypto he will not be able decrypt data which has been encrypted before.

The fix of this issue is ugly, because there is not way how to verify supported key length with old openssl API and only new API return err if length is not supported.


2) AES ciphere crashes when key is longer. It happens because return value from AES_set_encrypt_key is ignored and AES_encrypt is called with uninitialized structure.


I attach patch which fix both issues, but main problem is there that old openssl API is used and supported key lengths are hardcoded. I think we can add to TODO list rewrite pgcrypto to use evp openssl interface.


        Any comments?

                Zdenek

Index: openssl.c
===================================================================
RCS file: /projects/cvsroot/pgsql/contrib/pgcrypto/openssl.c,v
retrieving revision 1.30
diff -c -r1.30 openssl.c
*** openssl.c	4 Oct 2006 00:29:46 -0000	1.30
--- openssl.c	24 Jul 2007 11:20:02 -0000
***************
*** 380,385 ****
--- 380,399 ----
  {
  	ossldata   *od = c->ptr;
  
+ 	/* Test if key len is supported. BF_set_key silently cut large keys and it could be
+ 	 be a problem when user transfer crypted data from one server to another. */
+ 	EVP_CIPHER_CTX ctx;
+ 	EVP_CIPHER_CTX_init(&ctx);
+ 	EVP_EncryptInit_ex(&ctx, EVP_bf_cbc(), NULL, NULL, NULL);
+ 	EVP_CIPHER_CTX_set_key_length(&ctx,klen);
+ 	if( !EVP_EncryptInit_ex(&ctx,NULL, NULL, key, NULL) )
+ 	{
+ 		EVP_CIPHER_CTX_cleanup(&ctx);
+ 		return PXE_KEY_TOO_BIG;
+ 	}
+ 	EVP_CIPHER_CTX_cleanup(&ctx);
+ 
+ 	/* Key len is supported. We can use it. */
  	BF_set_key(&od->u.bf.key, klen, key);
  	if (iv)
  		memcpy(od->iv, iv, BF_BLOCK);
***************
*** 692,705 ****
  	return 0;
  }
  
! static void
  ossl_aes_key_init(ossldata * od, int type)
  {
  	if (type == AES_ENCRYPT)
! 		AES_set_encrypt_key(od->key, od->klen * 8, &od->u.aes_key);
  	else
! 		AES_set_decrypt_key(od->key, od->klen * 8, &od->u.aes_key);
! 	od->init = 1;
  }
  
  static int
--- 706,728 ----
  	return 0;
  }
  
! static int
  ossl_aes_key_init(ossldata * od, int type)
  {
+ 	int err;
+ 	/* Strong key support could miss on some openssl installation, we must
+ 		check return value, from set key function.
+ 	*/ 
  	if (type == AES_ENCRYPT)
! 	    err = AES_set_encrypt_key(od->key, od->klen * 8, &od->u.aes_key);
  	else
! 		err = AES_set_decrypt_key(od->key, od->klen * 8, &od->u.aes_key);
! 
! 	if (err == 0)
! 		od->init = 1;
! 	else 
! 		od->init = 0;
! 	return err;
  }
  
  static int
***************
*** 711,717 ****
  	const uint8 *end = data + dlen - bs;
  
  	if (!od->init)
! 		ossl_aes_key_init(od, AES_ENCRYPT);
  
  	for (; data <= end; data += bs, res += bs)
  		AES_ecb_encrypt(data, res, &od->u.aes_key, AES_ENCRYPT);
--- 734,741 ----
  	const uint8 *end = data + dlen - bs;
  
  	if (!od->init)
! 		if( ossl_aes_key_init(od, AES_ENCRYPT) )
! 			return PXE_KEY_TOO_BIG;
  
  	for (; data <= end; data += bs, res += bs)
  		AES_ecb_encrypt(data, res, &od->u.aes_key, AES_ENCRYPT);
***************
*** 727,733 ****
  	const uint8 *end = data + dlen - bs;
  
  	if (!od->init)
! 		ossl_aes_key_init(od, AES_DECRYPT);
  
  	for (; data <= end; data += bs, res += bs)
  		AES_ecb_encrypt(data, res, &od->u.aes_key, AES_DECRYPT);
--- 751,758 ----
  	const uint8 *end = data + dlen - bs;
  
  	if (!od->init)
! 		if( ossl_aes_key_init(od, AES_DECRYPT) )
! 			return PXE_KEY_TOO_BIG;
  
  	for (; data <= end; data += bs, res += bs)
  		AES_ecb_encrypt(data, res, &od->u.aes_key, AES_DECRYPT);
***************
*** 741,748 ****
  	ossldata   *od = c->ptr;
  
  	if (!od->init)
! 		ossl_aes_key_init(od, AES_ENCRYPT);
! 
  	AES_cbc_encrypt(data, res, dlen, &od->u.aes_key, od->iv, AES_ENCRYPT);
  	return 0;
  }
--- 766,774 ----
  	ossldata   *od = c->ptr;
  
  	if (!od->init)
! 		if( ossl_aes_key_init(od, AES_ENCRYPT) )
! 			return PXE_KEY_TOO_BIG;
! 	
  	AES_cbc_encrypt(data, res, dlen, &od->u.aes_key, od->iv, AES_ENCRYPT);
  	return 0;
  }
***************
*** 754,760 ****
  	ossldata   *od = c->ptr;
  
  	if (!od->init)
! 		ossl_aes_key_init(od, AES_DECRYPT);
  
  	AES_cbc_encrypt(data, res, dlen, &od->u.aes_key, od->iv, AES_DECRYPT);
  	return 0;
--- 780,787 ----
  	ossldata   *od = c->ptr;
  
  	if (!od->init)
! 		if( ossl_aes_key_init(od, AES_DECRYPT) )
! 			return PXE_KEY_TOO_BIG;
  
  	AES_cbc_encrypt(data, res, dlen, &od->u.aes_key, od->iv, AES_DECRYPT);
  	return 0;
---------------------------(end of broadcast)---------------------------
TIP 6: explain analyze is your friend

Reply via email to