StreamEncryptor.swift 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. // CryptoSwift
  2. //
  3. // Copyright (C) 2014-2018 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
  4. // This software is provided 'as-is', without any express or implied warranty.
  5. //
  6. // In no event will the authors be held liable for any damages arising from the use of this software.
  7. //
  8. // Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
  9. //
  10. // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
  11. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
  12. // - This notice may not be removed or altered from any source or binary distribution.
  13. //
  14. @usableFromInline
  15. final class StreamEncryptor: Cryptor, Updatable {
  16. @usableFromInline
  17. internal let blockSize: Int
  18. @usableFromInline
  19. internal var worker: CipherModeWorker
  20. @usableFromInline
  21. internal let padding: Padding
  22. @usableFromInline
  23. internal var lastBlockRemainder = 0
  24. @usableFromInline
  25. init(blockSize: Int, padding: Padding, _ worker: CipherModeWorker) throws {
  26. self.blockSize = blockSize
  27. self.padding = padding
  28. self.worker = worker
  29. }
  30. // MARK: Updatable
  31. @inlinable
  32. public func update(withBytes bytes: ArraySlice<UInt8>, isLast: Bool) throws -> Array<UInt8> {
  33. var accumulated = Array(bytes)
  34. if isLast {
  35. // CTR doesn't need padding. Really. Add padding to the last block if really want. but... don't.
  36. accumulated = self.padding.add(to: accumulated, blockSize: self.blockSize - self.lastBlockRemainder)
  37. }
  38. var encrypted = Array<UInt8>(reserveCapacity: bytes.count)
  39. for chunk in accumulated.batched(by: self.blockSize) {
  40. encrypted += self.worker.encrypt(block: chunk)
  41. }
  42. // omit unecessary calculation if not needed
  43. if self.padding != .noPadding {
  44. self.lastBlockRemainder = encrypted.count.quotientAndRemainder(dividingBy: self.blockSize).remainder
  45. }
  46. if var finalizingWorker = worker as? FinalizingEncryptModeWorker, isLast == true {
  47. encrypted = Array(try finalizingWorker.finalize(encrypt: encrypted.slice))
  48. }
  49. return encrypted
  50. }
  51. @usableFromInline
  52. func seek(to: Int) throws {
  53. fatalError("Not supported")
  54. }
  55. }