簡易的な暗号 | Programming Place Plus アルゴリズムとデータ構造編【その他のアルゴリズム】 第3章

トップページアルゴリズムとデータ構造編

この章の概要 🔗

この章の概要です。


暗号化 🔗

暗号化とは、データを第三者に解読されないように変換することをいいます。逆に、暗号化されたデータを、元の形式に戻すことを復号化といいます。

また、暗号化されていない元のデータを平文(ひらぶん、へいぶん)と言い、暗号化されたデータを暗号文といいます。

この章では、暗号のアルゴリズムの中でももっとも基礎的なものを紹介します。非常に基礎的なものであって、現実的にはこの程度の暗号では信頼性は皆無に等しいといえます。ですから、重要なデータを暗号化する目的では使わないようにしてください。信頼性のある暗号化を必要としているのならば、専門家に意見を仰ぐなど、十分に慎重に検討をおこなってください。おそらく自力で暗号化のアルゴリズムを設計するという結論にはならないはずです。

XOR暗号 🔗

XOR暗号は、XOR演算の性質を利用したごく簡単な暗号アルゴリズムです。

XOR演算は、同じ演算を2回繰り返すと、元の値に戻るという性質がありますC言語編第49章参照)。

平文を A、暗号の鍵を B とします。暗号のというのは、暗号アルゴリズムに渡すパラメータのことです。すると、XOR演算を使って A ^ B としてやれば、A とは異なるビットの並びが得られます。これを暗号文 C とします。

XOR の性質を使えば、同じ鍵 B を使って、C ^ B とすることで、暗号文 C を平文 A に戻すことができます。

鍵 B を知っていれば簡単に平文に戻すことができますが、知らなければ簡単には戻せません。そこで、鍵 B を無関係の人間に知られないように管理すれば、秘密を守れるということになります。


では、実際に XOR暗号のプログラムを書いてみます。

#include <stdio.h>

int main(void)
{
    char buf[256];
    int data, key;


    puts( "元の値を入力してください。" );
    fgets( buf, sizeof(buf), stdin );
    sscanf( buf, "%d", &data );

    puts( "鍵となる値を入力してください。" );
    fgets( buf, sizeof(buf), stdin );
    sscanf( buf, "%d", &key );

    data ^= key;
    puts( "暗号結果は次のようになりました。" );
    printf( "%d\n", data );

    data ^= key;
    puts( "復号結果は次のようになりました。" );
    printf( "%d\n", data );

    return 0;
}

実行結果:

元の値を入力してください。
10000
鍵となる値を入力してください。
395
暗号結果は次のようになりました。
9883
復号結果は次のようになりました。
10000


シーザ暗号 🔗

シーザ暗号(カエサル暗号)は、平文の各文字を辞書順に何文字分かずらすことで暗号化を行います

たとえば、平文が「ABC」のとき、5文字ずらすという方式でシーザ暗号を適用すると「FGH」になります。「A」を辞書順(アルファベット順)に 5つずらすと「F」に、「B」は「G」に、「C」は「H」になるということです。

シーザ暗号では、「何文字ずらすのか」の部分が暗号の鍵になります。これを秘密にしておかなければなりません。

シーザ暗号ような暗号化方式は、元の文字を他の文字に置き換えていくことで実現されるので、換字式暗号に分類されます。

では、シーザ暗号のプログラムを試してみましょう。

#include <stdio.h>
#include <string.h>

static void caesar_encryption(char* str, size_t len, int key);

int main(void)
{
    char data[256];
    char buf[32];
    int key;


    puts( "元の文字列を入力してください。" );
    fgets( data, sizeof(data), stdin );

    puts( "鍵となる値を入力してください。" );
    fgets( buf, sizeof(buf), stdin );
    sscanf( buf, "%d", &key );

    size_t len = strlen( data );

    caesar_encryption( data, len, key );
    puts( "暗号結果は次のようになりました。" );
    printf( "%s\n", data );

    caesar_encryption( data, len, -key );
    puts( "復号結果は次のようになりました。" );
    printf( "%s\n", data );

    return 0;
}

/*
    シーザ暗号

    引数:
        str:    暗号化(または復号化) する文字列。
        len:    引数str の文字列の長さ。
        key:    鍵。ずらす量を指定。

    引数str の内容が直接変更される。
*/
void caesar_encryption(char* str, size_t len, int key)
{
    for( size_t i = 0; i < len; ++i ){
        str[i] += key;
    }
}

実行結果:

元の文字列を入力してください。
acvky
鍵となる値を入力してください。
3
暗号結果は次のようになりました。
dfyn|
復号結果は次のようになりました。
acvky

caesar_encryption関数は、暗号化と復号化を兼ねています。実引数key の符号を反転させれば済むからです。

caesar_encryption関数の第2引数に文字列の長さを渡していますが、ここには平文のときの長さを渡すように注意が必要です。暗号化によって、平文の途中の文字が ‘\0’ に置き換わる可能性があるため、C言語では文字列の終わりと認識してしまい、平文と暗号文の長さが不一致になる可能性があるからです。

まとめ 🔗

XOR暗号にせよ、シーザ暗号にせよ、非常に簡易的なアルゴリズムです。最初に書いたように、重要なデータの暗号化に使おうとは思わないでください。


練習問題 🔗

問題① XOR暗号を、平文が整数でなく、文字列となるように実装してください。

問題② シーザ暗号の一種として ROT13 と呼ばれる暗号アルゴリズムがあります。これは、平文に含まれるアルファベットを、辞書順で 13文字ずらし、「Z (z)」を超えてしまったら「A (a)」に戻ってくるルールになっています。これを実装してください。


解答ページはこちら


参考リンク 🔗


更新履歴 🔗

 サンプルプログラムで、ファイルスコープでよい関数に static を付加。

 新規作成。



前の章へ (第2章 ランダムシャッフル)

次の章へ (第4章 マージのアルゴリズム)

アルゴリズムとデータ構造編のトップページへ

Programming Place Plus のトップページへ



はてなブックマーク に保存 Pocket に保存 Facebook でシェア
X で ポストフォロー LINE で送る noteで書く
rss1.0 取得ボタン RSS 管理者情報 プライバシーポリシー
先頭へ戻る