Annotation of embedaddon/strongswan/scripts/timeattack.c, revision 1.1.1.1

1.1       misho       1: #include <stdio.h>
                      2: #include <time.h>
                      3: 
                      4: #include <library.h>
                      5: 
                      6: typedef bool (*attackfn_t)(void *subj, u_char *data, size_t len);
                      7: 
                      8: static void start_timing(struct timespec *start)
                      9: {
                     10:        clock_gettime(CLOCK_PROCESS_CPUTIME_ID, start);
                     11: }
                     12: 
                     13: static uint64_t end_timing(struct timespec *start)
                     14: {
                     15:        struct timespec end;
                     16: 
                     17:        clock_gettime(CLOCK_THREAD_CPUTIME_ID, &end);
                     18:        return (end.tv_nsec - start->tv_nsec) +
                     19:                   (end.tv_sec - start->tv_sec) * 1000000000;
                     20: }
                     21: 
                     22: static int intcmp(const void *a, const void *b)
                     23: {
                     24:        return *(uint64_t*)a - *(uint64_t*)b;
                     25: }
                     26: 
                     27: static uint64_t median(uint64_t *m, int count)
                     28: {
                     29:        qsort(m, count, sizeof(uint64_t), intcmp);
                     30:        return m[count / 2];
                     31: }
                     32: 
                     33: static bool timeattack(attackfn_t attackfn, void *subj, size_t dlen,
                     34:                                           u_int iterations, u_int distance)
                     35: {
                     36:        struct timespec start;
                     37:        u_char test[dlen];
                     38:        uint64_t mini, maxi, t[256], m[256][10];
                     39:        float fastdist = 0, slowdist = 0;
                     40:        int i, j, k, l, byte, limit, retry = 0;
                     41:        int fastest = 0, slowest = 0;
                     42: 
                     43:        memset(test, 0, dlen);
                     44: 
                     45:        /* do some iterations to fill caches */
                     46:        for (i = 0; i < iterations; i++)
                     47:        {
                     48:                attackfn(subj, test, dlen);
                     49:        }
                     50: 
                     51:        for (byte = 0; byte < dlen;)
                     52:        {
                     53:                memset(t, 0, sizeof(t));
                     54:                memset(m, 0, sizeof(m));
                     55: 
                     56:                limit = iterations * (retry + 1);
                     57: 
                     58:                /* measure timing for all patterns in next byte */
                     59:                for (k = 0; k < 10; k++)
                     60:                {
                     61:                        for (j = 0; j < 256; j++)
                     62:                        {
                     63:                                for (l = 0; l < 100; l++)
                     64:                                {
                     65:                                        test[byte] = j;
                     66:                                        start_timing(&start);
                     67:                                        for (i = 0; i < limit; i++)
                     68:                                        {
                     69:                                                attackfn(subj, test, dlen);
                     70:                                        }
                     71:                                        m[j][k] += end_timing(&start);
                     72:                                }
                     73:                        }
                     74:                }
                     75: 
                     76:                for (j = 0; j < 256; j++)
                     77:                {
                     78:                        t[j] = median(m[j], countof(m[j]));
                     79:                }
                     80: 
                     81:                /* find fastest/slowest runs */
                     82:                mini = ~0;
                     83:                maxi = 0;
                     84:                for (j = 0; j < 256; j++)
                     85:                {
                     86:                        if (t[j] < mini)
                     87:                        {
                     88:                                mini = min(t[j], mini);
                     89:                                fastest = j;
                     90:                        }
                     91:                        if (t[j] > maxi)
                     92:                        {
                     93:                                maxi = max(t[j], maxi);
                     94:                                slowest = j;
                     95:                        }
                     96:                }
                     97:                /* calculate distance to next result */
                     98:                mini = ~0;
                     99:                maxi = 0;
                    100:                for (j = 0; j < 256; j++)
                    101:                {
                    102:                        if (fastest != j && t[j] < mini)
                    103:                        {
                    104:                                mini = min(t[j], mini);
                    105:                                fastdist = (float)(t[j] - t[fastest]) / distance;
                    106:                        }
                    107:                        if (slowest != j && t[j] > maxi)
                    108:                        {
                    109:                                maxi = max(t[j], maxi);
                    110:                                slowdist = (float)(t[slowest] - t[j]) / distance;
                    111:                        }
                    112:                }
                    113:                if (fastdist > 1.0f)
                    114:                {
                    115:                        fprintf(stderr, "byte %02d: %02x (fastest, dist %02.2f)\n",
                    116:                                        byte, fastest, fastdist);
                    117:                        test[byte] = fastest;
                    118:                        retry = 0;
                    119:                        byte++;
                    120:                }
                    121:                else if (slowdist > 1.0f)
                    122:                {
                    123:                        fprintf(stderr, "byte %02d: %02x (slowest, dist %02.2f)\n",
                    124:                                        byte, slowest, slowdist);
                    125:                        test[byte] = slowest;
                    126:                        retry = 0;
                    127:                        byte++;
                    128:                }
                    129:                else
                    130:                {
                    131:                        if (retry++ > 5 && byte > 0)
                    132:                        {
                    133:                                fprintf(stderr, "distance fastest %02.2f (%02x), "
                    134:                                                "slowest %02.2f (%02x), stepping back\n",
                    135:                                                fastdist, fastest, slowdist, slowest);
                    136:                                test[byte--] = 0;
                    137:                        }
                    138:                        else if (retry < 10)
                    139:                        {
                    140:                                fprintf(stderr, "distance fastest %02.2f (%02x), "
                    141:                                                "slowest %02.2f (%02x), retrying (%d)\n",
                    142:                                                fastdist, fastest, slowdist, slowest, retry);
                    143:                        }
                    144:                        else
                    145:                        {
                    146:                                printf("attack failed, giving up\n");
                    147:                                return FALSE;
                    148:                        }
                    149:                }
                    150:        }
                    151:        if (attackfn(subj, test, dlen))
                    152:        {
                    153:                printf("attack successful with %b\n", test, dlen);
                    154:                return TRUE;
                    155:        }
                    156:        printf("attack failed with %b\n", test, dlen);
                    157:        return FALSE;
                    158: }
                    159: 
                    160: CALLBACK(attack_memeq1, bool,
                    161:        u_char *subj, u_char *data, size_t len)
                    162: {
                    163:        return memeq(data, subj, len);
                    164: }
                    165: 
                    166: CALLBACK(attack_memeq2, bool,
                    167:        u_char *subj, u_char *data, size_t len)
                    168: {
                    169:        return memeq(subj, data, len);
                    170: }
                    171: 
                    172: CALLBACK(attack_memeq3, bool,
                    173:        u_char *subj, u_char *data, size_t len)
                    174: {
                    175:        int i;
                    176: 
                    177:        for (i = 0; i < len; i++)
                    178:        {
                    179:                if (subj[i] != data[i])
                    180:                {
                    181:                        return FALSE;
                    182:                }
                    183:        }
                    184:        return TRUE;
                    185: }
                    186: 
                    187: CALLBACK(attack_memeq4, bool,
                    188:        u_char *subj, u_char *data, size_t len)
                    189: {
                    190:        int i, m = 0;
                    191: 
                    192:        for (i = 0; i < len; i++)
                    193:        {
                    194:                m |= subj[i] != data[i];
                    195:        }
                    196:        return !m;
                    197: }
                    198: 
                    199: CALLBACK(attack_memeq5, bool,
                    200:        u_char *subj, u_char *data, size_t len)
                    201: {
                    202:        return memeq_const(subj, data, len);
                    203: }
                    204: 
                    205: static bool attack_memeq(char *name, u_int iterations, u_int distance)
                    206: {
                    207:        struct {
                    208:                char *name;
                    209:                attackfn_t fn;
                    210:        } attacks[] = {
                    211:                { "memeq1", attack_memeq1 },
                    212:                { "memeq2", attack_memeq2 },
                    213:                { "memeq3", attack_memeq3 },
                    214:                { "memeq4", attack_memeq4 },
                    215:                { "memeq5", attack_memeq5 },
                    216:        };
                    217:        u_char exp[16];
                    218:        int i;
                    219: 
                    220:        srandom(time(NULL));
                    221:        for (i = 0; i < sizeof(exp); i++)
                    222:        {
                    223:                exp[i] = random();
                    224:        }
                    225:        fprintf(stderr, "attacking %b\n", exp, sizeof(exp));
                    226: 
                    227:        for (i = 0; i < countof(attacks); i++)
                    228:        {
                    229:                if (streq(name, attacks[i].name))
                    230:                {
                    231:                        return timeattack(attacks[i].fn, exp, sizeof(exp),
                    232:                                                          iterations, distance);
                    233:                }
                    234:        }
                    235:        return FALSE;
                    236: }
                    237: 
                    238: CALLBACK(attack_chunk1, bool,
                    239:        u_char *subj, u_char *data, size_t len)
                    240: {
                    241:        return chunk_equals(chunk_create(subj, len), chunk_create(data, len));
                    242: }
                    243: 
                    244: CALLBACK(attack_chunk2, bool,
                    245:        u_char *subj, u_char *data, size_t len)
                    246: {
                    247:        return chunk_equals_const(chunk_create(subj, len), chunk_create(data, len));
                    248: }
                    249: 
                    250: static bool attack_chunk(char *name, u_int iterations, u_int distance)
                    251: {
                    252:        struct {
                    253:                char *name;
                    254:                attackfn_t fn;
                    255:        } attacks[] = {
                    256:                { "chunk1", attack_chunk1 },
                    257:                { "chunk2", attack_chunk2 },
                    258:        };
                    259:        u_char exp[16];
                    260:        int i;
                    261: 
                    262:        srandom(time(NULL));
                    263:        for (i = 0; i < sizeof(exp); i++)
                    264:        {
                    265:                exp[i] = random();
                    266:        }
                    267:        fprintf(stderr, "attacking %b\n", exp, sizeof(exp));
                    268: 
                    269:        for (i = 0; i < countof(attacks); i++)
                    270:        {
                    271:                if (streq(name, attacks[i].name))
                    272:                {
                    273:                        return timeattack(attacks[i].fn, exp, sizeof(exp),
                    274:                                                          iterations, distance);
                    275:                }
                    276:        }
                    277:        return FALSE;
                    278: }
                    279: 
                    280: CALLBACK(attack_aead, bool,
                    281:        aead_t *aead, u_char *data, size_t len)
                    282: {
                    283:        u_char iv[aead->get_iv_size(aead)];
                    284: 
                    285:        memset(iv, 0, sizeof(iv));
                    286:        return aead->decrypt(aead, chunk_create(data, len), chunk_empty,
                    287:                                                 chunk_from_thing(iv), NULL);
                    288: }
                    289: 
                    290: static bool attack_aeads(encryption_algorithm_t alg, size_t key_size,
                    291:                                                 u_int iterations, u_int distance)
                    292: {
                    293:        u_char buf[64];
                    294:        aead_t *aead;
                    295:        bool res;
                    296: 
                    297:        aead = lib->crypto->create_aead(lib->crypto, alg, key_size, 0);
                    298:        if (!aead)
                    299:        {
                    300:                fprintf(stderr, "creating AEAD %N failed\n",
                    301:                                encryption_algorithm_names, alg);
                    302:                return FALSE;
                    303:        }
                    304:        memset(buf, 0xe3, sizeof(buf));
                    305:        if (!aead->set_key(aead, chunk_create(buf, aead->get_key_size(aead))))
                    306:        {
                    307:                aead->destroy(aead);
                    308:                return FALSE;
                    309:        }
                    310:        memset(buf, 0, aead->get_iv_size(aead));
                    311:        if (!aead->encrypt(aead, chunk_create(buf, 0), chunk_empty,
                    312:                                           chunk_create(buf, aead->get_iv_size(aead)), NULL))
                    313:        {
                    314:                aead->destroy(aead);
                    315:                return FALSE;
                    316:        }
                    317:        fprintf(stderr, "attacking %b\n", buf, aead->get_icv_size(aead));
                    318: 
                    319:        res = timeattack(attack_aead, aead, aead->get_icv_size(aead),
                    320:                                         iterations, distance);
                    321:        aead->destroy(aead);
                    322:        return res;
                    323: }
                    324: 
                    325: CALLBACK(attack_signer, bool,
                    326:        signer_t *signer, u_char *data, size_t len)
                    327: {
                    328:        return signer->verify_signature(signer, chunk_empty, chunk_create(data, len));
                    329: }
                    330: 
                    331: static bool attack_signers(integrity_algorithm_t alg,
                    332:                                                   u_int iterations, u_int distance)
                    333: {
                    334:        u_char buf[64];
                    335:        signer_t *signer;
                    336:        bool res;
                    337: 
                    338:        signer = lib->crypto->create_signer(lib->crypto, alg);
                    339:        if (!signer)
                    340:        {
                    341:                fprintf(stderr, "creating signer %N failed\n",
                    342:                                integrity_algorithm_names, alg);
                    343:                return FALSE;
                    344:        }
                    345:        memset(buf, 0xe3, sizeof(buf));
                    346:        if (!signer->set_key(signer, chunk_create(buf, signer->get_key_size(signer))))
                    347:        {
                    348:                signer->destroy(signer);
                    349:                return FALSE;
                    350:        }
                    351:        if (!signer->get_signature(signer, chunk_empty, buf))
                    352:        {
                    353:                signer->destroy(signer);
                    354:                return FALSE;
                    355:        }
                    356:        fprintf(stderr, "attacking %b\n", buf, signer->get_block_size(signer));
                    357: 
                    358:        res = timeattack(attack_signer, signer, signer->get_block_size(signer),
                    359:                                         iterations, distance);
                    360:        signer->destroy(signer);
                    361:        return res;
                    362: }
                    363: 
                    364: static bool attack_transform(char *name, u_int iterations, u_int distance)
                    365: {
                    366:        const proposal_token_t *token;
                    367: 
                    368:        token = lib->proposal->get_token(lib->proposal, name);
                    369:        if (!token)
                    370:        {
                    371:                fprintf(stderr, "algorithm '%s' unknown\n", name);
                    372:                return FALSE;
                    373:        }
                    374: 
                    375:        switch (token->type)
                    376:        {
                    377:                case ENCRYPTION_ALGORITHM:
                    378:                        if (encryption_algorithm_is_aead(token->algorithm))
                    379:                        {
                    380:                                return attack_aeads(token->algorithm, token->keysize / 8,
                    381:                                                                        iterations, distance);
                    382:                        }
                    383:                        fprintf(stderr, "can't attack a crypter\n");
                    384:                        return FALSE;
                    385:                case INTEGRITY_ALGORITHM:
                    386:                        return attack_signers(token->algorithm, iterations, distance);
                    387:                default:
                    388:                        fprintf(stderr, "can't attack a %N\n", transform_type_names, token->type);
                    389:                        return FALSE;
                    390:        }
                    391: }
                    392: 
                    393: int main(int argc, char *argv[])
                    394: {
                    395:        library_init(NULL, "timeattack");
                    396:        atexit(library_deinit);
                    397:        lib->plugins->load(lib->plugins, getenv("PLUGINS") ?: PLUGINS);
                    398: 
                    399:        if (argc < 3)
                    400:        {
                    401:                fprintf(stderr, "usage: %s <attack> <iterations> <distance>\n", argv[0]);
                    402:                fprintf(stderr, "  <attack>: memeq[1-5] / chunk[1-2] / aead / signer\n");
                    403:                fprintf(stderr, "  <iterations>: number of invocations * 1000\n");
                    404:                fprintf(stderr, "  <distance>: time difference in ns for a hit\n");
                    405:                fprintf(stderr, "  example: %s memeq1 100 500\n", argv[0]);
                    406:                fprintf(stderr, "  example: %s aes128gcm16 100 4000\n", argv[0]);
                    407:                return 1;
                    408:        }
                    409:        if (strpfx(argv[1], "memeq"))
                    410:        {
                    411:                return !attack_memeq(argv[1], atoi(argv[2]), atoi(argv[3]));
                    412:        }
                    413:        if (strpfx(argv[1], "chunk"))
                    414:        {
                    415:                return !attack_chunk(argv[1], atoi(argv[2]), atoi(argv[3]));
                    416:        }
                    417:        return !attack_transform(argv[1], atoi(argv[2]), atoi(argv[3]));
                    418: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>