Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Use bit operations for constant-flow padding check
The previous code used comparison operators >= and == that are quite likely to be compiled to branches by some compilers on some architectures (with some optimisation levels). For example, take the following function: void old_update( size_t data_len, size_t *padlen ) { *padlen *= ( data_len >= *padlen + 1 ); } With Clang 3.8, let's compile it for the Arm v6-M architecture: % clang --target=arm-none-eabi -march=armv6-m -Os foo.c -S -o - | sed -n '/^old_update:$/,/\.size/p' old_update: .fnstart @ BB#0: .save {r4, lr} push {r4, lr} ldr r2, [r1] adds r4, r2, #1 movs r3, #0 cmp r4, r0 bls .LBB0_2 @ BB#1: mov r2, r3 .LBB0_2: str r2, [r1] pop {r4, pc} .Lfunc_end0: .size old_update, .Lfunc_end0-old_update We can see an unbalanced secret-dependant branch, resulting in a total execution time depends on the value of the secret (here padlen) in a straightforward way. The new version, based on bit operations, doesn't have this issue: new_update: .fnstart @ BB#0: ldr r2, [r1] subs r0, r0, #1 subs r0, r0, r2 asrs r0, r0, Mbed-TLS#31 bics r2, r0 str r2, [r1] bx lr .Lfunc_end1: .size new_update, .Lfunc_end1-new_update (As a bonus, it's smaller and uses less stack.) While there's no formal guarantee that the version based on bit operations in C won't be translated using branches by the compiler, experiments tend to show that's the case [1], and it is commonly accepted knowledge in the practical crypto community that if we want to sick to C, bit operations are the safest bet [2]. [1] https://github.com/mpg/ct/blob/master/results [2] https://github.com/veorq/cryptocoding Signed-off-by: Manuel Pégourié-Gonnard <[email protected]>
- Loading branch information