手頃で高速でマルチコアに強そうという理由でGo言語を使ってみた結果、1秒間に18万パスワードをトライできる性能となりました。数字7桁のパスワードなら1分、8桁でも遅くとも10分で突破できます。
パスワードトライ中、全CPUフルに使い切ってます!
goルーチンを使って、1,2,3,4,5・・・と増やしてみたところ、Core i5の2コア4ハイパースレッディングでは、3が最も速いという結果となりました。ただ、最速でも1スレッドの2倍弱にしかなりませんでした。
そもそも、今回のプログラムは無駄が多いので、パスワードトライに特化してメモリの動的確保を0にすれば、更に10倍くらい速くもできるはず。
GPUをうまく使えば、飛躍的な高速化ができるかも?
アルファベット小文字+数字の36種類使ったパスワードの場合、数字のみ8桁の10の8乗と比較し、10の12.4乗と1万倍時間がかかります。10万分=70日=2ヶ月ちょっと、そこそこかかりますが、超重要なファイルであれば待てない時間じゃないですね。
パソコンを動かしっぱなしにするのは困る場合、クラウドを使うのも手です。さくらのクラウド、仮想1コアならなんと1時間9円で借りられます。
100コア借りて、仮に同じ性能がでれば1000分、17時間で結果が得られて、15,300円。(実性能を測ってみました、追記)
仮想20コアだと割安です。20コアを5台借りた場合、13,005円!(追記、そう単純ではありませんでした)
無限にアタックできてしまうZIPファイルなどにかけるパスワード、少なくとも20桁くらいにはしておきたいですね。
「強いパスワードを作ろう「パスワードメーカー」 パスワード付きファイルのリスク計算」
→ さくらのクラウド、実際に仮想20コアを借りてみた編(追記)
ZIPファイルのパスワード取得プログラム(マルチコア対応 Go言語版)
package main import ( "flag" "fmt" "github.com/yeka/zip" "io/ioutil" "log" "os" "time" "sync" ) const LETTERS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" // 62 //const LETTERS = "0123456789abcdefghijklmnopqrstuvwxyz" // 36 //const LETTERS = "0123456789" // 10 func MakePassword(n int) string { plen := 1 nlen := 1 nl := len(LETTERS) for { nlen *= nl if n <= nlen { break } plen += 1 } b := make([]byte, plen) for i := range b { b[i] = LETTERS[n % nl] n /= nl } res := string(b) return res } func Check(wg *sync.WaitGroup, filename string, start int, skip int) { defer wg.Done() var err error r, err := zip.OpenReader(filename) if err != nil { log.Fatal(err) } defer r.Close() f := r.File[0] if !f.IsEncrypted() { println("this zip file is not encrypted") return } fmt.Printf("Check %d\n", start) tstart := time.Now() for i := start; i < 100000000; i += skip { pw := MakePassword(i) //println(pw) f.SetPassword(pw) r2, err := f.Open() if err != nil { print("ignore pw") } buf, err := ioutil.ReadAll(r2) if err != nil { r2.Close() continue } println("Password: " + pw) println(buf) r2.Close() break } println("Check end") tend := time.Now(); fmt.Printf("%fsec\n", tend.Sub(tstart).Seconds()) os.Exit(0) } func main() { ncpu := 3 var wg sync.WaitGroup flag.Parse() filename := flag.Arg(0) for i := 0; i < ncpu; i++ { wg.Add(1) go Check(&wg, filename, i, ncpu) } wg.Wait() }
仮想コア1(=n)のクラウド、3台(=max)で分散させて動かすには、下記のようにオフセット(=off)を指定して動かします。
cloud0$ go run getpassword.go -f test.zip -n 1 -max 3 -off 0 cloud1$ go run getpassword.go -f test.zip -n 1 -max 3 -off 1 cloud2$ go run getpassword.go -f test.zip -n 1 -max 3 -off 2
見つかったらメールでお知らせや、自動的にクラウドを解約しておくなどもプログラムしておくといいですね!