/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

#include <stdint.h>
#include <controller/ble_ll_crypto.h>
#include <testutil/testutil.h>

TEST_CASE_SELF(ble_ll_crypto_test_h6) {
    const uint8_t w[] = {
        0xec, 0x02, 0x34, 0xa3, 0x57, 0xc8, 0xad, 0x05,
        0x34, 0x10, 0x10, 0xa6, 0x0a, 0x39, 0x7d, 0x9b
    };
    const uint8_t key_id[] = { 0x6c, 0x65, 0x62, 0x72 };
    const uint8_t ok[] = {
        0x2d, 0x9a, 0xe1, 0x02, 0xe7, 0x6d, 0xc9, 0x1c,
        0xe8, 0xd3, 0xa9, 0xe2, 0x80, 0xb1, 0x63, 0x99
    };
    uint8_t out[16];
    int rc;

    rc = ble_ll_crypto_h6(w, key_id, out);
    TEST_ASSERT(rc == 0);

    rc = memcmp(out, ok, 16);
    TEST_ASSERT(rc == 0);
}

TEST_CASE_SELF(ble_ll_crypto_test_h7) {
    const uint8_t salt[] = {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x74, 0x6D, 0x70, 0x31
    };
    const uint8_t w[] = {
        0xec, 0x02, 0x34, 0xa3, 0x57, 0xc8, 0xad, 0x05,
        0x34, 0x10, 0x10, 0xa6, 0x0a, 0x39, 0x7d, 0x9b
    };
    const uint8_t ok[] = {
        0xfb, 0x17, 0x35, 0x97, 0xc6, 0xa3, 0xc0, 0xec,
        0xd2, 0x99, 0x8c, 0x2a, 0x75, 0xa5, 0x70, 0x11
    };
    uint8_t out[16];
    int rc;

    rc = ble_ll_crypto_h7(salt, w, out);
    TEST_ASSERT(rc == 0);

    rc = memcmp(out, ok, 16);
    TEST_ASSERT(rc == 0);
}

TEST_CASE_SELF(ble_ll_crypto_test_h8) {
    const uint8_t k[] = {
        0xec, 0x02, 0x34, 0xa3, 0x57, 0xc8, 0xad, 0x05,
        0x34, 0x10, 0x10, 0xa6, 0x0a, 0x39, 0x7d, 0x9b
    };
    const uint8_t s[] = {
        0x15, 0x36, 0xd1, 0x8d, 0xe3, 0xd2, 0x0d, 0xf9,
        0x9b, 0x70, 0x44, 0xc1, 0x2f, 0x9e, 0xd5, 0xba
    };
    const uint8_t key_id[] = { 0xcc, 0x03, 0x01, 0x48 };
    const uint8_t ok[] = {
        0xe5, 0xe5, 0xbe, 0xba, 0xae, 0x72, 0x28, 0xe7,
        0x22, 0xa3, 0x89, 0x04, 0xed, 0x35, 0x0f, 0x6d
    };
    uint8_t out[16];
    int rc;

    rc = ble_ll_crypto_h8(k, s, key_id, out);
    TEST_ASSERT(rc == 0);

    rc = memcmp(out, ok, 16);
    TEST_ASSERT(rc == 0);
}

TEST_CASE_SELF(ble_ll_crypto_test_gskd) {
    const uint8_t broadcast_code[] = {
        0x00, 0x00, 0x00, 0x00, 0x65, 0x73, 0x75, 0x6f,
        0x48, 0x20, 0x65, 0x6e, 0x72, 0xb8, 0xc3, 0x42
    };
    const uint8_t gskd[] = {
        0x55, 0x18, 0x8b, 0x3d, 0x32, 0xf6, 0xbb, 0x9a,
        0x90, 0x0a, 0xfc, 0xfb, 0xee, 0xd4, 0xe7, 0x2a
    };
    const uint8_t big1[] = {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x42, 0x49, 0x47, 0x31
    };
    const uint8_t big2[] = { 0x42, 0x49, 0x47, 0x32 };
    const uint8_t big3[] = { 0x42, 0x49, 0x47, 0x33 };
    const uint8_t ok_igltk[] = {
        0x4c, 0x0d, 0xd7, 0x4c, 0x2b, 0x19, 0xaa, 0x95,
        0xd8, 0x98, 0x23, 0x85, 0x5f, 0x10, 0x01, 0xb8
    };
    const uint8_t ok_gltk[] = {
        0xc4, 0xcd, 0x4b, 0x83, 0x49, 0xb5, 0xa1, 0x8a,
        0x02, 0xde, 0x66, 0x20, 0x90, 0x17, 0xae, 0xd3
    };
    const uint8_t ok_gsk[] = {
        0xbe, 0x2a, 0x16, 0xfc, 0x7a, 0xc4, 0x64, 0xe7,
        0x52, 0x30, 0x1b, 0xcc, 0xc8, 0x18, 0x81, 0x2c
    };
    uint8_t igltk[16];
    uint8_t gltk[16];
    uint8_t gsk[16];
    int rc;

    rc = ble_ll_crypto_h7(big1, broadcast_code, igltk);
    TEST_ASSERT(rc == 0);

    rc = memcmp(igltk, ok_igltk, 16);
    TEST_ASSERT(rc == 0);

    rc = ble_ll_crypto_h6(igltk, big2, gltk);
    TEST_ASSERT(rc == 0);

    rc = memcmp(gltk, ok_gltk, 16);
    TEST_ASSERT(rc == 0);

    rc = ble_ll_crypto_h8(gltk, gskd, big3, gsk);
    TEST_ASSERT(rc == 0);

    rc = memcmp(gsk, ok_gsk, 16);
    TEST_ASSERT(rc == 0);
}

TEST_SUITE(ble_ll_crypto_test_suite) {
    ble_ll_crypto_test_h6();
    ble_ll_crypto_test_h7();
    ble_ll_crypto_test_h8();
    ble_ll_crypto_test_gskd();
}
