RNCryptor.swift 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782
  1. //
  2. // RNCryptor.swift
  3. //
  4. // Copyright © 2015 Rob Napier. All rights reserved.
  5. //
  6. // This code is licensed under the MIT License:
  7. //
  8. // Permission is hereby granted, free of charge, to any person obtaining a
  9. // copy of this software and associated documentation files (the "Software"),
  10. // to deal in the Software without restriction, including without limitation
  11. // the rights to use, copy, modify, merge, publish, distribute, sublicense,
  12. // and/or sell copies of the Software, and to permit persons to whom the
  13. // Software is furnished to do so, subject to the following conditions:
  14. //
  15. // The above copyright notice and this permission notice shall be included in
  16. // all copies or substantial portions of the Software.
  17. //
  18. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
  21. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  23. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  24. // DEALINGS IN THE SOFTWARE.
  25. //
  26. import Foundation
  27. import Cryptor
  28. /// The `RNCryptorType` protocol defines generic API to a mutable,
  29. /// incremental, password-based encryptor or decryptor. Its generic
  30. /// usage is as follows:
  31. ///
  32. /// let cryptor = Encryptor(password: "mypassword")
  33. /// // or Decryptor()
  34. ///
  35. /// var result = Data()
  36. /// for data in datas {
  37. /// result.appendData(try cryptor.update(data))
  38. /// }
  39. /// result.appendData(try cryptor.final())
  40. ///
  41. /// After calling `finalData()`, the cryptor is no longer valid.
  42. public protocol RNCryptorType {
  43. /// Creates and returns a cryptor.
  44. ///
  45. /// - parameter password: Non-empty password string. This will be interpretted as UTF-8.
  46. init(password: String)
  47. /// Updates cryptor with data and returns processed data.
  48. ///
  49. /// - parameter data: Data to process. May be empty.
  50. /// - throws: `Error`
  51. /// - returns: Processed data. May be empty.
  52. func update(withData data: Data) throws -> Data
  53. /// Returns trailing data and invalidates the cryptor.
  54. ///
  55. /// - throws: `Error`
  56. /// - returns: Trailing data
  57. func finalData() throws -> Data
  58. }
  59. public extension RNCryptorType {
  60. /// Simplified, generic interface to `RNCryptorType`. Takes a data,
  61. /// returns a processed data. Generally you should use
  62. /// `RNCryptor.encrypt(data:withPassword:)`, or
  63. /// `RNCryptor.decrypt(data:withPassword:)` instead, but this is useful
  64. /// for code that is neutral on whether it is encrypting or decrypting.
  65. ///
  66. /// - throws: `Error`
  67. fileprivate func oneshot(data: Data) throws -> Data {
  68. var result = try update(withData: data)
  69. result.append(try finalData())
  70. return result
  71. }
  72. }
  73. /// RNCryptor encryption/decryption interface.
  74. public enum RNCryptor {
  75. /// Errors thrown by `RNCryptorType`.
  76. public enum Error: Int, Swift.Error {
  77. /// Ciphertext was corrupt or password was incorrect.
  78. /// It is not possible to distinguish between these cases in the v3 data format.
  79. case hmacMismatch = 1
  80. /// Unrecognized data format. Usually this means the data is corrupt.
  81. case unknownHeader = 2
  82. /// `final()` was called before sufficient data was passed to `update(withData:)`
  83. case messageTooShort
  84. /// Memory allocation failure. This should never happen.
  85. case memoryFailure
  86. /// A password-based decryptor was used on a key-based ciphertext, or vice-versa.
  87. case invalidCredentialType
  88. }
  89. /// Encrypt data using password and return encrypted data.
  90. public static func encrypt(data: Data, withPassword password: String) -> Data {
  91. return Encryptor(password: password).encrypt(data: data)
  92. }
  93. /// Decrypt data using password and return decrypted data. Throws if
  94. /// password is incorrect or ciphertext is in the wrong format.
  95. /// - throws `Error`
  96. public static func decrypt(data: Data, withPassword password: String) throws -> Data {
  97. return try Decryptor(password: password).decrypt(data: data)
  98. }
  99. /// Generates random Data of given length
  100. /// Crashes if `length` is larger than allocatable memory, or if the system random number generator is not available.
  101. public static func randomData(ofLength length: Int) -> Data {
  102. var data = Data(count: length)!
  103. let result = data.withUnsafeMutableBytes { return SecRandomCopyBytes(kSecRandomDefault, length, $0) }
  104. guard result == errSecSuccess else {
  105. fatalError("SECURITY FAILURE: Could not generate secure random numbers: \(result).")
  106. }
  107. return data
  108. }
  109. /// A encryptor for the latest data format. If compatibility with other RNCryptor
  110. /// implementations is required, you may wish to use the specific encryptor version rather
  111. /// than accepting "latest."
  112. ///
  113. public final class Encryptor: RNCryptorType {
  114. private let encryptor: EncryptorV3
  115. /// Creates and returns a cryptor.
  116. ///
  117. /// - parameter password: Non-empty password string. This will be interpretted as UTF-8.
  118. public init(password: String) {
  119. precondition(password != "")
  120. encryptor = EncryptorV3(password: password)
  121. }
  122. /// Updates cryptor with data and returns processed data.
  123. ///
  124. /// - parameter data: Data to process. May be empty.
  125. /// - returns: Processed data. May be empty.
  126. public func update(withData data: Data) -> Data {
  127. return encryptor.update(withData: data)
  128. }
  129. /// Returns trailing data and invalidates the cryptor.
  130. ///
  131. /// - returns: Trailing data
  132. public func finalData() -> Data {
  133. return encryptor.finalData()
  134. }
  135. /// Simplified, generic interface to `RNCryptorType`. Takes a data,
  136. /// returns a processed data, and invalidates the cryptor.
  137. public func encrypt(data: Data) -> Data {
  138. return encryptor.encrypt(data: data)
  139. }
  140. }
  141. /// Password-based decryptor that can handle any supported format.
  142. public final class Decryptor : RNCryptorType {
  143. private var decryptors: [VersionedDecryptorType.Type] = [DecryptorV3.self]
  144. private var buffer = Data()
  145. private var decryptor: RNCryptorType?
  146. private let password: String
  147. /// Creates and returns a cryptor.
  148. ///
  149. /// - parameter password: Non-empty password string. This will be interpretted as UTF-8.
  150. public init(password: String) {
  151. assert(password != "")
  152. self.password = password
  153. }
  154. /// Decrypt data using password and return decrypted data, invalidating decryptor. Throws if
  155. /// password is incorrect or ciphertext is in the wrong format.
  156. /// - throws `Error`
  157. public func decrypt(data: Data) throws -> Data {
  158. return try oneshot(data: data)
  159. }
  160. /// Updates cryptor with data and returns processed data.
  161. ///
  162. /// - parameter data: Data to process. May be empty.
  163. /// - throws: `Error`
  164. /// - returns: Processed data. May be empty.
  165. public func update(withData data: Data) throws -> Data {
  166. if let d = decryptor {
  167. return try d.update(withData: data)
  168. }
  169. buffer.append(data)
  170. let toCheck:[VersionedDecryptorType.Type]
  171. (toCheck, decryptors) = decryptors.splitPassFail { self.buffer.count >= $0.preambleSize }
  172. for decryptorType in toCheck {
  173. if decryptorType.canDecrypt(preamble: buffer.subdata(in: 0..<decryptorType.preambleSize)) {
  174. let d = decryptorType.init(password: password)
  175. decryptor = d
  176. let result = try d.update(withData: buffer)
  177. buffer.count = 0
  178. return result
  179. }
  180. }
  181. guard !decryptors.isEmpty else { throw Error.unknownHeader }
  182. return Data()
  183. }
  184. /// Returns trailing data and invalidates the cryptor.
  185. ///
  186. /// - throws: `Error`
  187. /// - returns: Trailing data
  188. public func finalData() throws -> Data {
  189. guard let d = decryptor else {
  190. throw Error.unknownHeader
  191. }
  192. return try d.finalData()
  193. }
  194. }
  195. }
  196. // V3 implementaion
  197. public extension RNCryptor {
  198. /// V3 format settings
  199. public final class FormatV3 {
  200. /// Size of AES and HMAC keys
  201. public static let keySize = kCCKeySizeAES256
  202. /// Size of PBKDF2 salt
  203. public static let saltSize = 8
  204. /// Generate a key from a password and salt
  205. /// - parameters:
  206. /// - password: Password to convert
  207. /// - salt: Salt. Generally constructed with RNCryptor.randomDataOfLength(FormatV3.saltSize)
  208. /// - returns: Key of length FormatV3.keySize
  209. public static func makeKey(forPassword password: String, withSalt salt: Data) -> Data {
  210. var derivedKey = Data(count: keySize)!
  211. let passwordData = password.data(using: String.Encoding.utf8)!
  212. let result: CCCryptorStatus = derivedKey.withUnsafeMutableBytes { (derivedKeyPtr : UnsafeMutablePointer<UInt8>) in
  213. passwordData.withUnsafeBytes { (passwordPtr : UnsafePointer<Int8>) in
  214. salt.withUnsafeBytes { (saltPtr : UnsafePointer<UInt8>) in
  215. // All the crazy casting because CommonCryptor hates Swift
  216. let algorithm = CCPBKDFAlgorithm(kCCPBKDF2)
  217. let prf = CCPseudoRandomAlgorithm(kCCPRFHmacAlgSHA1)
  218. let pbkdf2Rounds = UInt32(10000)
  219. return CCCryptorStatus(
  220. CCKeyDerivationPBKDF(
  221. algorithm,
  222. passwordPtr, passwordData.count,
  223. saltPtr, salt.count,
  224. prf, pbkdf2Rounds,
  225. derivedKeyPtr, derivedKey.count)
  226. )
  227. }
  228. }
  229. }
  230. guard result == CCCryptorStatus(kCCSuccess) else {
  231. fatalError("SECURITY FAILURE: Could not derive secure password (\(result)): \(derivedKey).")
  232. }
  233. return derivedKey
  234. }
  235. static let formatVersion = UInt8(3)
  236. static let ivSize = kCCBlockSizeAES128
  237. static let hmacSize = Int(CC_SHA256_DIGEST_LENGTH)
  238. static let keyHeaderSize = 1 + 1 + kCCBlockSizeAES128
  239. static let passwordHeaderSize = 1 + 1 + 8 + 8 + kCCBlockSizeAES128
  240. }
  241. /// Format version 3 encryptor. Use this to ensure a specific format verison
  242. /// or when using keys (which are inherrently versions-specific). To use
  243. /// "the latest encryptor" with a password, use `Encryptor` instead.
  244. public final class EncryptorV3 : RNCryptorType {
  245. private let engine: Engine
  246. private let hmac: HMACV3
  247. private var pendingHeader: Data?
  248. /// Creates and returns an encryptor.
  249. ///
  250. /// - parameter password: Non-empty password string. This will be interpretted as UTF-8.
  251. public convenience init(password: String) {
  252. self.init(
  253. password: password,
  254. encryptionSalt: RNCryptor.randomData(ofLength: V3.saltSize),
  255. hmacSalt: RNCryptor.randomData(ofLength: V3.saltSize),
  256. iv: RNCryptor.randomData(ofLength: V3.ivSize))
  257. }
  258. /// Creates and returns an encryptor using keys.
  259. ///
  260. /// - Attention: This method requires some expertise to use correctly.
  261. /// Most users should use `init(password:)` which is simpler
  262. /// to use securely.
  263. ///
  264. /// Keys should not be generated directly from strings (`.dataUsingEncoding()` or similar).
  265. /// Ideally, keys should be random (`Cryptor.randomDataOfLength()` or some other high-quality
  266. /// random generator. If keys must be generated from strings, then use `FormatV3.keyForPassword(salt:)`
  267. /// with a random salt, or just use password-based encryption (that's what it's for).
  268. ///
  269. /// - parameters:
  270. /// - encryptionKey: AES-256 key. Must be exactly FormatV3.keySize (kCCKeySizeAES256, 32 bytes)
  271. /// - hmacKey: HMAC key. Must be exactly FormatV3.keySize (kCCKeySizeAES256, 32 bytes)
  272. public convenience init(encryptionKey: Data, hmacKey: Data) {
  273. self.init(encryptionKey: encryptionKey, hmacKey: hmacKey, iv: RNCryptor.randomData(ofLength: V3.ivSize))
  274. }
  275. /// Takes a data, returns a processed data, and invalidates the cryptor.
  276. public func encrypt(data: Data) -> Data {
  277. return try! oneshot(data: data)
  278. }
  279. /// Updates cryptor with data and returns encrypted data.
  280. ///
  281. /// - parameter data: Data to process. May be empty.
  282. /// - returns: Processed data. May be empty.
  283. public func update(withData data: Data) -> Data {
  284. // It should not be possible for this to fail during encryption
  285. return handle(data: engine.update(withData: data))
  286. }
  287. /// Returns trailing data and invalidates the cryptor.
  288. ///
  289. /// - returns: Trailing data
  290. public func finalData() -> Data {
  291. var result = handle(data: engine.finalData())
  292. result.append(hmac.finalData())
  293. return result
  294. }
  295. // Expose random numbers for testing
  296. internal convenience init(encryptionKey: Data, hmacKey: Data, iv: Data) {
  297. let preamble = [V3.formatVersion, UInt8(0)]
  298. var header = Data(bytes: preamble)
  299. header.append(iv)
  300. self.init(encryptionKey: encryptionKey, hmacKey: hmacKey, iv: iv, header: header)
  301. }
  302. // Expose random numbers for testing
  303. internal convenience init(password: String, encryptionSalt: Data, hmacSalt: Data, iv: Data) {
  304. let encryptionKey = V3.makeKey(forPassword: password, withSalt: encryptionSalt)
  305. let hmacKey = V3.makeKey(forPassword: password, withSalt: hmacSalt)
  306. let preamble = [V3.formatVersion, UInt8(1)]
  307. var header = Data(bytes: preamble)
  308. header.append(encryptionSalt)
  309. header.append(hmacSalt)
  310. header.append(iv)
  311. self.init(encryptionKey: encryptionKey, hmacKey: hmacKey, iv: iv, header: header)
  312. }
  313. private init(encryptionKey: Data, hmacKey: Data, iv: Data, header: Data) {
  314. precondition(encryptionKey.count == V3.keySize)
  315. precondition(hmacKey.count == V3.keySize)
  316. precondition(iv.count == V3.ivSize)
  317. hmac = HMACV3(key: hmacKey)
  318. engine = Engine(operation: .encrypt, key: encryptionKey, iv: iv)
  319. pendingHeader = header
  320. }
  321. private func handle(data: Data) -> Data {
  322. let result: Data
  323. if var accum = pendingHeader {
  324. pendingHeader = nil
  325. accum.append(data)
  326. result = accum
  327. } else {
  328. result = data
  329. }
  330. hmac.update(withData: result)
  331. return result
  332. }
  333. }
  334. /// Format version 3 decryptor. This is required in order to decrypt
  335. /// using keys (since key configuration is version-specific). For password
  336. /// decryption, `Decryptor` is generally preferred, and will call this
  337. /// if appropriate.
  338. public final class DecryptorV3: VersionedDecryptorType {
  339. //
  340. // Static methods
  341. //
  342. fileprivate static let preambleSize = 1
  343. fileprivate static func canDecrypt(preamble: Data) -> Bool {
  344. assert(preamble.count >= 1)
  345. return preamble[0] == 3
  346. }
  347. //
  348. // Private properties
  349. //
  350. private var buffer = Data()
  351. private var decryptorEngine: DecryptorEngineV3?
  352. private let credential: Credential
  353. /// Creates and returns a decryptor.
  354. ///
  355. /// - parameter password: Non-empty password string. This will be interpretted as UTF-8.
  356. public init(password: String) {
  357. credential = .password(password)
  358. }
  359. /// Creates and returns a decryptor using keys.
  360. ///
  361. /// - parameters:
  362. /// - encryptionKey: AES-256 key. Must be exactly FormatV3.keySize (kCCKeySizeAES256, 32 bytes)
  363. /// - hmacKey: HMAC key. Must be exactly FormatV3.keySize (kCCKeySizeAES256, 32 bytes)
  364. public init(encryptionKey: Data, hmacKey: Data) {
  365. precondition(encryptionKey.count == V3.keySize)
  366. precondition(hmacKey.count == V3.hmacSize)
  367. credential = .keys(encryptionKey: encryptionKey, hmacKey: hmacKey)
  368. }
  369. /// Decrypt data using password and return decrypted data. Throws if
  370. /// password is incorrect or ciphertext is in the wrong format.
  371. /// - throws `Error`
  372. public func decrypt(data: Data) throws -> Data {
  373. return try oneshot(data: data)
  374. }
  375. /// Updates cryptor with data and returns encrypted data.
  376. ///
  377. /// - parameter data: Data to process. May be empty.
  378. /// - returns: Processed data. May be empty.
  379. public func update(withData data: Data) throws -> Data {
  380. if let e = decryptorEngine {
  381. return e.update(withData: data)
  382. }
  383. buffer.append(data)
  384. guard buffer.count >= requiredHeaderSize else {
  385. return Data()
  386. }
  387. let e = try makeEngine(credential: credential, header: buffer.subdata(in: 0..<requiredHeaderSize))
  388. decryptorEngine = e
  389. let body = buffer.subdata(in: requiredHeaderSize..<buffer.count)
  390. buffer.count = 0
  391. return e.update(withData: body)
  392. }
  393. /// Returns trailing data and invalidates the cryptor.
  394. ///
  395. /// - returns: Trailing data
  396. public func finalData() throws -> Data {
  397. guard let result = try decryptorEngine?.finalData() else {
  398. throw Error.messageTooShort
  399. }
  400. return result
  401. }
  402. //
  403. // Private functions
  404. //
  405. private var requiredHeaderSize: Int {
  406. switch credential {
  407. case .password: return V3.passwordHeaderSize
  408. case .keys: return V3.keyHeaderSize
  409. }
  410. }
  411. private func makeEngine(credential: Credential, header: Data) throws -> DecryptorEngineV3 {
  412. switch credential {
  413. case let .password(password):
  414. return try makeEngine(password: password, header: header)
  415. case let .keys(encryptionKey, hmacKey):
  416. return try makeEngine(encryptionKey: encryptionKey, hmacKey: hmacKey, header: header)
  417. }
  418. }
  419. private func makeEngine(password: String, header: Data) throws -> DecryptorEngineV3 {
  420. assert(password != "")
  421. precondition(header.count == V3.passwordHeaderSize)
  422. guard DecryptorV3.canDecrypt(preamble: header) else {
  423. throw Error.unknownHeader
  424. }
  425. guard header[1] == 1 else {
  426. throw Error.invalidCredentialType
  427. }
  428. let encryptionSalt = header.subdata(in: Range(2...9))
  429. let hmacSalt = header.subdata(in: Range(10...17))
  430. let iv = header.subdata(in: Range(18...33))
  431. let encryptionKey = V3.makeKey(forPassword: password, withSalt: encryptionSalt)
  432. let hmacKey = V3.makeKey(forPassword: password, withSalt: hmacSalt)
  433. return DecryptorEngineV3(encryptionKey: encryptionKey, hmacKey: hmacKey, iv: iv, header: header)
  434. }
  435. private func makeEngine(encryptionKey: Data, hmacKey: Data, header: Data) throws -> DecryptorEngineV3 {
  436. precondition(header.count == V3.keyHeaderSize)
  437. precondition(encryptionKey.count == V3.keySize)
  438. precondition(hmacKey.count == V3.keySize)
  439. guard DecryptorV3.canDecrypt(preamble: header) else {
  440. throw Error.unknownHeader
  441. }
  442. guard header[1] == 0 else {
  443. throw Error.invalidCredentialType
  444. }
  445. let iv = header.subdata(in: 2..<18)
  446. return DecryptorEngineV3(encryptionKey: encryptionKey, hmacKey: hmacKey, iv: iv, header: header)
  447. }
  448. }
  449. }
  450. internal enum CryptorOperation: CCOperation {
  451. case encrypt = 0 // CCOperation(kCCEncrypt)
  452. case decrypt = 1 // CCOperation(kCCDecrypt)
  453. }
  454. internal final class Engine {
  455. private let cryptor: CCCryptorRef?
  456. private var buffer = Data()
  457. init(operation: CryptorOperation, key: Data, iv: Data) {
  458. cryptor = key.withUnsafeBytes { (keyPtr: UnsafePointer<UInt8>) in
  459. iv.withUnsafeBytes { (ivPtr: UnsafePointer<UInt8>) in
  460. var cryptorOut: CCCryptorRef?
  461. let result = CCCryptorCreate(
  462. operation.rawValue,
  463. CCAlgorithm(kCCAlgorithmAES128), CCOptions(kCCOptionPKCS7Padding),
  464. keyPtr, key.count,
  465. ivPtr,
  466. &cryptorOut
  467. )
  468. // It is a programming error to create us with illegal values
  469. // This is an internal class, so we can constrain what is sent to us.
  470. // If this is ever made public, it should throw instead of asserting.
  471. assert(result == CCCryptorStatus(kCCSuccess))
  472. return cryptorOut
  473. }
  474. }
  475. }
  476. deinit {
  477. if cryptor != nil {
  478. CCCryptorRelease(cryptor)
  479. }
  480. }
  481. func sizeBuffer(forDataLength length: Int) -> Int {
  482. let size = CCCryptorGetOutputLength(cryptor, length, true)
  483. buffer.count = size
  484. return size
  485. }
  486. func update(withData data: Data) -> Data {
  487. let outputLength = sizeBuffer(forDataLength: data.count)
  488. var dataOutMoved = 0
  489. let result = data.withUnsafeBytes { dataPtr in
  490. buffer.withUnsafeMutableBytes { bufferPtr in
  491. return CCCryptorUpdate(
  492. cryptor,
  493. dataPtr, data.count,
  494. bufferPtr, outputLength,
  495. &dataOutMoved)
  496. }
  497. }
  498. // The only error returned by CCCryptorUpdate is kCCBufferTooSmall, which would be a programming error
  499. assert(result == CCCryptorStatus(kCCSuccess), "RNCRYPTOR BUG. PLEASE REPORT. (\(result)")
  500. buffer.count = dataOutMoved
  501. return buffer
  502. }
  503. func finalData() -> Data {
  504. let outputLength = sizeBuffer(forDataLength: 0)
  505. var dataOutMoved = 0
  506. let result = buffer.withUnsafeMutableBytes {
  507. CCCryptorFinal(
  508. cryptor,
  509. $0, outputLength,
  510. &dataOutMoved
  511. )
  512. }
  513. // Note that since iOS 6, CCryptor will never return padding errors or other decode errors.
  514. // I'm not aware of any non-catestrophic (MemoryAllocation) situation in which this
  515. // can fail. Using assert() just in case, but we'll ignore errors in Release.
  516. // https://devforums.apple.com/message/920802#920802
  517. assert(result == CCCryptorStatus(kCCSuccess), "RNCRYPTOR BUG. PLEASE REPORT. (\(result)")
  518. buffer.count = dataOutMoved
  519. defer { buffer = Data() }
  520. return buffer
  521. }
  522. }
  523. internal typealias V3 = RNCryptor.FormatV3
  524. private enum Credential {
  525. case password(String)
  526. case keys(encryptionKey: Data, hmacKey: Data)
  527. }
  528. private final class DecryptorEngineV3 {
  529. private let buffer = OverflowingBuffer(capacity: V3.hmacSize)
  530. private let hmac: HMACV3
  531. private let engine: Engine
  532. init(encryptionKey: Data, hmacKey: Data, iv: Data, header: Data) {
  533. precondition(encryptionKey.count == V3.keySize)
  534. precondition(hmacKey.count == V3.hmacSize)
  535. precondition(iv.count == V3.ivSize)
  536. hmac = HMACV3(key: hmacKey)
  537. hmac.update(withData: header)
  538. engine = Engine(operation: .decrypt, key: encryptionKey, iv: iv)
  539. }
  540. func update(withData data: Data) -> Data {
  541. let overflow = buffer.update(withData: data)
  542. hmac.update(withData: overflow)
  543. return engine.update(withData: overflow)
  544. }
  545. func finalData() throws -> Data {
  546. let hash = hmac.finalData()
  547. if !isEqualInConsistentTime(trusted: hash, untrusted: buffer.finalData()) {
  548. throw RNCryptor.Error.hmacMismatch
  549. }
  550. return engine.finalData()
  551. }
  552. }
  553. private final class HMACV3 {
  554. var context = CCHmacContext()
  555. init(key: Data) {
  556. key.withUnsafeBytes {
  557. CCHmacInit(
  558. &context,
  559. CCHmacAlgorithm(kCCHmacAlgSHA256),
  560. $0,
  561. key.count
  562. )
  563. }
  564. }
  565. func update(withData data: Data) {
  566. data.withUnsafeBytes { CCHmacUpdate(&context, $0, data.count) }
  567. }
  568. func finalData() -> Data {
  569. var hmac = Data(count: V3.hmacSize)!
  570. hmac.withUnsafeMutableBytes { CCHmacFinal(&context, $0) }
  571. return hmac
  572. }
  573. }
  574. // Internal protocol for version-specific decryptors.
  575. private protocol VersionedDecryptorType: RNCryptorType {
  576. static var preambleSize: Int { get }
  577. static func canDecrypt(preamble: Data) -> Bool
  578. init(password: String)
  579. }
  580. private extension Collection {
  581. // Split collection into ([pass], [fail]) based on predicate.
  582. func splitPassFail(forPredicate predicate: (Iterator.Element) -> Bool) -> ([Iterator.Element], [Iterator.Element]) {
  583. var pass: [Iterator.Element] = []
  584. var fail: [Iterator.Element] = []
  585. for e in self {
  586. if predicate(e) {
  587. pass.append(e)
  588. } else {
  589. fail.append(e)
  590. }
  591. }
  592. return (pass, fail)
  593. }
  594. }
  595. internal final class OverflowingBuffer {
  596. private var buffer = Data()
  597. let capacity: Int
  598. init(capacity: Int) {
  599. self.capacity = capacity
  600. }
  601. func update(withData data: Data) -> Data {
  602. if data.count >= capacity {
  603. return sendAll(data: data)
  604. } else if buffer.count + data.count <= capacity {
  605. buffer.append(data)
  606. return Data()
  607. } else {
  608. return sendSome(data: data)
  609. }
  610. }
  611. func finalData() -> Data {
  612. let result = buffer
  613. buffer.count = 0
  614. return result
  615. }
  616. private func sendAll(data: Data) -> Data {
  617. let toSend = data.count - capacity
  618. assert(toSend >= 0)
  619. assert(data.count - toSend <= capacity)
  620. var result = buffer
  621. result.append(data.subdata(in: 0..<toSend))
  622. buffer.count = 0
  623. buffer.append(data.subdata(in: toSend..<data.count)) // TODO: Appending here to avoid later buffer growth, but maybe just buffer = data.subdata would be better
  624. return result
  625. }
  626. private func sendSome(data: Data) -> Data {
  627. let toSend = (buffer.count + data.count) - capacity
  628. assert(toSend > 0) // If it were <= 0, we would have extended the array
  629. assert(toSend < buffer.count) // If we would have sent everything, replaceBuffer should have been called
  630. let result = buffer.subdata(in: 0..<toSend)
  631. buffer.replaceSubrange(0..<toSend, with: Data())
  632. buffer.append(data)
  633. return result
  634. }
  635. }
  636. /** Compare two Datas in time proportional to the untrusted data
  637. Equatable-based comparisons genreally stop comparing at the first difference.
  638. This can be used by attackers, in some situations,
  639. to determine a secret value by considering the time required to compare the values.
  640. We enumerate over the untrusted values so that the time is proportaional to the attacker's data,
  641. which provides the attack no informatoin about the length of the secret.
  642. */
  643. private func isEqualInConsistentTime(trusted: Data, untrusted: Data) -> Bool {
  644. // The point of this routine is XOR the bytes of each data and accumulate the results with OR.
  645. // If any bytes are different, then the OR will accumulate some non-0 value.
  646. var result: UInt8 = untrusted.count == trusted.count ? 0 : 1 // Start with 0 (equal) only if our lengths are equal
  647. for (i, untrustedByte) in untrusted.enumerated() {
  648. // Use mod to wrap around ourselves if they are longer than we are.
  649. // Remember, we already broke equality if our lengths are different.
  650. result |= trusted[i % trusted.count] ^ untrustedByte
  651. }
  652. return result == 0
  653. }
  654. // From https://github.com/apple/swift-corelibs-foundation/blob/swift-3/Foundation/Data.swift#L285
  655. // Remove when added to Xcode
  656. private extension Data {
  657. init?(count: Int) {
  658. if let memory = malloc(count) {
  659. self.init(bytesNoCopy: memory, count: count, deallocator: .free)
  660. } else {
  661. return nil
  662. }
  663. }
  664. }