swiftで暗号化、復号化

# 暗号化

## 読み込みと書き出し
暗号化したいファイルの読み込んで暗号化し、そのデータを書き出します。

```swift
// 読み込み
let inputUrl: URL = URL(fileURLWithPath: "/Users/ユーザー名/Desktop/before.json")
let inputData = try! Data(contentsOf: inputUrl)

// 書き出し
let outputUrl: URL = URL(fileURLWithPath: "/Users/ユーザー名/Desktop/encrypto.byte")
try cryptData.write(to: outputUrl)
```

## 暗号化後のデータサイズを計算
IV（initialization vector）を含めたサイズを計算します。

```swift
let ivSize = kCCBlockSizeAES128
let cryptLength = size_t(ivSize + inputData.count + kCCBlockSizeAES128)
```

## 暗号化

```swift
var numBytesEncrypted: size_t = 0
let options = CCOptions(kCCOptionPKCS7Padding)
let cryptStatus = cryptData.withUnsafeMutableBytes { cryptBytes in
  inputData.withUnsafeBytes { dataBytes in
    key.withUnsafeBytes { keyBytes in
      CCCrypt(
        CCOperation(kCCEncrypt),
        CCAlgorithm(kCCAlgorithmAES),
        options,
        keyBytes,
        keyLength,
        cryptBytes,
        dataBytes,
        inputData.count,
        cryptBytes + kCCBlockSizeAES128,
        cryptLength,
        &numBytesEncrypted
      )
    }
  }
}
```

## Bridging Headerの作成
今回はObjective-C製のCommonCryptoを用いるので、Bridging Headerファイルを作成します。

```objc
#import <CommonCrypto/CommonCrypto.h>
```

## ソースコード全文

```encrypto.swift
import Foundation

let inputUrl: URL = URL(fileURLWithPath: "/Users/ユーザー名/Desktop/before.json")
let inputData = try! Data(contentsOf: inputUrl)
let key = "0123456789ABCDEF".data(using: .utf8)!
let keyLength = key.count
let validKeyLengths = [kCCKeySizeAES128, kCCKeySizeAES192, kCCKeySizeAES256]
if validKeyLengths.contains(keyLength) {
  let ivSize = kCCBlockSizeAES128
  let cryptLength = size_t(ivSize + inputData.count + kCCBlockSizeAES128)
  var cryptData = Data(count: cryptLength)
  let status = cryptData.withUnsafeMutableBytes { ivBytes in
    SecRandomCopyBytes(kSecRandomDefault, kCCBlockSizeAES128, ivBytes)
  }
  if status == 0 {
    var numBytesEncrypted: size_t = 0
    let options = CCOptions(kCCOptionPKCS7Padding)
    let cryptStatus = cryptData.withUnsafeMutableBytes { cryptBytes in
      inputData.withUnsafeBytes { dataBytes in
        key.withUnsafeBytes { keyBytes in
          CCCrypt(
            CCOperation(kCCEncrypt),
            CCAlgorithm(kCCAlgorithmAES),
            options,
            keyBytes,
            keyLength,
            cryptBytes,
            dataBytes,
            inputData.count,
            cryptBytes + kCCBlockSizeAES128,
            cryptLength,
            &numBytesEncrypted
          )
        }
      }
    }
    if UInt32(cryptStatus) == UInt32(kCCSuccess) {
      cryptData.count = numBytesEncrypted + ivSize
    } else {
      print("Encryption failed")
      return
    }
    let outputUrl: URL = URL(fileURLWithPath: "/Users/ユーザー名/Desktop/encrypto.byte")
    try cryptData.write(to: outputUrl)
  }
}
```

```bridging-header.h
#import <CommonCrypto/CommonCrypto.h>
```

# 複合化

## 読み込みと書き出し
ファイルを読み込んで復号化して、そのデータを書き出します。

```swift
// 読み込み
let inputUrl: URL = URL(fileURLWithPath: "/Users/ユーザー名/Desktop/encrypto.byte")
let inputData = try! Data(contentsOf: inputUrl)

// 書き出し
let outputUrl: URL = URL(fileURLWithPath: "/Users/ユーザー名/Desktop/after.json")
try clearData.write(to: outputUrl)
```

## 復号化後のデータサイズを計算
IVを除いたサイズを計算します。

```swift
let ivSize = kCCBlockSizeAES128
let clearLength = size_t(inputData.count - ivSize)
```

## 複合

```swift
var numBytesDecrypted: size_t = 0
let options = CCOptions(kCCOptionPKCS7Padding)
let cryptStatus = clearData.withUnsafeMutableBytes { cryptBytes in
  inputData.withUnsafeBytes { dataBytes in
    key.withUnsafeBytes { keyBytes in
      CCCrypt(
        CCOperation(kCCDecrypt),
        CCAlgorithm(kCCAlgorithmAES128),
        options,
        keyBytes,
        keyLength,
        dataBytes,
        dataBytes + kCCBlockSizeAES128,
        clearLength,
        cryptBytes,
        clearLength,
        &numBytesDecrypted
      )
    }
  }
}
```

## Bridging Headerの作成
今回はObjective-C製のCommonCryptoを用いるので、Bridging Headerファイルを作成します。

```objc
#import <CommonCrypto/CommonCrypto.h>
```

## ソースコード全文

```decrypto.swift
import Foundation

let inputUrl: URL = URL(fileURLWithPath: "/Users/ユーザー名/Desktop/encrypto.byte")
let inputData = try! Data(contentsOf: inputUrl)
let key = "0123456789ABCDEF".data(using: .utf8)!
let keyLength = key.count
let validKeyLengths = [kCCKeySizeAES128, kCCKeySizeAES192, kCCKeySizeAES256]
if validKeyLengths.contains(keyLength) {
  let ivSize = kCCBlockSizeAES128
  let clearLength = size_t(inputData.count - ivSize)
  var clearData = Data(count: clearLength)
  var numBytesDecrypted: size_t = 0
  let options = CCOptions(kCCOptionPKCS7Padding)
  let cryptStatus = clearData.withUnsafeMutableBytes { cryptBytes in
    inputData.withUnsafeBytes { dataBytes in
      key.withUnsafeBytes { keyBytes in
        CCCrypt(
          CCOperation(kCCDecrypt),
          CCAlgorithm(kCCAlgorithmAES128),
          options,
          keyBytes,
          keyLength,
          dataBytes,
          dataBytes + kCCBlockSizeAES128,
          clearLength,
          cryptBytes,
          clearLength,
          &numBytesDecrypted
        )
      }
    }
  }
  if UInt32(cryptStatus) == UInt32(kCCSuccess) {
    clearData.count = numBytesDecrypted
  } else {
    print("Decryption failed:", cryptStatus)
    return
  }
  let outputUrl: URL = URL(fileURLWithPath: "/Users/ユーザー名/Desktop/after.json")
  try clearData.write(to: outputUrl)
}
```

```bridging-header.h
#import <CommonCrypto/CommonCrypto.h>
```

# コマンドラインでの実行
## コンパイル
swiftcコマンドでコンパイルします。
`-import-objc-header` オプションでブリッジングヘッダファイルを指定できます。

```
swiftc -import-objc-header bridging-header.h encrypto.swift
```

## 実行
生成された実行ファイルはシェルスクリプトと同じ感じで実行できます。

```
./encrypto
```