summaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'scripts')
-rw-r--r--scripts/Makefile.am4
-rw-r--r--scripts/Makefile.in20
-rw-r--r--scripts/crypt_burn.c264
-rw-r--r--scripts/timeattack.c418
4 files changed, 623 insertions, 83 deletions
diff --git a/scripts/Makefile.am b/scripts/Makefile.am
index abc6d75dd..c5155efc2 100644
--- a/scripts/Makefile.am
+++ b/scripts/Makefile.am
@@ -5,7 +5,7 @@ AM_CPPFLAGS = \
noinst_PROGRAMS = bin2array bin2sql id2sql key2keyid keyid2sql oid2der \
thread_analysis dh_speed pubkey_speed crypt_burn hash_burn fetch \
- dnssec malloc_speed aes-test settings-test
+ dnssec malloc_speed aes-test settings-test timeattack
if USE_TLS
noinst_PROGRAMS += tls_test
@@ -28,6 +28,7 @@ hash_burn_SOURCES = hash_burn.c
malloc_speed_SOURCES = malloc_speed.c
fetch_SOURCES = fetch.c
dnssec_SOURCES = dnssec.c
+timeattack_SOURCES = timeattack.c
id2sql_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la
key2keyid_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la
keyid2sql_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la
@@ -41,6 +42,7 @@ fetch_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la
dnssec_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la
aes_test_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la
settings_test_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la
+timeattack_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la
key2keyid.o : $(top_builddir)/config.status
diff --git a/scripts/Makefile.in b/scripts/Makefile.in
index d28783b4c..b03ff9d4f 100644
--- a/scripts/Makefile.in
+++ b/scripts/Makefile.in
@@ -83,7 +83,8 @@ noinst_PROGRAMS = bin2array$(EXEEXT) bin2sql$(EXEEXT) id2sql$(EXEEXT) \
thread_analysis$(EXEEXT) dh_speed$(EXEEXT) \
pubkey_speed$(EXEEXT) crypt_burn$(EXEEXT) hash_burn$(EXEEXT) \
fetch$(EXEEXT) dnssec$(EXEEXT) malloc_speed$(EXEEXT) \
- aes-test$(EXEEXT) settings-test$(EXEEXT) $(am__EXEEXT_1)
+ aes-test$(EXEEXT) settings-test$(EXEEXT) timeattack$(EXEEXT) \
+ $(am__EXEEXT_1)
@USE_TLS_TRUE@am__append_1 = tls_test
subdir = scripts
DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
@@ -176,6 +177,10 @@ settings_test_DEPENDENCIES = \
am_thread_analysis_OBJECTS = thread_analysis.$(OBJEXT)
thread_analysis_OBJECTS = $(am_thread_analysis_OBJECTS)
thread_analysis_LDADD = $(LDADD)
+am_timeattack_OBJECTS = timeattack.$(OBJEXT)
+timeattack_OBJECTS = $(am_timeattack_OBJECTS)
+timeattack_DEPENDENCIES = \
+ $(top_builddir)/src/libstrongswan/libstrongswan.la
am__tls_test_SOURCES_DIST = tls_test.c
@USE_TLS_TRUE@am_tls_test_OBJECTS = tls_test.$(OBJEXT)
tls_test_OBJECTS = $(am_tls_test_OBJECTS)
@@ -221,14 +226,16 @@ SOURCES = aes-test.c $(bin2array_SOURCES) $(bin2sql_SOURCES) \
$(key2keyid_SOURCES) $(keyid2sql_SOURCES) \
$(malloc_speed_SOURCES) $(oid2der_SOURCES) \
$(pubkey_speed_SOURCES) settings-test.c \
- $(thread_analysis_SOURCES) $(tls_test_SOURCES)
+ $(thread_analysis_SOURCES) $(timeattack_SOURCES) \
+ $(tls_test_SOURCES)
DIST_SOURCES = aes-test.c $(bin2array_SOURCES) $(bin2sql_SOURCES) \
$(crypt_burn_SOURCES) $(dh_speed_SOURCES) $(dnssec_SOURCES) \
$(fetch_SOURCES) $(hash_burn_SOURCES) $(id2sql_SOURCES) \
$(key2keyid_SOURCES) $(keyid2sql_SOURCES) \
$(malloc_speed_SOURCES) $(oid2der_SOURCES) \
$(pubkey_speed_SOURCES) settings-test.c \
- $(thread_analysis_SOURCES) $(am__tls_test_SOURCES_DIST)
+ $(thread_analysis_SOURCES) $(timeattack_SOURCES) \
+ $(am__tls_test_SOURCES_DIST)
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
@@ -502,6 +509,7 @@ hash_burn_SOURCES = hash_burn.c
malloc_speed_SOURCES = malloc_speed.c
fetch_SOURCES = fetch.c
dnssec_SOURCES = dnssec.c
+timeattack_SOURCES = timeattack.c
id2sql_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la
key2keyid_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la
keyid2sql_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la
@@ -515,6 +523,7 @@ fetch_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la
dnssec_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la
aes_test_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la
settings_test_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la
+timeattack_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la
all: all-am
.SUFFIXES:
@@ -623,6 +632,10 @@ thread_analysis$(EXEEXT): $(thread_analysis_OBJECTS) $(thread_analysis_DEPENDENC
@rm -f thread_analysis$(EXEEXT)
$(AM_V_CCLD)$(LINK) $(thread_analysis_OBJECTS) $(thread_analysis_LDADD) $(LIBS)
+timeattack$(EXEEXT): $(timeattack_OBJECTS) $(timeattack_DEPENDENCIES) $(EXTRA_timeattack_DEPENDENCIES)
+ @rm -f timeattack$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(timeattack_OBJECTS) $(timeattack_LDADD) $(LIBS)
+
tls_test$(EXEEXT): $(tls_test_OBJECTS) $(tls_test_DEPENDENCIES) $(EXTRA_tls_test_DEPENDENCIES)
@rm -f tls_test$(EXEEXT)
$(AM_V_CCLD)$(LINK) $(tls_test_OBJECTS) $(tls_test_LDADD) $(LIBS)
@@ -649,6 +662,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pubkey_speed.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/settings-test.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/thread_analysis.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/timeattack.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tls_test.Po@am__quote@
.c.o:
diff --git a/scripts/crypt_burn.c b/scripts/crypt_burn.c
index 1768d769b..3bd36d2dc 100644
--- a/scripts/crypt_burn.c
+++ b/scripts/crypt_burn.c
@@ -16,34 +16,190 @@
#include <stdio.h>
#include <library.h>
-int main(int argc, char *argv[])
+static int burn_crypter(const proposal_token_t *token, u_int limit, u_int len)
{
- const proposal_token_t *token;
- aead_t *aead;
+ chunk_t iv, key, data;
crypter_t *crypter;
- char buffer[1024], assoc[8], iv[32];
- size_t bs;
- int i = 0, limit = 0;
+ int i = 0;
+ bool ok;
+
+ crypter = lib->crypto->create_crypter(lib->crypto, token->algorithm,
+ token->keysize / 8);
+ if (!crypter)
+ {
+ fprintf(stderr, "%N-%zu not supported\n",
+ encryption_algorithm_names, token->algorithm, token->keysize);
+ return FALSE;
+ }
+
+ iv = chunk_alloc(crypter->get_iv_size(crypter));
+ memset(iv.ptr, 0xFF, iv.len);
+ data = chunk_alloc(round_up(len, crypter->get_block_size(crypter)));
+ memset(data.ptr, 0xDD, data.len);
+ key = chunk_alloc(crypter->get_key_size(crypter));
+ memset(key.ptr, 0xAA, key.len);
+
+ ok = crypter->set_key(crypter, key);
+ while (ok)
+ {
+ if (!crypter->encrypt(crypter, data, iv, NULL))
+ {
+ fprintf(stderr, "encryption failed!\n");
+ ok = FALSE;
+ break;
+ }
+ if (!crypter->decrypt(crypter, data, iv, NULL))
+ {
+ fprintf(stderr, "decryption failed!\n");
+ ok = FALSE;
+ break;
+ }
+ if (limit && ++i == limit)
+ {
+ break;
+ }
+ }
+ crypter->destroy(crypter);
+
+ free(iv.ptr);
+ free(data.ptr);
+ free(key.ptr);
+
+ return ok;
+}
+
+static bool burn_aead(const proposal_token_t *token, u_int limit, u_int len)
+{
+ chunk_t iv, key, data, dataicv, assoc;
+ aead_t *aead;
+ int i = 0;
+ bool ok;
+
+ aead = lib->crypto->create_aead(lib->crypto, token->algorithm,
+ token->keysize / 8, 0);
+ if (!aead)
+ {
+ fprintf(stderr, "%N-%zu not supported\n",
+ encryption_algorithm_names, token->algorithm, token->keysize);
+ return FALSE;
+ }
+
+ iv = chunk_alloc(aead->get_iv_size(aead));
+ memset(iv.ptr, 0xFF, iv.len);
+ dataicv = chunk_alloc(round_up(len, aead->get_block_size(aead)) +
+ aead->get_icv_size(aead));
+ data = chunk_create(dataicv.ptr, dataicv.len - aead->get_icv_size(aead));
+ memset(data.ptr, 0xDD, data.len);
+ assoc = chunk_alloc(13);
+ memset(assoc.ptr, 0xCC, assoc.len);
+ key = chunk_alloc(aead->get_key_size(aead));
+ memset(key.ptr, 0xAA, key.len);
+
+ ok = aead->set_key(aead, key);
+ while (ok)
+ {
+ if (!aead->encrypt(aead, data, assoc, iv, NULL))
+ {
+ fprintf(stderr, "aead encryption failed!\n");
+ ok = FALSE;
+ break;
+ }
+ if (!aead->decrypt(aead, dataicv, assoc, iv, NULL))
+ {
+ fprintf(stderr, "aead integrity check failed!\n");
+ ok = FALSE;
+ break;
+ }
+ if (limit && ++i == limit)
+ {
+ break;
+ }
+ }
+ aead->destroy(aead);
+
+ free(iv.ptr);
+ free(data.ptr);
+ free(key.ptr);
+ free(assoc.ptr);
+
+ return ok;
+}
+
+static int burn_signer(const proposal_token_t *token, u_int limit, u_int len)
+{
+ chunk_t key, data, sig;
+ signer_t *signer;
+ int i = 0;
+ bool ok;
+
+ signer = lib->crypto->create_signer(lib->crypto, token->algorithm);
+ if (!signer)
+ {
+ fprintf(stderr, "%N not supported\n",
+ integrity_algorithm_names, token->algorithm);
+ return FALSE;
+ }
+
+ data = chunk_alloc(len);
+ memset(data.ptr, 0xDD, data.len);
+ key = chunk_alloc(signer->get_key_size(signer));
+ memset(key.ptr, 0xAA, key.len);
+ sig = chunk_alloc(signer->get_block_size(signer));
+
+ ok = signer->set_key(signer, key);
+ while (ok)
+ {
+ if (!signer->get_signature(signer, data, sig.ptr))
+ {
+ fprintf(stderr, "creating signature failed!\n");
+ ok = FALSE;
+ break;
+ }
+ if (!signer->verify_signature(signer, data, sig))
+ {
+ fprintf(stderr, "verifying signature failed!\n");
+ ok = FALSE;
+ break;
+ }
+ if (limit && ++i == limit)
+ {
+ break;
+ }
+ }
+ signer->destroy(signer);
+ free(data.ptr);
+ free(key.ptr);
+ free(sig.ptr);
+
+ return ok;
+}
+
+int main(int argc, char *argv[])
+{
+ const proposal_token_t *token;
+ u_int limit = 0, len = 1024;
+ bool ok;
library_init(NULL, "crypt_burn");
- lib->plugins->load(lib->plugins, PLUGINS);
+ lib->plugins->load(lib->plugins, getenv("PLUGINS") ?: PLUGINS);
atexit(library_deinit);
- printf("loaded: %s\n", PLUGINS);
-
- memset(buffer, 0x12, sizeof(buffer));
- memset(assoc, 0x34, sizeof(assoc));
- memset(iv, 0x56, sizeof(iv));
+ fprintf(stderr, "loaded: %s\n", lib->plugins->loaded_plugins(lib->plugins));
if (argc < 2)
{
- fprintf(stderr, "usage: %s <algorithm>!\n", argv[0]);
+ fprintf(stderr, "usage: %s <algorithm> [buflen=%u] [rounds=%u]\n",
+ argv[0], len, limit);
return 1;
}
if (argc > 2)
{
- limit = atoi(argv[2]);
+ len = atoi(argv[2]);
+ }
+ if (argc > 3)
+ {
+ limit = atoi(argv[3]);
}
token = lib->proposal->get_token(lib->proposal, argv[1]);
@@ -52,76 +208,26 @@ int main(int argc, char *argv[])
fprintf(stderr, "algorithm '%s' unknown!\n", argv[1]);
return 1;
}
- if (token->type != ENCRYPTION_ALGORITHM)
- {
- fprintf(stderr, "'%s' is not an encryption/aead algorithm!\n", argv[1]);
- return 1;
- }
- if (encryption_algorithm_is_aead(token->algorithm))
+ switch (token->type)
{
- aead = lib->crypto->create_aead(lib->crypto,
- token->algorithm, token->keysize / 8, 0);
- if (!aead)
- {
- fprintf(stderr, "aead '%s' not supported!\n", argv[1]);
- return 1;
- }
- while (TRUE)
- {
- if (!aead->encrypt(aead,
- chunk_create(buffer, sizeof(buffer) - aead->get_icv_size(aead)),
- chunk_from_thing(assoc),
- chunk_create(iv, aead->get_iv_size(aead)), NULL))
+ case ENCRYPTION_ALGORITHM:
+ if (encryption_algorithm_is_aead(token->algorithm))
{
- fprintf(stderr, "aead encryption failed!\n");
- return 1;
+ ok = burn_aead(token, limit, len);
}
- if (!aead->decrypt(aead, chunk_create(buffer, sizeof(buffer)),
- chunk_from_thing(assoc),
- chunk_create(iv, aead->get_iv_size(aead)), NULL))
+ else
{
- fprintf(stderr, "aead integrity check failed!\n");
- return 1;
+ ok = burn_crypter(token, limit, len);
}
- if (limit && ++i == limit)
- {
- break;
- }
- }
- aead->destroy(aead);
- }
- else
- {
- crypter = lib->crypto->create_crypter(lib->crypto,
- token->algorithm, token->keysize / 8);
- if (!crypter)
- {
- fprintf(stderr, "crypter '%s' not supported!\n", argv[1]);
- return 1;
- }
- bs = crypter->get_block_size(crypter);
-
- while (TRUE)
- {
- if (!crypter->encrypt(crypter,
- chunk_create(buffer, sizeof(buffer) / bs * bs),
- chunk_create(iv, crypter->get_iv_size(crypter)), NULL))
- {
- continue;
- }
- if (!crypter->decrypt(crypter,
- chunk_create(buffer, sizeof(buffer) / bs * bs),
- chunk_create(iv, crypter->get_iv_size(crypter)), NULL))
- {
- continue;
- }
- if (limit && ++i == limit)
- {
- break;
- }
- }
- crypter->destroy(crypter);
+ break;
+ case INTEGRITY_ALGORITHM:
+ ok = burn_signer(token, limit, len);
+ break;
+ default:
+ fprintf(stderr, "'%s' is not a crypter/aead algorithm!\n", argv[1]);
+ ok = FALSE;
+ break;
}
- return 0;
+ return !ok;
}
diff --git a/scripts/timeattack.c b/scripts/timeattack.c
new file mode 100644
index 000000000..ef00e8c4e
--- /dev/null
+++ b/scripts/timeattack.c
@@ -0,0 +1,418 @@
+#include <stdio.h>
+#include <time.h>
+
+#include <library.h>
+
+typedef bool (*attackfn_t)(void *subj, u_char *data, size_t len);
+
+static void start_timing(struct timespec *start)
+{
+ clock_gettime(CLOCK_PROCESS_CPUTIME_ID, start);
+}
+
+static u_int64_t end_timing(struct timespec *start)
+{
+ struct timespec end;
+
+ clock_gettime(CLOCK_THREAD_CPUTIME_ID, &end);
+ return (end.tv_nsec - start->tv_nsec) +
+ (end.tv_sec - start->tv_sec) * 1000000000;
+}
+
+static int intcmp(const void *a, const void *b)
+{
+ return *(u_int64_t*)a - *(u_int64_t*)b;
+}
+
+static u_int64_t median(u_int64_t *m, int count)
+{
+ qsort(m, count, sizeof(u_int64_t), intcmp);
+ return m[count / 2];
+}
+
+static bool timeattack(attackfn_t attackfn, void *subj, size_t dlen,
+ u_int iterations, u_int distance)
+{
+ struct timespec start;
+ u_char test[dlen];
+ u_int64_t mini, maxi, t[256], m[256][10];
+ float fastdist = 0, slowdist = 0;
+ int i, j, k, l, byte, limit, retry = 0;
+ int fastest = 0, slowest = 0;
+
+ memset(test, 0, dlen);
+
+ /* do some iterations to fill caches */
+ for (i = 0; i < iterations; i++)
+ {
+ attackfn(subj, test, dlen);
+ }
+
+ for (byte = 0; byte < dlen;)
+ {
+ memset(t, 0, sizeof(t));
+ memset(m, 0, sizeof(m));
+
+ limit = iterations * (retry + 1);
+
+ /* measure timing for all patterns in next byte */
+ for (k = 0; k < 10; k++)
+ {
+ for (j = 0; j < 256; j++)
+ {
+ for (l = 0; l < 100; l++)
+ {
+ test[byte] = j;
+ start_timing(&start);
+ for (i = 0; i < limit; i++)
+ {
+ attackfn(subj, test, dlen);
+ }
+ m[j][k] += end_timing(&start);
+ }
+ }
+ }
+
+ for (j = 0; j < 256; j++)
+ {
+ t[j] = median(m[j], countof(m[j]));
+ }
+
+ /* find fastest/slowest runs */
+ mini = ~0;
+ maxi = 0;
+ for (j = 0; j < 256; j++)
+ {
+ if (t[j] < mini)
+ {
+ mini = min(t[j], mini);
+ fastest = j;
+ }
+ if (t[j] > maxi)
+ {
+ maxi = max(t[j], maxi);
+ slowest = j;
+ }
+ }
+ /* calculate distance to next result */
+ mini = ~0;
+ maxi = 0;
+ for (j = 0; j < 256; j++)
+ {
+ if (fastest != j && t[j] < mini)
+ {
+ mini = min(t[j], mini);
+ fastdist = (float)(t[j] - t[fastest]) / distance;
+ }
+ if (slowest != j && t[j] > maxi)
+ {
+ maxi = max(t[j], maxi);
+ slowdist = (float)(t[slowest] - t[j]) / distance;
+ }
+ }
+ if (fastdist > 1.0f)
+ {
+ fprintf(stderr, "byte %02d: %02x (fastest, dist %02.2f)\n",
+ byte, fastest, fastdist);
+ test[byte] = fastest;
+ retry = 0;
+ byte++;
+ }
+ else if (slowdist > 1.0f)
+ {
+ fprintf(stderr, "byte %02d: %02x (slowest, dist %02.2f)\n",
+ byte, slowest, slowdist);
+ test[byte] = slowest;
+ retry = 0;
+ byte++;
+ }
+ else
+ {
+ if (retry++ > 5 && byte > 0)
+ {
+ fprintf(stderr, "distance fastest %02.2f (%02x), "
+ "slowest %02.2f (%02x), stepping back\n",
+ fastdist, fastest, slowdist, slowest);
+ test[byte--] = 0;
+ }
+ else if (retry < 10)
+ {
+ fprintf(stderr, "distance fastest %02.2f (%02x), "
+ "slowest %02.2f (%02x), retrying (%d)\n",
+ fastdist, fastest, slowdist, slowest, retry);
+ }
+ else
+ {
+ printf("attack failed, giving up\n");
+ return FALSE;
+ }
+ }
+ }
+ if (attackfn(subj, test, dlen))
+ {
+ printf("attack successful with %b\n", test, dlen);
+ return TRUE;
+ }
+ printf("attack failed with %b\n", test, dlen);
+ return FALSE;
+}
+
+CALLBACK(attack_memeq1, bool,
+ u_char *subj, u_char *data, size_t len)
+{
+ return memeq(data, subj, len);
+}
+
+CALLBACK(attack_memeq2, bool,
+ u_char *subj, u_char *data, size_t len)
+{
+ return memeq(subj, data, len);
+}
+
+CALLBACK(attack_memeq3, bool,
+ u_char *subj, u_char *data, size_t len)
+{
+ int i;
+
+ for (i = 0; i < len; i++)
+ {
+ if (subj[i] != data[i])
+ {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+CALLBACK(attack_memeq4, bool,
+ u_char *subj, u_char *data, size_t len)
+{
+ int i, m = 0;
+
+ for (i = 0; i < len; i++)
+ {
+ m |= subj[i] != data[i];
+ }
+ return !m;
+}
+
+CALLBACK(attack_memeq5, bool,
+ u_char *subj, u_char *data, size_t len)
+{
+ return memeq_const(subj, data, len);
+}
+
+static bool attack_memeq(char *name, u_int iterations, u_int distance)
+{
+ struct {
+ char *name;
+ attackfn_t fn;
+ } attacks[] = {
+ { "memeq1", attack_memeq1 },
+ { "memeq2", attack_memeq2 },
+ { "memeq3", attack_memeq3 },
+ { "memeq4", attack_memeq4 },
+ { "memeq5", attack_memeq5 },
+ };
+ u_char exp[16];
+ int i;
+
+ srandom(time(NULL));
+ for (i = 0; i < sizeof(exp); i++)
+ {
+ exp[i] = random();
+ }
+ fprintf(stderr, "attacking %b\n", exp, sizeof(exp));
+
+ for (i = 0; i < countof(attacks); i++)
+ {
+ if (streq(name, attacks[i].name))
+ {
+ return timeattack(attacks[i].fn, exp, sizeof(exp),
+ iterations, distance);
+ }
+ }
+ return FALSE;
+}
+
+CALLBACK(attack_chunk1, bool,
+ u_char *subj, u_char *data, size_t len)
+{
+ return chunk_equals(chunk_create(subj, len), chunk_create(data, len));
+}
+
+CALLBACK(attack_chunk2, bool,
+ u_char *subj, u_char *data, size_t len)
+{
+ return chunk_equals_const(chunk_create(subj, len), chunk_create(data, len));
+}
+
+static bool attack_chunk(char *name, u_int iterations, u_int distance)
+{
+ struct {
+ char *name;
+ attackfn_t fn;
+ } attacks[] = {
+ { "chunk1", attack_chunk1 },
+ { "chunk2", attack_chunk2 },
+ };
+ u_char exp[16];
+ int i;
+
+ srandom(time(NULL));
+ for (i = 0; i < sizeof(exp); i++)
+ {
+ exp[i] = random();
+ }
+ fprintf(stderr, "attacking %b\n", exp, sizeof(exp));
+
+ for (i = 0; i < countof(attacks); i++)
+ {
+ if (streq(name, attacks[i].name))
+ {
+ return timeattack(attacks[i].fn, exp, sizeof(exp),
+ iterations, distance);
+ }
+ }
+ return FALSE;
+}
+
+CALLBACK(attack_aead, bool,
+ aead_t *aead, u_char *data, size_t len)
+{
+ u_char iv[aead->get_iv_size(aead)];
+
+ memset(iv, 0, sizeof(iv));
+ return aead->decrypt(aead, chunk_create(data, len), chunk_empty,
+ chunk_from_thing(iv), NULL);
+}
+
+static bool attack_aeads(encryption_algorithm_t alg, size_t key_size,
+ u_int iterations, u_int distance)
+{
+ u_char buf[64];
+ aead_t *aead;
+ bool res;
+
+ aead = lib->crypto->create_aead(lib->crypto, alg, key_size, 0);
+ if (!aead)
+ {
+ fprintf(stderr, "creating AEAD %N failed\n",
+ encryption_algorithm_names, alg);
+ return FALSE;
+ }
+ memset(buf, 0xe3, sizeof(buf));
+ if (!aead->set_key(aead, chunk_create(buf, aead->get_key_size(aead))))
+ {
+ aead->destroy(aead);
+ return FALSE;
+ }
+ memset(buf, 0, aead->get_iv_size(aead));
+ if (!aead->encrypt(aead, chunk_create(buf, 0), chunk_empty,
+ chunk_create(buf, aead->get_iv_size(aead)), NULL))
+ {
+ aead->destroy(aead);
+ return FALSE;
+ }
+ fprintf(stderr, "attacking %b\n", buf, aead->get_icv_size(aead));
+
+ res = timeattack(attack_aead, aead, aead->get_icv_size(aead),
+ iterations, distance);
+ aead->destroy(aead);
+ return res;
+}
+
+CALLBACK(attack_signer, bool,
+ signer_t *signer, u_char *data, size_t len)
+{
+ return signer->verify_signature(signer, chunk_empty, chunk_create(data, len));
+}
+
+static bool attack_signers(integrity_algorithm_t alg,
+ u_int iterations, u_int distance)
+{
+ u_char buf[64];
+ signer_t *signer;
+ bool res;
+
+ signer = lib->crypto->create_signer(lib->crypto, alg);
+ if (!signer)
+ {
+ fprintf(stderr, "creating signer %N failed\n",
+ integrity_algorithm_names, alg);
+ return FALSE;
+ }
+ memset(buf, 0xe3, sizeof(buf));
+ if (!signer->set_key(signer, chunk_create(buf, signer->get_key_size(signer))))
+ {
+ signer->destroy(signer);
+ return FALSE;
+ }
+ if (!signer->get_signature(signer, chunk_empty, buf))
+ {
+ signer->destroy(signer);
+ return FALSE;
+ }
+ fprintf(stderr, "attacking %b\n", buf, signer->get_block_size(signer));
+
+ res = timeattack(attack_signer, signer, signer->get_block_size(signer),
+ iterations, distance);
+ signer->destroy(signer);
+ return res;
+}
+
+static bool attack_transform(char *name, u_int iterations, u_int distance)
+{
+ const proposal_token_t *token;
+
+ token = lib->proposal->get_token(lib->proposal, name);
+ if (!token)
+ {
+ fprintf(stderr, "algorithm '%s' unknown\n", name);
+ return FALSE;
+ }
+
+ switch (token->type)
+ {
+ case ENCRYPTION_ALGORITHM:
+ if (encryption_algorithm_is_aead(token->algorithm))
+ {
+ return attack_aeads(token->algorithm, token->keysize / 8,
+ iterations, distance);
+ }
+ fprintf(stderr, "can't attack a crypter\n");
+ return FALSE;
+ case INTEGRITY_ALGORITHM:
+ return attack_signers(token->algorithm, iterations, distance);
+ default:
+ fprintf(stderr, "can't attack a %N\n", transform_type_names, token->type);
+ return FALSE;
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ library_init(NULL, "timeattack");
+ atexit(library_deinit);
+ lib->plugins->load(lib->plugins, getenv("PLUGINS") ?: PLUGINS);
+
+ if (argc < 3)
+ {
+ fprintf(stderr, "usage: %s <attack> <iterations> <distance>\n", argv[0]);
+ fprintf(stderr, " <attack>: memeq[1-5] / chunk[1-2] / aead / signer\n");
+ fprintf(stderr, " <iterations>: number of invocations * 1000\n");
+ fprintf(stderr, " <distance>: time difference in ns for a hit\n");
+ fprintf(stderr, " example: %s memeq1 100 500\n", argv[0]);
+ fprintf(stderr, " example: %s aes128gcm16 100 4000\n", argv[0]);
+ return 1;
+ }
+ if (strpfx(argv[1], "memeq"))
+ {
+ return !attack_memeq(argv[1], atoi(argv[2]), atoi(argv[3]));
+ }
+ if (strpfx(argv[1], "chunk"))
+ {
+ return !attack_chunk(argv[1], atoi(argv[2]), atoi(argv[3]));
+ }
+ return !attack_transform(argv[1], atoi(argv[2]), atoi(argv[3]));
+}