 Hello, I'm Raity. In this video, I'll be presenting my paper, Cash vs. Key Dependency. I've worked on this with Daniel Ganking, Romain Poesier, Yuval Yaroam, and Yuan Jingzhao. Cyphers can be vulnerable against cash attacks. We recover secret information if we know the internal structure of the cypher, and if we know the victim's cash access. In the paper, we show that secret key-dependent transformations do not guarantee additional protection against cash attacks. We'll be looking at the encryption algorithm Poesang, which is part of the North Korean Red Star OS 3.0. It was leaked a few years ago, and CryptosLogic has reverse engineered its code. It's what we've used to test our tech on. Poesang is based on the AES cypher, with the main differences of having key-dependent S-boxes and key-dependent shift role permutations. With AES, secret information can be recovered with cash attacks, and also because we know the internal structure of AES. In the paper, we find that secret transformations do not make Poesang more secure against cash attacks that are used for AES. So for the remainder of this video, I would first like to start off with a refresher on AES, then introduce a cash attack that we can use for AES, and then go into how that can be adapted for Poesang. AES is a cypher that encrypts messages over a number of rounds of transformation. In this slide, we will just look at one of those rounds. We start off with our initial state, S0, with the message that we want to encrypt, also known as the plaintext P. I represent to the AES state here as a four-by-four matrix, with each element representing a byte of information. We XOR the plaintext with the first round key. The round keys are generated from a master key that is expended to a number of round keys. After the add round key stage, each byte is substituted by looking at a lookup table or a substitution box. We then apply the shift row operation to the state. Looking at the colors here, we can see that the shift row cyclically shifts each row by some amount. We then apply mixed columns. Mixed columns essentially replaces each byte with a function of itself and the other bytes in the column. This is the last transformation of this round. The output of mixed columns is then used as the input for the next round, and this repeats for a number of times for AES to encrypt the message. Let's look at attacking AES. We have our input the plaintext, and then we XOR of the key. This is used to index the lookup table or the substitution box. From now on, I'll be referring to a SS box, and here I've represented a SSB, and it is indexed with the previous state plaintext XOR key. Thing to note here is that because the index is equal to plaintext XOR key, we can say that the key is equal to the index XOR P plaintext. If we know the plaintext and if we can somehow get the index, we can get the key. We can get the index by using cache attacks. We obtain S box accesses by observing memory accesses to the cache. We use prime and probe, which uses timing information to infer victim's cache accesses over a period of time. Let's look at this in practice. We have our initial state, the plaintext. Now say if we perform multiple encryptions with different plaintexts, but here we fix one of the plaintext byte. Then we perform the add ground key stage and we notice that across the encryption, that byte's value is too fixed, but to a different value this time, plaintext XOR key. Note that that fixes the S box access. We can observe this S box access in memory and since we know the plaintext and now we have the index, we can get the key. In reality, cache attacks on AES isn't as simple as that. There are some practical challenges that we will first have to address. One of this is the limited temporal resolution. With prime and probe, we sample the cache at regular intervals. That means that there are many accesses that happen between samples, some of which we don't care about and that creates noise. To help illustrate this, I've come out with a representation of the cache. Each region represents a cache line and the dark regions represent that cache line has been accessed. With this first one, we perform prime and probe over an encryption and we fix one of the plaintexts so we expect that one of these regions represent the S box access. Now we perform prime and probe over an encryption again and we notice a different cache access patterns. We do this over a number of times. What we can do is average over these results. What we will see is there is one region that is the darkest. That means that that cache line has been consistently accessed over the different encryption. Because we know that when we fix that one plaintext byte, it will fix the S box access in the first round. That dark region should correspond with the first round S box access. We found the index and also got the plaintext and we have the key. There is another challenge that we have to resolve that is limited spatial resolution. We can't distinguish between accesses to the same cache line. For AES, we have multiple S box entries that are present in the same cache line. With the 256 S box, in this case, they are mapped to four different cache lines with each cache line storing 64 of the S box entries. That means that we can only see the S box accesses to the resolution of the cache line. So if the first cache line was accessed, we know that one of the first 64 entries were accessed but we don't know which one. Same goes for the next one. That means if we perform the attack as we have just before, we can only recover partial information about the key. Here we can only recover two to four bits of each key byte. So the solution is to perform the attack in two rounds. The first round being what we've just seen and the second round is to look at more S box accesses in the second round to get more information and recover the remaining bits of each key byte. Let's look at the cache attack on AES in more detail. Here we have the first round attack and we fix the S box access for this byte which we observe in memory. When we perform the different encryptions, we also perform prime and probe to observe the cache accesses during the encryption and we see that there is one cache line that is consistently accessed throughout the encryption and that represents the S box access. We know that that's one part of the S box. Now we've got some information on the index and we've got the plain text so we can recover only some information of key in this case two to four bits. Now we have to perform another part to the attack to recover the remaining bits. For this next part we will be looking at the second round S box accesses. Note that for the first round we fix the first byte so that we fix the first round S box access. So for the second round we need to fix the second round S box accesses. The problem with that is that the input to the second round is the output of the first round and we will see how we can fix the output to the first round in the next slide. The second round attack we have the plain text again now we have different encryptions and this time we fix four bytes and we fix the four bytes across the diagonal of the matrix. We perform air ground key and sub bytes and shift rows and what we note is that the fixed bytes are mapped to the same column this time. Now when we perform mixed columns those bytes in the column will be fixed across the encryption. So we have four state bytes fixed at the end of the first round and we use that as the input to the next round and when we perform air ground key we find that those S box accesses are fixed as well. The idea for the second round attack is to fix four plain text bytes that map to the same column after shift rows. We need to know the transformation to know which four plain text bytes to fix so that they will map to the same column after shift rows. Luckily for AES we know the shift row transformation so we know which plain text bytes to fix but for Pilsang the shift row permutation is key dependent so this attack will be a little bit more tricky. So that's a brief description of the cache attack on AES. Now let's look at how that can be adapted for Pilsang. Let's first look at how Pilsang differs from AES. Pilsang is based on AES with key dependent transformations. Pilsang has a slightly different key schedule. The master key is passed through a shower and base function to generate K. Pilsang uses the AES key schedule with K to generate 11 round keys. Pilsang S boxes is slightly different as well. There are different S boxes that are used for each state byte at each round. So at each round there will be 16 different S boxes and the S boxes depend on the corresponding key byte of the next round. Here is a visualization of the S box accesses for AES in one of the rounds. We have the state XOR of the key and during sub bytes they all access the same S box. Now with Pilsang we see that each byte accesses a different S box. Pilsang also has a different shift row. Pilsang shift row uses a pseudo random permutation. The permutations depend on the key of the next round and from there it generates some permutation to shuffle the state. Here we have a representation of the AES shift rows. AES shift rows simply shifts each row by some amount. With Pilsang we get the next round key to generate a pseudo random permutation to shuffle the state around. Now let's look at the first round attack on Pilsang. It is exactly like we would do it for AES. For Pilsang we get the two most significant bits of each key byte and we use the cache access patterns to infer S box access indices and from here we can reduce the search space for the second round attack. In this slide we'll look at some experimental results for the first round attack. Here we have the heat map that represents the cache accesses when the byte is fixed. On the x-axis is the cache set. On the y-axis is the plain text value that the byte has been fixed to. The darker the regions represent that the cache set has been accessed. Here's a visual representation of the byte's S box. The byte, the S box is mapped contiguously across the cache set. So the first 64 goes to the leftmost cache set and the next 64 goes to the second left and so on. Now if we look at the first 64 S box entries they're accessed when the byte's plain the byte's plain text are set to 64 to 127. Now if we just look at the two most significant bits the S box entries two more significant bits are 0 0 and the byte plain text two more significant bits are 0 1. We can use set to get k with plain text x or index and we find that the key bytes two more significant bits are 0 1. Now when we look at the other region of the S box where the entries are 64 to 127 that occurs when the plain text is set to 0 to 63. Again we step through the same process we find that the key bytes two more significant bits are 0 1. We can do the same for the other regions and we find that the results are consistent. Now before moving on to the second round attack we call that the second round attack requires us to fix four bytes that map to the same column after shift rows. But because shift rows in Poosung is key dependent we don't know the permutation. So we will have to reverse shift rows. There are two steps to reversing shift row. One is to do a column mapping. We by observing cache accesses we can find the group of four bytes that map to the same column in shift row. We can also identify which column the group maps to. Here we see an example of a possible shift row permutation and we find that these four bytes map to those columns. Mix we can find column ordering. After finding the bytes that map to the same column we can find which row each byte goes to. So for example with the first column after finding the row each byte goes to we would have found where the byte maps to after shift row and we can do so for the remaining columns and we have completely reversed shift rows. Looking at the column mapping in more detail the idea here is to fix four bytes and then check if they map to the same column after shift rows. If they do then we have found the correct four bytes. An example here where we take multiple encryptions and we fix these four bytes and we find that after shift rows they don't map to the same column. So after mix columns across all the encryptions we won't see any fixed bytes. We can do the same again fixing four other bytes and they map to the same column after shift rows and when we when we apply mix columns those values will be fixed. We can observe this because fixing four bytes that map to the same column in shift row will fix the sbox accesses at the second round. Let's look at an experimental result for the wrong guess. Here is the normalized probe time and the x-axis is the cache set. The peaks represent that that cache set has been accessed. With the wrong guess we see four peaks. These four peaks represent the first round sbox accesses to the four fixed plain text bytes and there's nothing more to see here. Now let's look at the correct guess. We have fixed the columns after mix columns and that propagates to fixing the second round sbox accesses. When we look at the normalized probe time here we see eight different peaks. These four peaks are the first round sbox accesses of the four fixed plain text bytes. We know that because we have already performed the first round attack. The remaining four peaks are the second round sbox accesses and because we've performed the first round attack we know that this region of the cache set corresponds to the first column of bytes. Now we've done column mapping. We can look into column ordering. We have to understand mix columns a little bit more first. Mix columns is the matrix multiplication. Now let's focus just on one of those columns. Say we fix all the bytes except for one. That means that that column the elements of those columns can be expressed as the varying bytes value. So fixing three bytes in the column and varying the other results in a predictable behavior dependent on the varying byte. Where that byte is in the column will result in a different set of equations that represents the elements in the column and we observe that by looking at the cache access patterns. So by looking at the second round sbox accesses we can determine which equations they are and therefore determine the location of that byte in the column. Let's look at an experimental result of this. We have fixed these four bytes and varied the first byte. After shift row we are not sure where that varying byte is in the column but we observe the second round sbox accesses. Here with the cache sheet map we know where the first round sboxes are and we don't care about that. This region is the second round sbox accesses. We see that for the different plain text value of that varying byte we have a different second round sbox access patterns. This is different because of the because of the varying byte. Now we can look at this in more detail in this region. This region shows the four second round sbox accesses. What we need to know here is that by fixing three of the bytes and varying the other there will always be two second round sbox accesses that are identical up to xor with a constant. Identifying them will give us the role of the varying plain text byte. So for example with this one accesses in the first and second sboxes are identical up to xor with constant one zero. So when we look at plain text zero the two most significant bits of the first sbox is one one and the two most significant bits of the second sbox is zero one. When we xor them we get one zero and we can do that for the other plain text values and we'll find that they are all identical up to xor with constant one zero. And because they are the first and second sboxes we know that the varying byte is in the last row of column. So so far we've performed the first round attack and we've gotten two more significant bits of the first round key. We've prepared the second round attack by reversing the first round of the key dependent transformation shift rows. Now let's look at performing the second round attack. Here I've got the visual representation of the shift rows of the first round. We found that the byte is in the last row of the column. Note that for that byte the second round sbox access can be expressed as the following expression. We have sp1 representing the second round sbox access and sp0 is the first round sbox access. What we need to note here is that the index to the second round sbox we can observe this in the cache. Now if we can calculate this purple region we can see that it will match what we observe in the cache up to a constant. But to calculate this we have to get the first round sbox value and that is dependent on the next round key rk1. We don't know rk1 but we can guess rk1 and then calculate what the first round sbox value would be. So now we can calculate this purple region. We guess rk0 and rk1 and then calculate this value. If we guess the correct key this will match what we observe in the cache up to a constant. So for the second round attack for each key byte we get six unknown bits of the first round key and eight bits of the second round key. There's a total of two to the 14 possible guesses to test for each key byte and on average observing sbox accesses for around 30 different plain text byte values for each key byte is sufficient. To summarize Pulsang's secret dependent transformation can be reversed by observing cache accesses. To fully break the cypher we perform around 35 million encryptions and around 19 and a half thousand queries of sbox accesses. On average it takes about eight minutes to run on a typical laptop and we show that constant time implementation is needed as a defense for side channel attacks.