Why is chr () vulnerable to a cache-timing attack and pack () not?

5

Out of curiosity I'm looking for and slowing down many things about cryptography and also looking for some pure PHP libraries, such as Sodium_Compat , for the sole reason that I understand a lot more of PHP compared to C, which is ideal for encryption, as far as I know.

However, something caught my eye in the following following :

/**
* Use pack() and binary operators to turn the two integers
* into hexadecimal characters. We don't use chr() here, because
* it uses a lookup table internally and we want to avoid
* cache-timing side-channels.
*/
$hex .= pack(
'CC',
(55 + $b + ((($b - 10) >> 8) & ~6)),
(55 + $c + ((($c - 10) >> 8) & ~6))
);

I just did not find much information about cache-timing , remembering that there is cache-timing attack and timing attack , which are different things (or not?), the second has more information.

I found this information here , which is the most summarized and there is another reply and comment that seems to be almost the answer of this question , but I'm not sure. Even based on the comment of the code I assume that the problem is that chr() uses some type of array (would that be lookup table internally ?) While pack() not, but how then pack() is able to convert the integer to hexadecimal?

The issue is, pack() is not supposed to be vulnerable while chr() has such a problem, this is not even mentioned in PHP documentation, perhaps because it is very specific . What functions, on the inside, have different? How do they convert integers and why can one convert "more securely than the other"? Why are they both not vulnerable?

    
asked by anonymous 19.02.2017 / 14:04

2 answers

3

The implementation of the pack() function is much more robust compared to the chr() function.

It has various sanitizations and validations, among them, the RFC 4648 Encoding

A snippet of the pack () function routines where input values are filtered:

static void php_pack(zval *val, size_t size, int *map, char *output)
{
    size_t i;
    char *v;

    convert_to_long_ex(val);
    v = (char *) &Z_LVAL_P(val);

    for (i = 0; i < size; i++) {
        *output++ = v[map[i]];
    }
}

PHP-src: link

The functions like ord() and chr() , do not have much to comment. Just see how the simple implementation does not have filters as in the pack() function:

PHP_FUNCTION(ord)
{
    char   *str;
    size_t str_len;

    ZEND_PARSE_PARAMETERS_START(1, 1)
        Z_PARAM_STRING(str, str_len)
    ZEND_PARSE_PARAMETERS_END();

    RETURN_LONG((unsigned char) str[0]);
}
/* }}} */


PHP_FUNCTION(chr)
{
    zend_long c;

    if (ZEND_NUM_ARGS() != 1) {
        WRONG_PARAM_COUNT;
    }

    ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_QUIET, 1, 1)
        Z_PARAM_LONG(c)
    ZEND_PARSE_PARAMETERS_END_EX(c = 0);

    c &= 0xff;
    if (CG(one_char_string)[c]) {
        ZVAL_INTERNED_STR(return_value, CG(one_char_string)[c]);
    } else {
        ZVAL_NEW_STR(return_value, zend_string_alloc(1, 0));
        Z_STRVAL_P(return_value)[0] = (char)c;
        Z_STRVAL_P(return_value)[1] = '
static void php_pack(zval *val, size_t size, int *map, char *output)
{
    size_t i;
    char *v;

    convert_to_long_ex(val);
    v = (char *) &Z_LVAL_P(val);

    for (i = 0; i < size; i++) {
        *output++ = v[map[i]];
    }
}
'; } }

PHP-src: link

This is simple because of performance issues because you do not always need to filter. The filters are most suitable for use with encryption, security, etc.

Table look-ups

  

Even based on the code comment I assume that the problem is   that chr () uses some kind of "array" (this would be the lookup table   internally?)

Yes, this is how most programming languages use in their string manipulation functions.

The method by table look-ups has known exploits and are very exploited by attacks. One solution proposition is to use logical operations of "constant-time" sequences (RFC 4648) or at least references other than secret data (secret data). This issue is currently under open discussion, without a concrete definition.

    
19.02.2017 / 16:29
2

When it comes to encryption there are several things to keep in mind.

The use of pack() instead of char() refers to a concept called binary safe making both input and output consistent in terms of string manipulation for example.

And as I said earlier in one of the answers that you have researched, depending on how the encryption is done and the algorithm there is the possibility of identifying the mode and perhaps functions used to encrypt through behavior and exploit an existing vulnerability.

    
19.02.2017 / 15:47