はじめに
AES による暗号化・復号化について。
C による暗号化
tiny-AES-c というものが使える。
#include
#include "aes.h"
#define FILE_PATH 128
#define LINE_SIZE 4096
#define BUFFER_SIZE 4096
int main(int argc, char *argv[])
{
FILE *fp_in, *fp_out;
char *filename, filename_out[FILE_PATH];
char *key_str;
unsigned char key[AES_KEYLEN];
unsigned char iv[AES_BLOCKLEN];
struct AES_ctx ctx;
int i;
if(argc < 3){
printf("usage: encrypt <filename> <key>\n");
return 0;
}
filename = argv[1];
key_str = argv[2];
fp_in = fopen(filename, "r");
if(fp_in == NULL){
printf("error: Can't open file: %s", filename);
return 1;
}
if(strlen(key_str) != AES_KEYLEN){
printf("error: key length must be %d\n", AES_KEYLEN);
return 0;
}
sprintf(filename_out, "%s-encrypted", filename);
fp_out = fopen(filename_out, "wb");
if(fp_out == NULL){
printf("error: Can't open file: %s", filename_out);
fclose(fp_in);
return 1;
}
for(i = 0; i < AES_KEYLEN; i++){
key[i] = key_str[i];
}
srand(time(NULL));
for(i = 0; i < AES_BLOCKLEN; i++){
iv[i] = rand();
}
AES_init_ctx_iv(&ctx, key, iv);
fwrite(iv, sizeof(unsigned char), AES_BLOCKLEN, fp_out);
{
unsigned char line[LINE_SIZE];
unsigned char res[LINE_SIZE];
unsigned char buffer[BUFFER_SIZE];
int rlen0 = 0;
while(fgets(line, sizeof(line), fp_in)){
const int len = strlen(line);
/* If the previous rest exists, add it to the buffer. */
if(rlen0 > 0){
strncpy(buffer, res, rlen0);
buffer[rlen0] = '\0';
}
/* If the sum length does not reach the block size */
if(rlen0 + len < BUFFER_SIZE){
strncpy(&res[rlen0], line, len);
res[rlen0 + len] = '\0';
rlen0 += len;
}else{
int rlen = (rlen0 + len) % BUFFER_SIZE;
int blen;
/* If the current rest exists, save it. */
if(rlen > 0){
strncpy(res, &line[len - rlen], rlen);
res[rlen] = '\0';
line[len - rlen] = '\0';
}
/* write buffer */
strncpy(&buffer[rlen0], line, len - rlen);
blen = rlen0 + len - rlen;
buffer[blen] = '\0';
AES_CBC_encrypt_buffer(&ctx, buffer, blen);
fwrite(buffer, sizeof(unsigned char), blen, fp_out);
rlen0 = rlen;
}
}
if(rlen0 > 0){
const int plen = (BUFFER_SIZE - rlen0) % AES_BLOCKLEN;
int blen;
strncpy(buffer, res, rlen0);
buffer[rlen0] = '\0';
blen = rlen0 + plen;
/* padding */
if(plen > 0)
{
const unsigned char pad = plen;
for(i = rlen0; i < blen; i++){
buffer[i] = pad;
}
}
AES_CBC_encrypt_buffer(&ctx, buffer, blen);
fwrite(buffer, sizeof(unsigned char), blen, fp_out);
}
}
fclose(fp_out);
fclose(fp_in);
return 0;
}
まず、key を任意で決める。iv (initialization vector) を乱数で決めて、iv および暗号化したデータをファイルに書き出す。
参考: Good AES Initialization Vector practice (stackoverflow)
C による復号化
#include
#include "aes.h"
#define FILE_PATH 128
#define BUFFER_SIZE 4096
int main(int argc, char *argv[])
{
FILE *fp_in, *fp_out;
char *filename, filename_out[FILE_PATH];
char *key_str;
unsigned char key[AES_KEYLEN];
unsigned char iv[AES_BLOCKLEN];
unsigned char buffer[BUFFER_SIZE];
struct AES_ctx ctx;
int len;
int i;
if(argc < 3){
printf("usage: decrypt <filename> <key>\n");
return 0;
}
filename = argv[1];
key_str = argv[2];
fp_in = fopen(filename, "rb");
if(fp_in == NULL){
printf("error: Can't open file: %s", filename);
return 1;
}
if(strlen(key_str) != AES_KEYLEN){
printf("error: key length must be %d\n", AES_KEYLEN);
return 0;
}
sprintf(filename_out, "%s-decrypted", filename);
fp_out = fopen(filename_out, "w");
if(fp_out == NULL){
printf("error: Can't open file: %s", filename_out);
fclose(fp_in);
return 1;
}
for(i = 0; i < AES_KEYLEN; i++){
key[i] = key_str[i];
}
fread(iv, sizeof(unsigned char), AES_BLOCKLEN, fp_in);
AES_init_ctx_iv(&ctx, key, iv);
while(len = fread(buffer, sizeof(unsigned char), BUFFER_SIZE, fp_in)){
AES_CBC_decrypt_buffer(&ctx, buffer, BUFFER_SIZE);
for(i = 0; i < len; i++){
if(isprint(buffer[i])){
fprintf(fp_out, "%c", buffer[i]);
}else if(buffer[i] == '\n'){
fprintf(fp_out, "\n");
}
}
}
fclose(fp_out);
fclose(fp_in);
return 0;
}
ファイルを暗号化したときの key を受け取る。ファイルからまず iv を読み込み、暗号化データを読み込みつつ復号化する。
|