import CommonCrypto
import Foundation

extension Data {
    var bytes: [UInt8] {
        [UInt8](self)
    }
}

extension Array where Element == UInt8 {
    var data: Data {
        Data(self)
    }
}

extension Data {
    func hmac(key: Data) -> Data {
        var digest = [UInt8](repeating: 0, count: Int(CC_SHA1_DIGEST_LENGTH))
        CCHmac(CCHmacAlgorithm(kCCHmacAlgSHA1), key.bytes, key.count, bytes, count, &digest)
        return Data(digest)
    }

    func sha1() -> Data {
        var digest = [UInt8](repeating: 0, count: Int(CC_SHA1_DIGEST_LENGTH))
        withUnsafeBytes {
            _ = CC_SHA1($0.baseAddress, CC_LONG(self.count), &digest)
        }
        return digest.data
    }

    func pbkdf2(salt: Data, rounds: Int) -> Data {
        var buff = [UInt8](repeating: 0, count: salt.count)
        (salt as NSData).getBytes(&buff, length: salt.count)
        buff.append(contentsOf: [0, 0, 0, 1])

        var digest = buff.data.hmac(key: self)
        var result = digest

        for _ in 1 ..< rounds {
            digest = digest.hmac(key: self)
            for indx in 0 ..< digest.count {
                result[indx] ^= digest[indx]
            }
        }

        return result
    }

    func xor(other: Data) -> Data {
        let otherBytes = other.bytes
        var result = bytes
        for indx in 0 ..< result.count {
            result[indx] ^= otherBytes[indx]
        }
        return result.data
    }
}
