Makefile
# (1)コンパイラ
CC = g++
# (2)コンパイルオプション
CFLAGS =
# (3)実行ファイル名
TARGET = sample_app
# (4)コンパイル対象のソースコード
SRCS = sample.cpp
# (5)オブジェクトファイル名
OBJS = $(SRCS:.cpp=.o)
# (6)インクルードファイルのあるディレクトリパス
INCDIR = -I../inc
# (7)ライブラリファイルのあるディレクトリパス
LIBDIR =
# (8)追加するライブラリファイル
LIBS = -lssl -lcrypto
# (9)ターゲットファイル生成
$(TARGET): $(OBJS)
$(CC) -o $@ $^ $(LIBDIR) $(LIBS)
# (10)オブジェクトファイル生成
$(OBJS): $(SRCS)
$(CC) $(CFLAGS) $(INCDIR) -c $(SRCS)
# (11)"make all"で make cleanとmakeを同時に実施。
all: clean $(OBJS) $(TARGET)
# (12).oファイル、実行ファイル、.dファイルを削除
clean:
-rm -f $(OBJS) $(TARGET) *.d
sample1.cpp
#include <openssl/conf.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <string.h>
void handleErrors(void);
int gcm_encrypt(unsigned char *plaintext, int plaintext_len,
unsigned char *aad, int aad_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 *aad, int aad_len,
unsigned char *tag,
unsigned char *key,
unsigned char *iv, int iv_len,
unsigned char *plaintext);
int main (void)
{
/*
* Set up the key and iv. Do I need to say to not hard code these in a
* real application? :-)
*/
/* A 256 bit key */
unsigned char *key = (unsigned char *)"01234567890123456789012345678901";
/* A 128 bit IV */
unsigned char *iv = (unsigned char *)"0123456789012345";
size_t iv_len = 16;
/* Message to be encrypted */
unsigned char *plaintext =
(unsigned char *)"The quick brown fox jumps over the lazy dog";
/* Additional data */
unsigned char *additional =
(unsigned char *)"The five boxing wizards jump quickly.";
/*
* Buffer for ciphertext. Ensure the buffer is long enough for the
* ciphertext which may be longer than the plaintext, depending on the
* algorithm and mode.
*/
unsigned char ciphertext[128];
/* Buffer for the decrypted text */
unsigned char decryptedtext[128];
/* Buffer for the tag */
unsigned char tag[16];
int decryptedtext_len, ciphertext_len;
/* Encrypt the plaintext */
ciphertext_len = gcm_encrypt(plaintext, strlen ((char *)plaintext),
additional, strlen ((char *)additional),
key,
iv, iv_len,
ciphertext, tag);
/* Do something useful with the ciphertext here */
printf("Ciphertext is:\n");
BIO_dump_fp (stdout, (const char *)ciphertext, ciphertext_len);
printf("Tag is:\n");
BIO_dump_fp (stdout, (const char *)tag, 16);
/* Decrypt the ciphertext */
decryptedtext_len = gcm_decrypt(ciphertext, ciphertext_len,
additional, strlen ((char *)additional),
tag,
key, iv, iv_len,
decryptedtext);
if (decryptedtext_len >= 0) {
/* Add a NULL terminator. We are expecting printable text */
decryptedtext[decryptedtext_len] = '\0';
/* Show the decrypted text */
printf("Decrypted text is:\n");
printf("%s\n", decryptedtext);
} else {
printf("Decryption failed\n");
}
#if 1
// for occuring decryption error.
// tag[sizeof(tag)-1]+=0xAA;
// printf("\nModified tag is:\n");
// BIO_dump_fp (stdout, (const char *)tag, 16);
/* Decrypt the ciphertext with modified tag */
decryptedtext_len = gcm_decrypt(ciphertext, ciphertext_len,
additional, strlen ((char *)additional),
tag,
key, iv, iv_len,
decryptedtext);
if (decryptedtext_len >= 0) {
/* Add a NULL terminator. We are expecting printable text */
decryptedtext[decryptedtext_len] = '\0';
/* Show the decrypted text */
printf("Decrypted text is:\n");
printf("%s\n", decryptedtext);
} else {
printf("Decryption failed\n");
}
#endif
return 0;
}
void handleErrors(void)
{
ERR_print_errors_fp(stderr);
abort();
}
int gcm_encrypt(unsigned char *plaintext, int plaintext_len,
unsigned char *aad, int aad_len,
unsigned char *key,
unsigned char *iv, int iv_len,
unsigned char *ciphertext,
unsigned char *tag)
{
EVP_CIPHER_CTX *ctx;
int len;
int ciphertext_len;
/* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new()))
handleErrors();
/* Initialise the encryption operation. */
if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
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();
/* Initialise key and IV */
if(1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv))
handleErrors();
/*
* Provide any AAD data. This can be called zero or more times as
* required
*/
if(1 != EVP_EncryptUpdate(ctx, NULL, &len, aad, aad_len))
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;
/*
* 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;
/* Get the tag */
if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag))
handleErrors();
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
return ciphertext_len;
}
int gcm_decrypt(unsigned char *ciphertext, int ciphertext_len,
unsigned char *aad, int aad_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;
/* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new()))
handleErrors();
/* Initialise the decryption operation. */
if(!EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
handleErrors();
/* Set IV length. Not necessary if this is 12 bytes (96 bits) */
if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL))
handleErrors();
/* Initialise key and IV */
if(!EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv))
handleErrors();
/*
* Provide any AAD data. This can be called zero or more times as
* required
*/
if(!EVP_DecryptUpdate(ctx, NULL, &len, aad, aad_len))
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;
/* Set expected tag value. Works in OpenSSL 1.0.1d and later */
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);
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
if(ret > 0) {
/* Success */
plaintext_len += len;
return plaintext_len;
} else {
/* Verify failed */
return -1;
}
}
sample2.cpp
#include <openssl/conf.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <string.h>
// crypto key(256 bit)
const char* constKey{"01234567890123456789012345678901"};
// Initial Vector(128 bit)
const char* constIV{"0000000000000000"};
void cryptoHandleErrors(void);
int gcm_encrypt(unsigned char *plaindata, int plaindata_len,
unsigned char *key,
unsigned char *iv, int iv_len,
unsigned char *cipherdata,
unsigned char *tag);
int gcm_decrypt(unsigned char *cipherdata, int cipherdata_len,
unsigned char *tag,
unsigned char *key,
unsigned char *iv, int iv_len,
unsigned char *plaindata);
/// @brief メイン関数
/// @param none
/// @return 0 (always)
int main (void)
{
unsigned char* key = reinterpret_cast<unsigned char*>(const_cast<char*>(constKey));
unsigned char* iv = reinterpret_cast<unsigned char*>(const_cast<char*>(constKey));
size_t iv_len = strlen(constIV);
// plain data
unsigned char *plaindata = (unsigned char *)"The quick brown fox jumps over the lazy dog";
int plaindata_len = strlen(plaindata);
/*
* Buffer for ciphertext. Ensure the buffer is long enough for the
* ciphertext which may be longer than the plaintext, depending on the
* algorithm and mode.
*/
unsigned char cipherdata[128];
/* Buffer for the decrypted text */
unsigned char decrypteddata[128];
/* Buffer for the tag */
unsigned char tag[16];
int decrypteddata_len, cipherdata_len;
/* Encrypt the plaintext */
cipherdata_len = gcm_encrypt(plaindata, plaindata_len),
key,
iv, iv_len,
cipherdata, tag);
/* Do something useful with the ciphertext here */
printf("Ciphertext is:\n");
BIO_dump_fp (stdout, (const char *)cipherdata, cipherdata_len);
printf("Tag is:\n");
BIO_dump_fp (stdout, (const char *)tag, 16);
/* Decrypt the ciphertext */
decrypteddata_len = gcm_decrypt(cipherdata, cipherdata_len,
tag,
key, iv, iv_len,
decrypteddata);
if (decrypteddata_len >= 0) {
/* Add a NULL terminator. We are expecting printable text */
decrypteddata[decrypteddata_len] = '\0';
/* Show the decrypted text */
printf("Decrypted text is:\n");
printf("%s\n", decrypteddata);
} else {
printf("Decryption failed\n");
}
return 0;
}
void cryptoHandleErrors(void)
{
ERR_print_errors_fp(stderr);
abort();
}
int gcm_encrypt(unsigned char *plaindata, int plaindata_len,
unsigned char *key,
unsigned char *iv, int iv_len,
unsigned char *cipherdata,
unsigned char *tag)
{
EVP_CIPHER_CTX *ctx;
int len;
int cipherdata_len;
/* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new()))
cryptoHandleErrors();
/* Initialise the encryption operation. */
if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
cryptoHandleErrors();
/*
* 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))
cryptoHandleErrors();
/* Initialise key and IV */
if(1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv))
cryptoHandleErrors();
/*
* 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, cipherdata, &len, plaindata, plaindata_len))
cryptoHandleErrors();
cipherdata_len = len;
/*
* 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, cipherdata + len, &len))
cryptoHandleErrors();
cipherdata_len += len;
/* Get the tag */
if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag))
cryptoHandleErrors();
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
return cipherdata_len;
}
int gcm_decrypt(unsigned char *cipherdata, int cipherdata_len,
unsigned char *tag,
unsigned char *key,
unsigned char *iv, int iv_len,
unsigned char *plaindata)
{
EVP_CIPHER_CTX *ctx;
int len;
int plaindata_len;
int ret;
/* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new()))
cryptoHandleErrors();
/* Initialise the decryption operation. */
if(!EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
cryptoHandleErrors();
/* Set IV length. Not necessary if this is 12 bytes (96 bits) */
if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL))
cryptoHandleErrors();
/* Initialise key and IV */
if(!EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv))
cryptoHandleErrors();
/*
* Provide the message to be decrypted, and obtain the plaintext output.
* EVP_DecryptUpdate can be called multiple times if necessary
*/
if(!EVP_DecryptUpdate(ctx, plaindata, &len, cipherdata, cipherdata_len))
cryptoHandleErrors();
plaindata_len = len;
/* Set expected tag value. Works in OpenSSL 1.0.1d and later */
if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, tag))
cryptoHandleErrors();
/*
* Finalise the decryption. A positive return value indicates success,
* anything else is a failure - the plaintext is not trustworthy.
*/
ret = EVP_DecryptFinal_ex(ctx, plaindata + len, &len);
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
if(ret > 0) {
/* Success */
plaindata_len += len;
return plaindata_len;
} else {
/* Verify failed */
return -1;
}
}