理系学生日記

おまえはいつまで学生気分なのか

レイルフェンス暗号

思い出した!この日ちゃんと生きてたよ!!!


ぼくは今、暗号系のお話を読んでいる。たぶん分かる人には分かるんだけども、暗号のノンフィクションみたいなやつです。上下巻わかれてるやつ。まだ半分くらい、しかも上巻の半分くらいしか読んでないけども。


それでですね、その上巻の半分くらい読んだ中の1/4くらいで、レイルフェンス暗号とか出てきた。なんかクソ簡単ぽいので、とりあえずエンコードするヤツつくってた。本に載ってるのはわりかし簡単なレイルフェンス暗号で、秘密鍵はたぶんフェンス数だと思うのですが、じつはもうちょっと複雑で、何文字を一緒にするかというのも秘密鍵にできるぽい(ref:暗号化アルゴリズム(1):19世紀より前の暗号)。

sub encode_rail_fence {
    my ($plain, $fence, $length) = @_;
    $plain =~ s/\W+//g;

    my (@words, $cipher);
    my @chars = split //, $plain;
    push @words, join '', splice @chars, 0, $length while (@chars);

    my $cipher;
    for my $fence_no ( 0 .. $fence - 1 ) {
	$cipher .= join '', @words[ grep { $_ % $fence == $fence_no } 0 .. @words ];
    }
    $cipher;
}

これ使うと、

my $plain = 'THY SECRET IS THY PRISONER; IF THOU LET IT GO, THOU ART A PRISONER TO IT';

とかいう文字列が、

 print encode_rail_fence( $plain, 2, 1 ), "\n";

とかすると、

TYERTSHPIOEITOLTTOHURARSNROTHSCEITYRSNRFHUEIGTOATPIOETI

みたく暗号化される。$lengthが1だと簡単に復号できるのだけども、$length > 1が秘密鍵になるとわりかしプログラムが複雑になってきて、めんどくて復号用関数つくるのやめた。てか眠かったのです。


シーザー暗号はもっと簡単。とか言って即興で作ったので、じつはちがうかもわからない。愛嬌愛嬌。

sub encode_caeser {
    my ($plain, $offset) = @_;
    $plain =~ s/\W+//g;

    my @alpha = ('a' .. 'z');
    my %map;
    @map{@alpha} = @alpha[ $offset .. $#alpha, 0 .. $offset - 1];

    return join '', map { uc $map{ lc( $_ ) } } split //, $plain;
}

sub decode_caeser {
    my ($cipher, $offset) = @_;

    my @alpha = ('A' .. 'Z');
    my %map;
    @map{@alpha} = @alpha[ -$offset .. -1, 0 .. $#alpha - $offset - 1 ];
    
    return join '', map { lc $map{ $_ } } split //, $cipher;
}


そういうわけで、ぼくはちゃんと生きてたし、この日を無駄にしたわけじゃないよ、というお話でした。