Week 10
Lecture slides¶
- (Last week) intro to constant-time: pdf, key,
- Constant-time programming in C: pdf, key,
- Constant-time programming in FaCT: pdf, key,
Recommended reading¶
- FaCT: A Flexible, Constant-Time Programming Language by Cauligi et al.
- FaCT Language Reference
- Crypto coding rules is an excellent source for transforming C code to constant-time C code.
- Constant-Time Toolkit by Thomas Pornin
- On Subnormal Floating Point and Abnormal Timing by Andrysco, et al.
- Cache-timing attacks on AES by Daniel J. Bernstein
- (Last week) Why Constant-Time Crypto by Thomas Pornin
Code snippets¶
FaCT example¶
/* FaCT tutorial file for CSE 130 */ /* Basic stuff */ export // functions are not exposed to C without `export` keyword public int32 simple_fn() { // return value must be `public` or `secret` return 5; } export public int32 demo_fn( public int32 x, // arguments require a label secret mut uint32 y) { // y can be used as an output parameter since it is `mut` public int32 z = x + 5; // variables also need a label // the following line will cause an error, since z is not `mut` // z += 2; public mut int32 t = z; // this is ok, since t is mutable t += 22; secret mut uint32 w = 16; // error: cannot assign `secret` value to `public` variable // w + x is secret because w is secret // t = w + (uint32)x; // ok: y is secret so it can accept secret expressions y = w + (uint32)x; // this is an error: the return value is public but w is secret // return w; // ok: z is public return z; } export secret uint32 call_demo_fn( public int32 x) { secret mut uint32 output = 0; // has to be `mut` since we're passing it to be updated by `demo_fn` demo_fn(x, ref output); // `ref` keyword is necessary for mutable arguments return output; } export void fill_conditionally( public uint32[4] pattern, // fixed length buffer secret mut uint8[] buf, // buffer length won't be known until run time secret bool b) { // loop iterator must be declared in the for loop header for (uint32 i = 0; i < len buf; i += 1) { // runtime length of buf via `len` keyword // b is secret, so conditional will get transformed // into constant time code during compilation if (b) { // ok to update buf since it is mutable buf[i] = (uint8)pattern[i % 4]; // cast to uint8 so the types match } } } // no export because this is a helper function void twiddle_bytes( secret mut uint8[4] buf) { secret uint8 tmp = buf[0]; buf[0] = buf[2]; buf[2] = tmp; // can't reuse tmp because it was not declared `mut` // (although we could simply change it to be `mut`) secret uint8 tmp2 = buf[1]; buf[1] = buf[3]; buf[3] = tmp2; } void poorly_constructed_hash_fn( secret mut uint8[20] out, secret uint8[] in) { secret mut uint8[20] local = arrzeros(20); // local mutable array, initialized to all zeros for (uint32 i = 0; i < len in; i += 1) { local[i % len local] += in[i]; } for (uint32 i = 0; i < 20; i += 4) { // incrementing by 4s // create a "view" of `local` so that it matches with the signature of `twiddle_bytes` twiddle_bytes(ref arrview(local, i, 4)); // view of `local`, starting at index `i`, with a length of 4 } for (uint32 i = 0; i < 20; i += 1) { out[i] = local[i]; } } /* More "real" functions */ public int32 conditional_assign( secret mut uint8[] x, secret uint8[] y, secret bool assign) { // public branch if (len x != len y) { return -1; } // secret branch if (assign) { for (uint32 i = 0; i < len x; i += 1) { x[i] = y[i]; } } return 0; } // assuming lengths are public and are equal secret int32 safe_memcmp(secret uint8[] x, secret uint8[] y) { for (uint32 i = 0; i < len x; i += 1) { if (x[i] != y[i]) { return (int32)(x[i] - y[i]); } } return 0; }
Compiler-introduced branches¶
#include <stdint.h> #include <stdbool.h> #include <stdlib.h> void mpi_safe_cond_assign(uint8_t *X, const uint8_t *Y, unsigned char assign) { size_t i = 0; /* make sure assign is 0 or 1 */ assign = ( assign != 0 ); X[i] = X[i] * ( 1 - assign ) + Y[i] * assign; }
Compiled with clang 3.9.1 with -O2
, introduces a branch:
mpi_safe_cond_assign(unsigned char*, unsigned char const*, unsigned char): test dl, dl setne al je .LBB0_2 mov dl, byte ptr [rsi] .LBB0_2: or al, -2 inc al and al, byte ptr [rdi] add al, dl mov byte ptr [rdi], al ret