{"id":19963212,"url":"https://github.com/rncryptor/rncryptor-objc","last_synced_at":"2025-04-05T01:06:33.193Z","repository":{"id":10998971,"uuid":"67946335","full_name":"RNCryptor/RNCryptor-objc","owner":"RNCryptor","description":"RNCryptor framework in ObjC","archived":false,"fork":false,"pushed_at":"2024-04-16T22:32:33.000Z","size":1014,"stargazers_count":251,"open_issues_count":4,"forks_count":68,"subscribers_count":13,"default_branch":"master","last_synced_at":"2024-04-26T14:03:16.378Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Objective-C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/RNCryptor.png","metadata":{"files":{"readme":"README.md","changelog":"Changelog.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-09-11T18:15:52.000Z","updated_at":"2024-06-18T16:40:01.172Z","dependencies_parsed_at":"2024-06-18T16:56:03.462Z","dependency_job_id":null,"html_url":"https://github.com/RNCryptor/RNCryptor-objc","commit_stats":{"total_commits":304,"total_committers":30,"mean_commits":"10.133333333333333","dds":"0.21052631578947367","last_synced_commit":"4cffc43be0487fc7e884a11085a89b2061b748d4"},"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RNCryptor%2FRNCryptor-objc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RNCryptor%2FRNCryptor-objc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RNCryptor%2FRNCryptor-objc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RNCryptor%2FRNCryptor-objc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/RNCryptor","download_url":"https://codeload.github.com/RNCryptor/RNCryptor-objc/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247271529,"owners_count":20911587,"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-11-13T02:15:08.612Z","updated_at":"2025-04-05T01:06:33.179Z","avatar_url":"https://github.com/RNCryptor.png","language":"Objective-C","readme":"# RNCryptor\n\nCross-language AES Encryptor/Decryptor [data\nformat](https://github.com/RNCryptor/RNCryptor-Spec/blob/master/RNCryptor-Spec-v3.md).\n \nThe primary target is Objective-C, but implementations are available in\n[C++](https://github.com/RNCryptor/RNCryptor-cpp),\n[C#](https://github.com/RNCryptor/RNCryptor-cs),\n[Java](https://github.com/RNCryptor/JNCryptor),\n[PHP](https://github.com/RNCryptor/RNCryptor-php),\n[Python](https://github.com/RNCryptor/RNCryptor-python),\n[Javascript](https://github.com/RNCryptor/rncryptor-js),\nand [Ruby](https://github.com/RNCryptor/ruby_rncryptor).\n\nThe data format includes all the metadata required to securely implement AES\nencryption, as described in [\"Properly encrypting with AES with\nCommonCrypto,\"](http://robnapier.net/aes-commoncrypto) and [*iOS 6\nProgramming Pushing the Limits*](http://iosptl.com), Chapter 15. Specifically,\nit includes:\n\n* AES-256 encryption\n* CBC mode\n* Password stretching with PBKDF2\n* Password salting\n* Random IV\n* Encrypt-then-hash HMAC\n\n## Basic Objective-C Usage\n\nThe most common in-memory use case is as follows:\n\n``` objc\nNSData *data = [@\"Data\" dataUsingEncoding:NSUTF8StringEncoding];\nNSError *error;\nNSData *encryptedData = [RNEncryptor encryptData:data\n                                   \twithSettings:kRNCryptorAES256Settings\n                                          password:aPassword\n                                             error:\u0026error];\n```\n\nThis generates an `NSData` including a header, encryption salt, HMAC salt, IV,\nciphertext, and HMAC. To decrypt this bundle:\n\n``` objc\nNSData *decryptedData = [RNDecryptor decryptData:encryptedData\n                                    withPassword:aPassword\n                                           error:\u0026error];\n```\n\nNote that `RNDecryptor` does not require settings. These are read from the\nheader.\n\n## Asynchronous use\n\n`RNCryptor suports asynchronous use, specifically designed to work with\n`NSURLConnection. This is also useful for cases where the encrypted or decrypted\n`data will not comfortably fit in memory. If the data will comfortably fit in\n`memory, asynchronous operation is best acheived using dispatch_async().\n\nTo operate in asynchronous mode, you create an `RNEncryptor` or `RNDecryptor`,\nproviding it a handler. This handler will be called as data is encrypted or\ndecrypted. As data becomes available, call `addData:`. When you reach the end of\nthe data call `finish`.\n\n``` objc\n- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {\n  [self.encryptedData addData:[self.cryptor addData:data]];\n}\n\n- (void)connectionDidFinishLoading:(NSURLConnection *)connection {\n  [self.cryptor finish];\n}\n\n// Other connection delegates\n\n- (void)decryptionDidFinish {\n  if (self.cryptor.error) {\n    // An error occurred. You cannot trust encryptedData at this point\n  }\n  else {\n    // self.encryptedData is complete. Use it as you like\n  }\n  self.encryptedData = nil;\n  self.cryptor = nil;\n  self.connection = nil;\n}\n\n- (void)decryptRequest:(NSURLRequest *)request {\n  self.encryptedData = [NSMutableData data];\n  self.connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];\n  self.cryptor = [[RNDecryptor alloc] initWithPassword:self.password\n                                               handler:^(RNCryptor *cryptor, NSData *data) {\n                                                   [self.decryptedData appendData:data];\n                                                   if (cryptor.isFinished) {\n                                                     [self decryptionDidFinish];\n                                                   }\n                                                 }];\n}\n```\n\n## Async and Streams\n\nWhen performing async operations on streams, the data can come very quickly\n(particularly if you're reading from a local file). If you use RNCryptor in a\nnaïve way, you'll queue a work blocks faster than the engine can process them\nand your memory usage will spike. This is particularly true if there's only one\ncore, such as on an iPad 1. The solution is to only dispatch new work blocks as\nthe previous work blocks complete.\n\n``` objc\n// Make sure that this number is larger than the header + 1 block.\n// 33+16 bytes = 49 bytes. So it shouldn't be a problem.\nint blockSize = 32 * 1024;\n\nNSInputStream *cryptedStream = [NSInputStream inputStreamWithFileAtPath:@\"C++ Spec.pdf\"];\nNSOutputStream *decryptedStream = [NSOutputStream outputStreamToFileAtPath:@\"/tmp/C++.crypt\" append:NO];\n\n[cryptedStream open];\n[decryptedStream open];\n\n// We don't need to keep making new NSData objects. We can just use one repeatedly.\n__block NSMutableData *data = [NSMutableData dataWithLength:blockSize];\n__block RNEncryptor *decryptor = nil;\n\ndispatch_block_t readStreamBlock = ^{\n  [data setLength:blockSize];\n  NSInteger bytesRead = [cryptedStream read:[data mutableBytes] maxLength:blockSize];\n  if (bytesRead \u003c 0) {\n    // Throw an error\n  }\n  else if (bytesRead == 0) {\n    [decryptor finish];\n  }\n  else {\n    [data setLength:bytesRead];\n    [decryptor addData:data];\n    NSLog(@\"Sent %ld bytes to decryptor\", (unsigned long)bytesRead);\n  }\n};\n\ndecryptor = [[RNEncryptor alloc] initWithSettings:kRNCryptorAES256Settings\n                                         password:@\"blah\"\n                                          handler:^(RNCryptor *cryptor, NSData *data) {\n                                            NSLog(@\"Decryptor recevied %ld bytes\", (unsigned long)data.length);\n                                            [decryptedStream write:data.bytes maxLength:data.length];\n                                            if (cryptor.isFinished) {\n                                              [decryptedStream close];\n                                              // call my delegate that I'm finished with decrypting\n                                            }\n                                            else {\n                                              // Might want to put this in a dispatch_async(), but I don't think you need it.\n                                              readStreamBlock();\n                                            }\n                                          }];\n\n// Read the first block to kick things off    \nreadStreamBlock();\n```\n\nI'll eventually get this into the API to simplify things. See [Cyrille's SO\nquestion](http://stackoverflow.com/a/14586231/97337) for more discussion. Pull\nrequests welcome.\n\n## Building\n\nComes packaged as a static library, but the source files can be dropped into any\nproject. The OpenSSL files are not required.\n\nRequires `Security.framework`.\n\nSupports 10.6+ and iOS 4+.\n\nThe current file format is v3. To read v1 files (see Issue #44), you need to set the compile-time macro `RNCRYPTOR_ALLOW_V1_BAD_HMAC`. It is not possible to write v1 files anymore.\n\n## Design considerations\n\n`RNCryptor` has several design goals, in order of importance:\n\n### Easy to use correctly for most common use cases\n\nThe most critical concern is that it be easy for non-experts to use `RNCryptor` correctly. A framework that is more secure, but requires a steep learning curve on the developer will either be not used, or used incorrectly. Whenever possible, a single line of code should \"do the right thing\" for the most common cases.\n\nThis also requires that it fail correctly and provide good errors.\n\n### Reliance on CommonCryptor functionality\n\n`RNCryptor` has very little \"security\" code. It relies as much as possible on the OS-provided CommonCryptor. If a feature does not exist in CommonCryptor, then it generally will not be provided in `RNCryptor`.\n\n### Best practice security\n\nWherever possible within the above constraints, the best available algorithms\nare applied. This means AES-256, HMAC+SHA1, and PBKDF2:\n\n* AES-256. While Bruce Schneier has made some interesting recommendations\nregarding moving to AES-128 due to certain attacks on AES-256, my current\nthinking is in line with [Colin\nPercival](http://www.daemonology.net/blog/2009-07-31-thoughts-on-AES.html).\nPBKDF2 output is effectively random, which should negate related-keys attacks\nagainst the kinds of use cases we're interested in.\n\n* AES-CBC mode. This was a somewhat complex decision, but the ubiquity of CBC\noutweighs other considerations here. There are no major problems with CBC mode,\nand nonce-based modes like CTR have other trade-offs. See [\"Mode changes for\nRNCryptor\"](http://robnapier.net/blog/mode-rncryptor) for more details on this\ndecision.\n\n* Encrypt-then-MAC. If there were a good authenticated AES mode on iOS (GCM for\ninstance), I would probably use that for its simplicity. Colin Percival makes\n[good arguments for hand-coding an encrypt-than-\nMAC](http://www.daemonology.net/blog/2009-06-24-encrypt-then-mac.html) rather\nthan using an authenticated AES mode, but in RNCryptor mananging the HMAC\nactually adds quite a bit of complexity. I'd rather the complexity at a more\nbroadly peer-reviewed layer like CommonCryptor than at the RNCryptor layer. But\nthis isn't an option, so I fall back to my own Encrypt-than-MAC.\n\n* HMAC+SHA256. No surprises here.\n\n* PBKDF2. While bcrypt and scrypt may be more secure than PBKDF2, CommonCryptor\nonly supports PBKDF2. [NIST also continues to recommend\nPBKDF2](http://security.stackexchange.com/questions/4781/do-any-security-experts-recommend-bcrypt-for-password-storage). We use 10k rounds of PBKDF2\nwhich represents about 80ms on an iPhone 4.\n\n### Code simplicity\n\n`RNCryptor endeavors to be implemented as simply as possible, avoiding tricky\n`code. It is designed to be easy to read and code review.\n\n### Performance\n\nPerformance is a goal, but not the most important goal. The code must be secure\nand easy to use. Within that, it is as fast and memory-efficient as possible.\n\n### Portability\n\nWithout sacrificing other goals, it is preferable to read the output format of\n`RNCryptor` on other platforms.\n\n## Version History\n\n* v2.2 Switches to file format v3 to deal with Issue #77.\n* v2.1 Switches to file format v2 to deal with Issue #44.\n* v2.0 adds asynchronous modes.\n* v2.1 backports `RNCryptor` to older versions of Mac OS X (and possibly iOS).\n\n\n## LICENSE\n\nExcept where otherwise indicated in the source code, this code is licensed under\nthe MIT License:\n\n```\nPermission is hereby granted, free of charge, to any person obtaining a \ncopy of this software and associated documentation files (the \"Software\"),\nto deal in the Software without restriction, including without limitation\nthe rights to use, copy, modify, merge, publish, distribute, sublicense,\nand/or sell copies of the Software, and to permit persons to whom the\nSoftware is furnished to do so, subject to the following conditions:\n \nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR \nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\nDEALINGS IN THE SOFTWARE.\n```\n\nPortions of this code, indicated in the source, are licensed under the following\nlicense:\n\n```\n/*-\n * Copyright (c) 2008 Damien Bergamini \u003cdamien.bergamini@free.fr\u003e\n *\n * Permission to use, copy, modify, and distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n```\n\nPortions of this code, indicated in the source, are licensed under the APSL\nlicense:\n\n```\n/*\n * Copyright (c) 2006-2010 Apple Inc. All Rights Reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n *\n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n *\n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n *\n * @APPLE_LICENSE_HEADER_END@\n */\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frncryptor%2Frncryptor-objc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frncryptor%2Frncryptor-objc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frncryptor%2Frncryptor-objc/lists"}