1 /*
2 * Copyright (c) 2024 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 #include "hashstream_n_exporter.h"
16
17 #include <iomanip>
18 #include <sstream>
19
20 #include "hashstream_entity.h"
21
22 namespace OHOS {
23 namespace FileManagement {
24 namespace ModuleFileIO {
25 using namespace std;
26 using namespace OHOS::FileManagement::LibN;
27
GetHashAlgorithm(const string & alg)28 static HASH_ALGORITHM_TYPE GetHashAlgorithm(const string &alg)
29 {
30 return (algorithmMaps.find(alg) != algorithmMaps.end()) ? algorithmMaps.at(alg) : HASH_ALGORITHM_TYPE_UNSUPPORTED;
31 }
32
GetHsEntity(napi_env env,napi_value hs_entity)33 static tuple<bool, HashStreamEntity*> GetHsEntity(napi_env env, napi_value hs_entity)
34 {
35 auto hsEntity = NClass::GetEntityOf<HashStreamEntity>(env, hs_entity);
36 if (!hsEntity) {
37 return { false, nullptr };
38 }
39 return { true, hsEntity };
40 }
41
HashFinal(const unique_ptr<unsigned char[]> & hashBuf,size_t hashLen)42 static string HashFinal(const unique_ptr<unsigned char[]> &hashBuf, size_t hashLen)
43 {
44 stringstream ss;
45 for (size_t i = 0; i < hashLen; ++i) {
46 const int hexPerByte = 2;
47 ss << std::uppercase << std::setfill('0') << std::setw(hexPerByte) << std::hex
48 << static_cast<uint32_t>(hashBuf[i]);
49 }
50
51 return ss.str();
52 }
53
SetHsEntity(napi_env env,NFuncArg & funcArg,HASH_ALGORITHM_TYPE algType)54 static napi_value SetHsEntity(napi_env env, NFuncArg &funcArg, HASH_ALGORITHM_TYPE algType)
55 {
56 HashStreamEntity* rawPtr = new (std::nothrow) HashStreamEntity();
57 if (rawPtr == nullptr) {
58 HILOGE("Failed to request heap memory.");
59 NError(ENOMEM).ThrowErr(env);
60 return nullptr;
61 }
62 std::unique_ptr<HashStreamEntity> hsEntity(rawPtr);
63 hsEntity->algType = algType;
64
65 switch (algType) {
66 case HASH_ALGORITHM_TYPE_MD5: {
67 MD5_CTX ctx;
68 MD5_Init(&ctx);
69 hsEntity->md5Ctx = ctx;
70 break;
71 }
72 case HASH_ALGORITHM_TYPE_SHA1: {
73 SHA_CTX ctx;
74 SHA1_Init(&ctx);
75 hsEntity->shaCtx = ctx;
76 break;
77 }
78 case HASH_ALGORITHM_TYPE_SHA256: {
79 SHA256_CTX ctx;
80 SHA256_Init(&ctx);
81 hsEntity->sha256Ctx = ctx;
82 break;
83 }
84 default:
85 break;
86 }
87 if (!NClass::SetEntityFor<HashStreamEntity>(env, funcArg.GetThisVar(), move(hsEntity))) {
88 HILOGE("INNER BUG. Failed to wrap entity for obj hsEntity");
89 NError(EIO).ThrowErr(env);
90 return nullptr;
91 }
92 return funcArg.GetThisVar();
93 }
94
Constructor(napi_env env,napi_callback_info info)95 napi_value HashStreamNExporter::Constructor(napi_env env, napi_callback_info info)
96 {
97 NFuncArg funcArg(env, info);
98 if (!funcArg.InitArgs(NARG_CNT::ONE)) {
99 HILOGE("Number of arguments unmatched");
100 NError(EINVAL).ThrowErr(env);
101 return nullptr;
102 }
103
104 auto [succAlg, alg, ignore] = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8String();
105 if (!succAlg) {
106 HILOGE("Invalid algorithm");
107 NError(EINVAL).ThrowErr(env);
108 return nullptr;
109 }
110
111 HASH_ALGORITHM_TYPE algType = GetHashAlgorithm(alg.get());
112 if (algType == HASH_ALGORITHM_TYPE_UNSUPPORTED) {
113 HILOGE("Unsupport algorithm");
114 NError(EINVAL).ThrowErr(env);
115 return nullptr;
116 }
117
118 return SetHsEntity(env, funcArg, algType);
119 }
120
Digest(napi_env env,napi_callback_info info)121 napi_value HashStreamNExporter::Digest(napi_env env, napi_callback_info info)
122 {
123 NFuncArg funcArg(env, info);
124 if (!funcArg.InitArgs(NARG_CNT::ZERO)) {
125 HILOGE("Number of arguments unmatched");
126 NError(EINVAL).ThrowErr(env);
127 return nullptr;
128 }
129 auto [succEntity, hsEntity] = GetHsEntity(env, funcArg.GetThisVar());
130 if (!succEntity) {
131 HILOGE("Failed to get entity of RandomAccessFile");
132 NError(EIO).ThrowErr(env);
133 return nullptr;
134 }
135
136 string digestStr;
137 switch (hsEntity->algType) {
138 case HASH_ALGORITHM_TYPE_MD5: {
139 auto res = make_unique<unsigned char[]>(MD5_DIGEST_LENGTH);
140 MD5_Final(res.get(), &hsEntity->md5Ctx);
141 digestStr = HashFinal(res, MD5_DIGEST_LENGTH);
142 break;
143 }
144 case HASH_ALGORITHM_TYPE_SHA1: {
145 auto res = make_unique<unsigned char[]>(SHA_DIGEST_LENGTH);
146 SHA1_Final(res.get(), &hsEntity->shaCtx);
147 digestStr = HashFinal(res, SHA_DIGEST_LENGTH);
148 break;
149 }
150 case HASH_ALGORITHM_TYPE_SHA256: {
151 auto res = make_unique<unsigned char[]>(SHA256_DIGEST_LENGTH);
152 SHA256_Final(res.get(), &hsEntity->sha256Ctx);
153 digestStr = HashFinal(res, SHA256_DIGEST_LENGTH);
154 break;
155 }
156 default:
157 break;
158 }
159
160 return NVal::CreateUTF8String(env, digestStr).val_;
161 }
162
Update(napi_env env,napi_callback_info info)163 napi_value HashStreamNExporter::Update(napi_env env, napi_callback_info info)
164 {
165 NFuncArg funcArg(env, info);
166 if (!funcArg.InitArgs(NARG_CNT::ONE)) {
167 HILOGE("Number of arguments unmatched");
168 NError(EINVAL).ThrowErr(env);
169 return nullptr;
170 }
171
172 auto [succ, buf, bufLen] = NVal(env, funcArg[NARG_POS::FIRST]).ToArraybuffer();
173 if (!succ) {
174 HILOGE("illegal array buffer");
175 NError(EINVAL).ThrowErr(env);
176 return nullptr;
177 }
178
179 auto [succEntity, hsEntity] = GetHsEntity(env, funcArg.GetThisVar());
180 if (!succEntity) {
181 HILOGE("Failed to get entity of RandomAccessFile");
182 NError(EIO).ThrowErr(env);
183 return nullptr;
184 }
185
186 switch (hsEntity->algType) {
187 case HASH_ALGORITHM_TYPE_MD5:
188 MD5_Update(&hsEntity->md5Ctx, buf, bufLen);
189 break;
190 case HASH_ALGORITHM_TYPE_SHA1:
191 SHA1_Update(&hsEntity->shaCtx, buf, bufLen);
192 break;
193 case HASH_ALGORITHM_TYPE_SHA256:
194 SHA256_Update(&hsEntity->sha256Ctx, buf, bufLen);
195 break;
196 default:
197 break;
198 }
199 return NVal::CreateUndefined(env).val_;
200 }
201
Export()202 bool HashStreamNExporter::Export()
203 {
204 vector<napi_property_descriptor> props = {
205 NVal::DeclareNapiFunction("digest", Digest),
206 NVal::DeclareNapiFunction("update", Update),
207 };
208 string className = GetClassName();
209 bool succ = false;
210 napi_value classValue = nullptr;
211 tie(succ, classValue) = NClass::DefineClass(exports_.env_, className,
212 HashStreamNExporter::Constructor, move(props));
213 if (!succ) {
214 HILOGE("INNER BUG. Failed to define class");
215 NError(EIO).ThrowErr(exports_.env_);
216 return false;
217 }
218 succ = NClass::SaveClass(exports_.env_, className, classValue);
219 if (!succ) {
220 HILOGE("INNER BUG. Failed to define class");
221 NError(EIO).ThrowErr(exports_.env_);
222 return false;
223 }
224
225 return exports_.AddProp(className, classValue);
226 }
227
GetClassName()228 string HashStreamNExporter::GetClassName()
229 {
230 return HashStreamNExporter::className_;
231 }
232
HashStreamNExporter(napi_env env,napi_value exports)233 HashStreamNExporter::HashStreamNExporter(napi_env env, napi_value exports) : NExporter(env, exports) {}
234
~HashStreamNExporter()235 HashStreamNExporter::~HashStreamNExporter() {}
236 }
237 }
238 }