1/*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "common/log_wrapper.h"
17#include "handshake_helper.h"
18
19namespace OHOS::ArkCompiler::Toolchain {
20/* static */
21bool WebSocketKeyEncoder::EncodeKey(std::string_view key, unsigned char (&destination)[ENCODED_KEY_LEN + 1])
22{
23    std::string buffer(key.size() + WEB_SOCKET_GUID.size(), 0);
24    key.copy(buffer.data(), key.size());
25    WEB_SOCKET_GUID.copy(buffer.data() + key.size(), WEB_SOCKET_GUID.size());
26
27    return EncodeKey(reinterpret_cast<unsigned char *>(buffer.data()), buffer.size(), destination);
28}
29
30/* static */
31bool WebSocketKeyEncoder::EncodeKey(const unsigned char(&key)[KEY_LENGTH + 1],
32                                    unsigned char (&destination)[ENCODED_KEY_LEN + 1])
33{
34    constexpr size_t bufferSize = KEY_LENGTH + WEB_SOCKET_GUID.size();
35    unsigned char buffer[bufferSize];
36    auto *guid = std::copy(key, key + KEY_LENGTH, buffer);
37    WEB_SOCKET_GUID.copy(reinterpret_cast<char *>(guid), WEB_SOCKET_GUID.size());
38
39    return EncodeKey(buffer, bufferSize, destination);
40}
41
42/* static */
43bool WebSocketKeyEncoder::EncodeKey(const unsigned char *source, size_t length,
44                                    unsigned char (&destination)[ENCODED_KEY_LEN + 1])
45{
46    unsigned char hash[SHA_DIGEST_LENGTH];
47    SHA1(source, length, hash);
48
49    // base64-encoding is done via EVP_EncodeBlock, which writes a null-terminated string.
50    int encodedBytes = EVP_EncodeBlock(destination, hash, SHA_DIGEST_LENGTH);
51    // "EVP_EncodeBlock() returns the number of bytes encoded excluding the NUL terminator."
52    if (encodedBytes != ENCODED_KEY_LEN) {
53        LOGE("EVP_EncodeBlock failed to encode all bytes, encodedBytes = %{public}d", encodedBytes);
54        return false;
55    }
56    return true;
57}
58} // namespace OHOS::ArkCompiler::Toolchain
59