Swiftpack.co - Package - IBM-Swift/BlueCryptor

macOS iOS Linux Apache 2 Build Status - Master

BlueCryptor

Swift cross-platform crypto library derived from IDZSwiftCommonCrypto.

IMPORTANT NOTE: This release is NOT entirely source code compatible with previous releases. There are instances where exceptions are thrown now instead of the framework calling fatalError(). This means that there are more recoverable errors in the library than before. The only time that fatalError() is called is to indicate either a programming error or a non-recoverable system error.

Note: On macOS and iOS, BlueCryptor uses the Apple provided CommonCrypto library. On Linux, it uses libcrypto from the OpenSSL project.

Prerequisites

Swift

  • Swift Open Source swift-4.0.0-RELEASE toolchain (Minimum REQUIRED for latest release)
  • Swift Open Source swift-4.1.2-RELEASE toolchain (Recommended)
  • Swift toolchain included in Xcode Version 9.4 or higher.

macOS

  • macOS 10.11.6 (El Capitan) or higher.
  • Xcode Version 9.0 or higher using one of the above toolchains.
  • Xcode Version 9.4 or higher using the included toolchain (Recommended).
  • CommonCrypto is provided by macOS.

iOS

  • iOS 10.0 or higher
  • Xcode Version 9.0 or higher using one of the above toolchains.
  • Xcode Version 9.4 or higher using the included toolchain (Recommended).
  • CommonCrypto is provided by iOS.

Linux

  • Ubuntu 16.04 (or 16.10 but only tested on 16.04).
  • One of the Swift Open Source toolchain listed above.
  • OpenSSL 1.0.x is provided by the distribution. Note: Only the 1.0.x releases of OpenSSL are currently supported.

Build

To build Cryptor from the command line:

% cd <path-to-clone>
% swift build

Testing

To run the supplied unit tests for Cryptor from the command line:

% cd <path-to-clone>
% swift build
% swift test

Getting started

import Cryptor

API

Cryptor

The following code demonstrates encryption and decryption using AES single block CBC mode using optional chaining.

let key = CryptoUtils.byteArray(fromHex: "2b7e151628aed2a6abf7158809cf4f3c")
let iv = CryptoUtils.byteArray(fromHex: "00000000000000000000000000000000")
let plainText = CryptoUtils.byteArray(fromHex: "6bc1bee22e409f96e93d7e117393172a")

var textToCipher = plainText
if plainText.count % Cryptor.Algorithm.aes.blockSize != 0 {
	textToCipher = CryptoUtils.zeroPad(byteArray: plainText, blockSize: Cryptor.Algorithm.aes.blockSize)
}
do {
	let cipherText = try Cryptor(operation: .encrypt, algorithm: .aes, options: .none, key: key, iv: iv).update(byteArray: textToCipher)?.final()
		
	print(CryptoUtils.hexString(from: cipherText!))
		
	let decryptedText = try Cryptor(operation: .decrypt, algorithm: .aes, options: .none, key: key, iv: iv).update(byteArray: cipherText!)?.final()

	print(CryptoUtils.hexString(from: decryptedText!))
} catch let error {
	guard let err = error as? CryptorError else {
		// Handle non-Cryptor error...
		return
	}
	// Handle Cryptor error... (See Status.swift for types of errors thrown)
}

Digest

The following example illustrates generating an MD5 digest from both a String and an instance of NSData.

let qbfBytes : [UInt8] = [0x54,0x68,0x65,0x20,0x71,0x75,0x69,0x63,0x6b,0x20,0x62,0x72,0x6f,0x77,0x6e,0x20,0x66,0x6f,0x78,0x20,0x6a,0x75,0x6d,0x70,0x73,0x20,0x6f,0x76,0x65,0x72,0x20,0x74,0x68,0x65,0x20,0x6c,0x61,0x7a,0x79,0x20,0x64,0x6f,0x67,0x2e]
let qbfString = "The quick brown fox jumps over the lazy dog."

// String...
let md5 = Digest(using: .md5)
md5.update(string: qfbString)
let digest = md5.final()

// NSData using optional chaining...
let qbfData = CryptoUtils.data(from: qbfBytes)
let digest = Digest(using: .md5).update(data: qbfData)?.final()

HMAC

The following demonstrates generating an SHA256 HMAC using byte arrays for keys and data.

let myKeyData = "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"
let myData = "4869205468657265"
let key = CryptoUtils.byteArray(fromHex: myKeyData)
let data : [UInt8] = CryptoUtils.byteArray(fromHex: myData)

let hmac = HMAC(using: HMAC.Algorithm.sha256, key: key).update(byteArray: data)?.final()

Key Derivation

The following illustrates generating a key using a password, salt, number of rounds and a specified derived key length using the SHA1 algorithm. Then it shows how to generate a String from resultant key.

let password = "password"
let salt = salt
let rounds: UInt = 2
let derivedKeyLen = 20
do {
	let key = PBKDF.deriveKey(fromPassword: password, salt: salt, prf: .sha1, rounds: rounds, derivedKeyLength: derivedKeyLen)
	let keyString = CryptoUtils.hexString(from: key)
} catch let error {
	guard let err = error as? CryptorError else {
		// Handle non-Cryptor error...
		return
	}
	// Handle Cryptor error... (See Status.swift for types of errors thrown)
}

Random Byte Generation

The following demonstrates generating random bytes of a given length.

let numberOfBytes = 256*256
do {
	let randomBytes = try Random.generate(byteCount: numberOfBytes)
} catch {
  	print("Error generating random bytes")
}

Utilities

Cryptor also provides a set of data manipulation utility functions for conversion of data from various formats:

  • To byteArray ([UInt8])
    • From hex string
    • From UTF8 string
  • To Data
    • From hex string
    • From byte array ([UInt8])
  • To NSData
    • From hex string
    • From byte array ([UInt8])
  • To NSString
    • From byte array ([UInt8])
  • To hexList (String)
    • From byte array ([UInt8])

Also provided are an API to pad a byte array ([UInt8]) such that it is an integral number of block size in bytes long.

  • func zeroPad(byteArray: [UInt8], blockSize: Int) -> [UInt8]
  • func zeroPad(string: String, blockSize: Int) -> [UInt8]

Restrictions

The following algorithm is not available on Linux since it is not supported by OpenSSL.

  • Digest: MD2

In all cases, use of unsupported APIs or algorithms will result in a Swift fatalError(), terminating the program and should be treated as a programming error.

Github

link
Stars: 123
Help us keep the lights on

Releases

1.0.5 - Feb 27, 2018

Version 1.0

Swift cross-platform crypto library derived from [IDZSwiftCommonCrypto]Swift cross-platform crypto library derived from IDZSwiftCommonCrypto.

IMPORTANT NOTE: This release is NOT entirely source code compatible with previous releases. There are instances where exceptions are thrown now instead of the framework calling fatalError(). This means that there are more recoverable errors in the library than before. The only time that fatalError() is called is to indicate either a programming error or a non-recoverable system error.

Note: On macOS and iOS, BlueCryptor uses the Apple provided CommonCrypto library. On Linux, it uses libcrypto from the OpenSSL project.

Prerequisites

Swift

  • Swift Open Source swift-4.0.0-RELEASE toolchain (Minimum REQUIRED for latest release)
  • Swift Open Source swift-4.1-RELEASE toolchain (Recommended)
  • Swift toolchain included in Xcode Version 9.3 (9E145) or higher.

macOS

  • macOS 10.11.6 (El Capitan) or higher.
  • Xcode Version 9.0 (9A325) or higher using one of the above toolchains.
  • Xcode Version 9.3 (9E145) or higher using the included toolchain (Recommended).
  • CommonCrypto is provided by macOS.

iOS

  • iOS 10.0 or higher
  • Xcode Version 9.0 (9A325) or higher using one of the above toolchains.
  • Xcode Version 9.3 (9E145) or higher using the included toolchain (Recommended).
  • CommonCrypto is provided by iOS.

Linux

  • Ubuntu 16.04 (or 16.10 but only tested on 16.04).
  • One of the Swift Open Source toolchain listed above.
  • OpenSSL 1.0.x is provided by the distribution. Note: Only the 1.0.x releases of OpenSSL are currently supported.

Changes since 1.0.0

  • Fixed warnings from Swift 4.1, added build support for 3.1.1 thru 4.1. PR #34.
  • Make Swift 4.1 the default compiler. Issue #35.
  • Support for Xcode 10 Beta. PR #38.
  • Added Swift 4.2 builds to CI.

0.8.27 - Nov 17, 2016

This release minimally requires use of the swift-3.1.1-RELEASE toolchain or the swift-4.0.0-RELEASE toolchain which is recommended.

  • Compatible with Xcode 9.0 (9A235) General Release or higher using one of the above toolchains.
  • Removed old restriction on Digest by now allowing the Data extension to work on Linux as well as macOS.
  • Renamed Updateable protocol to Updatable.
  • Added new Data based update function to Updatable.
  • Added support for SHA1 algorithm in both Digest and HMAC.
  • For every function that took a NSData, there is now an equivalent function that takes a Data object.
  • Added tests for new Data based functions.
  • Allow use on iOS, tvOS and watchOS as well as macOS.
  • Removed the inout modifier from the update(data: Data) function in Updatable extension. It was unnecessary. See issue #7 for more details.
  • Added CI (PR#6).
  • Removed RSA stub. This will be replaced by a forthcoming RSA-centric cross-platform package in the near future.
  • Merged PR #20 to fix a memory leak on Linux.
  • Added iOS target to supplied Xcode project.
  • Merged PR #23 to improve documentation formatting.
  • Support of Xcode 9 Beta.
  • Support for Swift 4.
  • Detect an invalid initialization vector size passed in to the StreamCryptor initializers. Issue #26.
  • Fixed problem with passing the size of an IV passed as a String. Need to account for all the bytes not just the character length which could be different.
  • Added additional tests to cover issue #26.
  • Added CocoaPod support (not quite functional yet).
  • Remove build on Xcode 8.3.
  • CI updates.
  • Completed audit of fatalErrors as per issue #30 . Next step will be the code changes. No code changes with this release, just added comments where fatalError() calls will be removed in a future release and replaced by exceptions and/or Status changes.

0.6.1 - Aug 16, 2016

This release requires use of the swift-DEVELOPMENT-SNAPSHOT-2016-08-015-a toolchain.

  • Compatible with Xcode 8 Beta 6 using the above toolchains.
  • Removed old restriction on Digest by now allowing the Data extension to work on Linux as well as macOS.
  • Renamed Updateable protocol to Updatable.
  • Added new Data based update function to Updatable.
  • Added support for SHA1 algorithm in both Digest and HMAC.
  • For every function that took a NSData, there is now an equivalent function that takes a Data object.
  • Added tests for new Data based functions.

0.5.6 - Aug 6, 2016

This release requires use of the swift-DEVELOPMENT-SNAPSHOT-2016-08-04-a toolchain or the new swift-DEVELOPMENT-SNAPSHOT-2016-08-07-a toolchain.

  • Compatible with Xcode 8 Beta 5 using either of the above toolchains.
  • Removed old restriction on Digest by now allowing the Data extension to work on Linux as well as macOS.
  • Renamed Updateable protocol to Updatable.
  • Added new Data based update function to Updatable.
  • Added support for SHA1 algorithm in both Digest and HMAC.
  • For every function that took a NSData, there is now an equivalent function that takes a Data object.
  • Added tests for new Data based functions.

0.4.0 - Jul 26, 2016

This release requires use of the new swift-DEVELOPMENT-SNAPSHOT-2016-07-25-a toolchain.

Note: Due to inconsistencies in the implementation of Data on macOS and Linux, this release continues to use the NSData and NSMutableData types. Once these inconsistencies are rectified, the Data type will be adopted.