Try   HackMD

[0x03] Crypto III

slide: https://drive.google.com/drive/folders/1odb_qi-nW0tpKfEDXpmCCox6zxVCEGMD?usp=sharing
lecture: https://drive.google.com/file/d/1cthYF5PcZYoGC0uRhlf8Ba-NbtSAvviX/view

[HW] AES

首先來看看題目給的數據

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

可以看出有 10 round (下方突起)

我今天要取的是第一次 AddRoundKey 以及 SubBytes 的範圍
所以我們只需要橘色的部分

取第一次 AddRoundKey SubBytes 的原因

我們知道第一次 AddRoundKeykey 就是輸入 AESkey
而且第一次 AddRoundKey SubBytes 不會把不同的 bytes 混在一起
再加上 SubBytes 又是非線性的

Power Model

所取的中間值 state 如下
state=SubByte(AddRoundKey(PT,K))

將使用的為 Hamming Weight Model

Why is the Hamming Weight model suitable?

  1. In software case, the intermediate value may be moved between register and memory several times
  2. Bus may be precharged before moving data

講師簡報

計算 state[i]Hamming Weight 來當成那點的功率消耗
共會有 Dtraces
所以得到 D x KEY_BYTE_SPACE 的矩陣 powerMatrix

AES/exp2.ipynb
#  return Power Matrix (D * KEY_BYTE_SPACE)
def getPowerMatrix (key: bytearray, byte_index: int):
    global PT

    powerMatrix = []

    # for i in range(D):
    for pt in PT:
        pt = bytearray(pt)
        powerVector = []
        # for k in KEY_SPACE
        for k in range(K):
            key[byte_index] = k
            if not k in key_byte_space:

                key[byte_index] = 0
            
            intermediateState = CipherFirstAddKeyAndSubBytes(pt, key)
            HW = getHammingWeight(intermediateState[byte_index])
            powerVector.append(HW)

        powerMatrix.append(powerVector)
    return powerMatrix

接著將 powerMatrix (D x K)PM (D x T)column 進行計算 correlation

此步驟為比較我們猜的 key_byte 所模擬出來的功率消耗曲線與實際情況的相關性

AES/exp2.ipynb
# return correlation matrix of i th byte (K x T)
def getCorrBetweenPowerMatrixAndTraces2 (byte_index: int) -> list[list[int]]:
    # PM (D x T)
    global PM

    PM_NP_T = np.array(PM).transpose()

    # Power Matrix (D x KEY_BYTE_SPACE)
    powerMatrix = getPowerMatrix(bytearray(b'0000000000000000'), byte_index)

    powerMatrix_NP_T = np.array(powerMatrix).transpose()


    # K * T
    corrMatrix = [ ]
    for k in range(K):
        corrVector = []
        for t in range(T):
            corrVector.append(corr_calc(powerMatrix_NP_T[k], PM_NP_T[t]))
        corrMatrix.append(corrVector)

    assert(np.array(corrMatrix).shape == (K, T))

    return np.array(corrMatrix)

接著我們只要取相關性最大的 key_byte 就會是答案

AES/exp2.ipynb
def getKeyByte2 (byte_index: int) -> int:
    corrMatrix = getCorrBetweenPowerMatrixAndTraces2(byte_index)
    # get max index of corrMatrix
    maxIndex = np.argmax(corrMatrix)
    I = maxIndex // T
    J = maxIndex % T
    return I

對於每個 key_byte 都作一次就有完整的 key

AES/exp2.ipynb

def getKey2 () -> bytearray:
    key = bytearray(b'0000000000000000')
    for i in range(16):
        key[i] = getKeyByte2(i)
    return key

# output: bytearray(b'18MbH9oEnbXHyHTR')