// Database4.swift
// This file is part of KeePassKit.
//
// Copyright © 2019 Maxime Epain. All rights reserved.
//
// KeePassKit is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// KeePassKit is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with KeePassKit. If not, see .
import Foundation
import Binary
import Crypto
import XML
class Database4: Database {
struct Header {
let fields: [TLV]
let data: Bytes
}
let header: Header
let document: Document
required init(from input: Input, compositeKey: CompositeKey) throws {
header = try input.read()
var key = try header.masterKey(from: compositeKey)
let hmacKey = SHA512.hash( UInt64.max.bytes + SHA512.hash( key + 1 ) )
key = SHA256.hash( key )
let data = try input.read() as Bytes
let stream = Input(bytes: data)
guard
try stream.read(lenght: SHA256.Lenght) == SHA256.hash( header.data ),
try stream.read(lenght: SHA256.Lenght) == HMACSHA256.authenticate(header.data, key: hmacKey)
else { throw KDBXError.corruptedDatabase }
let cipher = try header.cipher(key: key)
let hash = try cipher.decrypt(data: data)
fatalError()
}
}
extension Database4: Writable {
func write(to output: Output) throws {
try output.write(header)
fatalError()
}
}
extension Database4.Header: Streamable {
init(from input: Input) throws {
var fields = [TLV]()
while true {
let field: TLV = try input.read()
fields.append(field)
if field.type == .end { break }
}
self.fields = fields
self.data = input.bytes.prefix(input.offset)
}
func write(to output: Output) throws {
try output.write(fields)
}
}
extension Database4.Header: Header {
subscript(_ field: OuterHeader) -> Bytes? {
return fields.first(where: { $0.type == field })?.value
}
}