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
19 namespace OHOS::ArkCompiler::Toolchain {
20 /* static */
GenerateRandomSecWSKey()21 std::string WebSocketKeyEncoder::GenerateRandomSecWSKey()
22 {
23 std::array<unsigned char, SEC_WEBSOCKET_KEY_BYTES_LEN> bytes {};
24 if (RAND_bytes(bytes.data(), bytes.size()) != 1) {
25 LOGE("RAND_bytes failed to generate secure random bytes");
26 return "";
27 }
28
29 std::array<unsigned char, KEY_LENGTH + 1> encoded {};
30 // base64-encoding is done via EVP_EncodeBlock, which writes a null-terminated string.
31 int encodedBytes = EVP_EncodeBlock(encoded.data(), bytes.data(), SEC_WEBSOCKET_KEY_BYTES_LEN);
32 if (encodedBytes != KEY_LENGTH) {
33 LOGE("EVP_EncodeBlock failed to encode Sec-WebSocket-Key bytes, encodedBytes = %{public}d", encodedBytes);
34 return "";
35 }
36 return std::string(reinterpret_cast<char *>(encoded.data()), KEY_LENGTH);
37 }
38
39 /* static */
EncodeKey(std::string_view key,unsigned char (& destination)[ENCODED_KEY_LEN+1])40 bool WebSocketKeyEncoder::EncodeKey(std::string_view key, unsigned char (&destination)[ENCODED_KEY_LEN + 1])
41 {
42 std::string buffer(key.size() + WEB_SOCKET_GUID.size(), 0);
43 key.copy(buffer.data(), key.size());
44 WEB_SOCKET_GUID.copy(buffer.data() + key.size(), WEB_SOCKET_GUID.size());
45
46 return EncodeKey(reinterpret_cast<unsigned char *>(buffer.data()), buffer.size(), destination);
47 }
48
49 /* static */
EncodeKey(const unsigned char (& key)[KEY_LENGTH+1],unsigned char (& destination)[ENCODED_KEY_LEN+1])50 bool WebSocketKeyEncoder::EncodeKey(const unsigned char(&key)[KEY_LENGTH + 1],
51 unsigned char (&destination)[ENCODED_KEY_LEN + 1])
52 {
53 constexpr size_t bufferSize = KEY_LENGTH + WEB_SOCKET_GUID.size();
54 unsigned char buffer[bufferSize];
55 auto *guid = std::copy(key, key + KEY_LENGTH, buffer);
56 WEB_SOCKET_GUID.copy(reinterpret_cast<char *>(guid), WEB_SOCKET_GUID.size());
57
58 return EncodeKey(buffer, bufferSize, destination);
59 }
60
61 /* static */
EncodeKey(const unsigned char * source,size_t length,unsigned char (& destination)[ENCODED_KEY_LEN+1])62 bool WebSocketKeyEncoder::EncodeKey(const unsigned char *source, size_t length,
63 unsigned char (&destination)[ENCODED_KEY_LEN + 1])
64 {
65 unsigned char hash[SHA_DIGEST_LENGTH];
66 SHA1(source, length, hash);
67
68 // base64-encoding is done via EVP_EncodeBlock, which writes a null-terminated string.
69 int encodedBytes = EVP_EncodeBlock(destination, hash, SHA_DIGEST_LENGTH);
70 // "EVP_EncodeBlock() returns the number of bytes encoded excluding the NUL terminator."
71 if (encodedBytes != ENCODED_KEY_LEN) {
72 LOGE("EVP_EncodeBlock failed to encode all bytes, encodedBytes = %{public}d", encodedBytes);
73 return false;
74 }
75 return true;
76 }
77 } // namespace OHOS::ArkCompiler::Toolchain
78