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 #include "pkg_algorithm.h"
16 #include "pkg_algo_deflate.h"
17 #include "pkg_algo_lz4.h"
18 #include "pkg_stream.h"
19 #include "pkg_utils.h"
20 #include "securec.h"
21 
22 namespace Hpackage {
23 constexpr uint32_t MAX_BUFFER_SIZE = (4 * 1024 * 1024);
24 
ReadData(const PkgStreamPtr inStream,size_t offset,PkgBuffer & buffer,size_t & remainSize,size_t & readLen) const25 int32_t PkgAlgorithm::ReadData(const PkgStreamPtr inStream, size_t offset, PkgBuffer &buffer,
26     size_t &remainSize, size_t &readLen) const
27 {
28     size_t readBytes = 0;
29     size_t remainBytes = (remainSize > buffer.length) ? buffer.length : remainSize;
30     if (remainBytes != 0) {
31         int32_t ret = inStream->Read(buffer, offset, remainBytes, readBytes);
32         if (ret != PKG_SUCCESS) {
33             PKG_LOGE("fail deflate write data ");
34             return ret;
35         }
36     }
37     remainSize -= readBytes;
38     readLen = readBytes;
39     return PKG_SUCCESS;
40 }
41 
FinalDigest(DigestAlgorithm::DigestAlgorithmPtr algorithm,PkgAlgorithmContext & context,bool check) const42 int32_t PkgAlgorithm::FinalDigest(DigestAlgorithm::DigestAlgorithmPtr algorithm,
43     PkgAlgorithmContext &context, bool check) const
44 {
45     if (context.digestMethod == PKG_DIGEST_TYPE_SHA256) {
46         PkgBuffer digest(DIGEST_MAX_LEN);
47         algorithm->Final(digest);
48         if (check && memcmp(digest.buffer, context.digest, DIGEST_MAX_LEN) != 0) {
49             return PKG_INVALID_DIGEST;
50         }
51         if (memcpy_s(context.digest, sizeof(context.digest), digest.buffer, DIGEST_MAX_LEN) != EOK) {
52             PKG_LOGE("FinalDigest memcpy failed");
53             return PKG_NONE_MEMORY;
54         }
55     }
56     return PKG_SUCCESS;
57 }
58 
Pack(const PkgStreamPtr inStream,const PkgStreamPtr outStream,PkgAlgorithmContext & context)59 int32_t PkgAlgorithm::Pack(const PkgStreamPtr inStream, const PkgStreamPtr outStream,
60     PkgAlgorithmContext &context)
61 {
62     DigestAlgorithm::DigestAlgorithmPtr algorithm = PkgAlgorithmFactory::GetDigestAlgorithm(context.digestMethod);
63     if (algorithm == nullptr) {
64         PKG_LOGE("Can not get digest algor");
65         return PKG_NOT_EXIST_ALGORITHM;
66     }
67     algorithm->Init();
68 
69     PkgBuffer buffer(MAX_BUFFER_SIZE);
70     int32_t ret = PKG_SUCCESS;
71     size_t srcOffset = context.srcOffset;
72     size_t destOffset = context.destOffset;
73     size_t remainSize = context.unpackedSize;
74     size_t readLen = 0;
75     while (remainSize > 0) {
76         ret = ReadData(inStream, srcOffset, buffer, remainSize, readLen);
77         if (ret != PKG_SUCCESS) {
78             PKG_LOGE("Fail read data ");
79             break;
80         }
81 
82         ret = outStream->Write(buffer, readLen, destOffset);
83         if (ret != PKG_SUCCESS) {
84             PKG_LOGE("Fail write data ");
85             break;
86         }
87 
88         algorithm->Update(buffer, readLen);
89         srcOffset += readLen;
90         destOffset += readLen;
91     }
92 
93     ret = FinalDigest(algorithm, context, true);
94     if (ret != 0) {
95         PKG_LOGE("Check digest fail");
96         return ret;
97     }
98     if (srcOffset - context.srcOffset != context.unpackedSize) {
99         PKG_LOGE("original size error %zu %zu", srcOffset, context.unpackedSize);
100         return PKG_INVALID_DIGEST;
101     }
102     context.packedSize = destOffset - context.destOffset;
103     return ret;
104 }
105 
Unpack(const PkgStreamPtr inStream,const PkgStreamPtr outStream,PkgAlgorithmContext & context)106 int32_t PkgAlgorithm::Unpack(const PkgStreamPtr inStream, const PkgStreamPtr outStream,
107     PkgAlgorithmContext &context)
108 {
109     DigestAlgorithm::DigestAlgorithmPtr algorithm = PkgAlgorithmFactory::GetDigestAlgorithm(context.digestMethod);
110     if (algorithm == nullptr) {
111         PKG_LOGE("Can not get digest algor");
112         return PKG_NOT_EXIST_ALGORITHM;
113     }
114     algorithm->Init();
115     PkgBuffer buffer(nullptr, MAX_BUFFER_SIZE);
116     int32_t ret = PKG_SUCCESS;
117     size_t srcOffset = context.srcOffset;
118     size_t destOffset = context.destOffset;
119     size_t remainSize = context.packedSize;
120     size_t readLen = 0;
121     while (remainSize > 0) {
122         ret = ReadData(inStream, srcOffset, buffer, remainSize, readLen);
123         if (ret != PKG_SUCCESS) {
124             PKG_LOGE("Fail read data ");
125             break;
126         }
127 
128         ret = outStream->Write(buffer, readLen, destOffset);
129         if (ret != PKG_SUCCESS) {
130             PKG_LOGE("Fail write data ");
131             break;
132         }
133 
134         algorithm->Update(buffer, readLen);
135         srcOffset += readLen;
136         destOffset += readLen;
137     }
138 
139     ret = FinalDigest(algorithm, context, true);
140     if (ret != 0) {
141         PKG_LOGE("Check digest fail");
142         return ret;
143     }
144     if (destOffset - context.destOffset != context.packedSize) {
145         PKG_LOGE("original size error %zu %zu", destOffset, context.packedSize);
146         return PKG_INVALID_DIGEST;
147     }
148     context.unpackedSize = srcOffset - context.srcOffset;
149     return ret;
150 }
151 
UnpackWithVerify(const PkgStreamPtr inStream,const PkgStreamPtr outStream,PkgAlgorithmContext & context,VerifyFunction verifier)152 int32_t PkgAlgorithm::UnpackWithVerify(const PkgStreamPtr inStream, const PkgStreamPtr outStream,
153     PkgAlgorithmContext &context, VerifyFunction verifier)
154 {
155     DigestAlgorithm::DigestAlgorithmPtr algorithm = PkgAlgorithmFactory::GetDigestAlgorithm(context.digestMethod);
156     if (algorithm == nullptr) {
157         PKG_LOGE("Can not get digest algor");
158         return PKG_NOT_EXIST_ALGORITHM;
159     }
160     algorithm->Init();
161     PkgBuffer buffer(nullptr, MAX_BUFFER_SIZE);
162 
163     int32_t ret = PKG_SUCCESS;
164     size_t srcOffset = context.srcOffset;
165     size_t destOffset = context.destOffset;
166     size_t remainSize = context.packedSize;
167     size_t readLen = 0;
168     while (remainSize > 0) {
169         ret = ReadData(inStream, srcOffset, buffer, remainSize, readLen);
170         if (ret != PKG_SUCCESS) {
171             PKG_LOGE("Fail read data ");
172             break;
173         }
174 
175         if (verifier != nullptr) {
176             ret = verifier(buffer, readLen, destOffset);
177             if (ret != PKG_SUCCESS) {
178                 PKG_LOGE("Fail verify read data");
179                 break;
180             }
181         }
182 
183         ret = outStream->Write(buffer, readLen, destOffset);
184         if (ret != PKG_SUCCESS) {
185             PKG_LOGE("Fail write data ");
186             break;
187         }
188 
189         algorithm->Update(buffer, readLen);
190         srcOffset += readLen;
191         destOffset += readLen;
192     }
193 
194     ret = FinalDigest(algorithm, context, true);
195     if (ret != 0) {
196         PKG_LOGE("Check digest fail");
197         return ret;
198     }
199     if (destOffset - context.destOffset != context.packedSize) {
200         PKG_LOGE("original size error %zu %zu", destOffset, context.packedSize);
201         return PKG_INVALID_DIGEST;
202     }
203     context.unpackedSize = srcOffset - context.srcOffset;
204     return ret;
205 }
206 
GetAlgorithm(const PkgManager::FileInfoPtr config)207 PkgAlgorithm::PkgAlgorithmPtr PkgAlgorithmFactory::GetAlgorithm(const PkgManager::FileInfoPtr config)
208 {
209     if (config == nullptr) {
210         PKG_LOGE("Fail to get algorithm ");
211         return nullptr;
212     }
213     switch (config->packMethod) {
214         case PKG_COMPRESS_METHOD_ZIP:
215         case PKG_COMPRESS_METHOD_GZIP: {
216             if (config == nullptr) {
217                 PKG_LOGE("Invalid param config");
218                 return nullptr;
219             }
220             const ZipFileInfo *info = (ZipFileInfo *)config;
221             return std::make_shared<PkgAlgoDeflate>(*info);
222         }
223         case PKG_COMPRESS_METHOD_NONE:
224             return std::make_shared<PkgAlgorithm>();
225         case PKG_COMPRESS_METHOD_LZ4: {
226             if (config == nullptr) {
227                 PKG_LOGE("Invalid param config");
228                 return nullptr;
229             }
230             const Lz4FileInfo *info = (Lz4FileInfo *)config;
231             return std::make_shared<PkgAlgorithmLz4>(*info);
232         }
233         case PKG_COMPRESS_METHOD_LZ4_BLOCK: {
234             if (config == nullptr) {
235                 PKG_LOGE("Invalid param config");
236                 return nullptr;
237             }
238             const Lz4FileInfo *info = (Lz4FileInfo *)config;
239             return std::make_shared<PkgAlgorithmBlockLz4>(*info);
240         }
241         default:
242             break;
243     }
244     return nullptr;
245 }
246 } // namespace Hpackage
247