Logo
Overview

ARIA Correlation Power Analysis

May 20, 2024
8 min read

This post is not an introduction to the ARIA block cipher itself. I assume the reader already knows the ARIA round structure, substitution layers, diffusion layer, and key schedule.

The goal here is narrower: given power traces, known plaintexts, and known ciphertexts from an unprotected ARIA-128 implementation, recover two encryption round keys with Correlation Power Analysis (CPA), then combine them through the key schedule to recover the master key.

References:

1. Attack Model

I assume the following setting.

  1. The implementation uses a fixed 128-bit ARIA key.
  2. The plaintext and ciphertext for each encryption trace are known.
  3. The traces are roughly aligned.
  4. The implementation is not masked or otherwise protected against first-order CPA.

For ARIA-128, recovering only the first encryption round key is not enough. The first round key ek1 is not the master key. ARIA derives encryption round keys from internal 128-bit words W0,W1,W2,W3W_0, W_1, W_2, W_3, so I need enough round-key material to cancel the unknown schedule word and isolate W0W_0.

The attack flow is:

  1. Use plaintext-side CPA to recover ek1.
  2. Use ciphertext-side CPA to recover ek13.
  3. Combine ek1 and ek13 using the ARIA-128 key schedule.
  4. Test the remaining master-key candidates against known plaintext/ciphertext pairs.

For ARIA-128, W0W_0 is the left half of the cipher key material. Because the key is exactly 128 bits, W0W_0 is the master key.

2. Trace Parsing and Alignment

The trace file starts with a small header. The first 32-bit value is the trace length.

ARIA trace header containing the trace length

The next 32-bit value is the number of traces. In this dataset the trace length is 24000, and the trace count is 5000.

ARIA trace header containing the trace count

The sample values are stored as float32. The parser reads the header first, then reads TraceLength * TraceNum floating-point samples.

Trace parser for the ARIA power trace file

Plotting a single trace gives a quick SPA sanity check. The repeated activity is visible, and there are 12 major round-like regions. That matches ARIA-128, which has 12 rounds. ARIA-192 and ARIA-256 would have 14 and 16 rounds.

Single ARIA power trace with repeated round activity

Before running CPA, I also overlay several traces in the same window. Point-wise correlation assumes that the same operation occurs at the same sample index across traces. If the traces are misaligned, the correct key guess can lose its peak.

Several ARIA traces overlaid in the same time window

The traces are aligned well enough for a first CPA pass.

3. First-Round CPA Target

ARIA uses two substitution-layer types. For the first round of encryption, the relevant pattern is type 1:

S1, S2, S11, S21, S1, S2, S11, S21, S1, S2, S11, S21, S1, S2, S11, S21S_1,\ S_2,\ S_1^{-1},\ S_2^{-1},\ S_1,\ S_2,\ S_1^{-1},\ S_2^{-1},\ S_1,\ S_2,\ S_1^{-1},\ S_2^{-1},\ S_1,\ S_2,\ S_1^{-1},\ S_2^{-1}

ARIA substitution layer types

The first useful CPA target is the substitution output after XORing the plaintext state with ek1.

First-round ARIA CPA target for ek1

For byte position bb, trace ii, and key-byte guess kk, the intermediate value is:

Yi(b)(k)=Sb(Pi(b)k)Y_i^{(b)}(k) = S_b(P_i^{(b)} \oplus k)

where SbS_b is selected by the ARIA byte position:

Sb={S1b0(mod4)S2b1(mod4)S11b2(mod4)S21b3(mod4)S_b = \begin{cases} S_1 & b \equiv 0 \pmod 4 \\ S_2 & b \equiv 1 \pmod 4 \\ S_1^{-1} & b \equiv 2 \pmod 4 \\ S_2^{-1} & b \equiv 3 \pmod 4 \end{cases}

Then I use a Hamming-weight leakage model:

Hi(b)(k)=HW(Yi(b)(k))H_i^{(b)}(k) = \operatorname{HW}(Y_i^{(b)}(k))

The ARIA implementation already has the four byte S-box tables, so the CPA code can index them directly.

ARIA S-box tables used for the CPA model

The core leakage model is the same shape as the AES CPA attack:

for (int byte_pos = 0; byte_pos < 16; byte_pos++) {
for (int key = 0; key < 256; key++) {
for (int trace_idx = 0; trace_idx < trace_count; trace_idx++) {
uint8_t iv = S[byte_pos % 4][PT[trace_idx][byte_pos] ^ key];
predicted_hw[trace_idx] = hamming_weight(iv);
}
correlate_against_trace_window(byte_pos, key, predicted_hw, traces);
}
}

Hamming-weight calculation in the CPA implementation

For each byte position, the correct key guess has the strongest absolute Pearson correlation peak:

kb=argmaxkmaxtρk,t(b)k_b = \arg\max_k \max_t |\rho_{k,t}^{(b)}|

The recovered first round key is:

ek1 = CB F6 D7 4C 0B 78 B9 30 22 B4 7E AA 06 E7 01 2A

Recovered ARIA ek1 bytes

The correlation trace also lands in the expected early-round region.

Correlation trace for ARIA ek1

At this point the CPA itself is working, but ek1 is only a round key. Recovering the ARIA-128 master key requires one more round key.

4. Key-Schedule Relation

ARIA key expansion has two stages:

  1. Generate the internal 128-bit words W0,W1,W2,W3W_0, W_1, W_2, W_3.
  2. Generate encryption and decryption round keys from those words with XOR and cyclic rotations.

For ARIA-128:

W0=KLW_0 = KL

and KLKL is the 128-bit master key.

ARIA key-schedule initialization equations

The round keys that use W0W_0 and W1W_1 are especially useful here. Using the rotation convention from the implementation:

ek1=W0rotr128(W1,19)ek13=W0rotr128(W1,97)\begin{aligned} ek1 &= W_0 \oplus \operatorname{rotr}_{128}(W_1, 19) \\ ek13 &= W_0 \oplus \operatorname{rotr}_{128}(W_1, 97) \end{aligned}

Equivalently, rotr128(W1,97)\operatorname{rotr}_{128}(W_1, 97) is rotl128(W1,31)\operatorname{rotl}_{128}(W_1, 31).

If I rotate ek1 left by 50 bits, the W1W_1 term lines up with the W1W_1 term in ek13:

rotl128(ek1,50)=rotl128(W0,50)rotr128(W1,97)\operatorname{rotl}_{128}(ek1, 50) = \operatorname{rotl}_{128}(W_0, 50) \oplus \operatorname{rotr}_{128}(W_1, 97)

XORing that with ek13 cancels W1W_1:

T=rotl128(ek1,50)ek13=rotl128(W0,50)W0T = \operatorname{rotl}_{128}(ek1, 50) \oplus ek13 = \operatorname{rotl}_{128}(W_0, 50) \oplus W_0

So after recovering ek13, the problem becomes solving:

T=W0rotl128(W0,50)T = W_0 \oplus \operatorname{rotl}_{128}(W_0, 50)

for W0W_0.

The implementation uses a byte rotation helper for the ARIA key schedule.

ARIA key-schedule rotation helper

5. Ciphertext-Side CPA for ek13

ARIA-128 uses 13 encryption round keys. The final whitening key is ek13, so the ciphertext gives another CPA entry point.

Ciphertext-side CPA target for ARIA ek13

The final substitution-layer direction is not identical to the first-round direction. In the encryption direction, the last substitution layer uses the other S-box ordering. However, when I work backward from the ciphertext, I first XOR a key guess and then apply the inverse substitution. Because ARIA pairs the S-boxes as inverses:

S1=S31,S2=S41S_1 = S_3^{-1},\qquad S_2 = S_4^{-1}

the same table order used for the ek1 CPA can be reused in the ciphertext-side model. The input changes from plaintext bytes to ciphertext bytes:

Yi(b)(k)=Sb(Ci(b)k)Y_i^{(b)}(k) = S_b(C_i^{(b)} \oplus k)

The recovered final round key is:

ek13 = 9F 6B DD 65 DB 73 71 3B F8 CF 67 77 D9 D1 95 9F

Recovered ARIA ek13 bytes

For this pass, I used fewer traces and a narrower window to speed up the run, so the result is noisier than the ek1 CPA. The peak is still strong enough to recover all 16 bytes.

Correlation trace for ARIA ek1 and ek13

6. Recovering the Master Key

Now both round keys are known:

ek1 = CB F6 D7 4C 0B 78 B9 30 22 B4 7E AA 06 E7 01 2A
ek13 = 9F 6B DD 65 DB 73 71 3B F8 CF 67 77 D9 D1 95 9F

The key-schedule relation gives:

T = rotl128(ek1, 50) ^ ek13
= 7B AB 57 B4 21 DB 6A A7 FC 64 48 AC 84 E1 B8 7D

and:

T=W0rotl128(W0,50)T = W_0 \oplus \operatorname{rotl}_{128}(W_0, 50)

This equation does not uniquely determine W0W_0 without a small brute force. Since:

gcd(128,50)=2\gcd(128, 50) = 2

the bit relation splits into two independent cycles: one for even bit positions and one for odd bit positions. Therefore, two seed bits are enough to enumerate every possible W0W_0 that satisfies the equation.

The bit-walk in the implementation looks like this:

for (int seed_odd = 0; seed_odd <= 1; seed_odd++) {
for (int seed_even = 0; seed_even <= 1; seed_even++) {
memset(key_bits, -1, sizeof(key_bits));
key_bits[127] = seed_odd;
walk_cycle(127, key_bits, T_bits);
key_bits[126] = seed_even;
walk_cycle(126, key_bits, T_bits);
print_candidate(key_bits);
}
}
void walk_cycle(int idx, int *key_bits, const int *T_bits) {
int start = idx;
do {
int next = (idx + 128 - 50) % 128;
key_bits[next] = key_bits[idx] ^ T_bits[idx];
idx = next;
} while (idx != start);
}

That produces four candidates:

12 27 66 34 21 1F 1A 63 0C 60 00 31 1C 31 3C 01
47 72 33 61 74 4A 4F 36 59 35 55 64 49 64 69 54
B8 8D CC 9E 8B B5 B0 C9 A6 CA AA 9B B6 9B 96 AB
ED D8 99 CB DE E0 E5 9C F3 9F FF CE E3 CE C3 FE

Bit-cycle candidates for the ARIA master key

Only one candidate encrypts the known plaintexts to the known ciphertexts:

Master key = 47 72 33 61 74 4A 4F 36 59 35 55 64 49 64 69 54

Verifying the recovered ARIA master key

The plaintext and ciphertext files provide the final check.

Known plaintext and ciphertext pairs

7. What Matters in This Attack

The CPA part is conceptually the same as the AES attack: choose a byte-wise nonlinear intermediate value, predict its Hamming weight for every key guess, and correlate that prediction against the measured traces.

The ARIA-specific part is what happens after recovering round keys. ek1 is not the master key, and stopping there would be a key-schedule mistake. The useful observation is that ek1 and ek13 share the same W0W_0 and rotated W1W_1 structure:

ek1=W0rotr128(W1,19)ek13=W0rotr128(W1,97)\begin{aligned} ek1 &= W_0 \oplus \operatorname{rotr}_{128}(W_1, 19) \\ ek13 &= W_0 \oplus \operatorname{rotr}_{128}(W_1, 97) \end{aligned}

After aligning the rotations, W1W_1 cancels and leaves a small two-bit ambiguity in W0W_0. Known plaintext/ciphertext pairs remove that ambiguity immediately.

So the attack succeeds in two layers:

  1. Side-channel analysis recovers enough round-key material.
  2. Cryptanalytic use of the key schedule turns that round-key material into the master key.