ファイルのSHA-256ハッシュ値を計算する

# ファイルのSHA-256ハッシュ値を計算する
## 背景
とある2つのファイルがあった場合に、同一性を確認したい場合があります。
そのときにそれぞれのファイルのハッシュ値を計算して比較する方法が一般的な手法の1つにあります。

SHA-256とはハッシュ値の計算アルゴリズムの1つです。collision（偶然の値の一致）が起きるは非常に低く、[collisionが起きる前に地球が滅びるらしい](https://stackoverflow.com/questions/4014090/is-it-safe-to-ignore-the-possibility-of-sha-collisions-in-practice)ので、ファイルの同一性を見るには信用できるものである。

## 参考
- ファイルの同一性の確認手法
    - [WindowsでMD5／SHA-1／SHA-256ハッシュ値を計算してファイルの同一性を確認する](https://www.atmarkit.co.jp/ait/articles/0507/30/news017.html)
- コードは以下を参考にしました
    - [【メモ】Objective-Cでハッシュ関数を使う（SHA256）](http://zak-za-k.blogspot.com/2011/09/objective-csha256.html)
- `description`の出力結果が`macOS10.15`から変わったようです。取り急ぎ`debugDescription`を使えば従来通りの処理が可能です。
    - [\[iOS13\]SHA256の値が取得出来なかった時の対処方法](https://ryukasublog.com/ios13-sha256/#i-1)
    - [【iOS】Push通知に必要なDeviceTokenの文字列取得に関して \- Iganinのブログ](https://iganin.hatenablog.com/entry/2019/10/14/173102)
    - [iOS 13 および macOS Catalina の VPN の強化点](https://support.apple.com/ja-jp/HT210432)
    - [What is the need of hh and h format specifiers?](https://stackoverflow.com/questions/21782244/what-is-the-need-of-hh-and-h-format-specifiers)
    - [String Format Specifiers\(フォーマット指定子\)の解説 \- 強火で進め](http://nakamura001.hatenablog.com/entry/20080912/1221229442)
- Swiftで書くなら私は以下を採用します。
    - [Swiftでプッシュ通知用のDevice Token\(Data型\)を16進数文字列へ変換する方法 \- Qiita](https://qiita.com/mono0926/items/3cf0dca3029f32f54a09)

## 実装
SHA-256の計算のところで下記のインポートが必要です。

``` ObjectiveC:
#import <CommonCrypto/CommonHMAC.h>
```

実際にSHA-256を計算する関数は下記の通り。

```objc
/**
 @brief ファイルのSHA-256ハッシュ値を計算する
 @param file 対象ファイルパス
 @return ハッシュ値の文字列
 */
- (NSString *)calculateSha256HashWithFilePath:(NSString *)file {
    
    NSData *fileData = [NSData dataWithContentsOfFile:file];
    uint8_t digest[CC_SHA256_DIGEST_LENGTH]={0};
    CC_SHA256(fileData.bytes, (int)fileData.length, digest);
    NSData *hashData = [NSData dataWithBytes:digest length:CC_SHA256_DIGEST_LENGTH];
    
    NSString *hash = [[NSString alloc] initWithString: hashData.debugDescription];
    
    NSLog(@"🐱 hashData.description: %@", hashData.description);
    NSLog(@"🐱 hashData.debugDescription: %@", hashData.debugDescription);
    
    hash = [hash stringByReplacingOccurrencesOfString:@" " withString:@""];
    hash = [hash stringByReplacingOccurrencesOfString:@"<" withString:@""];
    hash = [hash stringByReplacingOccurrencesOfString:@">" withString:@""];
    
    return hash;
}
```

- 出力例

```sh
# 10.15.4（19E287）
デフォルト	12:55:19.316584+0900	Fontinstaller	🐱 hashData.description: {length = 32, bytes = 0x45f62b0e 67be6057 4fc399aa c45234cb ... cc0877d1 d69dadde }
デフォルト	12:55:19.316634+0900	Fontinstaller	🐱 hashData.debugDescription: <45f62b0e 67be6057 4fc399aa c45234cb 38e61c8d 851f7fda cc0877d1 d69dadde>

# 10.14.4 Beta（18E194d）
デフォルト	13:09:56.653950 +0900	Fontinstaller	🐱 hashData.description: <45f62b0e 67be6057 4fc399aa c45234cb 38e61c8d 851f7fda cc0877d1 d69dadde>
デフォルト	13:09:56.654052 +0900	Fontinstaller	🐱 hashData.debugDescription: <45f62b0e 67be6057 4fc399aa c45234cb 38e61c8d 851f7fda cc0877d1 d69dadde>

# 10.12.6（16G1212）
デフォルト	13:00:03.831566 +0900	Fontinstaller	🐱 hashData.description: <45f62b0e 67be6057 4fc399aa c45234cb 38e61c8d 851f7fda cc0877d1 d69dadde>
デフォルト	13:00:03.831693 +0900	Fontinstaller	🐱 hashData.debugDescription: <45f62b0e 67be6057 4fc399aa c45234cb 38e61c8d 851f7fda cc0877d1 d69dadde>
```

呼び出し方の例。

``` ObjectiveC:呼び出し部分
NSString *kSampleFile = [@"~/Desktop/sample.txt" stringByExpandingTildeInPath]; // デスクトップにえテスト用のファイルを作成
NSURL    *file        = [NSURL fileURLWithPath:kSampleFile];
NSString *hash        = [self calculateSha256HashWithFileUrl:file];
NSLog(@"計算したハッシュ値:%@", hash);
```

## 結果とターミナルでハッシュ値の計算

プログラムの結果例は下記の通り。

``` ObjectiveC
計算したハッシュ値:adf0380c6469682dc23b63597267d1ee63595813b2f46ba72477109fcbecbceb
```

ターミナルでもハッシュ値の計算ができる。
上記の結果と一致していることが確認できる。

``` Bash:ターミナルでSHA-256の計算
shasum -a 256 sample.txt 
adf0380c6469682dc23b63597267d1ee63595813b2f46ba72477109fcbecbceb  sample.txt
```