RNCryptor.swift 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765
  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 CommonCrypto
  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 { SecRandomCopyBytes(kSecRandomDefault, length, $0.baseAddress!) }
  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. 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. let passwordArray = password.utf8.map(Int8.init)
  211. let saltArray = Array(salt)
  212. var derivedKey = Array<UInt8>(repeating: 0, count: keySize)
  213. // All the crazy casting because CommonCryptor hates Swift
  214. let algorithm = CCPBKDFAlgorithm(kCCPBKDF2)
  215. let prf = CCPseudoRandomAlgorithm(kCCPRFHmacAlgSHA1)
  216. let pbkdf2Rounds = UInt32(10000)
  217. let result = CCCryptorStatus(
  218. CCKeyDerivationPBKDF(
  219. algorithm,
  220. passwordArray, passwordArray.count,
  221. saltArray, saltArray.count,
  222. prf, pbkdf2Rounds,
  223. &derivedKey, keySize)
  224. )
  225. guard result == CCCryptorStatus(kCCSuccess) else {
  226. fatalError("SECURITY FAILURE: Could not derive secure password (\(result))")
  227. }
  228. return Data(derivedKey)
  229. }
  230. static let formatVersion = UInt8(3)
  231. static let ivSize = kCCBlockSizeAES128
  232. static let hmacSize = Int(CC_SHA256_DIGEST_LENGTH)
  233. static let keyHeaderSize = 1 + 1 + kCCBlockSizeAES128
  234. static let passwordHeaderSize = 1 + 1 + 8 + 8 + kCCBlockSizeAES128
  235. }
  236. /// Format version 3 encryptor. Use this to ensure a specific format verison
  237. /// or when using keys (which are inherrently versions-specific). To use
  238. /// "the latest encryptor" with a password, use `Encryptor` instead.
  239. final class EncryptorV3 : RNCryptorType {
  240. private let engine: Engine
  241. private let hmac: HMACV3
  242. private var pendingHeader: Data?
  243. /// Creates and returns an encryptor.
  244. ///
  245. /// - parameter password: Non-empty password string. This will be interpretted as UTF-8.
  246. public convenience init(password: String) {
  247. self.init(
  248. password: password,
  249. encryptionSalt: RNCryptor.randomData(ofLength: V3.saltSize),
  250. hmacSalt: RNCryptor.randomData(ofLength: V3.saltSize),
  251. iv: RNCryptor.randomData(ofLength: V3.ivSize))
  252. }
  253. /// Creates and returns an encryptor using keys.
  254. ///
  255. /// - Attention: This method requires some expertise to use correctly.
  256. /// Most users should use `init(password:)` which is simpler
  257. /// to use securely.
  258. ///
  259. /// Keys should not be generated directly from strings (`.dataUsingEncoding()` or similar).
  260. /// Ideally, keys should be random (`Cryptor.randomDataOfLength()` or some other high-quality
  261. /// random generator. If keys must be generated from strings, then use `FormatV3.keyForPassword(salt:)`
  262. /// with a random salt, or just use password-based encryption (that's what it's for).
  263. ///
  264. /// - parameters:
  265. /// - encryptionKey: AES-256 key. Must be exactly FormatV3.keySize (kCCKeySizeAES256, 32 bytes)
  266. /// - hmacKey: HMAC key. Must be exactly FormatV3.keySize (kCCKeySizeAES256, 32 bytes)
  267. public convenience init(encryptionKey: Data, hmacKey: Data) {
  268. self.init(encryptionKey: encryptionKey, hmacKey: hmacKey, iv: RNCryptor.randomData(ofLength: V3.ivSize))
  269. }
  270. /// Takes a data, returns a processed data, and invalidates the cryptor.
  271. public func encrypt(data: Data) -> Data {
  272. return try! oneshot(data: data)
  273. }
  274. /// Updates cryptor with data and returns encrypted data.
  275. ///
  276. /// - parameter data: Data to process. May be empty.
  277. /// - returns: Processed data. May be empty.
  278. public func update(withData data: Data) -> Data {
  279. // It should not be possible for this to fail during encryption
  280. return handle(data: engine.update(withData: data))
  281. }
  282. /// Returns trailing data and invalidates the cryptor.
  283. ///
  284. /// - returns: Trailing data
  285. public func finalData() -> Data {
  286. var result = handle(data: engine.finalData())
  287. result.append(hmac.finalData())
  288. return result
  289. }
  290. // Expose random numbers for testing
  291. internal convenience init(encryptionKey: Data, hmacKey: Data, iv: Data) {
  292. let preamble = [V3.formatVersion, UInt8(0)]
  293. var header = Data(preamble)
  294. header.append(iv)
  295. self.init(encryptionKey: encryptionKey, hmacKey: hmacKey, iv: iv, header: header)
  296. }
  297. // Expose random numbers for testing
  298. internal convenience init(password: String, encryptionSalt: Data, hmacSalt: Data, iv: Data) {
  299. let encryptionKey = V3.makeKey(forPassword: password, withSalt: encryptionSalt)
  300. let hmacKey = V3.makeKey(forPassword: password, withSalt: hmacSalt)
  301. let preamble = [V3.formatVersion, UInt8(1)]
  302. var header = Data(preamble)
  303. header.append(encryptionSalt)
  304. header.append(hmacSalt)
  305. header.append(iv)
  306. self.init(encryptionKey: encryptionKey, hmacKey: hmacKey, iv: iv, header: header)
  307. }
  308. private init(encryptionKey: Data, hmacKey: Data, iv: Data, header: Data) {
  309. precondition(encryptionKey.count == V3.keySize)
  310. precondition(hmacKey.count == V3.keySize)
  311. precondition(iv.count == V3.ivSize)
  312. hmac = HMACV3(key: hmacKey)
  313. engine = Engine(operation: .encrypt, key: encryptionKey, iv: iv)
  314. pendingHeader = header
  315. }
  316. private func handle(data: Data) -> Data {
  317. let result: Data
  318. if var accum = pendingHeader {
  319. pendingHeader = nil
  320. accum.append(data)
  321. result = accum
  322. } else {
  323. result = data
  324. }
  325. hmac.update(withData: result)
  326. return result
  327. }
  328. }
  329. /// Format version 3 decryptor. This is required in order to decrypt
  330. /// using keys (since key configuration is version-specific). For password
  331. /// decryption, `Decryptor` is generally preferred, and will call this
  332. /// if appropriate.
  333. final class DecryptorV3: VersionedDecryptorType {
  334. //
  335. // Static methods
  336. //
  337. fileprivate static let preambleSize = 1
  338. fileprivate static func canDecrypt(preamble: Data) -> Bool {
  339. assert(preamble.count >= 1)
  340. return preamble[0] == 3
  341. }
  342. //
  343. // Private properties
  344. //
  345. private var buffer = Data()
  346. private var decryptorEngine: DecryptorEngineV3?
  347. private let credential: Credential
  348. /// Creates and returns a decryptor.
  349. ///
  350. /// - parameter password: Non-empty password string. This will be interpretted as UTF-8.
  351. public init(password: String) {
  352. credential = .password(password)
  353. }
  354. /// Creates and returns a decryptor using keys.
  355. ///
  356. /// - parameters:
  357. /// - encryptionKey: AES-256 key. Must be exactly FormatV3.keySize (kCCKeySizeAES256, 32 bytes)
  358. /// - hmacKey: HMAC key. Must be exactly FormatV3.keySize (kCCKeySizeAES256, 32 bytes)
  359. public init(encryptionKey: Data, hmacKey: Data) {
  360. precondition(encryptionKey.count == V3.keySize)
  361. precondition(hmacKey.count == V3.hmacSize)
  362. credential = .keys(encryptionKey: encryptionKey, hmacKey: hmacKey)
  363. }
  364. /// Decrypt data using password and return decrypted data. Throws if
  365. /// password is incorrect or ciphertext is in the wrong format.
  366. /// - throws `Error`
  367. public func decrypt(data: Data) throws -> Data {
  368. return try oneshot(data: data)
  369. }
  370. /// Updates cryptor with data and returns encrypted data.
  371. ///
  372. /// - parameter data: Data to process. May be empty.
  373. /// - returns: Processed data. May be empty.
  374. public func update(withData data: Data) throws -> Data {
  375. if let e = decryptorEngine {
  376. return e.update(withData: data)
  377. }
  378. buffer.append(data)
  379. guard buffer.count >= requiredHeaderSize else {
  380. return Data()
  381. }
  382. let e = try makeEngine(credential: credential, header: buffer.subdata(in: 0..<requiredHeaderSize))
  383. decryptorEngine = e
  384. let body = buffer.subdata(in: requiredHeaderSize..<buffer.count)
  385. buffer.count = 0
  386. return e.update(withData: body)
  387. }
  388. /// Returns trailing data and invalidates the cryptor.
  389. ///
  390. /// - returns: Trailing data
  391. public func finalData() throws -> Data {
  392. guard let result = try decryptorEngine?.finalData() else {
  393. throw Error.messageTooShort
  394. }
  395. return result
  396. }
  397. //
  398. // Private functions
  399. //
  400. private var requiredHeaderSize: Int {
  401. switch credential {
  402. case .password: return V3.passwordHeaderSize
  403. case .keys: return V3.keyHeaderSize
  404. }
  405. }
  406. private func makeEngine(credential: Credential, header: Data) throws -> DecryptorEngineV3 {
  407. switch credential {
  408. case let .password(password):
  409. return try makeEngine(password: password, header: header)
  410. case let .keys(encryptionKey, hmacKey):
  411. return try makeEngine(encryptionKey: encryptionKey, hmacKey: hmacKey, header: header)
  412. }
  413. }
  414. private func makeEngine(password: String, header: Data) throws -> DecryptorEngineV3 {
  415. assert(password != "")
  416. precondition(header.count == V3.passwordHeaderSize)
  417. guard DecryptorV3.canDecrypt(preamble: header) else {
  418. throw Error.unknownHeader
  419. }
  420. guard header[1] == 1 else {
  421. throw Error.invalidCredentialType
  422. }
  423. let encryptionSalt = header.subdata(in: Range(2...9))
  424. let hmacSalt = header.subdata(in: Range(10...17))
  425. let iv = header.subdata(in: Range(18...33))
  426. let encryptionKey = V3.makeKey(forPassword: password, withSalt: encryptionSalt)
  427. let hmacKey = V3.makeKey(forPassword: password, withSalt: hmacSalt)
  428. return DecryptorEngineV3(encryptionKey: encryptionKey, hmacKey: hmacKey, iv: iv, header: header)
  429. }
  430. private func makeEngine(encryptionKey: Data, hmacKey: Data, header: Data) throws -> DecryptorEngineV3 {
  431. precondition(header.count == V3.keyHeaderSize)
  432. precondition(encryptionKey.count == V3.keySize)
  433. precondition(hmacKey.count == V3.keySize)
  434. guard DecryptorV3.canDecrypt(preamble: header) else {
  435. throw Error.unknownHeader
  436. }
  437. guard header[1] == 0 else {
  438. throw Error.invalidCredentialType
  439. }
  440. let iv = header.subdata(in: 2..<18)
  441. return DecryptorEngineV3(encryptionKey: encryptionKey, hmacKey: hmacKey, iv: iv, header: header)
  442. }
  443. }
  444. }
  445. internal enum CryptorOperation: CCOperation {
  446. case encrypt = 0 // CCOperation(kCCEncrypt)
  447. case decrypt = 1 // CCOperation(kCCDecrypt)
  448. }
  449. internal final class Engine {
  450. private let cryptor: CCCryptorRef?
  451. private var buffer = Data()
  452. init(operation: CryptorOperation, key: Data, iv: Data) {
  453. cryptor = key.withUnsafeBytes { (keyPtr) in
  454. iv.withUnsafeBytes { (ivPtr) in
  455. var cryptorOut: CCCryptorRef?
  456. let result = CCCryptorCreate(
  457. operation.rawValue,
  458. CCAlgorithm(kCCAlgorithmAES128), CCOptions(kCCOptionPKCS7Padding),
  459. keyPtr.baseAddress!, keyPtr.count,
  460. ivPtr.baseAddress!,
  461. &cryptorOut
  462. )
  463. // It is a programming error to create us with illegal values
  464. // This is an internal class, so we can constrain what is sent to us.
  465. // If this is ever made public, it should throw instead of asserting.
  466. assert(result == CCCryptorStatus(kCCSuccess))
  467. return cryptorOut
  468. }
  469. }
  470. }
  471. deinit {
  472. if cryptor != nil {
  473. CCCryptorRelease(cryptor)
  474. }
  475. }
  476. func sizeBuffer(forDataLength length: Int) -> Int {
  477. let size = CCCryptorGetOutputLength(cryptor, length, true)
  478. buffer.count = size
  479. return size
  480. }
  481. func update(withData data: Data) -> Data {
  482. let outputLength = sizeBuffer(forDataLength: data.count)
  483. var dataOutMoved = 0
  484. let result = data.withUnsafeBytes { dataPtr in
  485. buffer.withUnsafeMutableBytes { bufferPtr in
  486. return CCCryptorUpdate(
  487. cryptor,
  488. dataPtr.baseAddress!, dataPtr.count,
  489. bufferPtr.baseAddress!, outputLength,
  490. &dataOutMoved)
  491. }
  492. }
  493. // The only error returned by CCCryptorUpdate is kCCBufferTooSmall, which would be a programming error
  494. assert(result == CCCryptorStatus(kCCSuccess), "RNCRYPTOR BUG. PLEASE REPORT. (\(result)")
  495. buffer.count = dataOutMoved
  496. return buffer
  497. }
  498. func finalData() -> Data {
  499. let outputLength = sizeBuffer(forDataLength: 0)
  500. var dataOutMoved = 0
  501. let result = buffer.withUnsafeMutableBytes {
  502. CCCryptorFinal(
  503. cryptor,
  504. $0.baseAddress!, outputLength,
  505. &dataOutMoved
  506. )
  507. }
  508. // Note that since iOS 6, CCryptor will never return padding errors or other decode errors.
  509. // I'm not aware of any non-catastrophic (MemoryAllocation) situation in which this
  510. // can fail. Using assert() just in case, but we'll ignore errors in Release.
  511. // https://devforums.apple.com/message/920802#920802
  512. assert(result == CCCryptorStatus(kCCSuccess), "RNCRYPTOR BUG. PLEASE REPORT. (\(result)")
  513. buffer.count = dataOutMoved
  514. defer { buffer = Data() }
  515. return buffer
  516. }
  517. }
  518. internal typealias V3 = RNCryptor.FormatV3
  519. private enum Credential {
  520. case password(String)
  521. case keys(encryptionKey: Data, hmacKey: Data)
  522. }
  523. private final class DecryptorEngineV3 {
  524. private let buffer = OverflowingBuffer(capacity: V3.hmacSize)
  525. private let hmac: HMACV3
  526. private let engine: Engine
  527. init(encryptionKey: Data, hmacKey: Data, iv: Data, header: Data) {
  528. precondition(encryptionKey.count == V3.keySize)
  529. precondition(hmacKey.count == V3.hmacSize)
  530. precondition(iv.count == V3.ivSize)
  531. hmac = HMACV3(key: hmacKey)
  532. hmac.update(withData: header)
  533. engine = Engine(operation: .decrypt, key: encryptionKey, iv: iv)
  534. }
  535. func update(withData data: Data) -> Data {
  536. let overflow = buffer.update(withData: data)
  537. hmac.update(withData: overflow)
  538. return engine.update(withData: overflow)
  539. }
  540. func finalData() throws -> Data {
  541. let hash = hmac.finalData()
  542. if !isEqualInConsistentTime(trusted: hash, untrusted: buffer.finalData()) {
  543. throw RNCryptor.Error.hmacMismatch
  544. }
  545. return engine.finalData()
  546. }
  547. }
  548. private final class HMACV3 {
  549. var context = CCHmacContext()
  550. init(key: Data) {
  551. key.withUnsafeBytes {
  552. CCHmacInit(
  553. &context,
  554. CCHmacAlgorithm(kCCHmacAlgSHA256),
  555. $0.baseAddress!,
  556. key.count
  557. )
  558. }
  559. }
  560. func update(withData data: Data) {
  561. data.withUnsafeBytes { CCHmacUpdate(&context, $0.baseAddress!, data.count) }
  562. }
  563. func finalData() -> Data {
  564. var hmac = Data(count: V3.hmacSize)
  565. hmac.withUnsafeMutableBytes { CCHmacFinal(&context, $0.baseAddress!) }
  566. return hmac
  567. }
  568. }
  569. // Internal protocol for version-specific decryptors.
  570. private protocol VersionedDecryptorType: RNCryptorType {
  571. static var preambleSize: Int { get }
  572. static func canDecrypt(preamble: Data) -> Bool
  573. init(password: String)
  574. }
  575. private extension Collection {
  576. // Split collection into ([pass], [fail]) based on predicate.
  577. func splitPassFail(forPredicate predicate: (Iterator.Element) -> Bool) -> ([Iterator.Element], [Iterator.Element]) {
  578. var pass: [Iterator.Element] = []
  579. var fail: [Iterator.Element] = []
  580. for e in self {
  581. if predicate(e) {
  582. pass.append(e)
  583. } else {
  584. fail.append(e)
  585. }
  586. }
  587. return (pass, fail)
  588. }
  589. }
  590. internal final class OverflowingBuffer {
  591. private var buffer = Data()
  592. let capacity: Int
  593. init(capacity: Int) {
  594. self.capacity = capacity
  595. }
  596. func update(withData data: Data) -> Data {
  597. if data.count >= capacity {
  598. return sendAll(data: data)
  599. } else if buffer.count + data.count <= capacity {
  600. buffer.append(data)
  601. return Data()
  602. } else {
  603. return sendSome(data: data)
  604. }
  605. }
  606. func finalData() -> Data {
  607. let result = buffer
  608. buffer.count = 0
  609. return result
  610. }
  611. private func sendAll(data: Data) -> Data {
  612. let toSend = data.count - capacity
  613. assert(toSend >= 0)
  614. assert(data.count - toSend <= capacity)
  615. var result = buffer
  616. result.append(data.subdata(in: 0..<toSend))
  617. buffer.count = 0
  618. 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
  619. return result
  620. }
  621. private func sendSome(data: Data) -> Data {
  622. let toSend = (buffer.count + data.count) - capacity
  623. assert(toSend > 0) // If it were <= 0, we would have extended the array
  624. assert(toSend < buffer.count) // If we would have sent everything, replaceBuffer should have been called
  625. let result = buffer.subdata(in: 0..<toSend)
  626. buffer.replaceSubrange(0..<toSend, with: Data())
  627. buffer.append(data)
  628. return result
  629. }
  630. }
  631. /** Compare two Datas in time proportional to the untrusted data
  632. Equatable-based comparisons generally stop comparing at the first difference.
  633. This can be used by attackers, in some situations,
  634. to determine a secret value by considering the time required to compare the values.
  635. We enumerate over the untrusted values so that the time is proportaional to the attacker's data,
  636. which provides the attack no information about the length of the secret.
  637. */
  638. private func isEqualInConsistentTime(trusted: Data, untrusted: Data) -> Bool {
  639. // The point of this routine is XOR the bytes of each data and accumulate the results with OR.
  640. // If any bytes are different, then the OR will accumulate some non-0 value.
  641. var result: UInt8 = untrusted.count == trusted.count ? 0 : 1 // Start with 0 (equal) only if our lengths are equal
  642. for (i, untrustedByte) in untrusted.enumerated() {
  643. // Use mod to wrap around ourselves if they are longer than we are.
  644. // Remember, we already broke equality if our lengths are different.
  645. result |= trusted[i % trusted.count] ^ untrustedByte
  646. }
  647. return result == 0
  648. }