トップページ – アルゴリズムとデータ構造編 – 【その他のアルゴリズム】第3章
問題① XOR暗号を、平文が整数でなく、文字列となるように実装してください。
1文字ずつ取り出し、1バイト単位で XOR演算を行えば、平文が文字列でも適用できます。
#include <stdio.h>
#include <string.h>
static void xor_encryption(char* str, size_t len, int key);
static void print(const char* str, size_t len);
int main(void)
{
char data[256];
char buf[32];
int key;
( "元の値を入力してください。" );
puts( data, sizeof(data), stdin );
fgets
( "鍵となる値を入力してください。" );
puts( buf, sizeof(buf), stdin );
fgets( buf, "%d", &key );
sscanf
size_t len = strlen( data );
( data, len, key );
xor_encryption( "暗号結果は次のようになりました。" );
puts( data, len );
print
( data, len, key );
xor_encryption( "復号結果は次のようになりました。" );
puts( data, len );
print
return 0;
}
/*
XOR暗号
引数:
str: 暗号化(または復号化) する文字列。
len: 引数str の文字列の長さ。
key: 鍵。
引数str の内容が直接変更される。
*/
void xor_encryption(char* str, size_t len, int key)
{
for( size_t i = 0; i < len; ++i ){
[i] ^= key;
str}
}
/*
文字列出力
引数:
str: 文字列。
len: 引数str の文字列の長さ。
*/
void print(const char* str, size_t len)
{
for( size_t i = 0; i < len; ++i ){
( "%c", str[i] );
printf}
( "\n" );
printf}
実行結果:
元の値を入力してください。
abcde
鍵となる値を入力してください。
123
暗号結果は次のようになりました。
q
復号結果は次のようになりました。
abcde
本編でも触れたように、暗号化によって、暗号文の途中に ‘\0’ ができてしまう可能性があるので、結果を見るときにいは、print関数のように1文字ずつ出力しています。
問題② シーザ暗号の一種として ROT13 と呼ばれる暗号アルゴリズムがあります。これは、平文に含まれるアルファベットを、辞書順で 13文字ずらし、「Z (z)」を超えてしまったら「A (a)」に戻ってくるルールになっています。これを実装してください。
#include <stdio.h>
#include <string.h>
static void rot13_encryption(char* str, size_t len);
static void rot13_decryption(char* str, size_t len);
int main(void)
{
char data[256];
( "元の文字列を入力してください。" );
puts( data, sizeof(data), stdin );
fgets
size_t len = strlen( data );
( data, len );
rot13_encryption( "暗号結果は次のようになりました。" );
puts( "%s\n", data );
printf
( data, len );
rot13_decryption( "復号結果は次のようになりました。" );
puts( "%s\n", data );
printf
return 0;
}
/*
ROT13 による暗号化
引数:
str: 暗号化する文字列。
len: 引数str の文字列の長さ。
引数str の内容が直接変更される。
*/
void rot13_encryption(char* str, size_t len)
{
for( size_t i = 0; i < len; ++i ){
int c = str[i]; // 0x7f でオーバーフローしないように int型変数へ代入
// a~z, A~Z 以外は無視
if( 'a' <= c && c <= 'z' ){
+= 13;
c if( c > 'z' ){
= 'a' + (c - 'z' - 1);
c }
}
else if( 'A' <= c && c <= 'Z' ){
+= 13;
c if( c > 'Z' ){
= 'A' + (c - 'Z' - 1);
c }
}
[i] = c;
str}
}
/*
ROT13 による復号化
引数:
str: 復号化する文字列。
len: 引数str の文字列の長さ。
引数str の内容が直接変更される。
*/
void rot13_decryption(char* str, size_t len)
{
for( size_t i = 0; i < len; ++i ){
int c = str[i]; // 0x7f でオーバーフローしないように int型変数へ代入
// a~z, A~Z 以外は無視
if( 'a' <= c && c <= 'z' ){
-= 13;
c if( c < 'a' ){
= 'z' - ('a' - c - 1);
c }
}
else if( 'A' <= c && c <= 'Z' ){
-= 13;
c if( c < 'A' ){
= 'Z' - ('A' - c - 1);
c }
}
[i] = c;
str}
}
実行結果:
元の文字列を入力してください。
abyz012ABYZ
暗号結果は次のようになりました。
nolm012NOLM
復号結果は次のようになりました。
abyz012ABYZ
ASCIIコードを前提として、‘a’~‘z’ と ‘A’~‘Z’ だけを取り扱うように実装しています。char型のまま取り扱うと、+13 したときに上限値(127) を超えてしまうため注意が必要です。
さて、この例のように、暗号化と復号化の関数を分けて実装した人は多いと思いますが、実は暗号化の関数が、そのまま復号化にも使えます。main関数の復号化のところだけ修正します。
int main(void)
{
char data[256];
( "元の文字列を入力してください。" );
puts( data, sizeof(data), stdin );
fgets
size_t len = strlen( data );
( data, len );
rot13_encryption( "暗号結果は次のようになりました。" );
puts( "%s\n", data );
printf
( data, len );
rot13_encryption( "復号結果は次のようになりました。" );
puts( "%s\n", data );
printf
return 0;
}
今度は復号化のところでも、rot13_encryption関数を使っています。このときの実行結果は次のようになります。
実行結果:
元の文字列を入力してください。
abyz012ABYZ
暗号結果は次のようになりました。
nolm012NOLM
復号結果は次のようになりました。
abyz012ABYZ
このように、正しく復号化できました。
なぜこうなるかというと、ROT13 の以下の特性があるからです。
そして、アルファベットは全部で 26文字なのが決め手となります。13文字というのはちょうど半分なので、2回繰り返せば元の位置に戻ってくるわけです。
’2017/12/23 問題①の解答例の途中から、ページ内容が途切れて無くなっていたのを修復。
’2015/2/21 サンプルプログラムで、ファイルスコープでよい関数に static を付加。
’2012/5/25 新規作成。
Programming Place Plus のトップページへ
はてなブックマーク に保存 | Pocket に保存 | Facebook でシェア |
X で ポスト/フォロー | LINE で送る | noteで書く |
RSS | 管理者情報 | プライバシーポリシー |