前陣子參加一個 SHA1 暴力破解挑戰,寫了 .NET 程式用上 Parallel.ForEach 平行處理,幾經調校將嘗試次數推上每秒 300 萬次, 64 顆 CPU 齊上 85% 真是壯觀,是次有趣體驗:

這類大量破解運算用 CPU 跑吃力不討好。但決定入手迷你電腦當工作機的那一刻,便註定跟高階顯卡無緣,當時覺得自己用不到圖形顯示不必浪費錢浪費電浪費空間,這一年來發現機器學習、密碼學領域有好多地方 CUDA 平行運算可以派上用場,好像錯過了一些好玩的東西。

我的不專業暴力 SHA1 破解程式配 64 核 CPU 每秒可以算 300 萬筆 SHA1,如果換成目前常見入門獨顯 RTX 4070、甚至消費市場封頂的 RTX 4090,可以跑出什麼樣的成績。最專業的密碼破解還原軟體莫過於 Hashcat,其支援 CUDA,網路上可以找到不少效能測試數字,隨便查了一下得到答案: 4070 參考、4090 參考

顯卡MD5SHA1SHA2-256NVIDIA RTX 407056165.1 MH/s18456.5 MH/s7933.2 MH/sNVIDIA RTX 4090155.9 GH/s50894.8 MH/s21791.7 MH/s 嘿,不多不多,是我 CPU 版程式的 17,000 倍而已 XD (註:RTX 4090 有 16384 個 CUDA 核心)

每秒嘗試次數已知,由組成字元複雜度可推算可能組合(例如:12 碼純數字是 1012,8 碼大小寫混合是 528),若不考慮使用已知密碼表及字典攻擊,嘗試所有可能組合yo做暴力攻擊,二者相除就可以算出所需秒數生出一張不同密碼複雜度與長度所需暴力破解時間,感覺挺有趣的。於是乎我就用 PowerShell 寫了一個,之前可以計算無限位整數的 BigInteger 派上用場,程式範例如下:

$title = 'NVIDIA RTX 4090 / SHA256'

$hitsPerSec = 21791700000; #SHA2-256 21791.7 MH/s https://hashcat.net/forum/thread-11277.html

$complexity = [ordered]@{

'純數字' = '0';

'全大寫/全小寫' = 'A';

'大小寫混合' = 'Aa';

'大小寫+數字' = 'Aa0';

'大小寫+數字+符號' = 'Aa0!';

}

$html = @"

$title $($hitsPerSec.ToString('n0')) 次/秒

$($complexity.Keys | ForEach-Object { "

" })

"@

$units = @('', '萬', '億')

For ($len = 6; $len -lt 25; $len++) {

$html += "

"

$complexity.Keys | ForEach-Object {

$pattern = $complexity.$_

$charCount = 0;

if ($pattern -match '[0-9]') { $charCount += 10; }

if ($pattern -cmatch '[a-z]') { $charCount += 26; }

if ($pattern -cmatch '[A-Z]') { $charCount += 26; }

if ($pattern -match '[^0-9a-zA-Z]') { $charCount += 32; }

#Write-Host $_ $charCount

[bigint]$count = [bigint]::Pow($charCount, $len)

$secs = [bigint]::Divide($count, $hitsPerSec)

if ($secs -lt 60) { $time = "$secs 秒" }

elseif ($secs -lt 3600) { $time = "$([bigint]::Divide($secs, 60)) 分鐘" }

elseif ($secs -lt 86400) { $time = "$([bigint]::Divide($secs,3600)) 小時" }

elseif ($secs -lt 86400 * 365) { $time = "$([bigint]::Divide($secs,86400)) 天" }

else {

$years = [bigint]::Divide($secs, 86400 * 365)

$unitIdx = 0

$unit = $units[$unitIdx]

while ($years -gt 10000 -and $unitIdx -lt $units.Length - 1) {

$years = [bigint]::Divide($years, 10000)

$unit = $units[++$unitIdx]

}

if ($years -gt 100000000) {

$years = $years.ToString('e')

$m = [regex]::Match($years, '(?\d.\d+)e\+(?\d+)')

$years = [float]::Parse($m.Groups['n'].Value).ToString('n2') + ' x 10' + [int]::Parse($m.Groups['t'].Value) + ''

}

else {

$years = $years.ToString('n0')

}

$time = $years + ' ' + $unit + '年'

}

$html += "

"

}

$html += "

"

}

$html += "

長度 $_
$len $time
"

$tempFilePath = [System.IO.Path]::GetTempFileName() + ".html"

$html | Out-File $tempFilePath -Encoding UTF8

Start-Process $tempFilePath

如此,我們就能得到一張「以家用電腦暴力破解不同長度與複雜度密碼 SHA256 所需時間表」(取最大時間,除二約為平均時間):(希望沒計算錯誤 XD)

以當今的硬體算力,八個字元以下的密碼幾乎都像豆腐毫無防禦力;純數字密碼除非加長到 20 碼,不然也像砲灰;當今有一派主張密碼不要強迫混用特殊符號,用多個容易記憶的短單字或縮寫拼裝,讓密碼拉長到 12 到 14 碼,即使只用大小寫無數字,也有 568 年到 153 萬年的強度,混入數字則可再拉高至 4694 年到 1804 萬年;反觀用上大小寫數字加符號的最高複雜度,若只有短短 8 碼,用 4090 跑三天便能破防。 (註:以上數據是假設系統採用最基本的 SHA256 雜湊保存密碼,若專業一點會使用 PBKDF2、Scrypt、Bcrypt、Argon2 等密碼專用雜湊,其計算更耗時,在相同長度及複雜度下可提供更好的防禦效果。參考:密碼要怎麼儲存才安全?該加多少鹽?-科普角度)

短一寸、險一寸,這年頭密碼要安全,愈長愈保險。

A simple PowerShell example to calculate to time required to brute-force crack password hash.