Edited at

「数字6桁パスワードのMD5ハッシュ値の総当たり」をGolangでやってみた

More than 3 years have passed since last update.

今更だけど qiita でたまたま目についたので Golang ではどんなものなのかやってみた。

他の言語についてはここから参照されたし。


実行環境

OS: Ubuntu 14.04 LTS

CPU: Intel(R) Core(TM) i7-4510U CPU @ 2.00GHz

言語: go version go1.3 linux/amd64


ソースコード

まずは愚直にやってみたバージョン。

他の言語と比べてもかなりシンプルな方ですね。


bruteforce.go

package main

import (
"crypto/md5"
"fmt"
"os"
"bytes"
"encoding/hex"
)

const NUMMAX = 1000000

func main() {
pw, _ := hex.DecodeString(os.Args[2])

for i := 0; i < NUMMAX; i++ {
sum := md5.Sum([]byte(fmt.Sprintf("%s$%06d", os.Args[1], i)))
if bytes.Equal(pw, sum[:]) {
fmt.Printf("Solved: %06d\n", i)
return
}
}
}



実行結果


shell

$ time go run bruteforce.go hoge 4b364677946ccf79f841114e73ccaf4f

Solved: 567890

real 0m0.566s
user 0m0.540s
sys 0m0.027s


なんとコンパイル込みで約0.56秒でした。

この時点で結構早かったので高速化する気が一気に失せました。。。

ちなみにコンパイルして実行した結果は以下の通り。


shell

$ go build bruteforce.go

$ time ./bruteforce hoge 4b364677946ccf79f841114e73ccaf4f
Solved: 567890

real 0m0.445s
user 0m0.434s
sys 0m0.012s


コンパイルにかかっている時間は0.1秒のようです。

普段Scala使ってるとこのコンパイル速度は驚異的ですね!

続いて、皆さん並列実行版も計測してらっしゃるので、Goroutine版も用意しました。

並列化してもコードはシンプルでいいですね!


bruteforce2.go

package main

import (
"crypto/md5"
"fmt"
"os"
"bytes"
"encoding/hex"
"runtime"
"sync"
)

const NUMMAX = 1000000

func main() {
numCPU := runtime.NumCPU()
runtime.GOMAXPROCS(numCPU)
pw, _ := hex.DecodeString(os.Args[2])
var wg sync.WaitGroup
var once sync.Once
wg.Add(1)

for i := 0; i < numCPU; i++ {
go func(start, step int) {
defer once.Do(wg.Done)
for j := start; j < NUMMAX; j += step {
sum := md5.Sum([]byte(fmt.Sprintf("%s$%06d", os.Args[1], j)))
if bytes.Equal(pw, sum[:]) {
fmt.Printf("Solved: %06d\n", j)
return
}
}
}(i, numCPU)
}

wg.Wait()
}



実行結果


shell

$ go build bruteforce2.go

$ time ./bruteforce2 hoge 4b364677946ccf79f841114e73ccaf4f
Solved: 567890

real 0m0.256s
user 0m0.812s
sys 0m0.028s


0.25秒でした。

個人的にはもっと速度出てほしかったですけど、十分かな?

Ultrabookでこの速度なので、デスクトップとか4コアとかのCPUだともっと早いと思う。


まとめ

Golang で書いたコードは速いし書くのは簡単だし、オススメ