This is a rebase of the patch from [0]. It removes the internal padding implementation in pgcrypto and lets OpenSSL do it. The internal implementation was once applicable to the non-OpenSSL code paths, but those have since been removed.


[0]: https://www.postgresql.org/message-id/b1a62889-bb45-e5e0-d138-7a370a0a3...@enterprisedb.com
From 86e65690105e3a4a7e38276f48bd97c0e095beec Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <pe...@eisentraut.org>
Date: Mon, 14 Feb 2022 10:32:48 +0100
Subject: [PATCH v2] pgcrypto: Remove internal padding implementation

Use the padding provided by OpenSSL instead of doing it ourselves.
The internal implementation was once applicable to the non-OpenSSL
code paths, but those have since been removed.

Discussion: 
https://www.postgresql.org/message-id/b1a62889-bb45-e5e0-d138-7a370a0a3...@enterprisedb.com
---
 contrib/pgcrypto/openssl.c |  22 ++++---
 contrib/pgcrypto/pgp-cfb.c |   4 +-
 contrib/pgcrypto/px.c      | 119 +------------------------------------
 contrib/pgcrypto/px.h      |  12 ++--
 4 files changed, 25 insertions(+), 132 deletions(-)

diff --git a/contrib/pgcrypto/openssl.c b/contrib/pgcrypto/openssl.c
index e236b0d79c..68fd61b716 100644
--- a/contrib/pgcrypto/openssl.c
+++ b/contrib/pgcrypto/openssl.c
@@ -369,17 +369,17 @@ gen_ossl_free(PX_Cipher *c)
 }
 
 static int
-gen_ossl_decrypt(PX_Cipher *c, const uint8 *data, unsigned dlen,
-                                uint8 *res)
+gen_ossl_decrypt(PX_Cipher *c, int padding, const uint8 *data, unsigned dlen,
+                                uint8 *res, unsigned *rlen)
 {
        OSSLCipher *od = c->ptr;
-       int                     outlen;
+       int                     outlen, outlen2;
 
        if (!od->init)
        {
                if (!EVP_DecryptInit_ex(od->evp_ctx, od->evp_ciph, NULL, NULL, 
NULL))
                        return PXE_CIPHER_INIT;
-               if (!EVP_CIPHER_CTX_set_padding(od->evp_ctx, 0))
+               if (!EVP_CIPHER_CTX_set_padding(od->evp_ctx, padding))
                        return PXE_CIPHER_INIT;
                if (!EVP_CIPHER_CTX_set_key_length(od->evp_ctx, od->klen))
                        return PXE_CIPHER_INIT;
@@ -390,22 +390,25 @@ gen_ossl_decrypt(PX_Cipher *c, const uint8 *data, 
unsigned dlen,
 
        if (!EVP_DecryptUpdate(od->evp_ctx, res, &outlen, data, dlen))
                return PXE_DECRYPT_FAILED;
+       if (!EVP_DecryptFinal_ex(od->evp_ctx, res + outlen, &outlen2))
+               return PXE_DECRYPT_FAILED;
+       *rlen = outlen + outlen2;
 
        return 0;
 }
 
 static int
-gen_ossl_encrypt(PX_Cipher *c, const uint8 *data, unsigned dlen,
-                                uint8 *res)
+gen_ossl_encrypt(PX_Cipher *c, int padding, const uint8 *data, unsigned dlen,
+                                uint8 *res, unsigned *rlen)
 {
        OSSLCipher *od = c->ptr;
-       int                     outlen;
+       int                     outlen, outlen2;
 
        if (!od->init)
        {
                if (!EVP_EncryptInit_ex(od->evp_ctx, od->evp_ciph, NULL, NULL, 
NULL))
                        return PXE_CIPHER_INIT;
-               if (!EVP_CIPHER_CTX_set_padding(od->evp_ctx, 0))
+               if (!EVP_CIPHER_CTX_set_padding(od->evp_ctx, padding))
                        return PXE_CIPHER_INIT;
                if (!EVP_CIPHER_CTX_set_key_length(od->evp_ctx, od->klen))
                        return PXE_CIPHER_INIT;
@@ -416,6 +419,9 @@ gen_ossl_encrypt(PX_Cipher *c, const uint8 *data, unsigned 
dlen,
 
        if (!EVP_EncryptUpdate(od->evp_ctx, res, &outlen, data, dlen))
                return PXE_ENCRYPT_FAILED;
+       if (!EVP_EncryptFinal_ex(od->evp_ctx, res + outlen, &outlen2))
+               return PXE_ENCRYPT_FAILED;
+       *rlen = outlen + outlen2;
 
        return 0;
 }
diff --git a/contrib/pgcrypto/pgp-cfb.c b/contrib/pgcrypto/pgp-cfb.c
index dafa562daa..de41e825b0 100644
--- a/contrib/pgcrypto/pgp-cfb.c
+++ b/contrib/pgcrypto/pgp-cfb.c
@@ -220,7 +220,9 @@ cfb_process(PGP_CFB *ctx, const uint8 *data, int len, uint8 
*dst,
 
        while (len > 0)
        {
-               px_cipher_encrypt(ctx->ciph, ctx->fr, ctx->block_size, 
ctx->fre);
+               unsigned        rlen;
+
+               px_cipher_encrypt(ctx->ciph, 0, ctx->fr, ctx->block_size, 
ctx->fre, &rlen);
                if (ctx->block_no < 5)
                        ctx->block_no++;
 
diff --git a/contrib/pgcrypto/px.c b/contrib/pgcrypto/px.c
index 4205e9c3ef..5ccab44122 100644
--- a/contrib/pgcrypto/px.c
+++ b/contrib/pgcrypto/px.c
@@ -223,129 +223,14 @@ static int
 combo_encrypt(PX_Combo *cx, const uint8 *data, unsigned dlen,
                          uint8 *res, unsigned *rlen)
 {
-       int                     err = 0;
-       uint8      *bbuf;
-       unsigned        bs,
-                               bpos,
-                               i,
-                               pad;
-
-       PX_Cipher  *c = cx->cipher;
-
-       bbuf = NULL;
-       bs = px_cipher_block_size(c);
-
-       /* encrypt */
-       if (bs > 1)
-       {
-               bbuf = palloc(bs * 4);
-               bpos = dlen % bs;
-               *rlen = dlen - bpos;
-               memcpy(bbuf, data + *rlen, bpos);
-
-               /* encrypt full-block data */
-               if (*rlen)
-               {
-                       err = px_cipher_encrypt(c, data, *rlen, res);
-                       if (err)
-                               goto out;
-               }
-
-               /* bbuf has now bpos bytes of stuff */
-               if (cx->padding)
-               {
-                       pad = bs - (bpos % bs);
-                       for (i = 0; i < pad; i++)
-                               bbuf[bpos++] = pad;
-               }
-               else if (bpos % bs)
-               {
-                       /* ERROR? */
-                       pad = bs - (bpos % bs);
-                       for (i = 0; i < pad; i++)
-                               bbuf[bpos++] = 0;
-               }
-
-               /* encrypt the rest - pad */
-               if (bpos)
-               {
-                       err = px_cipher_encrypt(c, bbuf, bpos, res + *rlen);
-                       *rlen += bpos;
-               }
-       }
-       else
-       {
-               /* stream cipher/mode - no pad needed */
-               err = px_cipher_encrypt(c, data, dlen, res);
-               if (err)
-                       goto out;
-               *rlen = dlen;
-       }
-out:
-       if (bbuf)
-               pfree(bbuf);
-
-       return err;
+       return px_cipher_encrypt(cx->cipher, cx->padding, data, dlen, res, 
rlen);
 }
 
 static int
 combo_decrypt(PX_Combo *cx, const uint8 *data, unsigned dlen,
                          uint8 *res, unsigned *rlen)
 {
-       int                     err = 0;
-       unsigned        bs,
-                               i,
-                               pad;
-       unsigned        pad_ok;
-
-       PX_Cipher  *c = cx->cipher;
-
-       /* decide whether zero-length input is allowed */
-       if (dlen == 0)
-       {
-               /* with padding, empty ciphertext is not allowed */
-               if (cx->padding)
-                       return PXE_DECRYPT_FAILED;
-
-               /* without padding, report empty result */
-               *rlen = 0;
-               return 0;
-       }
-
-       bs = px_cipher_block_size(c);
-       if (bs > 1 && (dlen % bs) != 0)
-               goto block_error;
-
-       /* decrypt */
-       *rlen = dlen;
-       err = px_cipher_decrypt(c, data, dlen, res);
-       if (err)
-               return err;
-
-       /* unpad */
-       if (bs > 1 && cx->padding)
-       {
-               pad = res[*rlen - 1];
-               pad_ok = 0;
-               if (pad > 0 && pad <= bs && pad <= *rlen)
-               {
-                       pad_ok = 1;
-                       for (i = *rlen - pad; i < *rlen; i++)
-                               if (res[i] != pad)
-                               {
-                                       pad_ok = 0;
-                                       break;
-                               }
-               }
-
-               if (pad_ok)
-                       *rlen -= pad;
-       }
-
-       return 0;
-
-block_error:
-       return PXE_NOTBLOCKSIZE;
+       return px_cipher_decrypt(cx->cipher, cx->padding, data, dlen, res, 
rlen);
 }
 
 static void
diff --git a/contrib/pgcrypto/px.h b/contrib/pgcrypto/px.h
index 17d6f22498..9348d6c997 100644
--- a/contrib/pgcrypto/px.h
+++ b/contrib/pgcrypto/px.h
@@ -143,8 +143,8 @@ struct px_cipher
        unsigned        (*iv_size) (PX_Cipher *c);
 
        int                     (*init) (PX_Cipher *c, const uint8 *key, 
unsigned klen, const uint8 *iv);
-       int                     (*encrypt) (PX_Cipher *c, const uint8 *data, 
unsigned dlen, uint8 *res);
-       int                     (*decrypt) (PX_Cipher *c, const uint8 *data, 
unsigned dlen, uint8 *res);
+       int                     (*encrypt) (PX_Cipher *c, int padding, const 
uint8 *data, unsigned dlen, uint8 *res, unsigned *rlen);
+       int                     (*decrypt) (PX_Cipher *c, int padding, const 
uint8 *data, unsigned dlen, uint8 *res, unsigned *rlen);
        void            (*free) (PX_Cipher *c);
        /* private */
        void       *ptr;
@@ -207,10 +207,10 @@ void              px_debug(const char *fmt,...) 
pg_attribute_printf(1, 2);
 #define px_cipher_block_size(c)                (c)->block_size(c)
 #define px_cipher_iv_size(c)           (c)->iv_size(c)
 #define px_cipher_init(c, k, klen, iv) (c)->init(c, k, klen, iv)
-#define px_cipher_encrypt(c, data, dlen, res) \
-                                       (c)->encrypt(c, data, dlen, res)
-#define px_cipher_decrypt(c, data, dlen, res) \
-                                       (c)->decrypt(c, data, dlen, res)
+#define px_cipher_encrypt(c, padding, data, dlen, res, rlen) \
+                                       (c)->encrypt(c, padding, data, dlen, 
res, rlen)
+#define px_cipher_decrypt(c, padding, data, dlen, res, rlen) \
+                                       (c)->decrypt(c, padding, data, dlen, 
res, rlen)
 #define px_cipher_free(c)              (c)->free(c)
 
 
-- 
2.35.1

Reply via email to