アプリ内に保存するデータを暗号化する(iOS)

#最初に...
2回目の投稿です。去年の12月に投稿した際
>次回はSwift4で同じことをする予定です・・・。

と言っておりましたが、気づいたらこんな時期に。
宣言通りSwift4でAES暗号をやります。
Androidと同様にOpenSourceのライブラリは未使用です。

##下準備
今回はCommonCryptoを使用します。
基本、"/usr/include"にあるのですが、ない場合は
Commnad Line Toolsをインストールで解決すると思います。
https://qiita.com/mym/items/8bc079b7d0f5f55c49dc
上記URLをご確認ください。

また、Swift4からCommonCryptoを使用する場合はmodule.modulemapを作成する必要があります。
適当な位置に(今回はプロジェクト直下に作成しました)module.modulemapを作成します。
そのファイルに以下を記載します。

```
module CommonCrypto {
    header "/usr/include/CommonCrypto/CommonCrypto.h"
    export *
}
```

その後、Project->BuildSettings->Swift Compiler-Search paths->Import Pathsに
module.modulemapのパスを追加してください。
(私の場合は${SRCROOT})

##実際のソース

AES鍵作成

```swift
let key = Data.init(count: kCCKeySizeAES128)
        let addquery: [String: Any] = [kSecClass as String: kSecClassKey,
                                       kSecAttrApplicationTag as String: alias,
                                       kSecValueData as String: key as Any]
        _ = SecItemAdd(addquery as CFDictionary, nil)
```

AES鍵取得

```swift
let getquery: [String: Any] = [kSecClass as String: kSecClassKey,
                                       kSecAttrApplicationTag as String: alias,
                                       kSecReturnData as String: true]
        var item: AnyObject?
        SecItemCopyMatching(getquery as CFDictionary, &item)
        return item as? Data
```

暗号化

```swift
let keyData = getSaveKey()
        let textData = plainStr.data(using: .utf8)!
        let ivData = iv.data(using: .utf8)!
        let cryptLength  = size_t(textData.count + kCCKeySizeAES128)
        var cryptData = Data(count:cryptLength)
        let keyLength = size_t(kCCKeySizeAES128)
        let algoritm = CCAlgorithm(kCCAlgorithmAES)
        let options = CCOptions(kCCModeCBC | kCCOptionPKCS7Padding)
        var numBytesEncrypted: Int = 0
        let cryptStatus = keyData?.withUnsafeBytes {keyBytes in
            textData.withUnsafeBytes {dataBytes in
                ivData.withUnsafeBytes {iv in
                    cryptData.withUnsafeMutableBytes {cryptPointer in
                        CCCrypt(CCOperation(kCCEncrypt), algoritm,
                                options,
                                keyBytes, keyLength,
                                iv,
                                dataBytes, textData.count,
                                cryptPointer, cryptLength,
                                &numBytesEncrypted)
                    }
                }
            }
        }
        if cryptStatus == CCCryptorStatus(kCCSuccess) {
            cryptData.count = numBytesEncrypted
        } else {
            return ""
        }
        return (cryptData.base64EncodedString())
```

復号

```swift
let keyData = getSaveKey()
        let textData = Data(base64Encoded: encryptStr)!
        let ivData = iv.data(using: .utf8)!
        let cryptLength  = size_t(textData.count + kCCKeySizeAES128)
        var cryptData = Data(count:cryptLength)
        let keyLength = size_t(kCCKeySizeAES128)
        let algoritm = CCAlgorithm(kCCAlgorithmAES)
        let options = CCOptions(kCCModeCBC | kCCOptionPKCS7Padding)
        var numBytesEncrypted: Int = 0
        let cryptStatus = keyData?.withUnsafeBytes {keyBytes in
            textData.withUnsafeBytes {dataBytes in
                ivData.withUnsafeBytes {iv in
                    cryptData.withUnsafeMutableBytes {cryptPointer in
                        CCCrypt(CCOperation(kCCDecrypt), algoritm,
                                options,
                                keyBytes, keyLength,
                                iv,
                                dataBytes, textData.count,
                                cryptPointer, cryptLength,
                                &numBytesEncrypted)
                    }
                }
            }
        }
        if cryptStatus == CCCryptorStatus(kCCSuccess) {
            cryptData.count = numBytesEncrypted
        } else {
            return ""
        }
        return String.init(data: cryptData, encoding: .utf8)!
```

呼び出し

```swift
let service:KeySrv = KeySrv()
        let str:String = "5000兆円"
        service.generateAesKey()
        NSLog("暗号前:%@", str)
        let encrypt = service.encryptString(plainStr: str)
        NSLog("暗号後:%@", encrypt)
        NSLog("復号後:%@", service.decryptString(encryptStr: encrypt))
        let fake = "OPnpyT3z4PCc368AB3eZ8w=="
        NSLog("fake復号後:%@", service.decryptString(encryptStr: fake))
```

結果

```java
暗号前:5000兆円
暗号後:HPnpyT3z4PCc368AB3eZ8w==
復号後:5000兆円
fake復号後:
```
##最後に
ご覧いただき、ありがとうございます。
次回は、鍵は安全な所に保存されるとリファレンスで確認していたが
一部端末にて安全な所に保存されていないというケースが発生したのでそれを記事して
スマホの鍵操作シリーズは終わりにします。

また、後ほど時間ある時にgithubにプロジェクトをあげます。