diff --git a/.gitignore b/.gitignore index b4fb9ff..50be9a6 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ /boringssl/include /server/server /client/client +/tools/aes_128_gcm_decrypt diff --git a/client/Makefile b/client/Makefile index 6a5d7fa..85cee56 100644 --- a/client/Makefile +++ b/client/Makefile @@ -1,8 +1,8 @@ -CFLAGS += -I../boringssl/include +CFLAGS += -I../boringssl/include -Wall LDFLAGS += -L../boringssl -lssl -lcrypto client: main.c ../boringssl/libssl.a ../boringssl/libcrypto.a $(CC) $(CFLAGS) -o client main.c -Wall $(LDFLAGS) clean: - rm -f server + rm -f client diff --git a/server/Makefile b/server/Makefile index 23e78f3..d4bb1b8 100644 --- a/server/Makefile +++ b/server/Makefile @@ -1,4 +1,4 @@ -CFLAGS += -I../boringssl/include +CFLAGS += -I../boringssl/include -Wall LDFLAGS += -L../boringssl -lssl -lcrypto client: main.c ../boringssl/libssl.a ../boringssl/libcrypto.a diff --git a/tools/Makefile b/tools/Makefile new file mode 100644 index 0000000..dc07f04 --- /dev/null +++ b/tools/Makefile @@ -0,0 +1,7 @@ +CFLAGS += -I../boringssl/include -Wall +LDFLAGS += -L../boringssl -lssl -lcrypto + +all: aes_128_gcm_decrypt + +aes_128_gcm_decrypt: aes_128_gcm_decrypt.c ../boringssl/libssl.a ../boringssl/libcrypto.a + $(CC) $(CFLAGS) -o $@ aes_128_gcm_decrypt.c $(LDFLAGS) diff --git a/tools/aes_128_gcm_decrypt.c b/tools/aes_128_gcm_decrypt.c new file mode 100644 index 0000000..0131edb --- /dev/null +++ b/tools/aes_128_gcm_decrypt.c @@ -0,0 +1,115 @@ +#include +#include +#include +#include +#include + +typedef unsigned char uchar; + +static void die(const char *msg); +static void read_hex(const char *hex, uchar *out, size_t outmax, size_t *outlen); +static void build_iv(uchar *iv, uint64_t seq); + +const int gcm_ivlen = 12; +const int gcm_taglen = 16; +const int aes_keylen = 16; // aes-128 + +int main(int argc, char **argv) +{ + if (argc != 6) { + fprintf(stderr, "Usage: %s hexiv seq hexkey hexaad hextag\n", argv[0]); + fprintf(stderr, "\n"); + fprintf(stderr, "Reads ciphertext on stdin and prints plaintext on stdout\n"); + exit(1); + } + + uchar iv[1024], key[1024], aad[1024], tag[1024]; + size_t ivlen, keylen, aadlen, taglen; + read_hex(argv[1], iv, sizeof(iv), &ivlen); + read_hex(argv[3], key, sizeof(key), &keylen); + read_hex(argv[4], aad, sizeof(aad), &aadlen); + read_hex(argv[5], tag, sizeof(tag), &taglen); + uint64_t seq = atoi(argv[2]); + + if (keylen != aes_keylen) + die("Incorrect key length, expected 16 bytes"); + if (ivlen != gcm_ivlen) + die("Incorrect IV length, expected 12 bytes"); + if (taglen != gcm_taglen) + die("Incorrect IV length, expected 16 bytes"); + build_iv(iv, seq); + + EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); + if (!ctx) + die("cipher ctx create failed"); + + if (!EVP_DecryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL)) + die("init algorithm failed"); + + if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, ivlen, NULL)) + die("set ivlen failed"); + + if (!EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv)) + die("set key/iv failed"); + + int len = 0; + if (!EVP_DecryptUpdate(ctx, NULL, &len, aad, aadlen)) + die("set aad failed"); + + uchar bufin[1024], bufout[1024]; + char *out = NULL; + int outlen = 0; + while (!feof(stdin)) { + size_t num = fread(bufin, 1, sizeof(bufin), stdin); + if (!EVP_DecryptUpdate(ctx, bufout, &len, bufin, num)) + die("decrypt failed"); + out = realloc(out, outlen + len); + memcpy(out + outlen, bufout, len); + outlen += len; + } + + if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, taglen, tag)) + die("set expected tag failed"); + + // positive is success + int final = EVP_DecryptFinal_ex(ctx, bufout, &len); + out = realloc(out, outlen + len); + memcpy(out + outlen, bufout, len); + outlen += len; + + EVP_CIPHER_CTX_free(ctx); + + if (final > 0) { + fwrite(out, 1, outlen, stdout); + free(out); + } else { + free(out); + die("decrypt failed; tag value didn't match"); + } +} + +static void die(const char *msg) +{ + fprintf(stderr, "%s\n", msg); + exit(1); +} + +static void read_hex(const char *hex, uchar *out, size_t outmax, size_t *outlen) +{ + *outlen = 0; + if (strlen(hex) > 2*outmax) + die("read_hex overflow"); + for (size_t i = 0; hex[i] && hex[i+1]; i += 2) { + unsigned int value = 0; + if (!sscanf(hex + i, "%02x", &value)) + die("sscanf failure"); + out[(*outlen)++] = value; + } +} + +static void build_iv(uchar *iv, uint64_t seq) +{ + for (size_t i = 0; i < 8; i++) { + iv[gcm_ivlen-1-i] ^= ((seq>>(i*8))&0xFF); + } +}