shimxmemo

メモをのこすよ!

数字6桁パスワードのハッシュ値の総当たり、Perlでも約0.25秒で終わるよ

タイトルウソです。もっとかかりましたすみません。

 

徳丸浩の雑記帳: 数字6桁パスワードのハッシュ値の総当たり、PHPなら約0.25秒で終わるよ

を読んで、Perlでも実装してみた。

まあPHPとほとんど変わらないんですけれども。

今回はマルチプロセスの復習がてら実装。

環境

# OS
FreeBSD 9.1-RELEASE-p9 amd64
# CPU
Intel Xeon E312xx (Sandy Bridge)
# Perl
5.8.9

さくらのスタンダードプランです。はい。

コード

#!/usr/bin/perl

use common::sense;

use Getopt::Long;
use Digest::MD5 qw/md5_hex/;
use Parallel::ForkManager;
use Time::HiRes qw/time/;

GetOptions(
    's|salt=s'    => \my $salt,
    'hs|hash=s'   => \my $hash,
    'p|process=i' => \my $process,
    'verbose'     => \my $verbose,
);

my $max_num = 1000000;
$process ||= 2;

my $start_time = time;
main();
my $exec_time = time - $start_time;
print 'TOTAL_EXEC_TIME: ' . $exec_time . "\n";

exit;


sub main {
    my $current = 0;
    my $pm      = Parallel::ForkManager->new( $process );

    do {
        warn sprintf("parallel: %s process\n", $process);

        $pm->run_on_start(
            sub {
                my ($pid, $ident) = @_;
                warn sprintf("%s starts\n", $ident);
            }
        );

        $pm->run_on_finish(
            sub {
                my ($pid, $exit_code, $ident, $exit_signal, $core_dump, $data) = @_;
                $current++;
                warn sprintf("%s completes.(%d/%d)\n", $ident, $current, $process);
                warn sprintf("  sec : %s\n", $$data) if defined $data;# must Parallel::ForkManager over v0.7.6
            }
        );
    } if $verbose;

    for (my $start = 0; $start < $process; $start++) {
        $pm->start($start) and next;# parent go next

        my $child_start_time = time;
        _search_hash($start, $process);
        my $child_exec_time  = time - $child_start_time;

        $pm->finish(0, \$child_exec_time);
    }
    $pm->wait_all_children;

    return undef;
}

sub _search_hash {
    my ($start, $step) = @_;

    for ( my $i = $start; $i < $max_num; $i += $step) {
        my $pass = sprintf("%06d", $i);
        next if md5_hex($salt . '$' . $pass) ne $hash;

        # match
        my $time = time - $start_time;
        print sprintf("Solved: %s %s\n", $pass, $time);
    }

    return undef;
}

1;

Parallel::ForkManager 使って並行ダウンローダ作った - 理系学生日記

のコードを丸コピ…。

実行

[sv] $ perl ./jal.pl -p 4 -s hoge -hs 4b364677946ccf79f841114e73ccaf4f -v
parallel: 4 process
0 starts
1 starts
2 starts
3 starts
Solved: 567890 0.186630010604858
2 completes.(1/4)
  sec : 0.386913061141968
1 completes.(2/4)
  sec : 0.523470878601074
3 completes.(3/4)
  sec : 0.457498073577881
0 completes.(4/4)
  sec : 0.597269058227539
TOTAL_EXEC_TIME: 0.604266166687012

ぐはっ、思ったよりかかるな…共用サーバだから仕方ないか。

同じサーバで徳丸先生のコードを実行してみる。

f:id:shimx:20140210185838p:plain

おんなじぐらいか、Perlのがちょい遅いぐらいか。

同じようなコードの書き方でやったら同じぐらいになるかな?

という感じでした。

 

6桁の数字なら

パスワード忘れたよ!>キューに入れる>ワーカーが総当り>メールでパスワードを送信(この間わずか1秒)

が可能ですね!