Database4.swift 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. // Database4.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 XML
  22. class Database4: Database {
  23. struct Header {
  24. let fields: [TLV<OuterHeader, UInt32>]
  25. let data: Bytes
  26. }
  27. let header: Header
  28. let document: Document
  29. required init(from input: Input, compositeKey: CompositeKey) throws {
  30. header = try input.read()
  31. var key = try header.masterKey(from: compositeKey)
  32. let hmacKey = SHA512.hash( UInt64.max.bytes + SHA512.hash( key + 1 ) )
  33. key = SHA256.hash( key )
  34. let data = try input.read() as Bytes
  35. let stream = Input(bytes: data)
  36. guard
  37. try stream.read(lenght: SHA256.Lenght) == SHA256.hash( header.data ),
  38. try stream.read(lenght: SHA256.Lenght) == HMACSHA256.authenticate(header.data, key: hmacKey)
  39. else { throw KDBXError.corruptedDatabase }
  40. let cipher = try header.cipher(key: key)
  41. let hash = try cipher.decrypt(data: data)
  42. fatalError()
  43. }
  44. }
  45. extension Database4: Writable {
  46. func write(to output: Output) throws {
  47. try output.write(header)
  48. fatalError()
  49. }
  50. }
  51. extension Database4.Header: Streamable {
  52. init(from input: Input) throws {
  53. var fields = [TLV<OuterHeader, UInt32>]()
  54. while true {
  55. let field: TLV<OuterHeader, UInt32> = try input.read()
  56. fields.append(field)
  57. if field.type == .end { break }
  58. }
  59. self.fields = fields
  60. self.data = input.bytes.prefix(input.offset)
  61. }
  62. func write(to output: Output) throws {
  63. try output.write(fields)
  64. }
  65. }
  66. extension Database4.Header: Header {
  67. subscript(_ field: OuterHeader) -> Bytes? {
  68. return fields.first(where: { $0.type == field })?.value
  69. }
  70. }