File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / scripts / timeattack.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jun 3 09:46:49 2020 UTC (4 years, 4 months ago) by misho
Branches: strongswan, MAIN
CVS tags: v5_9_2p0, v5_8_4p7, HEAD
Strongswan

    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>