Swift 4で HMAC-SHA256

Amazon API 叩くのに HMAC-SHA256 が必要でその過程の部分のメモ。

極力他ライブラリを使わない方向。CryptoSwift とか便利だとは思います。

CommonCrypto はいつ廃止されるかは知らないですが、ひとまずは最初から入っているもの、ということで(多分)。

大まかな作業順番。

  1. BridgingHeader.h で CommonCrypto/CommomHMAC.h を定義
  2. プロジェクトに BridgingHeader.h を追加する
  3. Xcode 9.0 のプロジェクト設定で Objective-C Bridging Header の設定に 1. のファイルを指定する
  4. ソース側で HMAC-SHA256 を計算するコードを書く
  5. 呼び出し側で呼び出す

具体的な手順。

1. BridgingHeader.h

#ifndef BridgingHeader_h
#define BridgingHeader_h
#import "CommonCrypto/CommonHMAC.h"
#endif /* BridgingHeader_h */

参考サイト

Swift: Bridging-Header 作成・設定方法- http://www.sirochro.com/note/swift-bridging-header-generate/

2. プロジェクトを開いた状態で [File] → [Add Files to …] から BridgingHeader.h を追加

3. プロジェクト設定に追加 [Build Settings] → [Swift Compiler – General] → [Objective-C Bridging Header]

だいぶ下の方の設定。

4. HMAC-SHA256 の関数を書く

import Foundation
enum CryptoAlgorithm {
    case MD5, SHA1, SHA224, SHA256, SHA384, SHA512
    var HMACAlgorithm: CCHmacAlgorithm {
        var result: Int = 0
        switch self {
        case .MD5:      result = kCCHmacAlgMD5
        case .SHA1:     result = kCCHmacAlgSHA1
        case .SHA224:   result = kCCHmacAlgSHA224
        case .SHA256:   result = kCCHmacAlgSHA256
        case .SHA384:   result = kCCHmacAlgSHA384
        case .SHA512:   result = kCCHmacAlgSHA512
        }
        return CCHmacAlgorithm(result)
    }
    var digestLength: Int {
        var result: Int32 = 0
        switch self {
        case .MD5:      result = CC_MD5_DIGEST_LENGTH
        case .SHA1:     result = CC_SHA1_DIGEST_LENGTH
        case .SHA224:   result = CC_SHA224_DIGEST_LENGTH
        case .SHA256:   result = CC_SHA256_DIGEST_LENGTH
        case .SHA384:   result = CC_SHA384_DIGEST_LENGTH
        case .SHA512:   result = CC_SHA512_DIGEST_LENGTH
        }
        return Int(result)
    }
}
extension String {
    func hmac(algorithm: CryptoAlgorithm, key: String) -> String {
        var result: [CUnsignedChar]
        if let ckey = key.cString(using: String.Encoding.utf8), let cdata = self.cString(using: String.Encoding.utf8) {
            result = Array(repeating: 0, count: Int(algorithm.digestLength))
            CCHmac(algorithm.HMACAlgorithm, ckey, ckey.count-1, cdata, cdata.count-1, &result)
        } else {
            fatalError("Nil returned when processing input strings as UTF8")
        }

        //return Data(bytes: result, count: result.count).base64EncodedString()
        /**/
        let hash = NSMutableString()
        for val in result {
            hash.appendFormat("%02hhx", val)
        }
        return hash as String
        /**/
    }
}

5. HMAC-SHA256 で指定した文字列の HMAC を求める

var targetString: String = "foobarbaz"
let secretKey: String = "ThisIsSecretKey"
let hashedValue = targetString.hmac(algorithm: .SHA256, key: secretKey)
print("HMAC-SHA256: [\(hashedValue)]")

上記 hmac 内のコメントアウトしている部分は Amazon API 用。その部分にたどり着くまで丸二日浪費・・・(涙

NSMutableString() からの行はネットで検索したら大抵引っかかるサンプルコードで紹介されているもの。普通はこっち?

Swift から始めたので [CUnsignedChar] とか cString とかよくわかっていないです。

上記サンプルは一応動いていたコードをベースにいくつか抽出していますが、動作しなかったらごめんなさい。

HMAC 調べていた時に見つけた投稿。HMACの解法への道しるべになる・・・か?と思い。

https://forums.developer.apple.com/thread/85873

この Apple Staff なんか偉そうやな、、Tricky なのを先に何とかしてくれ、、、いえ、してください。と思った。

フォローする