|
@@ -1,6 +1,6 @@
|
|
|
#include <openssl/conf.h>
|
|
|
-#include <openssl/evp.h>
|
|
|
#include <openssl/err.h>
|
|
|
+#include <openssl/evp.h>
|
|
|
#include <stdio.h>
|
|
|
#include <string.h>
|
|
|
|
|
@@ -8,26 +8,17 @@
|
|
|
|
|
|
|
|
|
void handleErrors(void);
|
|
|
-int gcm_encrypt(unsigned char *plaintext, int plaintext_len,
|
|
|
- unsigned char *key,
|
|
|
- unsigned char *iv, int iv_len,
|
|
|
- unsigned char *ciphertext,
|
|
|
- unsigned char *tag);
|
|
|
-int gcm_decrypt(unsigned char *ciphertext, int ciphertext_len,
|
|
|
- unsigned char *tag,
|
|
|
- unsigned char *key,
|
|
|
- unsigned char *iv, int iv_len,
|
|
|
- unsigned char *plaintext);
|
|
|
-
|
|
|
-int main (int argc, char** argv)
|
|
|
-{
|
|
|
-
|
|
|
- * Set up the key and iv. Do I need to say to not hard code these in a
|
|
|
- * real application? :-)
|
|
|
- */
|
|
|
-
|
|
|
+int gcm_encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key, unsigned char *iv, int iv_len, unsigned char *ciphertext, unsigned char *tag);
|
|
|
+int gcm_decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *tag, unsigned char *key, unsigned char *iv, int iv_len, unsigned char *plaintext);
|
|
|
+
|
|
|
+int main(int argc, char **argv) {
|
|
|
+
|
|
|
+ * Set up the key and iv. Do I need to say to not hard code these in a
|
|
|
+ * real application? :-)
|
|
|
+ */
|
|
|
+
|
|
|
FILE *f, *o;
|
|
|
- unsigned char signature[4] = { 'C', 'C', 'A', 'T' };
|
|
|
+ unsigned char signature[4] = {'C', 'C', 'A', 'T'};
|
|
|
unsigned char key[32];
|
|
|
unsigned char iv[12];
|
|
|
unsigned char tag[16];
|
|
@@ -35,60 +26,55 @@ int main (int argc, char** argv)
|
|
|
unsigned char *cipher;
|
|
|
unsigned insize, mode;
|
|
|
int decryptedtext_len, ciphertext_len;
|
|
|
- if(argc < 4) {
|
|
|
+ if (argc < 4) {
|
|
|
printf("not enough args. use %s mode key in out\n", argv[0]);
|
|
|
return 1;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
mode = strtoul(argv[1], NULL, 10);
|
|
|
-
|
|
|
- if(!(f = fopen(argv[2], "rb"))) {
|
|
|
+
|
|
|
+ if (!(f = fopen(argv[2], "rb"))) {
|
|
|
printf("cannot open key\n");
|
|
|
return 1;
|
|
|
}
|
|
|
fread(key, sizeof(key), 1, f);
|
|
|
fclose(f);
|
|
|
-
|
|
|
- if(!(f = fopen("/dev/urandom", "rb"))) {
|
|
|
+
|
|
|
+ if (!(f = fopen("/dev/urandom", "rb"))) {
|
|
|
printf("cannot open urandom\n");
|
|
|
return 1;
|
|
|
}
|
|
|
fread(iv, sizeof(iv), 1, f);
|
|
|
fclose(f);
|
|
|
-
|
|
|
- if(!(f = fopen(argv[3], "rb"))) {
|
|
|
+
|
|
|
+ if (!(f = fopen(argv[3], "rb"))) {
|
|
|
printf("cannot open in\n");
|
|
|
return 1;
|
|
|
}
|
|
|
- if(!(o = fopen(argv[4], "wb"))) {
|
|
|
+ if (!(o = fopen(argv[4], "wb"))) {
|
|
|
printf("cannot open out\n");
|
|
|
return 1;
|
|
|
}
|
|
|
-
|
|
|
-
|
|
|
- if(mode) {
|
|
|
+
|
|
|
+ if (mode) {
|
|
|
fseek(f, 0, SEEK_END);
|
|
|
- insize = ftell(f)+4;
|
|
|
+ insize = ftell(f) + 4;
|
|
|
fseek(f, 0, SEEK_SET);
|
|
|
plain = malloc(insize);
|
|
|
cipher = malloc(insize);
|
|
|
- fread(plain+4, insize, 1, f);
|
|
|
+ fread(plain + 4, insize, 1, f);
|
|
|
fclose(f);
|
|
|
|
|
|
memcpy(plain, signature, 4);
|
|
|
|
|
|
- ciphertext_len = gcm_encrypt(plain, insize,
|
|
|
- key,
|
|
|
- iv, sizeof(iv),
|
|
|
- cipher, tag);
|
|
|
+ ciphertext_len = gcm_encrypt(plain, insize, key, iv, sizeof(iv), cipher, tag);
|
|
|
fwrite(iv, sizeof(iv), 1, o);
|
|
|
fwrite(tag, sizeof(tag), 1, o);
|
|
|
fwrite(cipher, ciphertext_len, 1, o);
|
|
|
fclose(o);
|
|
|
- }
|
|
|
- else {
|
|
|
+ } else {
|
|
|
fseek(f, 0, SEEK_END);
|
|
|
- insize = ftell(f)-sizeof(iv)-sizeof(tag);
|
|
|
+ insize = ftell(f) - sizeof(iv) - sizeof(tag);
|
|
|
fseek(f, 0, SEEK_SET);
|
|
|
cipher = malloc(insize);
|
|
|
plain = malloc(insize);
|
|
@@ -96,27 +82,24 @@ int main (int argc, char** argv)
|
|
|
fread(tag, sizeof(tag), 1, f);
|
|
|
fread(cipher, insize, 1, f);
|
|
|
fclose(f);
|
|
|
-
|
|
|
- decryptedtext_len = gcm_decrypt(cipher, insize,
|
|
|
- tag,
|
|
|
- key, iv, sizeof(iv),
|
|
|
- plain);
|
|
|
- if(decryptedtext_len < 0) {
|
|
|
+
|
|
|
+ decryptedtext_len = gcm_decrypt(cipher, insize, tag, key, iv, sizeof(iv), plain);
|
|
|
+ if (decryptedtext_len < 0) {
|
|
|
printf("decrypt failed\n");
|
|
|
fclose(o);
|
|
|
remove(argv[4]);
|
|
|
- }
|
|
|
- else if(memcmp(plain, signature, 4)) {
|
|
|
+ } else if (memcmp(plain, signature, 4)) {
|
|
|
printf("signature mismatch, expected ");
|
|
|
- for(int i = 0; i < sizeof(signature); i++) printf("%02x ", signature[i]);
|
|
|
+ for (int i = 0; i < sizeof(signature); i++)
|
|
|
+ printf("%02x ", signature[i]);
|
|
|
printf("but got ");
|
|
|
- for(int i = 0; i < sizeof(signature); i++) printf("%02x ", plain[i]);
|
|
|
+ for (int i = 0; i < sizeof(signature); i++)
|
|
|
+ printf("%02x ", plain[i]);
|
|
|
printf("\n");
|
|
|
fclose(o);
|
|
|
remove(argv[4]);
|
|
|
- }
|
|
|
- else {
|
|
|
- fwrite(plain+4, decryptedtext_len-4, 1, o);
|
|
|
+ } else {
|
|
|
+ fwrite(plain + 4, decryptedtext_len - 4, 1, o);
|
|
|
fclose(o);
|
|
|
}
|
|
|
}
|
|
@@ -126,126 +109,112 @@ int main (int argc, char** argv)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
-void handleErrors(void)
|
|
|
-{
|
|
|
- ERR_print_errors_fp(stderr);
|
|
|
- abort();
|
|
|
+void handleErrors(void) {
|
|
|
+ ERR_print_errors_fp(stderr);
|
|
|
+ abort();
|
|
|
}
|
|
|
|
|
|
+int gcm_encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key, unsigned char *iv, int iv_len, unsigned char *ciphertext, unsigned char *tag) {
|
|
|
+ EVP_CIPHER_CTX *ctx;
|
|
|
|
|
|
-int gcm_encrypt(unsigned char *plaintext, int plaintext_len,
|
|
|
- unsigned char *key,
|
|
|
- unsigned char *iv, int iv_len,
|
|
|
- unsigned char *ciphertext,
|
|
|
- unsigned char *tag)
|
|
|
-{
|
|
|
- EVP_CIPHER_CTX *ctx;
|
|
|
+ int len;
|
|
|
|
|
|
- int len;
|
|
|
+ int ciphertext_len;
|
|
|
|
|
|
- int ciphertext_len;
|
|
|
+
|
|
|
+ if (!(ctx = EVP_CIPHER_CTX_new()))
|
|
|
+ handleErrors();
|
|
|
|
|
|
+
|
|
|
+ if (1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
|
|
|
+ handleErrors();
|
|
|
|
|
|
-
|
|
|
- if(!(ctx = EVP_CIPHER_CTX_new()))
|
|
|
- handleErrors();
|
|
|
+
|
|
|
+ * Set IV length if default 12 bytes (96 bits) is not appropriate
|
|
|
+ */
|
|
|
+ if (1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL))
|
|
|
+ handleErrors();
|
|
|
|
|
|
-
|
|
|
- if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
|
|
|
- handleErrors();
|
|
|
+
|
|
|
+ if (1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv))
|
|
|
+ handleErrors();
|
|
|
|
|
|
-
|
|
|
- * Set IV length if default 12 bytes (96 bits) is not appropriate
|
|
|
- */
|
|
|
- if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL))
|
|
|
- handleErrors();
|
|
|
+
|
|
|
+ * Provide the message to be encrypted, and obtain the encrypted output.
|
|
|
+ * EVP_EncryptUpdate can be called multiple times if necessary
|
|
|
+ */
|
|
|
+ if (1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
|
|
|
+ handleErrors();
|
|
|
+ ciphertext_len = len;
|
|
|
|
|
|
-
|
|
|
- if(1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv))
|
|
|
- handleErrors();
|
|
|
+
|
|
|
+ * Finalise the encryption. Normally ciphertext bytes may be written at
|
|
|
+ * this stage, but this does not occur in GCM mode
|
|
|
+ */
|
|
|
+ if (1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len))
|
|
|
+ handleErrors();
|
|
|
+ ciphertext_len += len;
|
|
|
|
|
|
-
|
|
|
- * Provide the message to be encrypted, and obtain the encrypted output.
|
|
|
- * EVP_EncryptUpdate can be called multiple times if necessary
|
|
|
- */
|
|
|
- if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
|
|
|
- handleErrors();
|
|
|
- ciphertext_len = len;
|
|
|
+
|
|
|
+ if (1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag))
|
|
|
+ handleErrors();
|
|
|
|
|
|
-
|
|
|
- * Finalise the encryption. Normally ciphertext bytes may be written at
|
|
|
- * this stage, but this does not occur in GCM mode
|
|
|
- */
|
|
|
- if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len))
|
|
|
- handleErrors();
|
|
|
- ciphertext_len += len;
|
|
|
+
|
|
|
+ EVP_CIPHER_CTX_free(ctx);
|
|
|
|
|
|
-
|
|
|
- if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag))
|
|
|
- handleErrors();
|
|
|
-
|
|
|
-
|
|
|
- EVP_CIPHER_CTX_free(ctx);
|
|
|
-
|
|
|
- return ciphertext_len;
|
|
|
+ return ciphertext_len;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
-int gcm_decrypt(unsigned char *ciphertext, int ciphertext_len,
|
|
|
- unsigned char *tag,
|
|
|
- unsigned char *key,
|
|
|
- unsigned char *iv, int iv_len,
|
|
|
- unsigned char *plaintext)
|
|
|
-{
|
|
|
- EVP_CIPHER_CTX *ctx;
|
|
|
- int len;
|
|
|
- int plaintext_len;
|
|
|
- int ret;
|
|
|
-
|
|
|
-
|
|
|
- if(!(ctx = EVP_CIPHER_CTX_new()))
|
|
|
- handleErrors();
|
|
|
-
|
|
|
-
|
|
|
- if(!EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
|
|
|
- handleErrors();
|
|
|
-
|
|
|
-
|
|
|
- if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL))
|
|
|
- handleErrors();
|
|
|
-
|
|
|
-
|
|
|
- if(!EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv))
|
|
|
- handleErrors();
|
|
|
-
|
|
|
-
|
|
|
- * Provide the message to be decrypted, and obtain the plaintext output.
|
|
|
- * EVP_DecryptUpdate can be called multiple times if necessary
|
|
|
- */
|
|
|
- if(!EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
|
|
|
- handleErrors();
|
|
|
- plaintext_len = len;
|
|
|
-
|
|
|
-
|
|
|
- if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, tag))
|
|
|
- handleErrors();
|
|
|
-
|
|
|
-
|
|
|
- * Finalise the decryption. A positive return value indicates success,
|
|
|
- * anything else is a failure - the plaintext is not trustworthy.
|
|
|
- */
|
|
|
- ret = EVP_DecryptFinal_ex(ctx, plaintext + len, &len);
|
|
|
-
|
|
|
-
|
|
|
- EVP_CIPHER_CTX_free(ctx);
|
|
|
-
|
|
|
- if(ret > 0) {
|
|
|
-
|
|
|
- plaintext_len += len;
|
|
|
- return plaintext_len;
|
|
|
- } else {
|
|
|
-
|
|
|
- return -1;
|
|
|
- }
|
|
|
+int gcm_decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *tag, unsigned char *key, unsigned char *iv, int iv_len,
|
|
|
+ unsigned char *plaintext) {
|
|
|
+ EVP_CIPHER_CTX *ctx;
|
|
|
+ int len;
|
|
|
+ int plaintext_len;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+
|
|
|
+ if (!(ctx = EVP_CIPHER_CTX_new()))
|
|
|
+ handleErrors();
|
|
|
+
|
|
|
+
|
|
|
+ if (!EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
|
|
|
+ handleErrors();
|
|
|
+
|
|
|
+
|
|
|
+ if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL))
|
|
|
+ handleErrors();
|
|
|
+
|
|
|
+
|
|
|
+ if (!EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv))
|
|
|
+ handleErrors();
|
|
|
+
|
|
|
+
|
|
|
+ * Provide the message to be decrypted, and obtain the plaintext output.
|
|
|
+ * EVP_DecryptUpdate can be called multiple times if necessary
|
|
|
+ */
|
|
|
+ if (!EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
|
|
|
+ handleErrors();
|
|
|
+ plaintext_len = len;
|
|
|
+
|
|
|
+
|
|
|
+ if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, tag))
|
|
|
+ handleErrors();
|
|
|
+
|
|
|
+
|
|
|
+ * Finalise the decryption. A positive return value indicates success,
|
|
|
+ * anything else is a failure - the plaintext is not trustworthy.
|
|
|
+ */
|
|
|
+ ret = EVP_DecryptFinal_ex(ctx, plaintext + len, &len);
|
|
|
+
|
|
|
+
|
|
|
+ EVP_CIPHER_CTX_free(ctx);
|
|
|
+
|
|
|
+ if (ret > 0) {
|
|
|
+
|
|
|
+ plaintext_len += len;
|
|
|
+ return plaintext_len;
|
|
|
+ } else {
|
|
|
+
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
}
|