\x8ea2b7ca516745bfeafc49904b496089
(1 row)
+-- without padding, input not multiple of block size
+SELECT encrypt(
+'\x00112233445566778899aabbccddeeff00',
+'\x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f',
+'aes-cbc/pad:none');
+ERROR: encrypt error: Encryption failed
-- key padding
SELECT encrypt(
'\x0011223344',
foo
(1 row)
+-- data not multiple of block size
+select encode(decrypt(encrypt('foo', '0123456', 'aes') || '\x00'::bytea, '0123456', 'aes'), 'escape');
+ERROR: decrypt error: Decryption failed
+-- bad padding
+-- (The input value is the result of encrypt_iv('abcdefghijklmnopqrstuvwxyz', '0123456', 'abcd', 'aes')
+-- with the 16th byte changed (s/db/eb/) to corrupt the padding of the last block.)
+select encode(decrypt_iv('\xa21a9c15231465964e3396d32095e67eb52bab05f556a581621dee1b85385789', '0123456', 'abcd', 'aes'), 'escape');
+ERROR: decrypt_iv error: Decryption failed
-- iv
select encrypt_iv('foo', '0123456', 'abcd', 'aes');
encrypt_iv
}
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;
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;
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;
}
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++;
{PXE_ERR_GENERIC, "Some PX error (not specified)"},
{PXE_NO_HASH, "No such hash algorithm"},
{PXE_NO_CIPHER, "No such cipher algorithm"},
- {PXE_NOTBLOCKSIZE, "Data not a multiple of block size"},
{PXE_BAD_OPTION, "Unknown option"},
{PXE_BAD_FORMAT, "Badly formatted type"},
{PXE_KEY_TOO_BIG, "Key was too big"},
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
#define PXE_ERR_GENERIC -1
#define PXE_NO_HASH -2
#define PXE_NO_CIPHER -3
-#define PXE_NOTBLOCKSIZE -4
+/* -4 is unused */
#define PXE_BAD_OPTION -5
#define PXE_BAD_FORMAT -6
#define PXE_KEY_TOO_BIG -7
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;
#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)
'\x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f',
'aes-cbc/pad:none');
+-- without padding, input not multiple of block size
+SELECT encrypt(
+'\x00112233445566778899aabbccddeeff00',
+'\x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f',
+'aes-cbc/pad:none');
+
-- key padding
SELECT encrypt(
-- decrypt
select encode(decrypt(encrypt('foo', '0123456', 'aes'), '0123456', 'aes'), 'escape');
+-- data not multiple of block size
+select encode(decrypt(encrypt('foo', '0123456', 'aes') || '\x00'::bytea, '0123456', 'aes'), 'escape');
+-- bad padding
+-- (The input value is the result of encrypt_iv('abcdefghijklmnopqrstuvwxyz', '0123456', 'abcd', 'aes')
+-- with the 16th byte changed (s/db/eb/) to corrupt the padding of the last block.)
+select encode(decrypt_iv('\xa21a9c15231465964e3396d32095e67eb52bab05f556a581621dee1b85385789', '0123456', 'abcd', 'aes'), 'escape');
-- iv
select encrypt_iv('foo', '0123456', 'abcd', 'aes');