Kitura / BlueCryptor

Swift cross-platform crypto library using CommonCrypto/libcrypto
Apache License 2.0
190 stars 47 forks source link
commoncrypto cryptography libcrypto linux macos openssl swift

APIDoc Build Status - Master macOS iOS Linux Apache 2 Slack Status

# BlueCryptor Swift cross-platform crypto library derived from [IDZSwiftCommonCrypto](https://github.com/iosdevzone/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-5.1-RELEASE` toolchain (**Minimum REQUIRED for latest release**) * Swift Open Source `swift-5.4-RELEASE` toolchain (**Recommended**) * Swift toolchain included in *Xcode Version 11.0 or higher*. ### macOS * macOS 10.14.6 (*Mojave*) or higher. * Xcode Version 11.0 or higher using one of the above toolchains. * Xcode Version 12.5 or higher using the included toolchain (*Recommended*). * CommonCrypto is provided by macOS. ### iOS * iOS 10.0 or higher * Xcode Version 11.0 or higher using one of the above toolchains. * Xcode Version 12.5 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) and 18.04. * One of the Swift Open Source toolchain listed above. * OpenSSL is provided by the distribution. **Note:** 1.0.x, 1.1.x and later releases of OpenSSL are supported. * The appropriate **libssl-dev** package is required to be installed when building. ## Build To build **Cryptor** from the command line: ``` % cd % swift build ``` ## Testing To run the supplied unit tests for **Cryptor** from the command line: ``` % cd % swift build % swift test ``` ## Getting started ### Including in your project #### Swift Package Manager To include BlueCryptor into a Swift Package Manager package, add it to the `dependencies` attribute defined in your `Package.swift` file. You can select the version using the `majorVersion` and `minor` parameters. For example: ``` dependencies: [ .Package(url: "https://github.com/Kitura/BlueCryptor.git", majorVersion: , minor: ) ] ``` #### Carthage To include BlueCryptor in a project using Carthage, add a line to your `Cartfile` with the GitHub organization and project names and version. For example: ``` github "Kitura/BlueCryptor" ~> . ``` #### CocoaPods To include BlueCryptor in a project using CocoaPods, you just add `BlueCryptor` to your `Podfile`, for example: ``` platform :ios, '10.0' target 'MyApp' do use_frameworks! pod 'BlueCryptor' end ``` ### Before starting The first thing you need to do is import the Cryptor framework. This is done by the following: ```swift import Cryptor ``` ## API ### Cryptor The following code demonstrates encryption and decryption using `AES` single block CBC mode using optional chaining. ```swift 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`. ```swift 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. ```swift 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. ```swift 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. ```swift 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. ## Community We love to talk server-side Swift and Kitura. Join our [Slack](http://swift-at-ibm-slack.mybluemix.net/) to meet the team! ## License This library is licensed under Apache 2.0. Full license text is available in [LICENSE](https://github.com/Kitura/BlueCryptor/blob/master/LICENSE).