RNCryptor.swift 28 KB

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