Scalaで一方向ハッシュ関数を使いたかった

# TL;DR
- 基本はJavaの標準ライブラリを使うとよさそう
- パスワードハッシュにはSpringBootを使うかサードパーティ製ライブラリの利用を検討する

# 安全に認証したい
　アプリケーション利用者の認証に使うパスワードなどは、当然そのままDBに保存してはいけないものです。知らない人にDBを覗かれたら何もかもが暴露されてしまいますからね。そこで使うのが「一方向ハッシュ関数※」ですが、Scalaで一方向ハッシュ関数を使いたい場合は一癖ほどありそうだったので、少し調べた内容をまとめました。

※一方向ハッシュ関数：任意のデータを不可逆変換し、短い固定長のデータを生成する関数。一方向ハッシュ関数によって生成されたデータは「ハッシュ値」と呼ばれる。ハッシュ値から元データを復元することはできず、あるデータが元データと等しいかどうか（正真性）はハッシュ値が等しいかどうかで確かめられる。

# Scalaで使える一方向ハッシュ関数ライブラリ
## java.security
　Javaの標準ライブラリです。この中の`MessageDigest`というクラスが一方向ハッシュ関数を提供しています。メッセージを要約してくれるもの、という意味でMessageDigestという名前がついていますが、これは一方向ハッシュ関数の通称としても一般的です。

https://docs.oracle.com/en/java/javase/19/docs/api/java.base/java/security/MessageDigest.html

　このライブラリで使える一方向ハッシュ関数アルゴリズムが[Java Security Standard Algorithm Names](https://docs.oracle.com/en/java/javase/19/docs/specs/security/standard-names.html)にまとまっていますので、次に引用します。
>| Algorithm Name                                                | Description                                                                                                                                                                                                                                                                                                      |
>|---------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
>| MD2                                                           | The MD2 message digest algorithm as defined in RFC 1319.                                                                                                                                                                                                                                                         |
>| MD5                                                           | The MD5 message digest algorithm as defined in RFC 1321.                                                                                                                                                                                                                                                         |
>| SHA-1<br/>SHA-224<br/>SHA-256<br/>SHA-384<br/>SHA-512<br/>SHA-512/224<br/>SHA-512/256 | Secure hash algorithms as defined in FIPS PUB 180-4.<br/>SHA-1 produces a 160 bit digest.<br/>SHA-224 produces a 224 bit digest.<br/>SHA-256 produces a 256 bit digest.<br/>SHA-384 produces a 384 bit digest.<br/>SHA-512 produces a 512 bit digest.<br/>SHA-512/224 produces a 224 bit digest.<br/>SHA-512/256 produces a 256 bit digest. |
>| SHA3-224<br/>SHA3-256<br/>SHA3-384<br/>SHA3-512                           | Permutation-based hash and extendable-output functions as defined in FIPS PUB 202. An input message length can vary; the length of the output digest is fixed.<br/>SHA3-224 produces a 224 bit digest.<br/>SHA3-256 produces a 256 bit digest.<br/>SHA3-384 produces a 384 bit digest.<br/>SHA3-512 produces a 512 bit digest.  |

上のように一方向ハッシュ関数アルゴリズムは数多くありますが、昔からあるアルゴリズムは解析されて安全ではなくなって（危殆化して）いることがありますので、アプリケーションに組み込む際は注意が必要です。日本では総務省・経産省・国立研究開発法人情報通信研究機構（NICT）・独立行政法人情報処理推進機構（IPA）によるCRYPTECというプロジェクトが『電子政府における調達のために参照すべき暗号のリスト(CRYPTREC暗号リスト)』を発表しており、そこで利用を推奨するアルゴリズムが公開されています。

https://www.cryptrec.go.jp/list.html

このリストによると、上の表に現れたアルゴリズムのうちSHA-2とSHA-3に該当するものは、利用を推奨または今後推奨されるものとして指定されています。すなわち、java.security.MessageDigestでSHA-2とSHA-3を使って安全なハッシュ値を作れる、ということです。

## org.springframework.security
　JavaのWebアプリケーションフレームワークである、SpringBootのパッケージです。この中の次の4クラスが、主にアルゴリズム別の一方向ハッシュ関数を提供しています。

https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/crypto/password/Pbkdf2PasswordEncoder.html

https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/crypto/bcrypt/BCryptPasswordEncoder.html

https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/crypto/scrypt/SCryptPasswordEncoder.html

https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/crypto/argon2/Argon2PasswordEncoder.html

ここで使われているアルゴリズム（PBKDF2、BCrypt、SCrypt、Argon2）は、どれも「パスワードハッシュアルゴリズム」とも呼ばれるような、パスワードのハッシュに特化したアルゴリズムです。パスワードはレインボーテーブル攻撃（ハッシュ値の逆引き表からパスワードを特定するクラッキング）や辞書攻撃（ありがちなフレーズからパスワードを特定するクラッキング）に弱いため、そういった攻撃に強いアルゴリズムが独自に存在しています。
　パスワードに特化しすぎてCRYPTREC暗号リストには載っていないアルゴリズムですが、パスワードハッシュアルゴリズムとして安全性への信頼はあり、広く使われていることもあって実装されているものと思われます。すなわち、org.springframework.securityを使えばパスワードを安全にハッシュ化できる、ということです。

# 以上です
　えっ・・・Scalaは・・・？と思われたなら、筆者と同じ気持ちです。よろしくお願いします。
　調査不足なら申し訳ないのですが、Scala標準やフレームワーク等での一方向ハッシュ関数の実装は見当たりませんでした。一癖というのはそういうことです。フレームワークとして代表的なところではPlayFrameworkが思い当たりますが、一方向ハッシュ関数の提供はありません。しかし、Scalaでの実装が全く無いかというとそうではなく、個人によるサードパーティー製ライブラリはいくつか存在するようです。そのため、Scalaで一方向ハッシュ関数を利用したい場合は次のような方針になります。
- 基本はjava.securityを利用する
- パスワードをハッシュしたい場合は、SpringBootを利用する
- SpringBootを利用せずにパスワードをハッシュしたい場合は、サードパーティー製のライブラリ導入を検討する

あまりスッキリしない結論となってしまいましたが、筆者もスッキリしたいので引き続き調査を続けます。ありがとうございました。