LoginSignup
5
5

More than 5 years have passed since last update.

swiftで暗号化、復号化

Posted at

暗号化

読み込みと書き出し

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

// 読み込み
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)を含めたサイズを計算します。

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

暗号化

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ファイルを作成します。

#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>

複合化

読み込みと書き出し

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

// 読み込み
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を除いたサイズを計算します。

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

複合

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ファイルを作成します。

#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
5
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
5