{"id":20492544,"url":"https://github.com/redmadrobot/golden-key","last_synced_at":"2025-04-13T17:05:03.340Z","repository":{"id":56912845,"uuid":"188848405","full_name":"RedMadRobot/golden-key","owner":"RedMadRobot","description":"Security framework compatible with CryptoKit","archived":false,"fork":false,"pushed_at":"2019-11-07T12:38:57.000Z","size":430,"stargazers_count":12,"open_issues_count":0,"forks_count":2,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-04-13T17:05:01.089Z","etag":null,"topics":["aes","commoncrypto","cryptography","digest","swift"],"latest_commit_sha":null,"homepage":"","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/RedMadRobot.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}},"created_at":"2019-05-27T13:27:23.000Z","updated_at":"2023-07-15T10:10:44.000Z","dependencies_parsed_at":"2022-08-20T20:50:26.583Z","dependency_job_id":null,"html_url":"https://github.com/RedMadRobot/golden-key","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RedMadRobot%2Fgolden-key","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RedMadRobot%2Fgolden-key/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RedMadRobot%2Fgolden-key/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RedMadRobot%2Fgolden-key/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/RedMadRobot","download_url":"https://codeload.github.com/RedMadRobot/golden-key/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248750074,"owners_count":21155685,"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":["aes","commoncrypto","cryptography","digest","swift"],"created_at":"2024-11-15T17:29:32.369Z","updated_at":"2025-04-13T17:05:03.239Z","avatar_url":"https://github.com/RedMadRobot.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n    \u003cimg src=\"https://user-images.githubusercontent.com/1762267/60340408-2676e580-99b4-11e9-8661-c42d4bb7461b.png\" alt=\"GoldenKey\"\u003e\n\u003c/p\u003e\n\n# GoldenKey\n\nSwift wrapper around CommonCrypto and Security frameworks\n\n## Common Digest\n\nSupported algorithms: MD2, MD4, MD5, SHA1, SHA224, SHA256, SHA384, SHA512.\n\nStream hasher.\n\n```swift\nlet sha = SHA256()\nsha.update(data: Data(\"12\".utf8))\nsha.update(data: [1, 2])\n\nlet degest = sha.finalize()\n```\n\nOne shot.\n\n```swift\nlet digest = SHA256.hash(data: Data(\"123\".utf8))\n```\n\nAll hash functions return type conform to `Digest` protocol .\nYou can convert digest to common types like a `Data` and `[UInt8]`.\n\n```swift\nlet data = Data(digest)\nlet bytes: [UInt8] = Array(digest)\n```\n\n## HMAC\nhash-based message authentication code\n\nStream hasher.\n\n```swift\nlet key = Data(\"secret_key\".utf8)\nlet hmac = HMAC(algorithm: .md5, key: key)\n\nhmac.update(data: Data(\"ab\".utf8))\nhmac.update(data: Data(\"cd\".utf8))\nlet hash = hmac.finalize()\n```\n\nOne shot.\n\n```swift\nlet key = Data(\"secret_key\".utf8)\nlet data = Data(\"abcd\".utf8)\n\nlet hash = HMAC.hash(algorithm: .sha224, data: data, key: key)\n```\n\n## Setup for development\n\n```bash\n$ mkdir gyb\n$ cd gyb\n$ wget https://github.com/apple/swift/raw/master/utils/gyb\n$ wget https://github.com/apple/swift/raw/master/utils/gyb.py\n$ chmod +x gyb\n```\n\n# Efficient way to calculate hash of a large file\n\nTo calculate hash of a large file use `DispatchIO`.\n\nIn the example below `DispatchIO` reads a file by chunks and process every chunk by calling update method of `SHA256` class.\n\nThe default chunk size is set to 128 MB to limit maximum memory usage.\n\n![Screenshot](./scr.png)\n\n```swift\nimport Foundation\nimport GoldenKey\n\nfinal class FileHash {\n    \n    private let workQueue: DispatchQueue\n    private let dispatchIO: DispatchIO\n    \n    /// Opens and prepares a file for reading.\n    /// - Parameter fileURL: URL of the file.\n    /// - Parameter workQueue: DispatchQueue on which to perform work (read and calculating hash).\n    /// - Parameter queue: DispatchQueue of the completion handler.\n    /// - Parameter completion: Calls when the file closed. Useful when you want to calculate hash of multiple files sequentially.\n    init(\n        fileURL: URL,\n        workQueue: DispatchQueue = .init(label: \"work\", qos: .userInitiated),\n        queue: DispatchQueue = .main,\n        completion: (() -\u003e Void)? = nil) throws {\n        \n        self.workQueue = workQueue\n        \n        let fileHandle = try FileHandle(forReadingFrom: fileURL)\n        \n        dispatchIO = DispatchIO(\n            type: .stream,\n            fileDescriptor: fileHandle.fileDescriptor,\n            queue: queue,\n            cleanupHandler: { _ in\n                fileHandle.closeFile()\n                queue.async { completion?() }\n            }\n        )\n        dispatchIO.setLimit(lowWater: Int.max)\n    }\n    \n    /// Calculates hash of the file\n    /// - Parameter hashFunctionType: Hash function type. SHA256.self for example.\n    /// - Parameter chunkSize: Max memory usage. 128 MB by default.\n    /// - Parameter queue: DispatchQueue of the completion handler.\n    /// - Parameter completion: Completion handler.\n    func calculateHash(\n        hashFunctionType: Digest.Type,\n        chunkSize: Int = 128 * 1024 * 1024,\n        queue: DispatchQueue = .main,\n        completion: @escaping (Result\u003cData, POSIXError\u003e) -\u003e Void) {\n        \n        let hashFunction = hashFunctionType.init()\n        \n        func readNextChunk() {\n            dispatchIO.read(offset: 0, length: chunkSize, queue: workQueue) { [weak self] (done, data, error) in\n                guard let self = self else { return }\n                \n                guard error == 0 else {\n                    let error = POSIXError(POSIXErrorCode(rawValue: error)!)\n                    self.dispatchIO.close(flags: .stop)\n                    queue.async {\n                        completion(.failure(error))\n                    }\n                    return\n                }\n                \n                guard let data = data else { return }\n                \n                if data.isEmpty == false {\n                    data.regions.forEach { hashFunction.update(data: $0) }\n                }\n                \n                if done, data.isEmpty {\n                    self.dispatchIO.close()\n                    \n                    let digest = hashFunction.finalize()\n                    queue.async {\n                        completion(.success(digest))\n                    }\n                }\n                \n                if done, data.isEmpty == false {\n                    readNextChunk()\n                }\n            }\n        }\n        \n        readNextChunk()\n    }\n    \n}\n```\n\n## Usage example\n```swift\n\nextension Data {\n    /// Presents Data in hex format\n    var hexDescription: String {\n        return reduce(\"\") {$0 + String(format: \"%02x\", $1)}\n    }\n}\n\ndo {\n    let fileURL = URL(string: \"absolute_path_to_file\")!\n    let fileHash = try FileHash(fileURL: fileURL)\n    fileHash.calculateHash(hashFunctionType: SHA256.self) { result in\n        switch result {\n        case .success(let hash):\n            print(hash.hexDescription)\n        case .failure(let error):\n            print(error.localizedDescription)\n        }\n    }\n} catch (let error) {\n    print(error.localizedDescription)\n}\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fredmadrobot%2Fgolden-key","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fredmadrobot%2Fgolden-key","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fredmadrobot%2Fgolden-key/lists"}