1
0
mirror of https://github.com/postgres/postgres.git synced 2025-08-31 17:02:12 +03:00

pgcrypto: Add support for CFB mode in AES encryption

Cipher Feedback Mode, CFB, is a self-synchronizing stream cipher which
is very similar to CBC performed in reverse. Since OpenSSL supports it,
we can easily plug it into the existing cipher selection code without
any need for infrastructure changes.

This patch was simultaneously submitted by Umar Hayat and Vladyslav
Nebozhyn, the latter whom suggested the feauture. The committed patch
is Umar's version.

Author: Umar Hayat <postgresql.wizard@gmail.com>
Reviewed-by: Daniel Gustafsson <daniel@yesql.se>
Reviewed-by: Álvaro Herrera <alvherre@alvh.no-ip.org>
Discussion: https://postgr.es/m/CAPBGcbxo9ASzq14VTpQp3mnUJ5omdgTWUJOvWV0L6nNigWE5jw@mail.gmail.com
This commit is contained in:
Daniel Gustafsson
2025-02-14 21:18:37 +01:00
parent 760bf588de
commit 9ad1b3d01f
4 changed files with 217 additions and 1 deletions

View File

@@ -135,3 +135,121 @@ select encode(decrypt(encrypt('Lets try a longer message.', '0123456789', 'aes')
Lets try a longer message. Lets try a longer message.
(1 row) (1 row)
-- cfb
SELECT encrypt(
'\x00112233445566778899aabbccddeeff',
'\x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f',
'aes-cfb/pad:none');
encrypt
------------------------------------
\xf28122856e1cf9a7216a30d111f3997f
(1 row)
-- without padding, input not multiple of block size
SELECT encrypt(
'\x00112233445566778899aabbccddeeff00',
'\x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f',
'aes-cfb/pad:none');
encrypt
--------------------------------------
\xf28122856e1cf9a7216a30d111f3997fcb
(1 row)
-- key padding
SELECT encrypt(
'\x0011223344',
'\x000102030405',
'aes-cfb');
encrypt
--------------
\x8145d1a0ef
(1 row)
SELECT encrypt(
'\x0011223344',
'\x000102030405060708090a0b0c0d0e0f10111213',
'aes-cfb');
encrypt
--------------
\x52642c3b9c
(1 row)
SELECT encrypt(
'\x0011223344',
'\x000102030405060708090a0b0c0d0e0f101112131415161718191a1b',
'aes-cfb');
encrypt
--------------
\xc93b4468a4
(1 row)
-- empty data
select encrypt('', 'foo', 'aes-cfb');
encrypt
---------
\x
(1 row)
-- 10 bytes key
select encrypt('foo', '0123456789', 'aes-cfb');
encrypt
----------
\x6f8ced
(1 row)
-- 22 bytes key
select encrypt('foo', '0123456789012345678901', 'aes-cfb');
encrypt
----------
\xfb47d2
(1 row)
-- decrypt
select encode(decrypt(encrypt('foo', '0123456', 'aes-cfb'), '0123456', 'aes-cfb'), 'escape');
encode
--------
foo
(1 row)
-- data not multiple of block size
select encode(decrypt(encrypt('foo', '0123456', 'aes-cfb') || '\x00'::bytea, '0123456', 'aes-cfb'), 'escape');
encode
---------
foo\337
(1 row)
-- bad padding
-- (The input value is the result of encrypt_iv('abcdefghijklmnopqrstuvwxyz', '0123456', 'abcd', 'aes-cfb')
-- with the 16th byte changed (s/c5/d5/) to corrupt the padding of the last block.)
select encode(decrypt_iv('\xf9ad6817cb58d31dd9ba6571fbc4f55d56f65b631f0f437cb828', '0123456', 'abcd', 'aes-cfb'), 'escape');
encode
-------------------------------------------------
abcdefghijklmnoq\243:\205o\x7F\x05z\276\x07\332
(1 row)
-- iv
select encrypt_iv('foo', '0123456', 'abcd', 'aes-cfb');
encrypt_iv
------------
\xfea064
(1 row)
select encode(decrypt_iv('\xfea064', '0123456', 'abcd', 'aes-cfb'), 'escape');
encode
--------
foo
(1 row)
-- long message
select encrypt('Lets try a longer message.', '0123456789', 'aes-cfb');
encrypt
--------------------------------------------------------
\x4586f6c6351055051f723b1b0aad52c877eaf0c421d18fd73a28
(1 row)
select encode(decrypt(encrypt('Lets try a longer message.', '0123456789', 'aes-cfb'), '0123456789', 'aes-cfb'), 'escape');
encode
----------------------------
Lets try a longer message.
(1 row)

View File

@@ -617,6 +617,36 @@ ossl_aes_cbc_init(PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv
return err; return err;
} }
static int
ossl_aes_cfb_init(PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv)
{
OSSLCipher *od = c->ptr;
int err;
err = ossl_aes_init(c, key, klen, iv);
if (err)
return err;
switch (od->klen)
{
case 128 / 8:
od->evp_ciph = EVP_aes_128_cfb();
break;
case 192 / 8:
od->evp_ciph = EVP_aes_192_cfb();
break;
case 256 / 8:
od->evp_ciph = EVP_aes_256_cfb();
break;
default:
/* shouldn't happen */
err = PXE_CIPHER_INIT;
break;
}
return err;
}
/* /*
* aliases * aliases
*/ */
@@ -636,6 +666,7 @@ static PX_Alias ossl_aliases[] = {
{"rijndael", "aes-cbc"}, {"rijndael", "aes-cbc"},
{"rijndael-cbc", "aes-cbc"}, {"rijndael-cbc", "aes-cbc"},
{"rijndael-ecb", "aes-ecb"}, {"rijndael-ecb", "aes-ecb"},
{"rijndael-cfb", "aes-cfb"},
{NULL} {NULL}
}; };
@@ -707,6 +738,13 @@ static const struct ossl_cipher ossl_aes_cbc = {
128 / 8, 256 / 8 128 / 8, 256 / 8
}; };
static const struct ossl_cipher ossl_aes_cfb = {
ossl_aes_cfb_init,
NULL, /* EVP_aes_XXX_cfb(), determined in init
* function */
128 / 8, 256 / 8
};
/* /*
* Special handlers * Special handlers
*/ */
@@ -728,6 +766,7 @@ static const struct ossl_cipher_lookup ossl_cipher_types[] = {
{"cast5-cbc", &ossl_cast_cbc}, {"cast5-cbc", &ossl_cast_cbc},
{"aes-ecb", &ossl_aes_ecb}, {"aes-ecb", &ossl_aes_ecb},
{"aes-cbc", &ossl_aes_cbc}, {"aes-cbc", &ossl_aes_cbc},
{"aes-cfb", &ossl_aes_cfb},
{NULL} {NULL}
}; };

View File

@@ -70,3 +70,56 @@ select encode(decrypt_iv('\x2c24cb7da91d6d5699801268b0f5adad', '0123456', 'abcd'
-- long message -- long message
select encrypt('Lets try a longer message.', '0123456789', 'aes'); select encrypt('Lets try a longer message.', '0123456789', 'aes');
select encode(decrypt(encrypt('Lets try a longer message.', '0123456789', 'aes'), '0123456789', 'aes'), 'escape'); select encode(decrypt(encrypt('Lets try a longer message.', '0123456789', 'aes'), '0123456789', 'aes'), 'escape');
-- cfb
SELECT encrypt(
'\x00112233445566778899aabbccddeeff',
'\x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f',
'aes-cfb/pad:none');
-- without padding, input not multiple of block size
SELECT encrypt(
'\x00112233445566778899aabbccddeeff00',
'\x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f',
'aes-cfb/pad:none');
-- key padding
SELECT encrypt(
'\x0011223344',
'\x000102030405',
'aes-cfb');
SELECT encrypt(
'\x0011223344',
'\x000102030405060708090a0b0c0d0e0f10111213',
'aes-cfb');
SELECT encrypt(
'\x0011223344',
'\x000102030405060708090a0b0c0d0e0f101112131415161718191a1b',
'aes-cfb');
-- empty data
select encrypt('', 'foo', 'aes-cfb');
-- 10 bytes key
select encrypt('foo', '0123456789', 'aes-cfb');
-- 22 bytes key
select encrypt('foo', '0123456789012345678901', 'aes-cfb');
-- decrypt
select encode(decrypt(encrypt('foo', '0123456', 'aes-cfb'), '0123456', 'aes-cfb'), 'escape');
-- data not multiple of block size
select encode(decrypt(encrypt('foo', '0123456', 'aes-cfb') || '\x00'::bytea, '0123456', 'aes-cfb'), 'escape');
-- bad padding
-- (The input value is the result of encrypt_iv('abcdefghijklmnopqrstuvwxyz', '0123456', 'abcd', 'aes-cfb')
-- with the 16th byte changed (s/c5/d5/) to corrupt the padding of the last block.)
select encode(decrypt_iv('\xf9ad6817cb58d31dd9ba6571fbc4f55d56f65b631f0f437cb828', '0123456', 'abcd', 'aes-cfb'), 'escape');
-- iv
select encrypt_iv('foo', '0123456', 'abcd', 'aes-cfb');
select encode(decrypt_iv('\xfea064', '0123456', 'abcd', 'aes-cfb'), 'escape');
-- long message
select encrypt('Lets try a longer message.', '0123456789', 'aes-cfb');
select encode(decrypt(encrypt('Lets try a longer message.', '0123456789', 'aes-cfb'), '0123456789', 'aes-cfb'), 'escape');

View File

@@ -1082,6 +1082,11 @@ decrypt_iv(data bytea, key bytea, iv bytea, type text) returns bytea
<literal>cbc</literal> &mdash; next block depends on previous (default) <literal>cbc</literal> &mdash; next block depends on previous (default)
</para> </para>
</listitem> </listitem>
<listitem>
<para>
<literal>cfb</literal> &mdash; next block depends on previous encrypted block
</para>
</listitem>
<listitem> <listitem>
<para> <para>
<literal>ecb</literal> &mdash; each block is encrypted separately (for <literal>ecb</literal> &mdash; each block is encrypted separately (for
@@ -1112,7 +1117,8 @@ encrypt(data, 'fooz', 'bf-cbc/pad:pkcs')
</para> </para>
<para> <para>
In <function>encrypt_iv</function> and <function>decrypt_iv</function>, the In <function>encrypt_iv</function> and <function>decrypt_iv</function>, the
<parameter>iv</parameter> parameter is the initial value for the CBC mode; <parameter>iv</parameter> parameter is the initial value for the CBC and
CFB mode;
it is ignored for ECB. it is ignored for ECB.
It is clipped or padded with zeroes if not exactly block size. It is clipped or padded with zeroes if not exactly block size.
It defaults to all zeroes in the functions without this parameter. It defaults to all zeroes in the functions without this parameter.