久しぶりに無線ネタです。

先日Tews/Beckが発表したTKIPに対する攻撃では、Michaelが一方向関数になっていないことを利用していますが、これが本当かどうかを確かめるためにMichaelとその逆関数を実装してみました。うーーん、確かに平文とMichaelの64bitハッシュ値があれば、MIC Keyが逆算できますね。こら、盲点だった。言われて初めて気が付きました。

この64ビットMIC Keyは、256ビットのPairwise Master Key (PMK) を512ビットに拡張して得られるPairwise Transient Key (PTK) の1/8に相当するわけですので、大ざっぱに言うとPMKの1/8に相当する部分が解読されたことになりますが、PMKをPTKに拡張する際には、PMKをかなり激しくHMAC-SHA-1で攪拌していますので、解読できたMIC KeyからPMKを解読するのは、直観的にはかなり厳しそうに思えます。

Tews/Beckの攻撃は現実的には大きな脅威ではありませんが、TKIP攻撃に関しては大きな一歩を踏み出したと言えるでしょう。

u_int32_t lrot(u_int32_t a, int n)
{
    u_int32_t t;

    if (n == 0 || n == 32)
        return a;
    t = (a >> (32 - n));
    return (a << n) + t;
}

u_int32_t rrot(u_int32_t a, int n)
{
    u_int32_t t;

    if (n == 0 || n == 32)
        return a;
    t = (a << (32 - n)); return t + (a >> n);
}

u_int32_t xswap(u_int32_t a)
{
    u_int8_t b[4];

    b[0] = (a & 0x0000ff00) >> 8;
    b[1] = a & 0x000000ff;
    b[2] = (a & 0xff000000) >> 24;
    b[3] = (a & 0x00ff0000) >> 16;

    return (b[3] << 24) + (b[2] << 16) + (b[1] << 8) + b[0]; 
}

void b(u_int32_t l, u_int32_t r, u_int32_t *lv, u_int32_t *rv) {
    r = r ^ (lrot(l, 17));
    l = l + r;
    r = r ^ xswap(l);
    l = l + r;
    r = r ^ (lrot(l, 3));
    l = l + r;
    r = r ^ (rrot(l, 2));
    l = l + r;
    *lv = l;
    *rv = r;
}

void b_inv(u_int32_t l, u_int32_t r, u_int32_t *lv, u_int32_t *rv) {
    l = l - r;
    r = r ^ (rrot(l, 2));
    l = l - r;
    r = r ^ (lrot(l, 3));
    l = l - r;
    r = r ^ xswap(l);
    l = l - r;
    r = r ^ (lrot(l, 17));
    *lv = l;
    *rv = r;
}

void michael(u_int32_t k0, u_int32_t k1, u_int8_t msg[], int n, u_int32_t *lv, u_int32_t *rv) {
    u_int32_t l, r, ll, rr;
    u_int8_t *ptr;
    u_int32_t *m;
    int i;

    ptr = calloc(n + 8, sizeof(u_int8_t));
    memcpy(ptr, msg, n);
    *(ptr+n) = 0x5a;
    m = (u_int32_t *)ptr;

    l = k0;
    r = k1;
    for (i=0; i < n/4 + 2; i++) {
        l = l ^ *m;
        b(l, r, &ll, &rr);
        l = ll;
        r = rr;
        m++;
    }
    *lv = l;
    *rv = r;
    free(ptr);
}

void michael_inv(u_int32_t *k0, u_int32_t *k1, u_int8_t msg[], int n, u_int32_t lv, u_int32_t rv) {
    u_int32_t l, r, ll, rr;
    u_int8_t *ptr;
    u_int32_t *m;
    int i;

    ptr = calloc(n + 8, sizeof(u_int8_t));
    memcpy(ptr, msg, n);
    *(ptr+n) = 0x5a;
    m = (u_int32_t *)ptr + n/4 + 1;

    l = lv;
    r = rv;
    for (i=0; i < n/4 + 2; i++) { b_inv(l, r, &ll, &rr); l = ll; r = rr; l = l ^ *m; m--; } *k0 = l; *k1 = r; free(ptr); } void michael_print(u_int32_t l, u_int32_t r) { printf("%02x%02x%02x%02x", (l & 0x000000ff), ((l >>  8) & 0x000000ff),
            ((l >> 16) & 0x000000ff),
            ((l >> 24) & 0x000000ff));
        printf("%02x%02x%02x%02xn",
            (r & 0x000000ff),
            ((r  >> 8) & 0x000000ff),
            ((r >> 16) & 0x000000ff),
            ((r >> 24) & 0x000000ff));
}

int main()
{
    u_int32_t l, r, lv, rv;
    u_int32_t k0, k1;
    u_int8_t msg[] = {'M', 'i', 'c', 'h', 'a', 'e', 'l'};
    int i;

    /*
        test vectors for block function
    */
    b(0x0, 0x0, &lv, &rv);
    printf("b(00000000, 00000000) * 1 = (%08x, %08x)n", lv, rv);
    /* (00000000, 00000000) */

    b(0x0, 0x1, &lv, &rv);
    printf("b(00000000, 00000001) * 1 = (%08x, %08x)n", lv, rv);
    /* (c00015a8, c0000b95) */

    b(0x1, 0x0, &lv, &rv);
    printf("b(00000001, 00000000) * 1 = (%08x, %08x)n", lv, rv);
    /* (6b519593, 572b8b8a) */

    b(0x1234567, 0x83659326, &lv, &rv);
    printf("b(01234567, 83659326) * 1 = (%08x, %08x)n", lv, rv);
    /* (441492c2, 1d8427ed) */

    l = 0x1;
    r = 0x0;
    for (i=0; i<1000; i++) {
        b(l, r, &lv, &rv);
        l = lv;
        r = rv;
    }
    printf("b(00000001, 00000000) * 1000 = (%08x, %08x)n", lv, rv);
    /* (9f04c4ad, 2ec6c2bf) */

    /********
     inverse
    *********/
    b_inv(0x0, 0x0, &lv, &rv);
    printf("b_inv(0x0, 0x0) * 1 = (%08x, %08x)n", lv, rv);
    /* (00000000, 00000000) */

    b_inv(0xc00015a8, 0xc0000b95, &lv, &rv);
    printf("b_inv(0xc00015a8, 0xc0000b95) * 1 = (%08x, %08x)n", lv, rv);
    /* (00000000, 00000001) */

    /************************
     test vectors for michael
    *************************/
    l = 0x0;
    r = 0x0;
    michael(l, r, msg, 0, &l, &r);
    michael_print(l, r); // 82925c1ca1d130b8
    michael(l, r, msg, 1, &l, &r);
    michael_print(l, r); // 434721ca 40639b3f
    michael(l, r, msg, 2, &l, &r);
    michael_print(l, r); // e8f9becae97e5d29
    michael(l, r, msg, 3, &l, &r);
    michael_print(l, r); // 90038fc6cf13c1db
    michael(l, r, msg, 4, &l, &r);
    michael_print(l, r); // d55e100510128986
    michael(l, r, msg, 7, &l, &r);
    michael_print(l, r); // 0a942b124ecaa546

    /****************************
     test vectors for michael^-1
    *****************************/
    michael_inv(&k0, &k1, msg, 0, 0x1c5c9282, 0xb830d1a1);
    printf("*** k0 = %08x k1 = %08x ***n", k0, k1);

    michael_inv(&k0, &k1, msg, 1, 0xca214743, 0x3f9b6340);
    printf("*** k0 = %08x k1 = %08x ***n", k0, k1);

    return 0;
}