Annotation of embedaddon/strongswan/scripts/timeattack.c, revision 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>