• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "huks_master.h"
17 
18 #include <openssl/err.h>
19 #include <openssl/rand.h>
20 #include <openssl/sha.h>
21 
22 #include "hks_api.h"
23 #include "hks_param.h"
24 #include "storage_service_log.h"
25 
26 namespace OHOS {
27 namespace StorageDaemon {
Init()28 bool HuksMaster::Init()
29 {
30     return HksInitialize();
31 }
32 
GenerateRandomKey(KeyBlob & rawKey)33 bool HuksMaster::GenerateRandomKey(KeyBlob &rawKey)
34 {
35     LOGD("enter, size %{public}d", rawKey.size);
36     if (rawKey.IsEmpty()) {
37         LOGE("bad key size %{public}d", rawKey.size);
38         return false;
39     }
40     auto ret = RAND_bytes(rawKey.data.get(), rawKey.size);
41     if (ret <= 0) {
42         LOGE("RAND_bytes failed return %{public}d, errno %{public}lu", ret, ERR_get_error());
43         return false;
44     }
45     return true;
46 }
47 
GenerateKey(const KeyBlob & keyAlias)48 bool HuksMaster::GenerateKey(const KeyBlob &keyAlias)
49 {
50     LOGD("enter");
51     if (keyAlias.IsEmpty()) {
52         LOGE("bad keyAlias input, size %{public}d", keyAlias.size);
53         return false;
54     }
55 
56     HksParamSet *paramSet = nullptr;
57     struct HksParam keyParam[] = {
58         { .tag = HKS_TAG_KEY_STORAGE_FLAG, .uint32Param = HKS_STORAGE_PERSISTENT },
59         { .tag = HKS_TAG_PURPOSE, .uint32Param = HKS_KEY_PURPOSE_ENCRYPT | HKS_KEY_PURPOSE_DECRYPT },
60         { .tag = HKS_TAG_ALGORITHM, .uint32Param = HKS_ALG_AES },
61         { .tag = HKS_TAG_KEY_SIZE, .uint32Param = HKS_AES_KEY_SIZE_256 },
62         { .tag = HKS_TAG_DIGEST, .uint32Param = HKS_DIGEST_SHA256 },
63         { .tag = HKS_TAG_BLOCK_MODE, .uint32Param = HKS_MODE_GCM },
64         { .tag = HKS_TAG_PADDING, .uint32Param = HKS_PADDING_NONE }
65     };
66     auto ret = HksInitParamSet(&paramSet);
67     if (ret != HKS_SUCCESS) {
68         LOGE("HksInitParamSet failed ret %{public}d", ret);
69         return false;
70     }
71     ret = HksAddParams(paramSet, keyParam, HKS_ARRAY_SIZE(keyParam));
72     if (ret != HKS_SUCCESS) {
73         LOGE("HksAddParams failed ret %{public}d", ret);
74         HksFreeParamSet(&paramSet);
75         return false;
76     }
77     ret = HksBuildParamSet(&paramSet);
78     if (ret != HKS_SUCCESS) {
79         LOGE("HksBuildParamSet failed ret %{public}d", ret);
80         HksFreeParamSet(&paramSet);
81         return false;
82     }
83 
84     HksBlob hksAlias = {
85         .size = keyAlias.size,
86         .data = keyAlias.data.get(),
87     };
88     ret = HksGenerateKey(&hksAlias, paramSet, nullptr);
89     if (ret != HKS_SUCCESS) {
90         LOGE("HksGenerateKey failed ret %{public}d", ret);
91         HksFreeParamSet(&paramSet);
92         return false;
93     }
94     HksFreeParamSet(&paramSet);
95     LOGD("success");
96     return true;
97 }
98 
DeleteKey(const KeyBlob & keyAlias)99 bool HuksMaster::DeleteKey(const KeyBlob &keyAlias)
100 {
101     LOGD("enter");
102     if (keyAlias.IsEmpty()) {
103         LOGE("bad keyAlias input, size %{public}d", keyAlias.size);
104         return false;
105     }
106     HksBlob hksAlias = {
107         .size = keyAlias.size,
108         .data = keyAlias.data.get(),
109     };
110     auto ret = HksDeleteKey(&hksAlias, nullptr);
111     if (ret != HKS_SUCCESS) {
112         LOGE("HksDeleteKey failed ret %{public}d", ret);
113         return false;
114     }
115     LOGD("success");
116     return true;
117 }
118 
HashAndClip(const std::string & prefix,const KeyBlob & payload,const uint32_t length)119 static KeyBlob HashAndClip(const std::string &prefix, const KeyBlob &payload, const uint32_t length)
120 {
121     KeyBlob res;
122     res.Alloc(SHA512_DIGEST_LENGTH);
123     std::string header = prefix;
124     if (header.empty()) {
125         header = "dummy SHA512 header";
126     }
127 
128     SHA512_CTX c;
129     SHA512_Init(&c);
130     SHA512_Update(&c, header.data(), header.size());
131     if (!payload.IsEmpty()) {
132         SHA512_Update(&c, payload.data.get(), payload.size);
133     }
134     SHA512_Final(res.data.get(), &c);
135 
136     res.size = length;
137     return res;
138 }
139 
GenHksParam(KeyContext & ctx,const UserAuth & auth,const bool isEncrypt)140 static HksParamSet *GenHksParam(KeyContext &ctx, const UserAuth &auth, const bool isEncrypt)
141 {
142     HksParamSet *paramSet = nullptr;
143     struct HksParam encryptParam[] = {
144         { .tag = HKS_TAG_KEY_STORAGE_FLAG, .uint32Param = HKS_STORAGE_PERSISTENT },
145         { .tag = HKS_TAG_ALGORITHM, .uint32Param = HKS_ALG_AES },
146         { .tag = HKS_TAG_BLOCK_MODE, .uint32Param = HKS_MODE_GCM },
147         { .tag = HKS_TAG_PADDING, .uint32Param = HKS_PADDING_NONE },
148         { .tag = HKS_TAG_IS_KEY_ALIAS, .boolParam = true },
149         { .tag = HKS_TAG_PURPOSE, .uint32Param = isEncrypt ? HKS_KEY_PURPOSE_ENCRYPT : HKS_KEY_PURPOSE_DECRYPT},
150 
151     };
152     auto ret = HksInitParamSet(&paramSet);
153     if (ret != HKS_SUCCESS) {
154         LOGE("HksInitParamSet failed ret %{public}d", ret);
155         return nullptr;
156     }
157     ret = HksAddParams(paramSet, encryptParam, HKS_ARRAY_SIZE(encryptParam));
158     if (ret != HKS_SUCCESS) {
159         LOGE("HksAddParams failed ret %{public}d", ret);
160         HksFreeParamSet(&paramSet);
161         return nullptr;
162     }
163 
164     ctx.nonce = HashAndClip("NONCE SHA512 prefix", ctx.secDiscard, HKS_AE_NONCE_LEN);
165     if (ctx.nonce.IsEmpty()) {
166         HksFreeParamSet(&paramSet);
167         return nullptr;
168     }
169     ctx.aad = HashAndClip("AAD SHA512 prefix", ctx.secDiscard, CRYPTO_AES_AAD_LEN);
170     if (ctx.aad.IsEmpty()) {
171         HksFreeParamSet(&paramSet);
172         return nullptr;
173     }
174 
175     // pass the token here
176     struct HksParam addParam[] = {
177         { .tag = HKS_TAG_NONCE,
178           .blob =
179             { ctx.nonce.size, ctx.nonce.data.get() }
180         },
181         { .tag = HKS_TAG_ASSOCIATED_DATA,
182           .blob =
183             { ctx.aad.size, ctx.aad.data.get() }
184         }
185     };
186     ret = HksAddParams(paramSet, addParam, HKS_ARRAY_SIZE(addParam));
187     if (ret != HKS_SUCCESS) {
188         LOGE("HksAddParams failed ret %{public}d", ret);
189         HksFreeParamSet(&paramSet);
190         return nullptr;
191     }
192     return paramSet;
193 }
194 
EncryptKey(KeyContext & ctx,const UserAuth & auth,const KeyInfo & key)195 bool HuksMaster::EncryptKey(KeyContext &ctx, const UserAuth &auth, const KeyInfo &key)
196 {
197     LOGD("enter");
198     if (ctx.alias.IsEmpty()) {
199         LOGE("bad keyAlias input, size %{public}d", ctx.alias.size);
200         return false;
201     }
202     if (key.key.IsEmpty()) {
203         LOGE("bad rawKey input, size %{public}d", key.key.size);
204         return false;
205     }
206 
207     HksParamSet *paramSet = GenHksParam(ctx, auth, true);
208     if (paramSet == nullptr) {
209         return false;
210     }
211 
212     HksBlob hksAlias = {
213         .size = ctx.alias.size,
214         .data = ctx.alias.data.get(),
215     };
216     HksBlob hksRawKey = {
217         .size = key.key.size,
218         .data = key.key.data.get(),
219     };
220     ctx.encrypted.Alloc(CRYPTO_AES_256_LEN);
221     HksBlob hksEncrypted = {
222         .size = ctx.encrypted.size,
223         .data = ctx.encrypted.data.get(),
224     };
225     LOGI("alias len:%{public}d, data(hex):%{private}s", ctx.alias.size, ctx.alias.ToString().c_str());
226     auto ret = HksEncrypt(&hksAlias, paramSet, &hksRawKey, &hksEncrypted);
227     if (ret != HKS_SUCCESS) {
228         LOGE("HksEncrypt failed ret %{public}d", ret);
229         ctx.encrypted.Clear();
230         HksFreeParamSet(&paramSet);
231         return false;
232     }
233     // save the encrypted text real length
234     ctx.encrypted.size = hksEncrypted.size;
235     HksFreeParamSet(&paramSet);
236     LOGD("success");
237     return true;
238 }
239 
DecryptKey(KeyContext & ctx,const UserAuth & auth,KeyInfo & key)240 bool HuksMaster::DecryptKey(KeyContext &ctx, const UserAuth &auth, KeyInfo &key)
241 {
242     LOGD("enter");
243     if (ctx.alias.IsEmpty()) {
244         LOGE("bad keyAlias input, size %{public}d", ctx.alias.size);
245         return false;
246     }
247     if (ctx.encrypted.IsEmpty()) {
248         LOGE("bad encrypted input, size %{public}d", ctx.encrypted.size);
249         return false;
250     }
251 
252     HksParamSet *paramSet = GenHksParam(ctx, auth, false);
253     if (paramSet == nullptr) {
254         return false;
255     }
256 
257     HksBlob hksAlias = {
258         .size = ctx.alias.size,
259         .data = ctx.alias.data.get(),
260     };
261     HksBlob hksEncrypted = {
262         .size = ctx.encrypted.size,
263         .data = ctx.encrypted.data.get(),
264     };
265     key.key.Alloc(CRYPTO_AES_256_LEN);
266     HksBlob hksRawKey = {
267         .size = key.key.size,
268         .data = key.key.data.get(),
269     };
270     LOGI("alias len:%{public}d, data(hex):%{private}s", ctx.alias.size, ctx.alias.ToString().c_str());
271     auto ret = HksDecrypt(&hksAlias, paramSet, &hksEncrypted, &hksRawKey);
272     if (ret != HKS_SUCCESS) {
273         LOGE("HksDecrypt failed ret %{public}d", ret);
274         key.key.Clear();
275         HksFreeParamSet(&paramSet);
276         return false;
277     }
278     // restore the plaintext real length
279     key.key.size = hksRawKey.size;
280     HksFreeParamSet(&paramSet);
281     LOGD("success");
282     return true;
283 }
284 } // namespace StorageDaemon
285 } // namespace OHOS
286