Database3.swift 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. // Database3.swift
  2. // This file is part of KeePassKit.
  3. //
  4. // Copyright © 2019 Maxime Epain. All rights reserved.
  5. //
  6. // KeePassKit is free software: you can redistribute it and/or modify
  7. // it under the terms of the GNU General Public License as published by
  8. // the Free Software Foundation, either version 3 of the License, or
  9. // (at your option) any later version.
  10. //
  11. // KeePassKit is distributed in the hope that it will be useful,
  12. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. // GNU General Public License for more details.
  15. //
  16. // You should have received a copy of the GNU General Public License
  17. // along with KeePassKit. If not, see <https://www.gnu.org/licenses/>.
  18. import Foundation
  19. import Binary
  20. import Crypto
  21. import Gzip
  22. import XML
  23. class Database3: Database {
  24. let header: Header<OuterHeader, UInt16>
  25. let document: Document
  26. required init(from input: Input, compositeKey: CompositeKey) throws {
  27. header = try input.read()
  28. guard
  29. let startBytes: Bytes = header[.streamStartBytes]
  30. else { throw KDBXError.corruptedDatabase }
  31. let data = try input.read() as Bytes
  32. var key = try header.masterKey(from: compositeKey)
  33. key = SHA256.hash( key )
  34. let cipher = try header.cipher(key: key)
  35. let hash = try cipher.decrypt(data: data)
  36. let stream = Input(bytes: hash)
  37. guard try stream.read(lenght: SHA256.Lenght) == startBytes else { throw KDBXError.invalidCompositeKey }
  38. var index: UInt32 = 0
  39. var content = Bytes()
  40. while true {
  41. guard try stream.read() == index else { throw KDBXError.corruptedDatabase }
  42. index += 1
  43. let hash = try stream.read(lenght: SHA256.Lenght)
  44. let size: UInt32 = try stream.read()
  45. guard size > 0 else { break }
  46. let block = try stream.read(lenght: Int(size))
  47. guard SHA256.hash( block ) == hash else { throw KDBXError.corruptedDatabase }
  48. content += block
  49. }
  50. if header[.compressionFlags] == Compression.gzip {
  51. content = try content.gunzipped()
  52. }
  53. var options = XML.Options()
  54. options.parserSettings.shouldTrimWhitespace = false
  55. document = try XML.Document(xml: content.data, options: options)
  56. }
  57. func write(to output: Output, compositeKey: CompositeKey) throws {
  58. fatalError()
  59. }
  60. }