{"id":1941,"url":"https://github.com/iosdevzone/IDZSwiftCommonCrypto","last_synced_at":"2025-08-06T14:31:41.775Z","repository":{"id":20982282,"uuid":"24271480","full_name":"iosdevzone/IDZSwiftCommonCrypto","owner":"iosdevzone","description":"A wrapper for Apple's Common Crypto library written in Swift.","archived":false,"fork":false,"pushed_at":"2023-11-23T22:24:54.000Z","size":942,"stargazers_count":476,"open_issues_count":4,"forks_count":89,"subscribers_count":12,"default_branch":"master","last_synced_at":"2024-08-05T02:21:54.647Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/iosdevzone.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2014-09-20T18:55:11.000Z","updated_at":"2024-07-31T05:13:08.000Z","dependencies_parsed_at":"2023-11-23T23:36:54.468Z","dependency_job_id":null,"html_url":"https://github.com/iosdevzone/IDZSwiftCommonCrypto","commit_stats":{"total_commits":218,"total_committers":17,"mean_commits":"12.823529411764707","dds":"0.22477064220183485","last_synced_commit":"29c201ba349b025c671904a441e7631dce756792"},"previous_names":[],"tags_count":49,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iosdevzone%2FIDZSwiftCommonCrypto","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iosdevzone%2FIDZSwiftCommonCrypto/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iosdevzone%2FIDZSwiftCommonCrypto/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iosdevzone%2FIDZSwiftCommonCrypto/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/iosdevzone","download_url":"https://codeload.github.com/iosdevzone/IDZSwiftCommonCrypto/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":215780273,"owners_count":15929791,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-01-05T20:15:59.500Z","updated_at":"2024-08-17T16:31:13.413Z","avatar_url":"https://github.com/iosdevzone.png","language":"Swift","funding_links":[],"categories":["Security","Libs","Swift","Frameworks and Libs","Security [🔝](#readme)"],"sub_categories":["Encryption","Security","Other free courses","Swift"],"readme":"# IDZSwiftCommonCrypto \n[![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\u0026service=github)](https://coveralls.io/github/iosdevzone/IDZSwiftCommonCrypto?branch=master)\n\n\nA Swift wrapper for Apple's `CommonCrypto` library.\n\nIDZSwiftCommonCrypto works with both CocoaPods and Cathage. For more details on how to install it into your projects see [INSTALL.md](INSTALL.md)\n\n**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.**\n\nIDZSwiftCommonCrypto provides the following classes:\n\n* `Digest` for calculating message digests,\n* `HMAC` for calculating Hash-based Message Authentication Codes,\n* `Cryptor` for encrypting and decrypting bounded buffers,\n* `StreamCryptor` for encrypting and decrypting streaming information, and\n* `PBKDF` for deriving key material from a password or passphrase.\n\nWhich Release to Use\n--------------------\nWhich version you use depends on which version of Xcode and Swift you are currently using. Please refer to the list below:\n\n* 0.7.4 -- Xcode 7.3.1, Swift 2.2\n* 0.8.0 -- Xcode 7.3.1, Swift 2.2, with additional APIs for `CCMode`\n* 0.8.3 -- Xcode 8.0, Swift 2.3\n* 0.9.x -- Xcode 8.0, Swift 3.0\n* 0.10.x -- Xcode 9.0, Swift 4.0\n* 0.11.x -- Xcode 10.0, Swift 4.2\n* 0.12.x -- Xcode 10.2, Swift 5.0\n* 0.13.x -- Xcode 11.0, Swift 5.1, iOS 13.0\n\nUsing `Digest`\n--------------\n\nTo 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.\n\nThe `update` method can take a `String`\n```swift\nlet  s = \"The quick brown fox jumps over the lazy dog.\"\nvar md5s2 : Digest = Digest(algorithm:.MD5)\nmd5s2.update(s)\nlet digests2 = md5s2.final()\n\n// According to Wikipedia this should be\n// e4d909c290d0fb1ca068ffaddf22cbd0\nhexStringFromArray(digests2)\nassert(digests2 == arrayFromHexString(\"e4d909c290d0fb1ca068ffaddf22cbd0\"))\n```\nor an array of `UInt8` elements:\n```swift\nlet b : [UInt8] = \n[0x54,0x68,0x65,0x20,0x71,0x75,0x69,0x63,\n0x6b,0x20,0x62,0x72,0x6f,0x77,0x6e,0x20,\n0x66,0x6f,0x78,0x2e]\nvar md5s1 : Digest = Digest(algorithm:.MD5)\nmd5s1.update(b)\nlet digests1 = md5s1.final()\n```\n\nIf you only have a single buffer you can simply write\n```swift\n  var digests3 = Digest(algorithm: .md5).update(b)?.final() // digest is of type [UInt8]?\n```\nor \n```swift\n  var digests4 = Digest(algorithm: .md5).update(s)?.final() // digest is of type [UInt8]?\n```\n\n### Supported Algorithms\nThe `Digest` class supports the following algorithms:\n\n* `.md2` \n* `.md4` \n* `.md5` \n* `.sha1` \n* `.sha224` \n* `.sha256`\n* `.sha384`\n* `.sha512`\n\nUsing `HMAC`\n------------\n\nCalculating 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.\n\n```swift\nvar keys5 = arrayFrom(hexString: \"0102030405060708090a0b0c0d0e0f10111213141516171819\")\nvar datas5 : [UInt8] = Array(count:50, repeatedValue:0xcd)\nvar expecteds5 = arrayFrom(hexString: \"4c9007f4026250c6bc8414f9bf50c86c2d7235da\")\nvar hmacs5 = HMAC(algorithm:.sha1, key:keys5).update(datas5)?.final()\n\n// RFC2202 says this should be 4c9007f4026250c6bc8414f9bf50c86c2d7235da\nlet expectedRFC2202 = arrayFrom(hexString: \"4c9007f4026250c6bc8414f9bf50c86c2d7235da\")\nassert(hmacs5! == expectedRFC2202)\n```\n### Supported Algorithms\n* `.md5`\n* `.sha1`\n* `.sha224`\n* `.sha256`\n* `.sha384`\n* `.sha512`\n\n## Using `Cryptor`\n\n```swift\nlet algorithm = Cryptor.Algorithm.aes\nvar iv = try! Random.generateBytes(byteCount: algorithm.blockSize())\nvar key = arrayFrom(hexString: \"2b7e151628aed2a6abf7158809cf4f3c\")\nvar plainText = \"The quick brown fox jumps over the lazy dog. The fox has more or less had it at this point.\"\n\nvar cryptor = Cryptor(operation:.encrypt, algorithm:algorithm, options:.PKCS7Padding, key:key, iv:iv)\nvar cipherText = cryptor.update(plainText)?.final()\n\ncryptor = Cryptor(operation:.decrypt, algorithm:algorithm, options:.PKCS7Padding, key:key, iv:iv)\nvar decryptedPlainText = cryptor.update(cipherText!)?.final()\nvar decryptedString = String(bytes: decryptedPlainText!, encoding: .utf8)\ndecryptedString\nassert(decryptedString == plainText)\n```\n\n### Supported Algorithms\n* `.AES`\n* `.DES` \n* `.TripleDES` \n* `.CAST` \n* `.RC2` \n* `.Blowfish`\n\n## Using `StreamCryptor`\n\nTo 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. \n\nThe example below shows how to use `StreamCryptor` to encrypt and decrypt an image file.\n```swift\nfunc crypt(sc : StreamCryptor,  inputStream: InputStream, outputStream: OutputStream, bufferSize: Int) -\u003e (bytesRead: Int, bytesWritten: Int)\n{\n    var inputBuffer = Array\u003cUInt8\u003e(repeating:0, count:1024)\n    var outputBuffer = Array\u003cUInt8\u003e(repeating:0, count:1024)\n\n\n    var cryptedBytes : Int = 0\n    var totalBytesWritten = 0\n    var totalBytesRead = 0\n    while inputStream.hasBytesAvailable\n    {\n        let bytesRead = inputStream.read(\u0026inputBuffer, maxLength: inputBuffer.count)\n        totalBytesRead += bytesRead\n        let status = sc.update(bufferIn: inputBuffer, byteCountIn: bytesRead, bufferOut: \u0026outputBuffer, byteCapacityOut: outputBuffer.count, byteCountOut: \u0026cryptedBytes)\n        assert(status == Status.success)\n        if(cryptedBytes \u003e 0)\n        {\n            let bytesWritten = outputStream.write(outputBuffer, maxLength: Int(cryptedBytes))\n            assert(bytesWritten == Int(cryptedBytes))\n            totalBytesWritten += bytesWritten\n        }\n    }\n    let status = sc.final(bufferOut: \u0026outputBuffer, byteCapacityOut: outputBuffer.count, byteCountOut: \u0026cryptedBytes)    \n    assert(status == Status.success)\n    if(cryptedBytes \u003e 0)\n    {\n        let bytesWritten = outputStream.write(outputBuffer, maxLength: Int(cryptedBytes))\n        assert(bytesWritten == Int(cryptedBytes))\n        totalBytesWritten += bytesWritten\n    }\n    return (totalBytesRead, totalBytesWritten)\n}\n\nlet imagePath = Bundle.main.path(forResource: \"Riscal\", ofType:\"jpg\")!\nlet tmp = NSTemporaryDirectory() as NSString\nlet encryptedFilePath = \"\\(tmp)/Riscal.xjpgx\"\nvar decryptedFilePath = \"\\(tmp)/RiscalDecrypted.jpg\"\n\n// Prepare the input and output streams for the encryption operation\nguard let imageInputStream = InputStream(fileAtPath: imagePath) else {\n    fatalError(\"Failed to initialize the image input stream.\")\n}\nimageInputStream.open()\nguard let  encryptedFileOutputStream = OutputStream(toFileAtPath: encryptedFilePath, append:false) else\n{\n    fatalError(\"Failed to open output stream.\")\n}\nencryptedFileOutputStream.open()\n\n// Generate a new, random initialization vector\nlet initializationVector = try! Random.generateBytes(byteCount: algorithm.blockSize())\n\n// A common way to communicate the initialization vector is to write it at the beginning of the encrypted data.\nlet bytesWritten = encryptedFileOutputStream.write(initializationVector, maxLength: initializationVector.count)\n\n// Now write the encrypted data\nvar sc = StreamCryptor(operation:.encrypt, algorithm:algorithm, options:.PKCS7Padding, key:key, iv:initializationVector)\nguard  bytesWritten == initializationVector.count else\n{\n    fatalError(\"Failed to write initialization vector to encrypted output file.\")\n}\nlet outputResult = crypt(sc: sc, inputStream: imageInputStream, outputStream: encryptedFileOutputStream, bufferSize: 1024)\nencryptedFileOutputStream.close()\noutputResult\n\n// Uncomment this line to verify that the file is encrypted\n//var encryptedImage = NSImage(contentsOfFile:encryptedFile)\n\n// Prepare the input and output streams for the decryption operation\nguard let encryptedFileInputStream = InputStream(fileAtPath: encryptedFilePath) else\n{\n    fatalError(\"Failed to open the encrypted file for input.\")\n}\nencryptedFileInputStream.open()\nguard let decryptedFileOutputStream = OutputStream(toFileAtPath: decryptedFilePath, append:false) else {\n    fatalError(\"Failed to open the file for the decrypted output file.\")\n}\ndecryptedFileOutputStream.open()\n\n// Read back the initialization vector.\nvar readbackInitializationVector = Array\u003cUInt8\u003e(repeating: 0, count: algorithm.blockSize())\nlet bytesRead = encryptedFileInputStream.read(\u0026readbackInitializationVector, maxLength: readbackInitializationVector.count)\n\n// Uncomment this to verify that we did indeed read back the initialization vector.\n//assert(readbackInitializationVector == initializationVector)\n\n// Now use the read back initialization vector (along with the key) to\nsc = StreamCryptor(operation:.decrypt, algorithm:algorithm, options:.PKCS7Padding, key:key, iv:readbackInitializationVector)\nlet inputResult = crypt(sc: sc, inputStream: encryptedFileInputStream, outputStream: decryptedFileOutputStream, bufferSize: 1024)\n\n// Uncomment this to verify that decrypt operation consumed all the encrypted data\n// and produced the correct number of bytes of plaintext output.\n//assert(inputResult.bytesRead == outputResult.bytesWritten \u0026\u0026 inputResult.bytesWritten == outputResult.bytesRead)\n\nvar image = NSImage(named:\"Riscal.jpg\")\nvar decryptedImage = NSImage(contentsOfFile:decryptedFilePath)\ndecryptedImage\n\n\n```\n\n## Using `PBKDF` \n\nThe `PBKDF` class provides a method of deriving keys from a user password. \nThe following example derives a 20-byte key:\n\n```swift\nlet keys6 = PBKDF.deriveKey(\"password\", salt: \"salt\", prf: .SHA1, rounds: 1, derivedKeyLength: 20)\n// RFC 6070 - Should derive 0c60c80f961f0e71f3a9b524af6012062fe037a6\nlet expectedRFC6070 = arrayFrom(hexString: \"0c60c80f961f0e71f3a9b524af6012062fe037a6\")\nassert(keys6 == expectedRFC6070)\n```\n### Supported Pseudo-Random Functions\n* `.sha1`\n* `.sha224` \n* `.sha256` \n* `.sha384` \n* `.sha512`\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fiosdevzone%2FIDZSwiftCommonCrypto","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fiosdevzone%2FIDZSwiftCommonCrypto","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fiosdevzone%2FIDZSwiftCommonCrypto/lists"}