Thanks retep. I was thinking the same thing: Instead of a random delay, you could profile the algorithms to estimate the longest time and add a delay up until this time each time the algorithms are run. An additional random delay would be good also. As for the power problem, wouldn't it be best to focus on the hardware to mask this? With the algorithms there may be detectable power variations for the actual different operations computed right?
It depends on who the attacker is. If you assume they have access to your computer, as is the case with a virus, you're job is a lot easier and hardware or software solutions to keep the power draw constant are fine. However, if you are trying to defeat an attacker who has the actual device, then a hardware solution is trivial to attack by just taking the device apart. At that point though, there are a *lot* of possible attacks which this design can't prevent anyway.
I'd argue for fixing the problem in software first, and then once you've done that, determine if a cheap hardware fix is possible too. Having said that, a USB powered device with this fix is pretty easy to make as USB provides +5V and most uC's will run on 3.3V. If one of the easy-to-use FTDI FT-X chips is used for the uC<->USB communication we have no issue as well, as those chips have 3.3V-tolerant IO. The only issue left is the LCD screen, most of them run off of 5V. Still, simple level translation isn't hard and won't add much cost.
BTW, for the non-electrical engineers out there, this is how the zener-regulator works, and why it makes the current constant:
Vs represents the 5V supplied by the computer over USB, and R2 representing your uC. DZ is the zener. In operation, the effective value of R2 changes as the uC draws different amounts of current. At what extreme, R2 might be nearly infinite if the uC is in sleep mode, at the other extreme, the most current the uC can draw will look like an R2 of a few dozen ohms. What we want is for the current being drawn out of Vs to be fixed, regardless of the value of R2.
The zener diode has a property called breakdown where if the voltage applied to it in the reverse direction increases over a certain threshhold, it starts conducting current exponentially. Suppose we pick a 3.3V zener, and R2 is an open circuit. (the uC is off) If the zener is not conducting any current, the voltage across it will rise, and as the voltage reaches 3.3V, it will start conducting current again. This means we can pick the value of R1 assuming a given amount of current flows through it. Lets assume 30mA: R1=(Vs-Vz)/I=(5V-3.3V)/30mA=73Ohms. Now the zener is happily allowing 30mA of current to flow through it, which causes 30mA of current to flow through R1, and there is a voltage drop across R1 of 2.2V, just enough that 3.3V is across the zener.
Now lets suppose the uC starts doing a cryptographic operation. It's now consuming 20mA of current computing a bitcoin transaction. If the zener continues to draw 30mA of current, the total would be 50mA, and the voltage drop across R1 would be (20mA+50mA)*73Ohms=3.65V. However, 5V-3.65V=1.35Volts, way less than the 3.3V breakdown of the zener. Instead what happens is as the uC draws more current, the zener draws less, so the total current between the two stays the same. Now we have the zener drawing 10mA and the uC drawing 20mA.
An external observer, such as a wallet-stealing virus that can ask the computer for how much power the USB port is drawing, now has no idea how much power the uC is drawing no matter what it's doing. The disadvantage of course being that the power consumed is constant, even when the wallet isn't doing anything. Still, 150mW isn't a lot of power.
Of course, the above example is a bit hand-wavey, what actually happens is more subtle. A zener's current-to-voltage relationship is actually an exponential relationship, in the form I=k(V-Vth)^n with k and n being device-specific coefficients. Effectively, the total current drawn is *not* actually constant, it's just that the change in current draw is small.
Lets assume that the computer we're using has the ability to measure the current draw on an individual USB port with a precision (
not accuracy!) of 0.1%, and the range of that measurement is one standard USB load, 100mA. 100mA * 0.1%=0.1mA, so if we keep our *change* in current draw to less than half of that, we can guarantee that there will be no detectable change in the current measured. We'll assume that uC draws 25mA fully on, or a change in uC current from off to on of 25mA. In the small signal model a zener looks like a resistor, so our circuit is now:
R1 is the 73Ohms we calculated earlier, and Rz is the impedance of the zener. (also known as the zener differential resistance) Our load now looks like a current source, and the input voltage disappears. What we want is for IR1 to be less than 0.05mA for I=25mA. So, I=IR1+IRz -> I=IR1+V/Rz Now what's V? Simply I*(R1*Rz)/(R1+Rz), so I=IR1+I(R1*Rz)/((R1+Rz)Rz) -> Rz=I*R1/(I-IR1) - R1=0.146Ohms
See, that's the catch, seemingly OK zeners can't meet this spec. For instance all of the BZX84 series zeners have maximum impedance of greater than 10Ohms, even if they look OK otherwise. Unfortunately, it looks like zeners that meet our requirements don't actually exist; the minimum zener impedance on digikey for a 3.3V zener is 3Ohms, and that spec only applies if you are drawing 380mA.
So lets go back to a software/hardware solution. Suppose we can get the change in current down to 0.25mA by clever software that carefully uses the same amount of power no matter what the cryptographic engine is doing. The above equation now gives us 18Ohms at the maximum, and as it turns out the $0.20 225mW MMBZ5226BLT1G is almost suitable at 28Ohms. (measured at 20mA) Solving for IR1 we get 0.18mA maximum, IE, this is the maximum change in current allowed before the host could detect it. So go work on the software some more!
Now what happens if the zener fails? Specifically, suppose the zener's impedance rises, such that the change in current through R1 increases. The only way we would know is if the voltage across R1 increases, so basically the uC now has to monitor the change in it's own voltage supply as it begins a cryptographic operation. That change would be equal to V=I(R1*Rz)/(R1+Rz)=3.4mV, tiny! Fortunately 10bit ADC's are quite common, so 3.3V/1024=3.22mV - we probably can't detect a subtle failure, but anything major is detectable. Such a design doesn't even have to be all that expensive if you use the other side of the R1 resistor as your Vref, which is OK because we only care about the difference between the too. Total implementation would be 4 0.1% resistors, $0.20 in volume.
Ugly 'eh? What looked so simple, just isn't. I gotta admit, I wasn't expecting a combined hardware/software implementation to be mandatory myself.