MD5,SHA256でハッシュ化して時間を計測してみる

iosの標準SDKCommonCryptoを使えばSwiftで簡単にハッシュ化をすることができます。
適当なZipファイルをMD5とSHA256でハッシュ化を行いどれくらい時間がかかるのかを計測してみました。

ハッシュ化はチェックサムを行う際に使います。iosでもandriodでもおそらく内部的にチェックは行ってくれているので壊れることはないと思いますが、念には念を入れて確認しておくと良いかもしれません。

MD5とSHA256に変換するメソッド

簡単にハッシュ化できるメソッドを作成しました!この2つのメソッドを使って検証をしていきます。

MD5

func MD5(data: Data) -> String {
    let length = Int(CC_MD5_DIGEST_LENGTH)
    var digest = [UInt8](repeating: 0, count: length)
    _ = data.withUnsafeBytes { CC_MD5($0, CC_LONG(data.count), &digest) }
    return digest.map { String(format: "%02x", $0) }.joined(separator: "")
}

SHA256

func SHA256(data: Data) -> String{
    let length = Int(CC_SHA256_DIGEST_LENGTH)
    var digest = [UInt8](repeating: 0, count: length)
    _ = data.withUnsafeBytes { CC_SHA256($0, CC_LONG(data.count), &digest) }
    return digest.map { String(format: "%02x", $0) }.joined(separator: "")
}

ハッシュ化するファイル

ハッシュ化するファイルはなんでもよかったのですが、先日ReleaseしたOh! Natto!をzip化して使ってみました。

ちなファイルの容量は22.4MBでした。

ログ出力とハッシュ化にかかった時間

SHA256とMD5デカかった時間はこのようになりました。
SHA256が217ms, MD5が132msでした。何回か繰り返してみてもあたいはだいたい同じでした。SHA256の方がちょっと長い感じです。
単純計算で120MBくらいの容量のファイルをSHA256でハッシュ化すると1秒かかるかな?くらいの感覚です。

SHA256 start: 21:29:17.811
result: 46da89624858bfdb865e0da2c70f4119620ca7f4c0d9845c94a7f2a5be10a363
SHA256 end: 21:29:18.028

MD5 start: 21:29:18.028
result: 4eedc3ad2a167b2961b2258130b45e23
MD5 end: 21:29:18.160

これから新規でデータのチェックサムを行う際はMD5でなくSHA256を使うのが良いらしいです。
なぜかというと、MD5は脆弱性が見つかってしまっており現在主要な標準・推奨規格に入っていないようです。

コード全部

import UIKit
import CommonCrypto

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        if let firmware = Bundle.main.path(forResource: "oh-natto.zip", ofType: ""){
            do {
                let url = URL(fileURLWithPath: firmware)
                let fileHandle:FileHandle = try FileHandle(forReadingFrom: url)
                //zipデータをData配列化
                let allData = fileHandle.readDataToEndOfFile()
                
                print("SHA256 start: \(nowTime())")
                print("result: \(SHA256(data: allData))")
                print("SHA256 end: \(nowTime())")
                
                print("MD5 start: \(nowTime())")
                print("result: \(MD5(data: allData))")
                print("MD5 end: \(nowTime())")
                
            } catch  {
                print("内容取得時失敗")
            }
        } else {
            print("読み込み失敗")
        }
    }

    func MD5(data: Data) -> String {
        let length = Int(CC_MD5_DIGEST_LENGTH)
        var digest = [UInt8](repeating: 0, count: length)
        _ = data.withUnsafeBytes { CC_MD5($0, CC_LONG(data.count), &digest) }
        return digest.map { String(format: "%02x", $0) }.joined(separator: "")
    }
    func SHA256(data: Data) -> String{
        let length = Int(CC_SHA256_DIGEST_LENGTH)
        var digest = [UInt8](repeating: 0, count: length)
        _ = data.withUnsafeBytes { CC_SHA256($0, CC_LONG(data.count), &digest) }
        return digest.map { String(format: "%02x", $0) }.joined(separator: "")
    }
    func nowTime() -> String {
        let format = DateFormatter()
        format.dateFormat = "HH:mm:ss.SSS"
        return format.string(from: Date())
    }
}


Macのコマンドでハッシュ値を確認しチェックサムしてみる

mac: sha256, md5 コマンド

下記のコマンドをmacのターミナルで実行するとハッシュ化を行えます

//SHA256
openssl sha256 ファイル名

//MD5
md5 ファイル名

実行した時のコマンドのスクリーンショットはこんな感じです。oh-natto.zipがファイル名に当たります。

先ほどのSwiftのコードで出力したログと比較してみて同じになっているのでしっかりハッシュ化できていてデータが壊れていないことも証明されました。

データが壊れているとハッシュ化された値が一致しません。

SHA256 start: 21:29:17.811
result: 46da89624858bfdb865e0da2c70f4119620ca7f4c0d9845c94a7f2a5be10a363
SHA256 end: 21:29:18.028

MD5 start: 21:29:18.028
result: 4eedc3ad2a167b2961b2258130b45e23
MD5 end: 21:29:18.160

参考文献

Swift 3 で文字列を sha1、MD5 でハッシュ化する

Swift 4でハッシュ値の計算(MD5, SHA1, SHA256, etc.)

現在時刻のミリ秒表示(Swift4)

チェックサム (checksum)

MD5とSHA