【Delphi】ハッシュ値を生成する

# はじめに

Delphi には XE8 以降、`System.Hash.pas` ユニットが提供されており、各種ハッシュ値生成用の高度なレコード型が用意されています。

 - [ハッシュ関数 (Wikipedia)](https://ja.wikipedia.org/wiki/%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E9%96%A2%E6%95%B0)
 - [暗号学的ハッシュ関数 (CHF) (Wikipedia)](https://ja.wikipedia.org/wiki/%E6%9A%97%E5%8F%B7%E5%AD%A6%E7%9A%84%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E9%96%A2%E6%95%B0
)
 - [非暗号化ハッシュ関数 (NCHF) (Wikipedia: en)](https://en.wikipedia.org/wiki/Non-cryptographic_hash_function)
 - [HMAC  (Wikipedia)](https://ja.wikipedia.org/wiki/HMAC)
 - [System.Hash (DocWiki)](https://docwiki.embarcadero.com/Libraries/ja/System.Hash)

# ハッシュ値の生成

以下、ハッシュ関数の概略とコード例です。

## ■ Jenkins
Jenkins は 1997年に Bob Jenkins によって開発されたハッシュ関数 (NCHF) です。

Delphi に実装されている `THashBobJenkins` では 16進値で 8 桁のハッシュ値が生成されます。

 - [Jenkins ハッシュ関数 (Wikipedia: en)](https://en.wikipedia.org/wiki/Jenkins_hash_function)
 - [System.Hash.THashBobJenkins (DocWiki)](https://docwiki.embarcadero.com/Libraries/ja/System.Hash.THashBobJenkins)

## ■ FNV-1a

FNV は (1991年頃？) Glenn Fowler, Landon Curt Noll, Kiem-Phong Vo によって開発されたハッシュ関数 (NCHF) です。FNV-1a はそのバリエーションです。

FNV-1a にはハッシュ値のサイズとして 32bit、64bit、128bit、256bit、512bit、1024bit があります。

Delphi に実装されている `THashFNV1a32` は 32ビットハッシュ値を生成し、16進値で 8 桁のハッシュ値が生成されます。同様に `THashFNV1a64` は 64ビットハッシュ値を生成し、16進値で 16 桁のハッシュ値が生成されます。

 - [Fowler-Noll-Vo (FNV) ハッシュ関数 (Wikipedia:en)](https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function)
 - [System.Hash.THashFNV1a32 (DocWiki)](https://docwiki.embarcadero.com/Libraries/ja/System.Hash.THashFNV1a32)
 - [System.Hash.THashFNV1a64 (DocWiki)](https://docwiki.embarcadero.com/Libraries/ja/System.Hash.THashFNV1a64)

::: note
THashFNV1a32 は Delphi 11 Alexandria 以降で利用可能です。
:::

::: note
THashFNV1a64 は Delphi 12 Athens 以降で利用可能です。
:::

## ■ MD5
MD5 は 1991年に Ronald Linn Rivest によって開発されたハッシュ関数 (CHF) です。

Delphi に実装されている `THashMD5` では 16進値で 32 桁のハッシュ値が生成されます。

 - [MD5 ハッシュ関数 (Wikipedia)](https://ja.wikipedia.org/wiki/MD5)
 - [System.Hash.THashMD5 (DocWiki)](https://docwiki.embarcadero.com/Libraries/ja/System.Hash.THashMD5)


## ■ SHA-1
SHA-1 は 1995年に アメリカ国家安全保障局 (NSA) によって開発されたハッシュ関数 (CHF) です。

Delphi に実装されている `THashSHA1` では 16進値で 40 桁のハッシュ値が生成されます。

 - [SHA-1 ハッシュ関数 (Wikipedia)](https://ja.wikipedia.org/wiki/SHA-1)
 - [System.Hash.THashSHA1 (DocWiki)](https://docwiki.embarcadero.com/Libraries/ja/System.Hash.THashSHA1)


## ■ SHA-2

SHA-2 は 2001年に アメリカ国家安全保障局 (NSA) によって開発されたハッシュ関数 (CHF) です。

SHA-224、SHA-256、SHA-384、SHA-512、SHA-512/224、SHA-512/256 というの 6 つのバリエーションがありますが、Delphi の THashSHA2 のデフォルトでは SHA-256 が使われます。

Delphi に実装されている `THashSHA1` では 16進値で 56～128 桁のハッシュ値が生成されます。

 - [SHA-2 ハッシュ関数 (Wikipedia)](https://ja.wikipedia.org/wiki/SHA-2)
 - [System.Hash.THashSHA2 (DocWiki)](https://docwiki.embarcadero.com/Libraries/ja/System.Hash.THashSHA2)

::: note
SHA-2 (THashSHA2) は Delphi 10 Seattle 以降で利用可能です。
:::


## ■ コード例

### ・文字列からハッシュ値 (文字列) を生成する

最も単純な使い方です。例では `THashMD5` を使っていますが、SHA-1 のハッシュ値を得たければ `THashSHA1` に変更するだけです。

```pascal
var Src := 'Hello,world.';
var Dst := THashMD5.GetHashString(Src);
```

### ・ファイルからハッシュ値 (文字列) を生成する

ファイルのハッシュダイジェストからハッシュ値を生成します。Jenkins / FNV-1a では利用できません。

```pascal
var Src := 'c:\Windows\notepad.exe';
var Dst := THashMD5.GetHashStringFromFile(Src);
```

::: note
GetHashStringFromFile() は Delphi 10.2 Tokyo 以降で利用可能です。
:::


### ・HMAC に適したハッシュ値 (文字列) を生成する

HMAC に適したハッシュ値を生成します。同一の秘密鍵を用いた場合に限り、同じハッシュ値が得られます。Jenkins / FNV-1a では利用できません。

```pascal
var Key := 'HogeHoge'; // 秘密鍵
var Src := 'Hello,world.';
var Dst := THashMD5.GetHMAC(Src, Key);
```

### ・SHA-2 のバリエーションを指定する

SHA-2 のバリエーションを指定してハッシュ値を生成します。コンストラクタのパラメータでバリエーションを指定します。

| 値 | バリエーション | 桁数 |
|:---|:---|:---:|
| SHA224 | SHA-224 | 56 |
| SHA256 | SHA-256 | 64 |
| SHA384 | SHA-384 | 96 |
| SHA512 | SHA-512 | 128 |
| SHA512_224 | SHA-512/224 | 56 |
| SHA512_256 | SHA-512/256 | 64 |

```pascal
  with THashSHA2.Create(SHA384) do
  begin
    var Src := 'Hello,world.';
    Update(Src);
    var Dst := HashAsString;
  end;
```

# おわりに
各種ハッシュ値生成用の高度なレコード型を使う際、大抵の事はクラスメソッドで済ませられるようになっているのがお手軽でいいですね。

:::note warn
古い Delphi でハッシュ値を生成するには Indy を使う事になるかと思います。
:::

**See also:**

 - [Indy 10 で文字列から MD5 ハッシュを生成する (偏った言語信者の垂れ流し)](https://tokibito.hatenablog.com/entry/20090415/1239781391)