In the last segment in this module, I wanna show you a general attack that affects many implementations of Mac algorithms. And there's a nice lesson to be learned from an attack like this. So let's look at a particular implementation of HMAC verification. This happens to be an implementation from the Keyczar library, that happens to be written in Python. So here's the code that's used to verify a tag generated by HMAC. This code is actually simplified. I just wanted to kinda simplify it as much as I can to get the point across. So basically, what the inputs are, the key, the message, and the tag bytes. The way we verify it is, we re-compute the HMAC on the message and then we compare say the resulting sixteen bytes. To the actual given signature bites. So this looks perfectly fine. In fact, anyone might implement it like this. And, in fact, many people have implemented it like this. The problem is, that if you look at how the comparison is done, the comparison, as you might expect, is done byte by byte. There's a loop inside of the Python interpreter that loops over all sixteen bytes. And it so happens that the first time it finds an inequality, the loop terminates and says the strings are not equal. And the fact that the comparator exits when the first inequality is found introduces a significant timing attack on this library. So let me show you how one might attack it. So imagine you're the attacker, and you have the message m, for which you want to obtain a valid tag. Now, your goal is to attack a server that has an HMAC secret key stored in it. And the server exposes an interface that basically takes message MAC pairs. Checks that the MAC is valid, if the MAC is valid it does something with the message. And if the MAC is not valid, it says reject. Okay, so it's back to the originator or the message rejects. So now this attacker has an opportunity to basically submit lots of message it appears and see if it can deduce the tags of the particular message for which it once attacked. Here's how we might use the broken implementation from the previous slide to do just that. So what the attacker is gonna do is to submit many message tag queries, where the message is always the same. But with a tag, he's gonna experiment with lots and lots and lots of different tags. So in the first query, what he's gonna do is just submit a random tag along with the target message. And he's gonna measure how long the server took to respond. The next query that he's gonna submit, is he's gonna try all possible first bytes for the tags. Let me explain what I mean by that. So the remaining bytes of the tags that he submits are just arbitrary, doesn't really matter what they are. But for the first bite, what he'll do is he'll submit a tag starting with a byte zero. And then he's gonna see whether the server took a little bit longer to verify the tag than before. If the server took exactly the same amount of time to verify the tag as in step one, then he's gonna try again, this time with bytes at one. If still the server responded very quickly, he's going to try with byte sets of two. If the server responded quickly then he's going to try with byte sets of three, and so on until finally, let's say, when the byte sets of three the server takes a little bit longer to respond. What that means is actually when it did the comparison between the correct MAC and the MAC submitted by the attacker. The two matched on this byte, and the rejection happened on the second bytes. Aha. So now the attacker knows that the first bite of the tag is set to three and now he can mount exactly the same attack on the second bite. So here. It's going to submit the tag. And the second, back here. Here This should go here. So it's gonna submit a tag when the second byte is set to zero. And it's gonna measure whether this took a little bit longer than in step two. If not, he's gonna change this to be set to one, and he's gonna measure if the server's response time is a little longer than before. Eventually, let's say when he sets this to, I don't know. When the byte is set to, to 53, say, all of a sudden, the server takes a little bit longer to respond. Which means that now, the comparator matched on the first two bytes. And now the attacker learned that the first two bytes of the Mac are three and 53. And now he can move on and do the exact same thing on the third byte and then on the fourth byte and so on and so forth. Until finally, the server says, yes, I accept. You actually gave me the right Mac. And then we'll go ahead and act on this bogus message. That, attack our supply. So this is a beautiful example of how a timing attack can reveal the value of a MAC, the correct value of the MAC. Kind of byte by byte, until eventually, the attacker obtains all the correct bytes of the tag, and then he's able to fool the server into accepting this message tag pair. The reason I like this example is this is a perfectly reasonable way of implementing a MAC verification routine. And yet, if you right it this way, it will be completely broken. So what do we do? So let me show you two defenses, the first defense, I'll write it in again in python is, is as follows. In fact the Keyczar library exactly implemented this defense. This code is actually taken out of the updated version of the library. The first thing we do is we test if the signature bytes submitted by the attacker are of the correct length, say for HMAC this would be say, you know 96 bits or 128 bits, and if not we reject that as an invalid MAC. But now, if the signature bytes really do have the correct length, what we do is implement our own comparator. And it always takes the same amount of time to compare the two strings. So in particular, this uses the zip function in Python, which will, essentially, if you are giving it two sixteen byte strings. It will create sixteen pairs. Of bytes. So it'll just create a, a list of sixteen elements, where each element is a pair of bytes. One taken from the left and one taken from the right. And then you loop, you know, you loop through this list of pairs. You compute the XOR of the first pair, and the OR into the result. Then you compute the XOR of the second pair, and you OR that into the result. And you note that, if at any point in this loop, two bytes happen to be not equal, then the XOR will evaluate to something that's non zero. And therefore, when we OR'ed it into the result. The result will also be counting on zero, and then we'll return false, at the end of the comparison. So the point here is that now the comparator always takes the same amount of time. Even if it finds difference in byte number three, it will continue running down the both strings until the very end. And only then will it return the results. So now the timing attack supposedly is impossible. However, this can be quite problematic, because compilers tried to be too helpful here. So an optimized compiler might look at this code and say, hey, wait a minute. I can actually improve this code by making the four loop end. As soon as an incompatible set of bytes is discovered. And so, an optimizing compiler could be your, kind of, Achilles heel when it comes to making programs always take the same amount of time. And so a different defense, which is not as widely implemented, is to try and hide from the adversary, what strings are actually being compared. So let me show you what I mean by that. So again, here we have our verification algorithm. So it takes as inputs, a key, a message, and a candidate's MAC from the adversary. And then, the way we do the comparison is we first of all, compute the correct MAC on the message. But then instead of directly comparing the MAC and the signature bytes adversary, what we're gonna do is we're gonna hash one more time. So we compute a hash here of the MAC. We compute a hash of the signature bytes. Of course, if these two happen to be the same, then the resulting HMACs will also be the same, so the comparison will actually succeed. But the point is now, if sig bytes happen to equal MAC on the first byte, but not on the remaining bytes. Then, when we do this additional hash layer, it's likely that the two resulting values are completely different. And as a result, the byte by byte comparator will just output on the first iteration. The point here is that the adversary doesn't actually know what strings are being compared. And as a result, he can't mount a timing attack that we discussed earlier. Okay, so this is another defense. At least now, you're not at the mercy of an optimizing compiler. The main lesson from all of this is that you realize that people who even are experts at implementing cryptolibraries, get this stuff wrong. And the right code that words perfectly fine and yet is completely vulnerable to a timing attack that completely undo all security of the system. So the lesson here is of course you should not be inventing your own crypto but you shouldn't even be implementing your own crypto because most likely it'll be vulnerable to the side channel attacks. Just use a standard library like OpenSSL. Keyczar is actually a fine library to use that would reduce the chances that you're vulnerable to these types of attacks.