課題,シーザー暗号でファイルのデータを暗号化及び復号化する

スポンサーリンク

課題 1

C言語,シーザー暗号でファイルのデータを暗号化及び復号化する

自分への課題 1

「シーザー暗号を使用してデータを暗号化、復号化するプログラムをC言語で書け。」

鍵の値は0~999までの範囲とする。

暗号化する場合は平文用のデータファイルを読み込み、暗号化した後、暗号文用のデータファイルに書き込むこと。

復号化する場合は暗号文用のデータファイルを読み込み、復号化した後、平文用のデータファイルに書き込むこと。

ファイル名や鍵の値は、標準入力から指定できるようにすること。

スポンサーリンク

平文ファイル

以下は、今回使用する平文のファイル plain.txt です。

このファイルを暗号化や復号化に利用します。

His name is John.
His assets are steadily increasing.
He keeps working quietly to achieve his goals.
スポンサーリンク

プログラム

以下は、シーザー暗号でファイルのデータを暗号化、または復号化するプログラム、caesar_cipher.c です。

// include
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

// preprocessor
#define FILENAME_LIMIT 256		// ファイル名の最大長
#define DATA_MAX 1024			// ファイル読込データの最大長
#define CAESAR_ENCRYPTION 1		// 暗号化
#define CAESAR_DECRYPTION 2		// 復号化
#define EXCLUDE_LF 0			// 改行コードを除く
#define INCLUDE_LF 1			// 改行コードを含める

// prototype
int CreateCiphertext(char *plaintext, char *ciphertext, int key);
int CreateDecryption(char *ciphertext, char *plaintext, int key);
int CheckProc(char *ciphertext, char *plaintext, int *key);
int GetStdin(char *rtmp, size_t size, int mode);
int ReadFileData(char *filename, char *data);
int WriteFileData(char *filename, char *data);

// main
int main(void)
{
	char ciphertext[256] = "";
	char plaintext[256] = "";
	int key;
	int proc_num;
	int ret;
	
	// 処理を選択(標準入力)
	proc_num = CheckProc(ciphertext, plaintext, &key);
	if (proc_num == -1) {
		printf("ERROR,CheckProc(),ret=%d\n", proc_num);
		exit(EXIT_FAILURE);
	}
	
	// 暗号化
	if (proc_num == CAESAR_ENCRYPTION) {
		ret = CreateCiphertext(plaintext, ciphertext, key);
		if (ret == -1) {
			printf("ERROR,CreateCiphertext(),ret=%d\n", ret);
			exit(EXIT_FAILURE);
		}
		printf("暗号文を作成しました\n");
	}
	
	// 復号化
	else if (proc_num == CAESAR_DECRYPTION) {
		ret = CreateDecryption(ciphertext, plaintext, key);
		if (ret == -1) {
			printf("ERROR,CreateDecryption(),ret=%d\n", ret);
			exit(EXIT_FAILURE);
		}
		printf("復号文を作成しました\n");
	}
	
	return 0;
}

// ==========================================
// @brief  シーザー暗号で平文のファイルを
// @brief  暗号文のファイルに変換する.
// @param  plaintext  [in],平文のファイル名
// @param  ciphertext [in],暗号文のファイル名
// @param  key        [in],鍵
// @return 0  成功
// @return -1 エラー
// @note   無し
// ==========================================
int CreateCiphertext(char *plaintext, char *ciphertext, int key)
{
	char rtmp[DATA_MAX] = "";
	char data[DATA_MAX] = "";
	int len;
	int i;
	
	// 平文を読込
	len = ReadFileData(plaintext, rtmp);
	if (len == -1) {
		printf("ERROR,ReadFileData(),ret=%d\n", len);
		return -1;
	}
	
	// 暗号文に変換
	for (i = 0; i < len; i++) {
		data[i] = rtmp[i] + key;
	}
	
	// 暗号文を書込
	len = WriteFileData(ciphertext, data);
	if (len == -1) {
		printf("ERROR,WriteFileData(),ret=%d\n", len);
		return -1;
	}
	
	return 0;
}

// ==========================================
// @brief  シーザー暗号で暗号文のファイルを
// @brief  平文のファイルに変換する.
// @param  ciphertext [in],暗号文のファイル名
// @param  plaintext  [in],平文のファイル名
// @param  key        [in],鍵
// @return 0  成功
// @return -1 エラー
// @note   無し
// ==========================================
int CreateDecryption(char *ciphertext, char *plaintext, int key)
{
	char rtmp[DATA_MAX] = "";
	char data[DATA_MAX] = "";
	int len;
	int i;
	
	// 暗号文を読込
	len = ReadFileData(ciphertext, rtmp);
	if (len == -1) {
		printf("ERROR,ReadFileData(),ret=%d\n", len);
		return -1;
	}
	
	// 復号文に変換
	for (i = 0; i < len; i++) {
		data[i] = rtmp[i] - key;
	}
	
	// 復号文を書込
	len = WriteFileData(plaintext, data);
	if (len == -1) {
		printf("ERROR,WriteFileData(),ret=%d\n", len);
		return -1;
	}
	
	return 0;
}

// ===========================================
// @brief  条件を標準入力で入力する
// @param  ciphertext [out],暗号文のファイル名
// @param  plaintext  [out],平文のファイル名
// @param  key        [out],鍵
// @return proc_num 1:暗号化 2:復号化
// @return -1       エラー
// @note   無し
// ===========================================
int CheckProc(char *ciphertext, char *plaintext, int *key)
{
	char rtmp[256] = "";
	int proc_num;
	int mode;
	int len;
	int i;
	
	// 処理を選択
	printf("実行する処理を選択してください\n");
	printf("1:暗号化  2:復号化\n");
	printf("> ");
	mode = EXCLUDE_LF;	// モード:CRLFを除外
	len = GetStdin(rtmp, sizeof(rtmp) - 1, mode);
	if (len == -1) {
		printf("ERROR,GetStdin(),ret=%d\n", len);
		return -1;
	}
	if (len != 1) {
		printf("ERROR,1文字の数字のみを入力してください\n");
		return -1;
	}
	if (rtmp[0] != '1' && rtmp[0] != '2') {
		printf("ERROR,1か2のどちらかを入力してください\n");
		return -1;
	}
	printf("\n");
	
	// 暗号化の場合
	if (atoi(rtmp) == CAESAR_ENCRYPTION) {
		proc_num = CAESAR_ENCRYPTION;
	}
	// 復号化の場合
	else if (atoi(rtmp) == CAESAR_DECRYPTION) {
		proc_num = CAESAR_DECRYPTION;
	}
	
	// 鍵を入力
	printf("鍵を数値(0~999の範囲)で入力してください\n");
	printf("> ");
	mode = EXCLUDE_LF;	// モード:CRLFを除外
	len = GetStdin(rtmp, sizeof(rtmp) - 1, mode);
	if (len == -1) {
		printf("ERROR,GetStdin(),ret=%d\n", len);
		return -1;
	}
	if (len > 3) {
		printf("数値は最大3桁(0~999の範囲)で入力してください\n");
		return -1;
	}
	for (i = 0; i < len; i++) {
		if (rtmp[i] < '0' && rtmp[i] > '9') {
			printf("ERROR,数値を入力してください\n");
			return -1;
		}
	}
	*key = atoi(rtmp);
	printf("\n");
	
	// 暗号化の場合
	if (proc_num == CAESAR_ENCRYPTION) {
		printf("暗号化します\n");
		printf("ファイル名(平文)を入力してください\n");
		printf("> ");
		mode = EXCLUDE_LF;	// モード:CRLFを除外
		len = GetStdin(rtmp, sizeof(rtmp) - 1, mode);
		if (len == -1) {
			printf("ERROR,GetStdin(),ret=%d\n", len);
			return -1;
		}
		strncpy(plaintext, rtmp, FILENAME_LIMIT - 1);
		printf("\n");
		
		printf("ファイル名(暗号文)を入力してください\n");
		printf("> ");
		mode = EXCLUDE_LF;	// モード:CRLFを除外
		len = GetStdin(rtmp, sizeof(rtmp) - 1, mode);
		if (len == -1) {
			printf("ERROR,GetStdin(),ret=%d\n", len);
			return -1;
		}
		strncpy(ciphertext, rtmp, FILENAME_LIMIT - 1);
		printf("\n");
	}
	
	// 復号化の場合
	else if (proc_num == CAESAR_DECRYPTION) {
		printf("復号化します\n");
		printf("ファイル名(暗号文)を入力してください\n");
		printf("> ");
		mode = EXCLUDE_LF;	// モード:CRLFを除外
		len = GetStdin(rtmp, sizeof(rtmp) - 1, mode);
		if (len == -1) {
			printf("ERROR,GetStdin(),ret=%d\n", len);
			return -1;
		}
		strncpy(ciphertext, rtmp, FILENAME_LIMIT - 1);
		printf("\n");
		
		printf("ファイル名(平文)を入力してください\n");
		printf("> ");
		mode = EXCLUDE_LF;	// モード:CRLFを除外
		len = GetStdin(rtmp, sizeof(rtmp) - 1, mode);
		if (len == -1) {
			printf("ERROR,GetStdin(),ret=%d\n", len);
			return -1;
		}
		strncpy(plaintext, rtmp, FILENAME_LIMIT - 1);
		printf("\n");
	}
	
	printf("-------------------------------------\n");
	printf("ファイル名(平文)\n> [%s]\n", plaintext);
	printf("ファイル名(暗号文)\n> [%s]\n", ciphertext);
	printf("鍵\n> [%d]\n", *key);
	printf("-------------------------------------\n");
	printf("\n");
	
	return proc_num;
}

// ================================================
// @brief  標準入力で入力したデータを変数に格納する
// @param  rtmp [out],入力データ
// @param  size [in],読込時の上限サイズ
// @param  mode [out],モード
// @return len 格納したデータの長さ
// @return -1  エラー
// @note   モード:EXCLUDE_LF(改行コードを除く)
// @note   モード:INCLUDE_LF(改行コードを含める)
// ================================================
int GetStdin(char *rtmp, size_t size, int mode)
{
	char *cp;
	size_t st_i;
	int len;
	
	memset(rtmp, '\0', size);
	cp = fgets(rtmp, size, stdin);
	if (cp == NULL) {
		printf("ERROR,fgets\n");
		return -1;
	}
	len = 0;
	for (st_i = 0; st_i < size; st_i++) {
		if (rtmp[st_i] == 0x0d || rtmp[st_i] == 0x0a) {
			if (mode == EXCLUDE_LF) {
				rtmp[st_i] = '\0';
				break;
			}
			else if (mode == INCLUDE_LF) {
				st_i++;
				len++;
				if (rtmp[st_i] == 0x0d || rtmp[st_i] == 0x0a) {
					st_i++;
					len++;
				}
				rtmp[st_i] = '\0';
				break;
			}
		}
		len++;
	}
	
	return len;
}

// ====================================
// @brief  ファイルからデータを読み込む
// @param  filename [in],ファイル名
// @param  data     [out],読込データ
// @return len 読み込んだデータの長さ
// @return -1  エラー
// @note   無し
// ====================================
int ReadFileData(char *filename, char *data)
{
	int len;
	int ret;
	int fd;
	
	if ((fd = open(filename, O_RDONLY)) == -1) {
		perror("open");
		return -1;
	}
	
	if ((len = read(fd, data, DATA_MAX - 1)) == -1) {
		perror("read");
		close(fd);
		return -1;
	}
	
	if ((ret = close(fd)) == -1) {
		perror("close");
		return -1;
	}
	
	return len;
}

// ==================================
// @brief  ファイルにデータを書き込む
// @param  filename [in],ファイル名
// @param  data     [in],書込データ
// @return len 書き込んだデータの長さ
// @return -1  エラー
// @note   無し
// ==================================
int WriteFileData(char *filename, char *data)
{
	int len;
	int ret;
	int fd;
	
	if ((fd = open(filename, O_RDWR | O_TRUNC | O_CREAT,
				   S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1) {
		perror("open");
		return -1;
	}
	
	len = strlen(data);
	if (((ret = write(fd, data, len)) == -1) || (ret != len)) {
		perror("write");
		close(fd);
		return -1;
	}
	fsync(fd);
	
	if ((ret = close(fd)) == -1) {
		perror("close");
		return -1;
	}
	
	return len;
}
スポンサーリンク

実行結果

以下は、プログラム caesar_cipher.c を実行しています。

今回は、平文データのファイル名を「plain.txt」、暗号文データのファイル名を「crypt.txt」として実行しています。

***@ubuntu:~/***/test/c$ 
***@ubuntu:~/***/test/c$ gcc -Wall -Wextra caesar_cipher.c -o caesar_cipher
***@ubuntu:~/***/test/c$ 
***@ubuntu:~/***/test/c$ 
***@ubuntu:~/***/test/c$ cat plain.txt
His name is John.
His assets are steadily increasing.
He keeps working quietly to achieve his goals.
***@ubuntu:~/***/test/c$ 
***@ubuntu:~/***/test/c$ 
***@ubuntu:~/***/test/c$ ./caesar_cipher
実行する処理を選択してください
1:暗号化  2:復号化
> 1

鍵を数値(0~999の範囲)で入力してください
> 123

暗号化します
ファイル名(平文)を入力してください
> plain.txt

ファイル名(暗号文)を入力してください
> crypt.txt

-------------------------------------
ファイル名(平文)
> [plain.txt]
ファイル名(暗号文)
> [crypt.txt]
鍵
> [123]
-------------------------------------

暗号文を作成しました
***@ubuntu:~/***/test/c$ 
***@ubuntu:~/***/test/c$ 
***@ubuntu:~/***/test/c$ hexdump -C plain.txt
00000000  48 69 73 20 6e 61 6d 65  20 69 73 20 4a 6f 68 6e  |His name is John|
00000010  2e 0a 48 69 73 20 61 73  73 65 74 73 20 61 72 65  |..His assets are|
00000020  20 73 74 65 61 64 69 6c  79 20 69 6e 63 72 65 61  | steadily increa|
00000030  73 69 6e 67 2e 0a 48 65  20 6b 65 65 70 73 20 77  |sing..He keeps w|
00000040  6f 72 6b 69 6e 67 20 71  75 69 65 74 6c 79 20 74  |orking quietly t|
00000050  6f 20 61 63 68 69 65 76  65 20 68 69 73 20 67 6f  |o achieve his go|
00000060  61 6c 73 2e 0a                                    |als..|
00000065
***@ubuntu:~/***/test/c$ 
***@ubuntu:~/***/test/c$ 
***@ubuntu:~/***/test/c$ hexdump -C crypt.txt
00000000  c3 e4 ee 9b e9 dc e8 e0  9b e4 ee 9b c5 ea e3 e9  |................|
00000010  a9 85 c3 e4 ee 9b dc ee  ee e0 ef ee 9b dc ed e0  |................|
00000020  9b ee ef e0 dc df e4 e7  f4 9b e4 e9 de ed e0 dc  |................|
00000030  ee e4 e9 e2 a9 85 c3 e0  9b e6 e0 e0 eb ee 9b f2  |................|
00000040  ea ed e6 e4 e9 e2 9b ec  f0 e4 e0 ef e7 f4 9b ef  |................|
00000050  ea 9b dc de e3 e4 e0 f1  e0 9b e3 e4 ee 9b e2 ea  |................|
00000060  dc e7 ee a9 85                                    |.....|
00000065
***@ubuntu:~/***/test/c$ 
***@ubuntu:~/***/test/c$ 
***@ubuntu:~/***/test/c$ rm plain.txt
***@ubuntu:~/***/test/c$ 
***@ubuntu:~/***/test/c$ 
***@ubuntu:~/***/test/c$ ./caesar_cipher
実行する処理を選択してください
1:暗号化  2:復号化
> 2

鍵を数値(0~999の範囲)で入力してください
> 123

復号化します
ファイル名(暗号文)を入力してください
> crypt.txt

ファイル名(平文)を入力してください
> plain.txt

-------------------------------------
ファイル名(平文)
> [plain.txt]
ファイル名(暗号文)
> [crypt.txt]
鍵
> [123]
-------------------------------------

復号文を作成しました
***@ubuntu:~/***/test/c$ 
***@ubuntu:~/***/test/c$ 
***@ubuntu:~/***/test/c$ cat plain.txt
His name is John.
His assets are steadily increasing.
He keeps working quietly to achieve his goals.
タイトルとURLをコピーしました