1 /*
2  * Copyright (C) 2021 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 "obex_utils.h"
17 #include <algorithm>
18 #include <codecvt>
19 #include <cstring>
20 #include <endian.h>
21 #include <iomanip>
22 #include <locale>
23 #include <sstream>
24 #include "log.h"
25 #include "raw_address.h"
26 #include "securec.h"
27 #include "stub/message_digest.h"
28 
29 namespace OHOS {
30 namespace bluetooth {
31 int ObexUtils::g_bigEndian = -1;
32 
SysIsBigEndian()33 bool ObexUtils::SysIsBigEndian()
34 {
35 
36     if (g_bigEndian == -1) {
37         union {
38             int aInt;
39             char bChar;
40         } tempUnion;
41         tempUnion.aInt = 1;
42         if (tempUnion.bChar == 1) {
43             g_bigEndian = 0;
44         } else {
45             g_bigEndian = 1;
46         }
47     }
48     return g_bigEndian == 1;
49 }
50 
51 std::mutex ObexUtils::g_mutex;
52 
DataReverse(uint8_t * data,const uint16_t & len,const uint8_t & unitLen)53 void ObexUtils::DataReverse(uint8_t *data, const uint16_t &len, const uint8_t &unitLen)
54 {
55     if (unitLen < 1) {
56         OBEX_LOG_ERROR("LittleToBigEndian: unitLen is incorrect");
57         return;
58     }
59     if (unitLen == 1) {
60         return;
61     }
62     for (uint16_t pos = 0; pos < len; pos += unitLen) {
63         for (uint16_t subPos = 0; subPos < unitLen / 0x02; subPos++) {
64             uint8_t temp = data[pos + subPos];
65             data[pos + subPos] = data[pos + (unitLen - subPos - 1)];
66             data[pos + (unitLen - subPos - 1)] = temp;
67         }
68     }
69 }
70 
SetBufData16(uint8_t * bigEndData,uint16_t pos,const uint16_t & value)71 void ObexUtils::SetBufData16(uint8_t *bigEndData, uint16_t pos, const uint16_t &value)
72 {
73     *(reinterpret_cast<uint16_t *>(&bigEndData[pos])) = htobe16(value);
74 }
75 
SetBufData32(uint8_t * bigEndData,uint16_t pos,const uint32_t & value)76 void ObexUtils::SetBufData32(uint8_t *bigEndData, uint16_t pos, const uint32_t &value)
77 {
78     *(reinterpret_cast<uint32_t *>(&bigEndData[pos])) = htobe32(value);
79 }
80 
SetBufData64(uint8_t * bigEndData,uint16_t pos,const uint64_t & value)81 void ObexUtils::SetBufData64(uint8_t *bigEndData, uint16_t pos, const uint64_t &value)
82 {
83     *(reinterpret_cast<uint64_t *>(&bigEndData[pos])) = htobe64(value);
84 }
85 
GetBufData16(const uint8_t * bigEndData,uint16_t pos)86 uint16_t ObexUtils::GetBufData16(const uint8_t *bigEndData, uint16_t pos)
87 {
88     return be16toh(*(reinterpret_cast<uint16_t *>(const_cast<uint8_t *>(&bigEndData[pos]))));
89 }
90 
GetBufData32(const uint8_t * bigEndData,uint16_t pos)91 uint32_t ObexUtils::GetBufData32(const uint8_t *bigEndData, uint16_t pos)
92 {
93     return be32toh(*(reinterpret_cast<uint32_t *>(const_cast<uint8_t *>(&bigEndData[pos]))));
94 }
95 
GetBufData64(const uint8_t * bigEndData,uint16_t pos)96 uint64_t ObexUtils::GetBufData64(const uint8_t *bigEndData, uint16_t pos)
97 {
98     return be64toh(*(reinterpret_cast<uint64_t *>(const_cast<uint8_t *>(&bigEndData[pos]))));
99 }
100 
ToDebugString(Packet & obexPacket)101 std::string ObexUtils::ToDebugString(Packet &obexPacket)
102 {
103     Buffer *tmpBuffer = PacketContinuousPayload(&obexPacket);
104     uint8_t *packetBuf = (uint8_t *)BufferPtr(tmpBuffer);
105     size_t packetBufSize = BufferGetSize(tmpBuffer);
106     return ToDebugString(packetBuf, packetBufSize, true);
107 }
108 
ToDebugString(const uint8_t * v,const size_t & s,bool wrap)109 std::string ObexUtils::ToDebugString(const uint8_t *v, const size_t &s, bool wrap)
110 {
111     std::stringstream ss;
112     ss << std::uppercase << std::hex << std::setfill('0');
113     for (size_t i = 0; i < s; i++) {
114         if (wrap && i > 0 && i % DEBUG_MAX_COL_COUNT == 0) {
115             ss << std::endl;
116         }
117         if (i == DEBUG_MAX_DATA_LEN) {
118             ss << "......";
119             break;
120         }
121         ss << std::hex << std::setw(DEBUG_COL_ITEM_LEN) << static_cast<int>(v[i]) << " ";
122     }
123     return ss.str();
124 }
125 
ObexHeaderItemDebug(const ObexOptionalHeader & hi)126 void ObexUtils::ObexHeaderItemDebug(const ObexOptionalHeader &hi)
127 {
128     OBEX_LOG_INFO("HeaderId:0x%02X", hi.GetHeaderId());
129         OBEX_LOG_INFO("DataSize(dec):%{public}d, AllSize(dec):%{public}d",
130         int(hi.GetHeaderDataSize()), int(hi.GetHeaderTotalSize()));
131     OBEX_LOG_INFO("DataType:0x%02hhX, DataTypeName:%{public}s",
132         hi.GetHeaderClassType(), hi.GetHeaderClassTypeName().c_str());
133     switch (hi.GetHeaderClassType()) {
134         case ObexHeaderDataType::BYTES: {
135             auto bytes = hi.GetBytes();
136             if (bytes) {
137                 OBEX_LOG_INFO("BYTES:%{public}s", ToDebugString(bytes.get(), hi.GetHeaderDataSize(), false).c_str());
138             } else {
139                 OBEX_LOG_INFO("BYTES: null");
140             }
141             break;
142         }
143         case ObexHeaderDataType::BYTE:
144             OBEX_LOG_INFO("BYTE:0x%02X", static_cast<const ObexOptionalByteHeader *>(&hi)->GetByte());
145             break;
146         case ObexHeaderDataType::WORD:
147             OBEX_LOG_INFO("WORD(dec):%{public}d", static_cast<const ObexOptionalWordHeader *>(&hi)->GetWord());
148             break;
149         case ObexHeaderDataType::UNICODE_TEXT:
150             OBEX_LOG_INFO("UNICODE_TEXT:%{public}s",
151                 UnicodeToUtf8(static_cast<const ObexOptionalUnicodeHeader *>(&hi)->GetUnicodeText()).c_str());
152             break;
153         case ObexHeaderDataType::STRING:
154             OBEX_LOG_INFO("String:%{public}s", static_cast<const ObexOptionalStringHeader *>(&hi)->GetString().c_str());
155             break;
156         case ObexHeaderDataType::TLV: {
157             auto &tlvParamters = static_cast<const ObexOptionalTlvHeader *>(&hi)->GetTlvParamters();
158             if (tlvParamters != nullptr) {
159                 int index = 0;
160                 for (auto &pm : static_cast<const ObexOptionalTlvHeader *>(&hi)->GetTlvParamters()->GetTlvTriplets()) {
161                     OBEX_LOG_INFO("----TlvHeader At:%{public}d, TAG:0x%02X, LEN:%{public}d",
162                         index, pm->GetTagId(), pm->GetLen());
163                     OBEX_LOG_INFO("--VAL:%{public}s",
164                         ObexUtils::ToDebugString(pm->GetVal(), pm->GetLen(), false).c_str());
165                     index++;
166                 }
167             }
168             break;
169         }
170         default:
171             OBEX_LOG_ERROR("HdrType is illegal");
172             break;
173     }
174     OBEX_LOG_INFO("DATA HEX:\n%{public}s",
175         ObexUtils::ToDebugString(hi.GetBytes().get(), hi.GetHeaderDataSize(), true).c_str());
176 }
177 
ObexHeaderDebug(const ObexHeader & header)178 void ObexUtils::ObexHeaderDebug(const ObexHeader &header)
179 {
180     OBEX_LOG_INFO("----------ObexHeader Debug Start----------");
181 
182     OBEX_LOG_INFO("Code:0x%02X", header.GetFieldCode());
183     OBEX_LOG_INFO("PacketLength(dec):%{public}d", int(header.GetFieldPacketLength()));
184     if (header.GetFieldObexVersionNum() != nullptr) {
185         OBEX_LOG_INFO("ObexVersionNum:0x%02X", header.GetFieldObexVersionNum()[0]);
186     }
187     if (header.GetFieldFlags() != nullptr) {
188         OBEX_LOG_INFO("Flags:0x%02X", header.GetFieldFlags()[0]);
189     }
190     if (header.GetFieldMaxPacketLength() != nullptr) {
191         OBEX_LOG_INFO("MaxPacketLength(dec):%{public}d", int(header.GetFieldMaxPacketLength()[0]));
192     }
193     if (header.GetFieldConstants() != nullptr) {
194         OBEX_LOG_INFO("Constants:0x%02X", header.GetFieldConstants()[0]);
195     }
196 
197     auto &headerList = header.GetOptionalHeaders();
198     OBEX_LOG_INFO("--------------------OptionalHeaders Start");
199 
200     for (size_t i = 0; i < headerList.size(); i++) {
201         OBEX_LOG_INFO("----------Header At:%zu", i);
202         auto &headerItem = headerList.at(i);
203         ObexHeaderItemDebug(*headerItem);
204     }
205     OBEX_LOG_INFO("--------------------OptionalHeaders End");
206 
207     auto obexPacket = header.Build();
208     OBEX_LOG_INFO(
209         "ALL HEX:\n%{public}s", ObexUtils::ToDebugString(obexPacket->GetBuffer(), obexPacket->GetSize(), true).c_str());
210 
211     OBEX_LOG_INFO("----------ObexHeader Debug End----------");
212 }
213 
BtAddr2String(const BtAddr & addr)214 std::string ObexUtils::BtAddr2String(const BtAddr &addr)
215 {
216     return RawAddress::ConvertToString(addr.addr).GetAddress();
217 }
218 
MakeNonce(const uint32_t & privateKey)219 std::vector<uint8_t> ObexUtils::MakeNonce(const uint32_t &privateKey)
220 {
221     std::unique_lock<std::mutex> unilock(g_mutex);
222 
223     struct timespec tp;
224     clock_gettime(CLOCK_REALTIME, &tp);
225     const int bufSize = 20;
226     char secBuf[bufSize] = {0};
227     (void)sprintf_s(secBuf, sizeof(secBuf), "%ld", tp.tv_sec);
228     std::string sec(secBuf);
229 
230     char nsecBuf[bufSize] = {0};
231     (void)sprintf_s(nsecBuf, sizeof(nsecBuf), "%ld", tp.tv_nsec);
232     std::string nsec(nsecBuf);
233 
234     std::string timeStamp = sec + nsec;
235 
236     char key[bufSize] = {0};
237     (void)sprintf_s(key, sizeof(key), "%{public}d", int(privateKey));
238     std::string priKey(key);
239 
240     std::string nonce = timeStamp + ":" + priKey;
241 
242     stub::MessageDigest *digest = stub::MessageDigestFactory::GetInstance(stub::DIGEST_TYPE_MD5);
243 
244     return digest->Digest((uint8_t *)nonce.data(), nonce.size());
245 }
246 
MakeRequestDigest(const uint8_t * nonce,int sz,const std::string & password)247 std::vector<uint8_t> ObexUtils::MakeRequestDigest(const uint8_t *nonce, int sz, const std::string &password)
248 {
249     std::unique_lock<std::mutex> unilock(g_mutex);
250     const int bufSize = 256;
251     uint8_t nonceBuf[bufSize];
252     (void)memcpy_s(nonceBuf, sizeof(nonceBuf), nonce, sz);
253     nonceBuf[sz] = ':';
254     (void)memcpy_s(&nonceBuf[sz + 1], sizeof(nonceBuf) - sz - 1,
255         reinterpret_cast<uint8_t *>(const_cast<char *>(password.c_str())), password.size());
256 
257     stub::MessageDigest *digest = stub::MessageDigestFactory::GetInstance(stub::DIGEST_TYPE_MD5);
258     std::vector<uint8_t> vc = digest->Digest((uint8_t *)nonceBuf, sz + password.size() + 1);
259 
260     return vc;
261 }
262 
UnicodeToUtf8(const std::u16string & str16)263 std::string ObexUtils::UnicodeToUtf8(const std::u16string &str16)
264 {
265     std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
266     return convert.to_bytes(str16);
267 }
268 
Utf8ToUnicode(const std::string & strUtf8)269 std::u16string ObexUtils::Utf8ToUnicode(const std::string &strUtf8)
270 {
271     std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
272     return convert.from_bytes(strUtf8);
273 }
274 }  // namespace bluetooth
275 }  // namespace OHOS