6

I have a question about attacks on the implementation of cryptographic code that are enabled by compilation and compiler-optimisations. I am aware of this. Would anyone be able to point me to other examples? In particular, are there examples of timing attacks that are enabled by compilation (in particular by compiler optimisations) that are not possible w.r.t. the semantics of the source language?

$\mathbf{Edit:}$ Let me illustrate what I mean by this in two ways.

First, sometimes the semantics of a programming language is given using a one-step reduction relation. In particular, the one-step reductions of equality might be specified like this.

  • For all values $x$: $x = x \rightarrow \mathtt{true}$.
  • For all values $x, y$ such that $x$ is not equal to $y$: $x = y \rightarrow \mathtt{false}$.

You can see the one step reductions as taking one unit of time, so in this model, all computations of equality take the same amount of time. But for complex data-structures like strings, lists or arrays, compilation would typically be to code that has data-dependent run-time (or power consumption or EM radiation or whatever is your favourite side-channel).

Second, I know that not all programming languages have nice, simple operational semantics like that. So another way of looking at the same problem is: if I compile a program twice, once with little/no optimisation turned on, and once with a high degree of compiler optimisation, would the latter open my executable vulnerable to attacks in ways that the former does not? I'm thinking in particular of the optimisations (tracing) JIT compilers do.

PS I don't have enough reputation to give more/better tags to my question. Please feel free to do so.

Martin Berger
  • 215
  • 2
  • 12
  • "that are not possible w.r.t. the semantics of the source language?" What do you mean by that? – CodesInChaos Jun 06 '12 at 17:29
  • Are there any mainstream programming languages whose semantics contains timing specifications? – Paŭlo Ebermann Jun 06 '12 at 20:05
  • @Martin: Are you also interested in side channel attacks (like DPA) on cryptographic algorithms implemented on smart cards or is your question restricted to PCs/servers? – j.p. Jun 07 '12 at 19:25
  • 1
    @PaŭloEbermann: Some algorithms in the C++ Standard Template Library must fulfill certain performance requirements like "amortized O(log(n))". You could call this a "timing specification" ;-). – j.p. Jun 07 '12 at 19:32
  • @CodeInChaos, I have added some explanations to my question. I hope it's clearer now. – Martin Berger Jun 07 '12 at 22:31
  • @PaŭloEbermann I'd say that most forms of semantics have a notion of atomic computational step (e.g. in the $\lambda$-calculus that would be $(\lambda x.M)V \rightarrow M{V/x}$). I interprete these atomic steps as taking one unit of time. – Martin Berger Jun 07 '12 at 22:33
  • @jug I'm interested in all those. – Martin Berger Jun 07 '12 at 22:38
  • 1
    That's a completely unrealistic model. Not even handcoded assembly conforms to that in the general case. Duration of memory access depends on CPU caches, different operations cost a different number of clocks, there are CPU specific rules like "After an addition you get a bitshift for free". On some CPUs even the cost of simple things like integer arithmetic is data dependent. – CodesInChaos Jun 07 '12 at 22:41
  • @CodeInChaos I know, but that's how a lot of programming languages are specified at a high level. A lot of program verification works with such simplifications. All models are unrealistic because the abstract from some detail. – Martin Berger Jun 07 '12 at 22:46
  • 1
    @MartinBerger: The critical parts of cryptographic algorithms on smart cards are always programmed in assembler, since you need to have full control. If the smart card has cache (luckily few have), you have to ensure for table accesses that you know what's in your cache. Out of order execution is not yet implemented in CPUs on smart cards, but many have a pipeline, which can cause trouble. Small optimizations of the CPU (like shrinking) can make an implementation insecure that was secure before. – j.p. Jun 08 '12 at 07:51
  • @jug. Thank you very much. I didn't know that smard-cards are typically hand-coded in assembler. I'm specifically interested in security vulnerabilities introduced by compilers. There must be some, given how complicated modern compilers are. BTW what do you mean by "Small optimizations of the CPU"? Do you mean optimisations the programmer introduces, or changes in the CPU? – Martin Berger Jun 08 '12 at 13:49
  • 1
    @MartinBerger: Changes in the CPU (the programmers [should] know about the risk). Especially how the RAM is connected to the CPU is critical. Similar, even SW-compatible smart cards can have quite different DPA-behavior running identical code. – j.p. Jun 08 '12 at 14:00

2 Answers2

2

Not something I have a real life example of, just an idea.

Certain computationally intensive tasks can be done much faster using memoization. Now if the compiler manages to automatically use memoization for some piece of code that code might run much faster than what the language notation suggests. I'm not aware of any compiler actually doing this though.

In C++, for example, any optimization is allowed as long as observable behavior is preserved which includes accesses to volatile memory and calls to I/O library functions. The compiler is allowed to transform the program in any way otherwise.

SEJPM
  • 45,967
  • 7
  • 99
  • 205
sharptooth
  • 399
  • 2
  • 9
  • One could argue that lazy functional languages like Haskell do something like this. Maybe also Umut Acar's languages for self-adjusting computation? – Martin Berger Jun 13 '12 at 13:26
0

A paper JIT Leaks: Inducing Timing Side Channels through Just-In-Time Compilation that just appeared does investigate this phenomenon in more details.

Martin Berger
  • 215
  • 2
  • 12