Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/iosdevzone/IDZSwiftCommonCrypto
A wrapper for Apple's Common Crypto library written in Swift.
https://github.com/iosdevzone/IDZSwiftCommonCrypto
Last synced: 3 days ago
JSON representation
A wrapper for Apple's Common Crypto library written in Swift.
- Host: GitHub
- URL: https://github.com/iosdevzone/IDZSwiftCommonCrypto
- Owner: iosdevzone
- License: mit
- Created: 2014-09-20T18:55:11.000Z (about 10 years ago)
- Default Branch: master
- Last Pushed: 2023-11-23T22:24:54.000Z (about 1 year ago)
- Last Synced: 2024-08-05T02:21:54.647Z (4 months ago)
- Language: Swift
- Size: 920 KB
- Stars: 476
- Watchers: 12
- Forks: 89
- Open Issues: 4
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
- awesome-ios - IDZSwiftCommonCrypto - A wrapper for Apple's Common Crypto library written in Swift. (Security / Encryption)
- awesome-swift - IDZSwiftCommonCrypto - A wrapper for Apple's Common Crypto library. (Libs / Security)
- awesome-cryptography - IDZSwiftCommonCrypto - Wrapper for Apple's [CommonCrypto](https://opensource.apple.com/source/CommonCrypto/) library written in Swift. (Frameworks and Libs / Swift)
- awesome-swift - IDZSwiftCommonCrypto - A wrapper for Apple's Common Crypto library. (Libs / Security)
- awesome-cryptography - IDZSwiftCommonCrypto - Wrapper for Apple's [CommonCrypto](https://opensource.apple.com/source/CommonCrypto/) library written in Swift. (Frameworks and Libs / Swift)
- awesome-ios-star - IDZSwiftCommonCrypto - A wrapper for Apple's Common Crypto library written in Swift. (Security / Encryption)
- fucking-awesome-swift - IDZSwiftCommonCrypto - A wrapper for Apple's Common Crypto library. (Libs / Security)
- awesome-swift-cn - IDZSwiftCommonCrypto - A wrapper for Apple's Common Crypto library written in Swift. (Libs / Security)
- fucking-awesome-cryptography - IDZSwiftCommonCrypto - Wrapper for Apple's 🌎 [CommonCrypto](opensource.apple.com/source/CommonCrypto/) library written in Swift. (Frameworks and Libs / Swift)
- awesome-swift - IDZSwiftCommonCrypto - A wrapper for Apple's Common Crypto library written in Swift. ` 📝 a year ago` (Security [🔝](#readme))
README
# IDZSwiftCommonCrypto
[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) [![Build Status](https://travis-ci.org/iosdevzone/IDZSwiftCommonCrypto.svg?branch=master)](https://travis-ci.org/iosdevzone/IDZSwiftCommonCrypto) [![Coverage Status](https://coveralls.io/repos/iosdevzone/IDZSwiftCommonCrypto/badge.svg?branch=master&service=github)](https://coveralls.io/github/iosdevzone/IDZSwiftCommonCrypto?branch=master)A Swift wrapper for Apple's `CommonCrypto` library.
IDZSwiftCommonCrypto works with both CocoaPods and Cathage. For more details on how to install it into your projects see [INSTALL.md](INSTALL.md)
**If you are using CococaPods you must use `pod cache clean IDZSwiftCommonCrypto --all` after you upgrade Xcode. This is needed to avoid stale module maps being used from the CocoaPods cache. Removing your Podfile.lock and Pods directory is not sufficient.**
IDZSwiftCommonCrypto provides the following classes:
* `Digest` for calculating message digests,
* `HMAC` for calculating Hash-based Message Authentication Codes,
* `Cryptor` for encrypting and decrypting bounded buffers,
* `StreamCryptor` for encrypting and decrypting streaming information, and
* `PBKDF` for deriving key material from a password or passphrase.Which Release to Use
--------------------
Which version you use depends on which version of Xcode and Swift you are currently using. Please refer to the list below:* 0.7.4 -- Xcode 7.3.1, Swift 2.2
* 0.8.0 -- Xcode 7.3.1, Swift 2.2, with additional APIs for `CCMode`
* 0.8.3 -- Xcode 8.0, Swift 2.3
* 0.9.x -- Xcode 8.0, Swift 3.0
* 0.10.x -- Xcode 9.0, Swift 4.0
* 0.11.x -- Xcode 10.0, Swift 4.2
* 0.12.x -- Xcode 10.2, Swift 5.0
* 0.13.x -- Xcode 11.0, Swift 5.1, iOS 13.0Using `Digest`
--------------To calculate a message digest you create an instance of `Digest`, call `update` one or more times with the data over which the digest is being calculated and finally call `final` to obtain the digest itself.
The `update` method can take a `String`
```swift
let s = "The quick brown fox jumps over the lazy dog."
var md5s2 : Digest = Digest(algorithm:.MD5)
md5s2.update(s)
let digests2 = md5s2.final()// According to Wikipedia this should be
// e4d909c290d0fb1ca068ffaddf22cbd0
hexStringFromArray(digests2)
assert(digests2 == arrayFromHexString("e4d909c290d0fb1ca068ffaddf22cbd0"))
```
or an array of `UInt8` elements:
```swift
let b : [UInt8] =
[0x54,0x68,0x65,0x20,0x71,0x75,0x69,0x63,
0x6b,0x20,0x62,0x72,0x6f,0x77,0x6e,0x20,
0x66,0x6f,0x78,0x2e]
var md5s1 : Digest = Digest(algorithm:.MD5)
md5s1.update(b)
let digests1 = md5s1.final()
```If you only have a single buffer you can simply write
```swift
var digests3 = Digest(algorithm: .md5).update(b)?.final() // digest is of type [UInt8]?
```
or
```swift
var digests4 = Digest(algorithm: .md5).update(s)?.final() // digest is of type [UInt8]?
```### Supported Algorithms
The `Digest` class supports the following algorithms:* `.md2`
* `.md4`
* `.md5`
* `.sha1`
* `.sha224`
* `.sha256`
* `.sha384`
* `.sha512`Using `HMAC`
------------Calculating a keyed-Hash Message Authentication Code (HMAC) is very similar to calculating a message digest, except that the initialization routine now takes a key as well as an algorithm parameter.
```swift
var keys5 = arrayFrom(hexString: "0102030405060708090a0b0c0d0e0f10111213141516171819")
var datas5 : [UInt8] = Array(count:50, repeatedValue:0xcd)
var expecteds5 = arrayFrom(hexString: "4c9007f4026250c6bc8414f9bf50c86c2d7235da")
var hmacs5 = HMAC(algorithm:.sha1, key:keys5).update(datas5)?.final()// RFC2202 says this should be 4c9007f4026250c6bc8414f9bf50c86c2d7235da
let expectedRFC2202 = arrayFrom(hexString: "4c9007f4026250c6bc8414f9bf50c86c2d7235da")
assert(hmacs5! == expectedRFC2202)
```
### Supported Algorithms
* `.md5`
* `.sha1`
* `.sha224`
* `.sha256`
* `.sha384`
* `.sha512`## Using `Cryptor`
```swift
let algorithm = Cryptor.Algorithm.aes
var iv = try! Random.generateBytes(byteCount: algorithm.blockSize())
var key = arrayFrom(hexString: "2b7e151628aed2a6abf7158809cf4f3c")
var plainText = "The quick brown fox jumps over the lazy dog. The fox has more or less had it at this point."var cryptor = Cryptor(operation:.encrypt, algorithm:algorithm, options:.PKCS7Padding, key:key, iv:iv)
var cipherText = cryptor.update(plainText)?.final()cryptor = Cryptor(operation:.decrypt, algorithm:algorithm, options:.PKCS7Padding, key:key, iv:iv)
var decryptedPlainText = cryptor.update(cipherText!)?.final()
var decryptedString = String(bytes: decryptedPlainText!, encoding: .utf8)
decryptedString
assert(decryptedString == plainText)
```### Supported Algorithms
* `.AES`
* `.DES`
* `.TripleDES`
* `.CAST`
* `.RC2`
* `.Blowfish`## Using `StreamCryptor`
To encrypt a large file or a network stream use `StreamCryptor`. The `StreamCryptor` class does not accumulate the encrypted or decrypted data, instead each call to `update` produces an output buffer.
The example below shows how to use `StreamCryptor` to encrypt and decrypt an image file.
```swift
func crypt(sc : StreamCryptor, inputStream: InputStream, outputStream: OutputStream, bufferSize: Int) -> (bytesRead: Int, bytesWritten: Int)
{
var inputBuffer = Array(repeating:0, count:1024)
var outputBuffer = Array(repeating:0, count:1024)var cryptedBytes : Int = 0
var totalBytesWritten = 0
var totalBytesRead = 0
while inputStream.hasBytesAvailable
{
let bytesRead = inputStream.read(&inputBuffer, maxLength: inputBuffer.count)
totalBytesRead += bytesRead
let status = sc.update(bufferIn: inputBuffer, byteCountIn: bytesRead, bufferOut: &outputBuffer, byteCapacityOut: outputBuffer.count, byteCountOut: &cryptedBytes)
assert(status == Status.success)
if(cryptedBytes > 0)
{
let bytesWritten = outputStream.write(outputBuffer, maxLength: Int(cryptedBytes))
assert(bytesWritten == Int(cryptedBytes))
totalBytesWritten += bytesWritten
}
}
let status = sc.final(bufferOut: &outputBuffer, byteCapacityOut: outputBuffer.count, byteCountOut: &cryptedBytes)
assert(status == Status.success)
if(cryptedBytes > 0)
{
let bytesWritten = outputStream.write(outputBuffer, maxLength: Int(cryptedBytes))
assert(bytesWritten == Int(cryptedBytes))
totalBytesWritten += bytesWritten
}
return (totalBytesRead, totalBytesWritten)
}let imagePath = Bundle.main.path(forResource: "Riscal", ofType:"jpg")!
let tmp = NSTemporaryDirectory() as NSString
let encryptedFilePath = "\(tmp)/Riscal.xjpgx"
var decryptedFilePath = "\(tmp)/RiscalDecrypted.jpg"// Prepare the input and output streams for the encryption operation
guard let imageInputStream = InputStream(fileAtPath: imagePath) else {
fatalError("Failed to initialize the image input stream.")
}
imageInputStream.open()
guard let encryptedFileOutputStream = OutputStream(toFileAtPath: encryptedFilePath, append:false) else
{
fatalError("Failed to open output stream.")
}
encryptedFileOutputStream.open()// Generate a new, random initialization vector
let initializationVector = try! Random.generateBytes(byteCount: algorithm.blockSize())// A common way to communicate the initialization vector is to write it at the beginning of the encrypted data.
let bytesWritten = encryptedFileOutputStream.write(initializationVector, maxLength: initializationVector.count)// Now write the encrypted data
var sc = StreamCryptor(operation:.encrypt, algorithm:algorithm, options:.PKCS7Padding, key:key, iv:initializationVector)
guard bytesWritten == initializationVector.count else
{
fatalError("Failed to write initialization vector to encrypted output file.")
}
let outputResult = crypt(sc: sc, inputStream: imageInputStream, outputStream: encryptedFileOutputStream, bufferSize: 1024)
encryptedFileOutputStream.close()
outputResult// Uncomment this line to verify that the file is encrypted
//var encryptedImage = NSImage(contentsOfFile:encryptedFile)// Prepare the input and output streams for the decryption operation
guard let encryptedFileInputStream = InputStream(fileAtPath: encryptedFilePath) else
{
fatalError("Failed to open the encrypted file for input.")
}
encryptedFileInputStream.open()
guard let decryptedFileOutputStream = OutputStream(toFileAtPath: decryptedFilePath, append:false) else {
fatalError("Failed to open the file for the decrypted output file.")
}
decryptedFileOutputStream.open()// Read back the initialization vector.
var readbackInitializationVector = Array(repeating: 0, count: algorithm.blockSize())
let bytesRead = encryptedFileInputStream.read(&readbackInitializationVector, maxLength: readbackInitializationVector.count)// Uncomment this to verify that we did indeed read back the initialization vector.
//assert(readbackInitializationVector == initializationVector)// Now use the read back initialization vector (along with the key) to
sc = StreamCryptor(operation:.decrypt, algorithm:algorithm, options:.PKCS7Padding, key:key, iv:readbackInitializationVector)
let inputResult = crypt(sc: sc, inputStream: encryptedFileInputStream, outputStream: decryptedFileOutputStream, bufferSize: 1024)// Uncomment this to verify that decrypt operation consumed all the encrypted data
// and produced the correct number of bytes of plaintext output.
//assert(inputResult.bytesRead == outputResult.bytesWritten && inputResult.bytesWritten == outputResult.bytesRead)var image = NSImage(named:"Riscal.jpg")
var decryptedImage = NSImage(contentsOfFile:decryptedFilePath)
decryptedImage```
## Using `PBKDF`
The `PBKDF` class provides a method of deriving keys from a user password.
The following example derives a 20-byte key:```swift
let keys6 = PBKDF.deriveKey("password", salt: "salt", prf: .SHA1, rounds: 1, derivedKeyLength: 20)
// RFC 6070 - Should derive 0c60c80f961f0e71f3a9b524af6012062fe037a6
let expectedRFC6070 = arrayFrom(hexString: "0c60c80f961f0e71f3a9b524af6012062fe037a6")
assert(keys6 == expectedRFC6070)
```
### Supported Pseudo-Random Functions
* `.sha1`
* `.sha224`
* `.sha256`
* `.sha384`
* `.sha512`