ハッシュ文字列から方式を見分ける実務手順

· 更新日: · · ハッシュ, セキュリティ, パスワード, 既存資産活用, 技術調査

更新履歴(3件・最終更新 2026年08月02日)

この記事に加えた変更の記録です。アーカイブした更新前のバージョンは、DOI付きの固定URLから読めます。

記事の冒頭に「この記事の知識マップ」節を追加しました。本文で扱っている概念とその関係を、要約・図・詳細ページへのリンクにまとめたものです。本文の主張は変えていません。
外部レビュー(1283件)への対応として本文を更新しました。個々の変更内容は、この下の履歴を参照してください。
冒頭と本文に、許可された環境でのみ調査するという注意を追加しました。判定した形式を検証する手順(`hashlib`での照合、`openssl passwd`での再計算)を拡充し、掲載している例が実際に再現できることを手元で確認しています。hashcatのモード番号表、Base64の文字数の読み方、用語ミニ辞書も追加しました。あわせて「NTLM系」としていた箇所を「NTハッシュ(MD4ベース)」に直し、両者を同じものとして扱う誤りを説明する節を新設しました。
初版公開
この記事を引用する(DOI: 10.5281/zenodo.21589772)

この記事はZenodoにアーカイブされています。常に最新版へ解決されるDOIと、いま表示している版に固定されたDOIの両方を下に示します。

小村 豪(2026)「ハッシュ文字列から方式を見分ける実務手順」合同会社小村ソフト. https://doi.org/10.5281/zenodo.21589772 https://staging.comcomponent.com/blog/2026/04/08/000-hash-format-identification/

DOI(最新版)
10.5281/zenodo.21589772
DOI(この版)
10.5281/zenodo.21732787

ログや DB に残っている 5f4dcc3b5aa765d61d8327deb882cf99$2b$12$... のような文字列を見て、「これは何のハッシュか」を判定したい場面はかなりあります。既存システムの移行、認証方式の調査、ログ解析、他社システム連携では、ここで止まることが珍しくありません。

ただ、ここで危ないのは 長さだけで即断すること です。 64 桁の 16 進文字列を見て「SHA-256 ですね」と言い切るのは早すぎます。SHA3-256、SHA-512/256、BLAKE2s-256、BLAKE3 の既定 32-byte 出力でも同じ長さになりえます。逆に、$2b$$argon2id$ のように 接頭辞やパラメータまで含む保存形式 は、文字列だけでかなり高い精度で判定できます。

この記事では、hash という言葉を広めに使い、MD5 / SHA-2 / SHA-3 のようなメッセージダイジェストだけでなく、bcrypt / scrypt / Argon2 / PBKDF2 のような パスワード保存用の文字列表現 も含めて扱います。 内容は 2026 年 4 月時点で公開されている RFC、NIST、Linux crypt(5)、Apache、Django、Spring Security などの公式資料をもとに整理しています。

対象読者は、既存システムの移行、認証方式の調査、ログ解析を担当していて、手元にある「ハッシュらしき文字列」が何なのかを切り分けたい方です。前提知識は、16 進表記と Base64 が何かを知っている程度で足ります。

なお、この記事の手順は 自分たちが管理している環境、または調査を明示的に許可された環境の文字列 に対してのみ使ってください。他人のアカウントのパスワードハッシュを取り出す、権限のないシステムのハッシュを解析するといった行為は、目的が調査であっても正当化されません。後半で挙げる検証コマンドも、テスト用アカウントや自分で作ったサンプルで試すことを前提にしています。

目次

  1. まず結論
  2. 一目で見る判定表
  3. 実務での判定手順
  4. よくある誤判定
  5. 100% 確定したいときの確認順
  6. まとめ
  7. このテーマがつながるサービス
  8. 参考資料

この記事の知識マップ

この記事は、ログやDBに残るハッシュ文字列の方式を見分ける手順を扱っており、bcryptやArgon2のように先頭に方式名を置くMCFやPHC string format系の保存形式は文字列だけでほぼ特定できる一方、プレーンな16進やBase64だけの文字列は長さと文字種から候補を絞ることしかできないと整理しています。sha256crypt・sha512crypt・md5cryptはいずれもcrypt(3)関数の出力形式でSHA-256・SHA-512・MD5を反復適用しており、openssl passwdで同じsaltを与えて再計算すれば形式を検証できます。また64桁の16進はSHA-256だけでなく複数のアルゴリズムが候補になるため長さだけでの断定は避けるべきであり、NTハッシュはMD5ではなくMD4をもとに計算される点でNTLMとも区別すべきだとしています。候補方式が分かったあとはhashcatのモード番号に翻訳して調査を進めます。

ハッシュ形式識別の知識マップハッシュ文字列の判定手がかりとして接頭辞ベースの保存形式であるMCF・PHC string formatと、文字種・長さだけによる推定がどう関係し、crypt(3)系のmd5crypt・sha256crypt・sha512crypt、bcrypt、Argon2などの具体的な形式や、NTハッシュとNTLMの違い、hashcatやopenssl passwdによる検証手段までを示す図利用するの後継利用する利用する利用する利用する利用する利用する利用する利用する原因になり得る防止する利用する利用するで確認できるで確認できるで確認できるで構成できるで構成できるで構成できるで構成できるで構成できるで構成できるで構成できる利用する利用する防止するパスワードハッシュ文字列長さだけによる誤判定crypt(3)MCF(Modular Crypt Format)PHC string formatArgon2bcryptsha256cryptsha512cryptmd5cryptSHA-256SHA-512MD516進表現(hex encoding)NTハッシュMD4NTLMopenssl passwdhashcatPBKDF2scryptLDAPスキームプレフィックス({SHA}等)Base64(RFC 4648)SHA-1

図の実線は常に成り立つ関係、破線は条件付きの関係です(成立条件は詳細ページの各関係の説明に記載)。関係すべての一覧(全27件、根拠・確度つき)と主要概念の定義は知識マップ詳細ページにまとめています。データ: JSON-LD / Turtle

1. まず結論

先に結論だけ短くまとめておきます。

  • 接頭辞や区切りがある保存形式 は、文字列だけでかなり特定しやすいです。 例: $argon2id$..., $2b$..., $5$..., $6$..., {SHA}..., pbkdf2_sha256$...

  • プレーンな 16 進文字列や Base64 だけ では、たいてい「候補を絞る」までです。 例: 32 hex = MD5 かもしれないが、MD4 や NT ハッシュ由来かもしれない

  • 文字種は長さと同じくらい重要 です。 + / = があれば RFC 4648 の Base64 らしい、. が入っていて $ 区切りなら crypt(3) 系らしい、といった見分けが効きます。

  • 100% 確定したいなら文脈が必要 です。 /etc/shadow なのか、.htpasswd なのか、Django の auth_user なのか、Spring Security なのかで話が変わります。

要するに、「文字列だけで特定できる方式」と「文字列だけでは候補群までしか分からない方式」は別物 です。 ここを分けて考えるだけで、調査の進み方が変わります。

2. 一目で見る判定表

表を読む前に、この記事で「形式の名前」として出てくる言葉を 4 つだけ整理しておきます。どれも似た文脈で使われますが、指しているものが違います。

用語 フルスペル 何を指すか
crypt(3) - Unix のパスワードハッシュ 関数 そのもの。C ライブラリの関数名で、man の 3 章(ライブラリ関数)に載っているのでこう書きます
crypt(5) - その関数が読み書きする 文字列フォーマット を説明した man ページ。man の 5 章(ファイル形式)で、$6$salt$hash のような書式はここに載っています
MCF Modular Crypt Format 「先頭に $id$ を置いて方式を示す」書き方の通称。単一の仕様書があるわけではなく、crypt(3) 系の実装が増える中で慣習として固まった呼び名です
PHC string format Password Hashing Competition string format MCF を整理し直した仕様。$argon2id$v=19$m=65536,t=3,p=4$salt$hash のように、バージョンとパラメータの書き方まで決めてあります

ざっくり言うと、crypt(3) は関数、crypt(5) はその出力形式の仕様、MCF はその形式の通称、PHC string format はそれを明文化し直したもの です。以降の表で「PHC string format」「crypt 系」と書いてあるときは、この区別で読んでください。

2.1 接頭辞や形式マーカーでほぼ特定できるもの

表中の「判定の強さ」は、この意味で使っています。

  • : 文字列だけでほぼ特定できる
  • : 候補はかなり絞れるが、実装差異に注意がいる
  • : 長さや見た目だけでは断定できない
見た目の特徴 まず疑う方式 判定の強さ 補足
$argon2id$... Argon2id PHC string format。v=, m=, t=, p= が続くことが多い $argon2id$v=19$m=65536,t=3,p=4$MDEyMzQ1Njc4OWFiY2RlZg$uKZLaN6muIyoyIYr5waqw3y+zaDbe9aLSPj6Ln/rbz4
$argon2i$... Argon2i 同上 $argon2i$v=19$m=65536,t=3,p=4$MDEyMzQ1Njc4OWFiY2RlZg$Kx1koF/7n8EytGJYTS5krh+ag+FlG5ksM4xOsjOSDvo
$argon2d$... Argon2d 同上 $argon2d$v=19$m=65536,t=3,p=4$MDEyMzQ1Njc4OWFiY2RlZg$HLIGA+T1bwK8akx3LGOco+Df+PvxX6cIXhycO7O7t6c
$2a$... / $2b$... / $2y$... bcrypt 2 桁コスト + crypt 系 alphabet $2b$12$9YQ2u/e5Y/ArOnG.gJKxK.0makLATcYLP1q.Nsabzrw7XErYCfoYO
$1$... md5crypt Unix 系の MD5 パスワード保存形式 $1$vA7mQ9xZ$Erz32JUFnZ9991KdU5.N3.
$5$... sha256crypt plain SHA-256 ではない $5$rounds=5000$N3v8Kx2Lq9Rt$uOTla5GAHaRH2aHlUSjkrZUBCuFiahQZ36O/seB39r3
$6$... sha512crypt plain SHA-512 ではない $6$rounds=5000$N3v8Kx2Lq9Rt$6LUcSUAELX3aC/.60pTB.TFLTQi1mOGRCwKqNCqtRSaXjorxj01HJ9oNni97Kci1uDt7a/Kn4t3OS20Dw/.vi1
$7$... scrypt (crypt 系) Linux crypt(5) 系実装で見かける $7$CU..../....k2XAnEHBqQ1Ct2aMXFKNa/$y3Q0e/UlCHacIGWQshgvvz6UIbP.BCja.5BfVWP2Ml8
$y$... yescrypt 新しめの Linux 系で見かける $y$j9T$k2XAnEHBqQ1Ct2aMXFKNa/$OVYXzjlkiQpWT/F1CUE0JrvV4phLY8FB.ofDttnrSQ7
$apr1$... Apache APR1-MD5 .htpasswd でよく見る $apr1$vA7mQ9xZ$ZE64.ohiyK11sPZmtnJZQ.
{SHA}... SHA-1 digest の Base64 表現 Apache / LDAP 系でよく見る {SHA}VBPuJHI7uixaa6LQGWx4s+5GKNE=
{SSHA}... salted SHA-1 LDAP 系 {SSHA}/OczD0GNNkOAUPbYhA3L9fjmcyBCbHVlTWVzYTQyIQ==
{MD5}... / {SMD5}... MD5 / salted MD5 LDAP 系 {MD5}X03MO1qnZdYdgyfeuILPmQ==
{SMD5}fOn1rOv4ZH0OrO/KT9H0fEJsdWVNZXNhNDIh
pbkdf2_sha256$... PBKDF2-HMAC-SHA256 中〜強 Django など、実装が形式名を前置している pbkdf2_sha256$600000$N3v8Kx2Lq9Rt$CLxGB+zTiV1IdOt2y4m9JpaAONzHuRTOd96xKQwRQAs
{bcrypt}$2b$... bcrypt Spring Security の {id} ラッパー付き {bcrypt}$2b$12$9YQ2u/e5Y/ArOnG.gJKxK.0makLATcYLP1q.Nsabzrw7XErYCfoYO
{pbkdf2}... / {scrypt}... 実装ラベル付き方式 中〜強 Spring Security など、アルゴリズム本体よりラッパー形式を見分ける {pbkdf2}sha256$600000$Qmx1ZU1lc2E0MiE$4eNuai1qNkgs1kXz3+tBUMzAexVsSUz9SrQKEhbk0Cw
{scrypt}ln=14,r=8,p=1$Qmx1ZU1lc2E0MiE$xAgBRhXbMtHB1UHUR0br5bI+1XdXWKbwauiFv5VRQBY

この表のポイントは、先頭の数文字に意味がある形式は強い ということです。 とくに $...$ で区切られたものは、Unix crypt(3) / MCF / PHC 系の可能性が高く、長さより先に prefix を見たほうが早い です。

2.2 プレーンな 16 進 / Base64 の長さで候補を絞る表

こちらは prefix なしの「ただの digest 文字列」 を見るときの表です。 :-、空白が混ざる表現は、まず区切りを取り除いて長さを数えます。

生バイト長 16 進文字数 Base64 文字数 (= あり / なし) 主な候補
4 8 8 / 6 CRC32 などのチェックサム cbf43926
16 32 24 / 22 MD5、MD4、NT ハッシュ(MD4 ベース) 5f4dcc3b5aa765d61d8327deb882cf99
20 40 28 / 27 SHA-1、RIPEMD-160 da39a3ee5e6b4b0d3255bfef95601890afd80709
28 56 40 / 38 SHA-224、SHA-512/224、SHA3-224 d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f
32 64 44 / 43 SHA-256、SHA-512/256、SHA3-256、BLAKE2s-256、BLAKE3 の既定 32-byte 出力 e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
48 96 64 / 64 SHA-384、SHA3-384、BLAKE2b-384 38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b
64 128 88 / 86 SHA-512、SHA3-512、BLAKE2b-512、Whirlpool cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e

「Base64 文字数」列の読み方: この列は = によるパディングを 含めた場合 / 省いた場合 の 2 通りを並べています。RFC 4648 の Base64 は 4 文字単位に揃えるため、生バイト長が 3 の倍数でないときだけ、末尾に = が 1〜2 個付きます。JWT や URL 埋め込みではこの = を落とす実装が多いので、同じ digest でも 43 文字と 44 文字の両方がありえます。逆に 48 バイトのように 3 の倍数のときはパディングが発生しないので、64 / 64 と同じ数字が並びます。長さで候補を絞るときは、必ず両方の数字と照らしてください。

ここで大事なのは、長さが一致しても方式は一意に決まらない ことです。 とくに 32 / 64 / 128 桁の 16 進は候補が多く、これだけで断定すると外しやすいです。

2.3 迷いやすい代表例

文字列の見え方 ありがちな即断 実際の見方
5f4dcc3b5aa765d61d8327deb882cf99 MD5 で確定 MD5 っぽいが、MD4 や NT ハッシュ、アプリ固有の MD5 利用もありうる 8846f7eaee8fb117ad06bdd830b7586c
2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824 のような 64 hex SHA-256 で確定 SHA-256 候補ではあるが、SHA3-256 / SHA-512/256 / BLAKE2s-256 / BLAKE3 もありうる e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
$6$rounds=5000$salt$hash SHA-512 の hex 表現 そうではなく sha512crypt という password hash 文字列 $6$rounds=5000$N3v8Kx2Lq9Rt$6LUcSUAELX3aC/.60pTB.TFLTQi1mOGRCwKqNCqtRSaXjorxj01HJ9oNni97Kci1uDt7a/Kn4t3OS20Dw/.vi1
{SHA}VBPuJHI7uixaa6LQGWx4s+5GKNE= 何かの「SHA」 Apache / LDAP 系では Base64 化した SHA-1 digest を指すことが多い {SHA}VBPuJHI7uixaa6LQGWx4s+5GKNE=
{bcrypt}$2b$12$... {bcrypt} という独自方式 Spring Security のラッパー付き bcrypt {bcrypt}$2b$12$9YQ2u/e5Y/ArOnG.gJKxK.0makLATcYLP1q.Nsabzrw7XErYCfoYO

3. 実務での判定手順

ここからは、実際にどう見るかを順番に整理します。 おすすめは prefix → 区切り → 文字種 → 長さ → 文脈 の順です。

3.1 まず先頭の記号を見る

最初の 1 文字から 10 文字くらいで、かなり絞れます。

  • $argon2id$ / $argon2i$ / $argon2d$ Argon2 の PHC string format を強く疑います。構成要素は 2.1 の 列を見ると追いやすいです。

  • $2a$ / $2b$ / $2y$ bcrypt を強く疑います。

  • $1$ / $5$ / $6$ / $7$ / $y$ Unix crypt(3) 系の password hash を疑います。

  • {SHA} / {SSHA} / {MD5} / {SMD5} LDAP / Apache 系の表現を疑います。

  • {bcrypt} / {pbkdf2} / {scrypt} Spring Security のような 実装ラベル付き保存形式 を疑います。

ここでのコツは、「アルゴリズム本体」だけでなく「保存形式」も見る ことです。 たとえば $6$ は「SHA-512 の digest」ではなく、「SHA-512 を使った password hash 文字列」です。ここを取り違えると、その後の調査がずれます。

3.2 区切り文字の数を見る

次に、$, :, {}, ,, = のような区切りを見ます。

  • $ が複数ある パラメータ、salt、hash を一緒に持つ形式を疑います。Argon2、bcrypt、sha256crypt、sha512crypt などが典型です。

  • {name} で始まる LDAP / Spring Security など、方式名を明示したラッパー を疑います。

  • algo:salt:hashalgo$iterations$salt$hash のような形 フレームワークやアプリ固有形式を疑います。Django の pbkdf2_sha256$iterations$salt$hash はその典型です。

区切りが多い文字列ほど、方式を特定しやすい です。 逆に、ただの 16 進や Base64 が 1 塊で置かれているだけだと、かなり曖昧になります。

3.3 文字種を見る

文字種は、長さと同じくらい重要です。

16 進表現

[0-9a-fA-F] だけでできているなら、まずは 16 進表現を疑います。 この場合は 文字数 ÷ 2 = 生バイト長 です。

  • 32 hex → 16 bytes
  • 40 hex → 20 bytes
  • 64 hex → 32 bytes
  • 128 hex → 64 bytes

RFC 4648 の Base64 / Base64url

+ / = があれば、まず普通の Base64 を疑います。 - _ があれば Base64url を疑います。 padding の = が省略されることもあるので、43 / 44, 86 / 88 のような「両方ありうる長さ」を持ちます。

crypt 系の radix64

./ が出てきて、しかも $...$ 区切りなら、普通の Base64 より crypt 系の alphabet を疑うほうが自然です。 bcrypt、sha256crypt、sha512crypt、md5crypt、yescrypt、scrypt などは、この系統の文字集合を使います。

ここは地味ですが、かなり効きます。 . が入っているから壊れた Base64 だ と見てしまうと、bcrypt や crypt(3) 系を見落としやすくなります。

3.4 長さを数える

文字種を見たら、次に長さです。 考え方は単純です。

  • 16 進なら 生バイト長 = 文字数 / 2
  • Base64 なら 文字数 ≒ 4 × ceil(生バイト長 / 3) ただし padding の = が省略されると 0〜2 文字短くなります

この段階で候補を絞ります。 ただし、64 hex を見て SHA-256 で確定、のような飛躍はしない ほうが安全です。

3.5 文脈で確定する

最後に効くのは文脈です。ここで 100% に近づけます。

  • /etc/shadow にある $y$, $6$, $5$, $1$ など Linux の password hash 形式を疑う

  • .htpasswd にある $apr1$, {SHA}, bcrypt など Apache 系を疑う

  • Django の設定や auth_user.password にある pbkdf2_sha256$...argon2$... のような Django 形式を疑う

  • Spring Security の認証テーブルにある {bcrypt}...{pbkdf2}... のような {id} 付き形式を疑う

  • SMB / AD 連携まわりにある 32 hex NT ハッシュ(MD4 ベース)の可能性を強く考える

実務では、文字列そのものだけ見るより、保存元の製品・フレームワーク・設定ファイル名を見るほうが早い 場面が少なくありません。

4. よくある誤判定

4.1 64 hex = SHA-256 と決め打ちする

これはかなりありがちです。 もちろん SHA-256 は有力候補ですが、同じ 32-byte 出力を持つ方式は複数あります。SHA3-256、SHA-512/256、BLAKE2s-256、BLAKE3 の既定出力なども同じ長さです。

長さは候補群を作る材料であって、確定材料ではありません。

4.2 $6$ を plain SHA-512 と誤解する

$6$... は sha512crypt の prefix です。 これは「SHA-512 の hex digest」ではなく、salt や rounds を含む password hash 文字列 です。

同様に、

  • $5$ は sha256crypt
  • $1$ は md5crypt

です。 prefix が付いている時点で、もう「ただの digest」ではありません。

4.3 {SHA} を「SHA-256 か SHA-512 のどれか」と思う

Apache や LDAP の文脈で {SHA} は、ふわっと「SHA 系」の意味ではありません。 多くの場合、Base64 化した SHA-1 digest を指します。{SSHA} は salted SHA-1 です。

{SHA} の見た目だけで「何かの SHA」と曖昧に扱うと、検証コードや移行処理を間違えます。

4.4 パスワードハッシュとコンテンツハッシュを同じものとして扱う

同じ「ハッシュ文字列」でも、目的が違います。

  • ファイル整合性確認の digest
  • API の署名用 digest
  • パスワード保存用 hash / KDF 文字列

この 3 つは見た目が似ていても、扱いが違います。 とくに password hash は salt、rounds、memory cost、parallelism などを文字列に含むことが多く、「生 digest を比べる」発想では見抜けません。

4.5 XOF や可変長 digest を忘れる

SHAKE128 / SHAKE256 は XOF なので、出力長を自由に選べます。 BLAKE2 も digest length を変えられますし、BLAKE3 も extendable output を持ちます。

つまり、「この長さだからこの方式」 という推定は、固定長の古典的 digest を前提にしすぎると外します。

4.6 「NTLM」と「NT ハッシュ」を同じものとして扱う

これは用語の話ですが、Windows / AD まわりの調査ではかなり効きます。

  • NT ハッシュ: パスワードを UTF-16LE でエンコードし、MD4 にかけた 16 バイトの値です。8846f7eaee8fb117ad06bdd830b7586c のように、32 桁の 16 進として現れます。仕様上も NTOWFv1(Passwd, User, UserDom) = MD4(UNICODE(Passwd)) と定義されています。この定義は、参考資料 13 に挙げた MS-NLMP の NTLM v1 Authentication の項にそのまま載っています。
  • NTLM: その値を鍵にしてチャレンジ / レスポンスを行う 認証プロトコル の名前です。文字列の形式名ではありません。

現場では「NTLM ハッシュ」という言い方も通じますが、判定表に落とすときは NT ハッシュ(MD4 ベース) と書いたほうが正確です。ここを分けておくと、「この 32 hex は MD5 なのか NT ハッシュなのか」という 形式の判定 と、「この通信は NTLM なのか Kerberos なのか」という プロトコルの話 が混ざらずに済みます。

なお、NT ハッシュには salt がありません。同じパスワードなら常に同じ 32 hex になるので、「salt が付いていない 32 hex が AD 由来のテーブルに並んでいる」こと自体が手がかりになります。

5. 100% 確定したいときの確認順

移行や認証連携では、最終的に 確定 が必要です。そのときは次の順で見ると事故りにくいです。

5.1 保存元を特定する

まず、どこから来た文字列かを確定します。

  • Linux の shadow か
  • Apache / Nginx の basic auth か
  • LDAP か
  • Django / Spring Security か
  • 独自アプリの DB か

文字列単体より、保存元の仕様 のほうが強いことが多いです。

5.2 公式ドキュメントで「保存形式」を調べる

次に、アルゴリズム名ではなく 保存形式 を調べます。

  • Django password format
  • Spring Security password storage format
  • crypt(5) sha512crypt format
  • Apache htpasswd password formats

のように、format / storage / encoding をキーワードにすると見つけやすいです。

5.3 既知の平文があるなら、候補方式で実際に照合する

テスト用アカウントや既知の平文があるなら、候補方式で実際に計算して比較するのが早いです。 このとき、password hash では salt や rounds を文字列から取り出して再計算 する必要があります。

手順の型は、どの方式でも同じ 3 段です。

  1. 文字列から salt とパラメータを取り出す
  2. 既知の平文に対して、同じ salt とパラメータで再計算する
  3. 出てきた文字列が、元の文字列と 完全一致するか を見る

prefix なしの digest を確かめる

まずは「ただの digest」からです。Python 3 の標準ライブラリだけで足ります。

# Python 3.8 以降 / 標準ライブラリのみ
import base64
import hashlib

target = "5f4dcc3b5aa765d61d8327deb882cf99"   # 判定したい文字列
plain = b"password"                            # 既知の平文

for name in ("md5", "sha1", "sha256", "sha512", "sha3_256", "blake2s"):
    digest = hashlib.new(name, plain).digest()
    if digest.hex() == target.lower():
        print("hex 一致:", name)
    if base64.b64encode(digest).decode() == target:
        print("base64 一致:", name)

この例なら hex 一致: md5 が出ます。2.2 の表で候補に挙げた方式を、そのまま for の中に並べていくのが基本形です。

NT ハッシュを試したくなったときは、hashlib.new("md4", "password".encode("utf-16-le")) のように書くことになりますが、OpenSSL 3 系にリンクされた Python では legacy provider が既定で無効なため、unsupported hash type md4 になることがあります。ここは先に手元の環境で確認しておいてください。

crypt 系のパスワードハッシュを確かめる

$1$ / $5$ / $6$ / $apr1$ は、openssl passwd に salt を渡せば再計算できます。2.1 の表に載せた例も、この方法で再現できます。

# OpenSSL 3.x
openssl passwd -6 -salt N3v8Kx2Lq9Rt password
# $6$N3v8Kx2Lq9Rt$6LUcSUAELX3aC/.60pTB.TFLTQi1mOGRCwKqNCqtRSaXjorxj01HJ9oNni97Kci1uDt7a/Kn4t3OS20Dw/.vi1

openssl passwd -5 -salt N3v8Kx2Lq9Rt password    # sha256crypt
openssl passwd -1 -salt vA7mQ9xZ password        # md5crypt
openssl passwd -apr1 -salt vA7mQ9xZ password     # Apache APR1-MD5

出力が判定対象と一致すれば、その時点で 方式と平文の両方 が確定します。 rounds= が付いている文字列は、その値も一緒に渡す必要があります。$6$rounds=5000$... は既定値なので、明示してもしなくても同じ digest になりますが、rounds=100000 のように既定と違う値なら、必ずその値で計算してください。

Debian / Ubuntu 系なら、whois パッケージに入っている mkpasswd でも同じことができます(mkpasswd -m sha512crypt -S N3v8Kx2Lq9Rt password の形です)。

bcrypt や Argon2 を確かめる

bcrypt や Argon2 は salt が独自 alphabet でエンコードされているので、手で切り出すより、ライブラリの verify に文字列を丸ごと渡すほうが確実です。

# pip install "passlib[bcrypt]" argon2-cffi
from passlib.hash import argon2, bcrypt

samples = [
    (bcrypt, "$2b$12$9YQ2u/e5Y/ArOnG.gJKxK.0makLATcYLP1q.Nsabzrw7XErYCfoYO"),
    (argon2, "$argon2id$v=19$m=65536,t=3,p=4$MDEyMzQ1Njc4OWFiY2RlZg$uKZLaN6muIyoyIYr5waqw3y+zaDbe9aLSPj6Ln/rbz4"),
]

for handler, stored in samples:
    # identify はその形式かどうか、verify は平文と一致するかを返します
    print(handler.name, handler.identify(stored), handler.verify("password", stored))

verify は cost や rounds、salt を文字列側から読み取って再計算してくれるので、パラメータの取り出しを自分で書かずに済みます。上の bcrypt の例は平文が password なので True が返ります。

なお、Python 標準の crypt モジュールは非推奨化され、Python 3.13 で削除 されました。3.13 以降で crypt 系を扱うなら、openssl passwdpasslib 側へ寄せてください。

5.4 候補方式を hashcat の番号や john の名前へ置き換える

平文が分からず、ツール側で扱いたいときは、方式名ではなく ツールが使う識別子 に翻訳する必要があります。ここでよく詰まるので、代表的なものを表にしておきます。

見た目 方式 hashcat のモード(-m
32 hex MD5 0
32 hex(AD 由来) NT ハッシュ 1000
40 hex SHA-1 100
64 hex SHA-256 1400
128 hex SHA-512 1700
$1$... md5crypt 500
$apr1$... Apache APR1-MD5 1600
$2a$ / $2b$ / $2y$ bcrypt 3200
$5$... sha256crypt 7400
$6$... sha512crypt 1800
pbkdf2_sha256$... Django PBKDF2-HMAC-SHA256 10000
scrypt 系の保存形式 scrypt 8900

モード番号は版が上がるたびに増えるので、Argon2 や yescrypt のように新しめの方式は、手元の hashcat のヘルプに出る一覧で確認してください。

John the Ripper 側は数値ではなく 名前 で指定します。本体(1.8.0)で有効なのは descryptbsdicryptmd5cryptbcryptLMAFStripcodedummycrypt で、これ以外の多くは jumbo 版で追加されます。使いたい方式の名前が本体にない場合は、jumbo 版のドキュメントで確認してください。

繰り返しになりますが、ここで挙げたツールは 自分たちの環境、または調査の許可が取れている環境 に対してだけ使ってください。

5.5 実装コードか設定を確認する

調査対象が自社システムなら、最終的にはコードや設定を見るのがいちばん確実です。

  • 使用ライブラリ
  • フレームワークの設定
  • 生成時オプション
  • 出力エンコード方式(hex / Base64 / Base64url / crypt alphabet)

ここを見れば、たいてい決着がつきます。

5.6 今後のために、方式ラベル付きで保存する

これから設計する側なら、方式を文字列に埋め込む形式 を選ぶと、将来の移行がかなり楽になります。

  • Argon2 の PHC string format
  • Spring Security の {id}encodedPassword
  • Django の algo$iterations$salt$hash
  • Unix crypt(3) 系の prefix 付き形式

こうしておくと、後から見た人が迷いにくいです。 逆に「ただの 64 hex」だけを DB に置く設計は、将来の自分にやさしくありません。

6. まとめ

ハッシュ値の文字列表現から方式を見分けるときは、次の順で見ると整理しやすいです。

  1. prefix があるか
  2. 区切り文字が何か
  3. 文字集合が何か
  4. 長さが何バイト相当か
  5. 保存元の文脈が何か

いちばん大事なのは、次の 2 点です。

  • 接頭辞付きの保存形式はかなり特定しやすい
  • プレーンな 16 進 / Base64 は候補群までしか分からないことが多い

なので、実務での判断はこうなります。

  • $argon2id$..., $2b$..., $6$..., {SHA}..., pbkdf2_sha256$... なら、文字列だけでかなり前に進める
  • 32 / 40 / 64 / 128 桁の 16 進だけなら、断定ではなく「候補を絞る」と考える
  • 本当に確定が必要なら、保存元の製品・設定・実装まで見る

この順で見れば、調査がかなり速くなります。 逆に、長さだけで即断すると、静かに遠回りします。

7. このテーマがつながるサービス

技術相談・設計レビュー

既存 DB に残ったパスワードハッシュの方式特定、認証基盤の移行、Windows / Web 混在システムのログ調査では、文字列の見た目だけでなく、保存元の実装や移行方針まで整理する必要があります。方式特定から移行設計まで、まとめて見ると事故を減らしやすいです。

不具合調査・原因解析

「この文字列が何なのか分からないので検証が進まない」という調査は珍しくありません。ログ、設定ファイル、DB スキーマ、アプリ実装のどこで方式が決まっているのかを切り分けると、原因特定がかなり早くなります。

8. 参考資料

  1. RFC 1321 - The MD5 Message-Digest Algorithm
  2. NIST FIPS 180-4 - Secure Hash Standard (SHA-1, SHA-2, SHA-512/224, SHA-512/256)
  3. NIST FIPS 202 - SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions
  4. PHC string format specification
  5. Argon2 reference implementation
  6. RFC 7693 - The BLAKE2 Cryptographic Hash and Message Authentication Code (MAC)
  7. BLAKE3 C README - default output length and extendable output
  8. crypt(5) - prefixes and hashed passphrase formats
  9. Apache HTTP Server 2.4 - Password Formats
  10. slappasswd(8) - RFC 2307 schemes such as {SHA} and {SSHA}
  11. Django documentation - example of pbkdf2_sha256$...
  12. Spring Security - DelegatingPasswordEncoder storage format {id}encodedPassword
  13. MS-NLMP: NTLM v1 Authentication - NTOWFv1(Passwd, User, UserDom) = MD4(UNICODE(Passwd))
  14. hashcat wiki - example hashes(モード番号の一覧)
  15. John the Ripper - command line options(--format=NAME で使える名前)
  16. passlib - PasswordHash API(identifyverify
  17. openssl-passwd(1) - -1 / -apr1 / -5 / -6-salt

同じタグを共有する最新の記事です。さらに近い話題で知識を深められます。

このテーマと近いトピックページです。記事を起点に、関連するサービスや他の記事へ進めます。

この記事は次のサービスページにつながります。近い入口からご覧ください。

よくある質問

この記事のテーマについて、相談時によくある質問をまとめています。

ハッシュ文字列から方式を見分けるにはどの順番で見ればよいですか?
prefix → 区切り文字 → 文字種 → 長さ → 文脈の順で見ると整理しやすいです。先頭の数文字に意味がある形式は特定しやすく、$argon2id$ならArgon2、$2b$ならbcrypt、$5$はsha256crypt、$6$はsha512cryptを強く疑えます。逆に、prefixのないプレーンな16進やBase64は候補を絞るまでしかできないため、最終的には保存元の製品やフレームワーク、設定を確認して確定します。
64桁の16進文字列はSHA-256と断定してよいですか?
断定は危険です。SHA-256は有力候補ですが、同じ32バイト出力を持つ方式にはSHA3-256、SHA-512/256、BLAKE2s-256、BLAKE3の既定出力などもあり、長さだけでは区別できません。長さは候補群を作る材料であって、確定材料ではありません。確定が必要なら、保存元の仕様、公式ドキュメントの保存形式、既知の平文での照合、実装コードや設定の確認まで進める必要があります。
$6$で始まる文字列はSHA-512のハッシュですか?
違います。$6$はsha512cryptというUnix系パスワード保存形式のprefixで、SHA-512のhex digestそのものではなく、saltやroundsを含むパスワードハッシュ文字列です。同様に$5$はsha256crypt、$1$はmd5cryptです。prefixが付いている時点で「ただのdigest」ではないため、ここを取り違えると移行や検証コードの実装がずれます。
文字の種類からは何が分かりますか?
文字種は長さと同じくらい重要な手がかりです。0-9a-fA-Fの範囲の文字だけなら16進表現で、文字数の半分が生バイト長になります。+ / = があればRFC 4648のBase64、- や _ があればBase64urlを疑います。ピリオドとスラッシュが出てきて$区切りなら、普通のBase64ではなくbcryptやsha512cryptなどcrypt系のalphabetを疑うほうが自然です。ピリオド入りを壊れたBase64と見てしまうと、crypt系形式を見落とします。

著者プロフィール

記事の著者プロフィールページです。

小村 豪

合同会社小村ソフト 代表

Windows ソフト開発、技術相談、不具合調査を中心に、既存資産が残る案件や原因が見えにくい障害調査に強みがあります。

ブログ一覧に戻る