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(¶mSet);
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(¶mSet);
75 return false;
76 }
77 ret = HksBuildParamSet(¶mSet);
78 if (ret != HKS_SUCCESS) {
79 LOGE("HksBuildParamSet failed ret %{public}d", ret);
80 HksFreeParamSet(¶mSet);
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(¶mSet);
92 return false;
93 }
94 HksFreeParamSet(¶mSet);
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(¶mSet);
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(¶mSet);
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(¶mSet);
167 return nullptr;
168 }
169 ctx.aad = HashAndClip("AAD SHA512 prefix", ctx.secDiscard, CRYPTO_AES_AAD_LEN);
170 if (ctx.aad.IsEmpty()) {
171 HksFreeParamSet(¶mSet);
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(¶mSet);
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(¶mSet);
231 return false;
232 }
233 // save the encrypted text real length
234 ctx.encrypted.size = hksEncrypted.size;
235 HksFreeParamSet(¶mSet);
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(¶mSet);
276 return false;
277 }
278 // restore the plaintext real length
279 key.key.size = hksRawKey.size;
280 HksFreeParamSet(¶mSet);
281 LOGD("success");
282 return true;
283 }
284 } // namespace StorageDaemon
285 } // namespace OHOS
286