Skip to content

Commit ad4d139

Browse files
committed
Make bin2hex() and hex2bin() timing safe
1 parent 668ecaa commit ad4d139

File tree

1 file changed

+18
-13
lines changed

1 file changed

+18
-13
lines changed

ext/standard/string.c

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,16 @@ void register_string_constants(INIT_FUNC_ARGS)
117117

118118
int php_tag_find(char *tag, size_t len, const char *set);
119119

120+
#ifdef PHP_WIN32
121+
# define SET_ALIGNED(alignment, decl) __declspec(align(alignment)) decl
122+
#elif HAVE_ATTRIBUTE_ALIGNED
123+
# define SET_ALIGNED(alignment, decl) decl __attribute__ ((__aligned__ (alignment)))
124+
#else
125+
# define SET_ALIGNED(alignment, decl) decl
126+
#endif
127+
120128
/* this is read-only, so it's ok */
121-
static char hexconvtab[] = "0123456789abcdef";
129+
SET_ALIGNED(16, static char hexconvtab[]) = "0123456789abcdef";
122130

123131
/* localeconv mutex */
124132
#ifdef ZTS
@@ -155,25 +163,22 @@ static zend_string *php_hex2bin(const unsigned char *old, const size_t oldlen)
155163

156164
for (i = j = 0; i < target_length; i++) {
157165
unsigned char c = old[j++];
166+
unsigned char l = c & ~0x20;
167+
int is_letter = ((unsigned int) ((l - 'A') ^ (l - 'F' - 1))) >> (8 * sizeof(unsigned int) - 1);
158168
unsigned char d;
159169

160-
if (c >= '0' && c <= '9') {
161-
d = (c - '0') << 4;
162-
} else if (c >= 'a' && c <= 'f') {
163-
d = (c - 'a' + 10) << 4;
164-
} else if (c >= 'A' && c <= 'F') {
165-
d = (c - 'A' + 10) << 4;
170+
/* basically (c >= '0' && c <= '9') || (l >= 'A' && l <= 'F') */
171+
if (EXPECTED((((c ^ '0') - 10) >> (8 * sizeof(unsigned int) - 1)) | is_letter)) {
172+
d = (l - 0x10 - 0x27 * is_letter) << 4;
166173
} else {
167174
zend_string_free(str);
168175
return NULL;
169176
}
170177
c = old[j++];
171-
if (c >= '0' && c <= '9') {
172-
d |= c - '0';
173-
} else if (c >= 'a' && c <= 'f') {
174-
d |= c - 'a' + 10;
175-
} else if (c >= 'A' && c <= 'F') {
176-
d |= c - 'A' + 10;
178+
l = c & ~0x20;
179+
is_letter = ((unsigned int) ((l - 'A') ^ (l - 'F' - 1))) >> (8 * sizeof(unsigned int) - 1);
180+
if (EXPECTED((((c ^ '0') - 10) >> (8 * sizeof(unsigned int) - 1)) | is_letter)) {
181+
d |= l - 0x10 - 0x27 * is_letter;
177182
} else {
178183
zend_string_free(str);
179184
return NULL;

0 commit comments

Comments
 (0)