Skip to content

Commit 0c707fc

Browse files
committed
Add OPENSSL_DONT_ZERO_PAD_KEY constant to prevent key padding
It fixes bug #71917 (openssl_open() returns junk on envelope < 16 bytes) and bug #72362 (OpenSSL Blowfish encryption is incorrect for short keys).
1 parent bda0f4e commit 0c707fc

File tree

7 files changed

+77
-16
lines changed

7 files changed

+77
-16
lines changed

NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ PHP NEWS
1414
- OpenSSL:
1515
. Fixed bug #74798 (pkcs7_en/decrypt does not work if \x0a is used in content).
1616
(Anatol)
17+
. Added OPENSSL_DONT_ZERO_PAD_KEY constant to prevent key padding and fix bug
18+
#71917 (openssl_open() returns junk on envelope < 16 bytes) and bug #72362
19+
(OpenSSL Blowfish encryption is incorrect for short keys). (Jakub Zelenka)
1720

1821
- SPL:
1922
. Fixed bug #73471 (PHP freezes with AppendIterator). (jhdxr)

ext/openssl/openssl.c

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1511,6 +1511,7 @@ PHP_MINIT_FUNCTION(openssl)
15111511

15121512
REGISTER_LONG_CONSTANT("OPENSSL_RAW_DATA", OPENSSL_RAW_DATA, CONST_CS|CONST_PERSISTENT);
15131513
REGISTER_LONG_CONSTANT("OPENSSL_ZERO_PADDING", OPENSSL_ZERO_PADDING, CONST_CS|CONST_PERSISTENT);
1514+
REGISTER_LONG_CONSTANT("OPENSSL_DONT_ZERO_PAD_KEY", OPENSSL_DONT_ZERO_PAD_KEY, CONST_CS|CONST_PERSISTENT);
15141515

15151516
#ifndef OPENSSL_NO_TLSEXT
15161517
/* SNI support included */
@@ -6280,20 +6281,7 @@ static int php_openssl_cipher_init(const EVP_CIPHER *cipher_type,
62806281
int key_len, password_len;
62816282
size_t max_iv_len;
62826283

6283-
/* check and set key */
6284-
password_len = (int) *ppassword_len;
6285-
key_len = EVP_CIPHER_key_length(cipher_type);
6286-
if (key_len > password_len) {
6287-
key = emalloc(key_len);
6288-
memset(key, 0, key_len);
6289-
memcpy(key, *ppassword, password_len);
6290-
*ppassword = (char *) key;
6291-
*ppassword_len = key_len;
6292-
*free_password = 1;
6293-
} else {
6294-
key = (unsigned char*)*ppassword;
6295-
*free_password = 0;
6296-
}
6284+
*free_password = 0;
62976285

62986286
max_iv_len = EVP_CIPHER_iv_length(cipher_type);
62996287
if (enc && *piv_len == 0 && max_iv_len > 0 && !mode->is_aead) {
@@ -6318,9 +6306,28 @@ static int php_openssl_cipher_init(const EVP_CIPHER *cipher_type,
63186306
return FAILURE;
63196307
}
63206308
}
6321-
if (password_len > key_len && !EVP_CIPHER_CTX_set_key_length(cipher_ctx, password_len)) {
6322-
php_openssl_store_errors();
6309+
/* check and set key */
6310+
password_len = (int) *ppassword_len;
6311+
key_len = EVP_CIPHER_key_length(cipher_type);
6312+
if (key_len > password_len) {
6313+
if ((OPENSSL_DONT_ZERO_PAD_KEY & options) && !EVP_CIPHER_CTX_set_key_length(cipher_ctx, password_len)) {
6314+
php_openssl_store_errors();
6315+
php_error_docref(NULL, E_WARNING, "Key length cannot be set for the cipher method");
6316+
return FAILURE;
6317+
}
6318+
key = emalloc(key_len);
6319+
memset(key, 0, key_len);
6320+
memcpy(key, *ppassword, password_len);
6321+
*ppassword = (char *) key;
6322+
*ppassword_len = key_len;
6323+
*free_password = 1;
6324+
} else {
6325+
if (password_len > key_len && !EVP_CIPHER_CTX_set_key_length(cipher_ctx, password_len)) {
6326+
php_openssl_store_errors();
6327+
}
6328+
key = (unsigned char*)*ppassword;
63236329
}
6330+
63246331
if (!EVP_CipherInit_ex(cipher_ctx, NULL, NULL, key, (unsigned char *)*piv, enc)) {
63256332
php_openssl_store_errors();
63266333
return FAILURE;

ext/openssl/php_openssl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ extern zend_module_entry openssl_module_entry;
3131

3232
#define OPENSSL_RAW_DATA 1
3333
#define OPENSSL_ZERO_PADDING 2
34+
#define OPENSSL_DONT_ZERO_PAD_KEY 4
3435

3536
#define OPENSSL_ERROR_X509_PRIVATE_KEY_VALUES_MISMATCH 0x0B080074
3637

ext/openssl/tests/bug71917.phpt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
--TEST--
2+
Bug #71917: openssl_open() returns junk on envelope < 16 bytes
3+
--SKIPIF--
4+
<?php
5+
if (!extension_loaded("openssl")) die("skip openssl not loaded");
6+
?>
7+
--FILE--
8+
<?php
9+
function test($envkey) {
10+
$publicKey = "file://" . dirname(__FILE__) . "/public.key";
11+
$privateKey = "file://" . dirname(__FILE__) . "/private_rsa_1024.key";
12+
openssl_public_encrypt($envkey, $envelope, $publicKey);
13+
$sealed = openssl_encrypt('plaintext', 'rc4', $envkey, OPENSSL_RAW_DATA | OPENSSL_DONT_ZERO_PAD_KEY);
14+
openssl_open($sealed, $output, $envelope, $privateKey, 'rc4');
15+
var_dump($output === 'plaintext');
16+
}
17+
18+
// works - key of 16 bytes
19+
test('1234567890123456i');
20+
// fails - key of 15 bytes
21+
test('123456789012345');
22+
?>
23+
--EXPECT--
24+
bool(true)
25+
bool(true)

ext/openssl/tests/bug72362.phpt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
--TEST--
2+
Bug #72362: OpenSSL Blowfish encryption is incorrect for short keys
3+
--SKIPIF--
4+
<?php
5+
if (!extension_loaded("openssl")) die("skip openssl not loaded");
6+
?>
7+
--FILE--
8+
<?php
9+
var_dump(bin2hex(openssl_encrypt("this is a test string","bf-ecb","12345678", OPENSSL_RAW_DATA | OPENSSL_DONT_ZERO_PAD_KEY)));
10+
var_dump(bin2hex(openssl_encrypt("this is a test string","bf-ecb","1234567812345678" , OPENSSL_RAW_DATA)));
11+
?>
12+
--EXPECT--
13+
string(48) "e3214d1b16e574828c8a3e222202dde81afd1ad2cb165ab3"
14+
string(48) "e3214d1b16e574828c8a3e222202dde81afd1ad2cb165ab3"

ext/openssl/tests/openssl_decrypt_basic.phpt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,13 @@ $padded_data = $data . str_repeat(' ', 16 - (strlen($data) % 16));
2424
$encrypted = openssl_encrypt($padded_data, $method, $password, OPENSSL_RAW_DATA|OPENSSL_ZERO_PADDING, $iv);
2525
$output = openssl_decrypt($encrypted, $method, $password, OPENSSL_RAW_DATA|OPENSSL_ZERO_PADDING, $iv);
2626
var_dump(rtrim($output));
27+
// if we want to prefer variable length cipher setting
28+
$encrypted = openssl_encrypt($data, "bf-ecb", $password, OPENSSL_DONT_ZERO_PAD_KEY);
29+
$output = openssl_decrypt($encrypted, "bf-ecb", $password, OPENSSL_DONT_ZERO_PAD_KEY);
30+
var_dump($output);
2731
?>
2832
--EXPECT--
2933
string(45) "openssl_encrypt() and openssl_decrypt() tests"
3034
string(45) "openssl_encrypt() and openssl_decrypt() tests"
3135
string(45) "openssl_encrypt() and openssl_decrypt() tests"
36+
string(45) "openssl_encrypt() and openssl_decrypt() tests"

ext/openssl/tests/openssl_encrypt_error.phpt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ var_dump(openssl_encrypt($data, $method, $arr));
2323

2424
// invalid using of an authentication tag
2525
var_dump(openssl_encrypt($data, $method, $password, 0, $iv, $wrong));
26+
27+
// padding of the key is disabled
28+
var_dump(openssl_encrypt($data, $method, $password, OPENSSL_DONT_ZERO_PAD_KEY, $iv));
2629
?>
2730
--EXPECTF--
2831
Warning: openssl_encrypt(): Unknown cipher algorithm in %s on line %d
@@ -48,3 +51,6 @@ NULL
4851

4952
Warning: openssl_encrypt(): The authenticated tag cannot be provided for cipher that doesn not support AEAD in %s on line %d
5053
string(44) "iPR4HulskuaP5Z6me5uImk6BqVyJG73+63tkPauVZYk="
54+
55+
Warning: openssl_encrypt(): Key length cannot be set for the cipher method in %s on line %d
56+
bool(false)

0 commit comments

Comments
 (0)