1 /*
2 * Copyright (c) 2022-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
16 #include "base_key.h"
17
18 #include <fcntl.h>
19 #include <fstream>
20 #include <string>
21 #include <unistd.h>
22
23 #include "directory_ex.h"
24 #include "fbex.h"
25 #include "file_ex.h"
26 #include "huks_master.h"
27 #include "iam_client.h"
28 #include "key_backup.h"
29 #include "libfscrypt/key_control.h"
30 #include "openssl_crypto.h"
31 #include "storage_service_log.h"
32 #include "string_ex.h"
33 #include "utils/file_utils.h"
34 #include "utils/string_utils.h"
35
36 namespace {
37 const std::string PATH_LATEST_BACKUP = "/latest_bak";
38 const std::string PATH_KEY_VERSION = "/version_";
39 const std::string PATH_KEY_TEMP = "/temp";
40 const std::string PATH_NEED_RESTORE_SUFFIX = "/latest/need_restore";
41 const std::string PATH_USER_EL1_DIR = "/data/service/el1/public/storage_daemon/sd/el1/";
42
43 #ifndef F2FS_IOCTL_MAGIC
44 #define F2FS_IOCTL_MAGIC 0xf5
45 #endif
46
47 #ifndef F2FS_IOC_SEC_TRIM_FILE
48 struct F2fsSectrimRange {
49 uint64_t start;
50 uint64_t len;
51 uint64_t flags;
52 };
53 using F2fsSectrim = F2fsSectrimRange;
54 #define F2FS_IOC_SEC_TRIM_FILE _IOW(F2FS_IOCTL_MAGIC, 20, F2fsSectrim)
55 #define F2FS_TRIM_FILE_DISCARD 0x1
56 #define F2FS_TRIM_FILE_ZEROOUT 0x2
57 #endif
58 #ifndef F2FS_IOC_SET_PIN_FILE
59 #define F2FS_IOC_SET_PIN_FILE _IOW(F2FS_IOCTL_MAGIC, 13, set)
60 #define F2FS_IOC_GET_PIN_FILE _IOR(F2FS_IOCTL_MAGIC, 14, set)
61 #endif
62 }
63
64 namespace OHOS {
65 namespace StorageDaemon {
BaseKey(const std::string & dir,uint8_t keyLen)66 BaseKey::BaseKey(const std::string &dir, uint8_t keyLen) : dir_(dir), keyLen_(keyLen),
67 keyEncryptType_(KeyEncryptType::KEY_CRYPT_HUKS)
68 {
69 }
70
DoTempStore(const KeyContext & sourceCtx,KeyContext & targetCtx)71 static void DoTempStore(const KeyContext &sourceCtx, KeyContext &targetCtx)
72 {
73 LOGI("Store huks result temporary.");
74 KeyBlob tempAad(sourceCtx.aad);
75 KeyBlob tempNonce(sourceCtx.nonce);
76 KeyBlob tempRndEnc(sourceCtx.rndEnc);
77 KeyBlob tempShield(sourceCtx.shield);
78 targetCtx.aad = std::move(tempAad);
79 targetCtx.nonce = std::move(tempNonce);
80 targetCtx.rndEnc = std::move(tempRndEnc);
81 targetCtx.shield = std::move(tempShield);
82 }
83
InitKey(bool needGenerateKey)84 bool BaseKey::InitKey(bool needGenerateKey)
85 {
86 LOGI("enter");
87 if (keyInfo_.version == FSCRYPT_INVALID || keyInfo_.version > KeyCtrlGetFscryptVersion(MNT_DATA.c_str())) {
88 LOGE("invalid version %{public}u", keyInfo_.version);
89 return false;
90 }
91 if (!keyInfo_.key.IsEmpty()) {
92 LOGE("key is not empty");
93 return false;
94 }
95 if (needGenerateKey && !GenerateKeyBlob(keyInfo_.key, keyLen_)) {
96 LOGE("GenerateKeyBlob raw key failed");
97 return false;
98 }
99 return true;
100 }
101
GenerateKeyBlob(KeyBlob & blob,const uint32_t size)102 bool BaseKey::GenerateKeyBlob(KeyBlob &blob, const uint32_t size)
103 {
104 blob = HuksMaster::GenerateRandomKey(size);
105 return !blob.IsEmpty();
106 }
107
SaveKeyBlob(const KeyBlob & blob,const std::string & path)108 bool BaseKey::SaveKeyBlob(const KeyBlob &blob, const std::string &path)
109 {
110 if (blob.IsEmpty()) {
111 LOGE("blob is empty");
112 return false;
113 }
114 LOGI("enter %{public}s, size=%{public}d", path.c_str(), blob.size);
115 return WriteFileSync(path.c_str(), blob.data.get(), blob.size);
116 }
117
GenerateAndSaveKeyBlob(KeyBlob & blob,const std::string & path,const uint32_t size)118 bool BaseKey::GenerateAndSaveKeyBlob(KeyBlob &blob, const std::string &path, const uint32_t size)
119 {
120 if (!GenerateKeyBlob(blob, size)) {
121 return false;
122 }
123 return SaveKeyBlob(blob, path);
124 }
125
LoadKeyBlob(KeyBlob & blob,const std::string & path,const uint32_t size=0)126 bool BaseKey::LoadKeyBlob(KeyBlob &blob, const std::string &path, const uint32_t size = 0)
127 {
128 LOGW("enter %{public}s, size=%{public}d", path.c_str(), size);
129 std::ifstream file(path, std::ios::binary);
130 if (file.fail()) {
131 LOGE("open %{public}s failed, errno %{public}d", path.c_str(), errno);
132 return false;
133 }
134
135 file.seekg(0, std::ios::end);
136 uint32_t length = static_cast<uint32_t>(file.tellg());
137 // zero size means use the file length.
138 if ((size != 0) && (length != size)) {
139 LOGE("file:%{public}s size error, real len %{public}d not expected %{public}d", path.c_str(), length, size);
140 return false;
141 }
142 if (!blob.Alloc(length)) {
143 return false;
144 }
145
146 file.seekg(0, std::ios::beg);
147 if (file.read(reinterpret_cast<char *>(blob.data.get()), length).fail()) {
148 LOGE("read %{public}s failed, errno %{public}d", path.c_str(), errno);
149 return false;
150 }
151 return true;
152 }
153
GetCandidateVersion() const154 int BaseKey::GetCandidateVersion() const
155 {
156 auto prefix = PATH_KEY_VERSION.substr(1); // skip the first slash
157 std::vector<std::string> files;
158 GetSubDirs(dir_, files);
159 int candidate = -1;
160 for (const auto &it: files) {
161 if (it.rfind(prefix) == 0) {
162 std::string str = it.substr(prefix.length());
163 int ver;
164 if (IsNumericStr(str) && StrToInt(str, ver) && ver >= candidate) {
165 candidate = ver;
166 }
167 }
168 }
169 LOGW("candidate key version is %{public}d", candidate);
170 return candidate;
171 }
172
173 // Get last version_xx dir to load key files.
GetCandidateDir() const174 std::string BaseKey::GetCandidateDir() const
175 {
176 auto candidate = GetCandidateVersion();
177 // candidate is -1 means no version_xx dir.
178 if (candidate == -1) {
179 return "";
180 }
181
182 return dir_ + PATH_KEY_VERSION + std::to_string(candidate);
183 }
184
185 // Get next available version_xx dir to save key files.
GetNextCandidateDir() const186 std::string BaseKey::GetNextCandidateDir() const
187 {
188 auto candidate = GetCandidateVersion();
189 return dir_ + PATH_KEY_VERSION + std::to_string(candidate + 1);
190 }
191
192 #ifdef USER_CRYPTO_MIGRATE_KEY
StoreKey(const UserAuth & auth,bool needGenerateShield)193 bool BaseKey::StoreKey(const UserAuth &auth, bool needGenerateShield)
194 #else
195 bool BaseKey::StoreKey(const UserAuth &auth)
196 #endif
197 {
198 LOGI("enter");
199 auto pathTemp = dir_ + PATH_KEY_TEMP;
200 #ifdef USER_CRYPTO_MIGRATE_KEY
201 if (DoStoreKey(auth, needGenerateShield)) {
202 #else
203 if (DoStoreKey(auth)) {
204 #endif
205 // rename keypath/temp/ to keypath/version_xx/
206 auto candidate = GetNextCandidateDir();
207 LOGI("rename %{public}s to %{public}s", pathTemp.c_str(), candidate.c_str());
208 if (rename(pathTemp.c_str(), candidate.c_str()) == 0) {
209 LOGI("start sync");
210 SyncKeyDir();
211 LOGI("sync end");
212 return true;
213 }
214 LOGE("rename fail return %{public}d, cleanup the temp dir", errno);
215 } else {
216 LOGE("DoStoreKey fail, cleanup the temp dir");
217 }
218 OHOS::ForceRemoveDirectory(pathTemp);
219 LOGI("start sync");
220 SyncKeyDir();
221 LOGI("sync end");
222 return false;
223 }
224
225 // All key files are saved under keypath/temp/ in this function.
226 #ifdef USER_CRYPTO_MIGRATE_KEY
227 bool BaseKey::DoStoreKey(const UserAuth &auth, bool needGenerateShield)
228 #else
229 bool BaseKey::DoStoreKey(const UserAuth &auth)
230 #endif
231 {
232 LOGI("enter");
233 auto pathTemp = dir_ + PATH_KEY_TEMP;
234 if (!MkDirRecurse(pathTemp, S_IRWXU)) {
235 LOGE("MkDirRecurse failed!");
236 }
237 if (!CheckAndUpdateVersion()) {
238 return false;
239 }
240 uint32_t keyType = GetTypeFromDir();
241 if (keyType == TYPE_EL1 || keyType == TYPE_GLOBAL_EL1) {
242 return EncryptDe(auth, pathTemp);
243 }
244 if ((auth.token.IsEmpty() && auth.secret.IsEmpty()) || // Create user/Delete pincode(EL2-4)
245 !auth.token.IsEmpty()) { // add/change pin code (EL2-4)
246 LOGE("Encrypt huks openssl.");
247 KeyContext keyCtx = {};
248 if (!InitKeyContext(auth, pathTemp, keyCtx)) {
249 LOGE("init key context failed !");
250 return false;
251 }
252
253 if (!EncryptEceSece(auth, keyType, keyCtx)) {
254 LOGE("Encrypt key failed !");
255 ClearKeyContext(keyCtx);
256 return false;
257 }
258 // save key buff nonce+rndEnc+aad
259 if (!SaveAndCleanKeyBuff(pathTemp, keyCtx)) {
260 LOGE("save key buff failed !");
261 return false;
262 }
263 }
264 LOGI("finish");
265 return true;
266 }
267
268 bool BaseKey::CheckAndUpdateVersion()
269 {
270 auto pathVersion = dir_ + PATH_FSCRYPT_VER;
271 std::string version;
272 if (OHOS::LoadStringFromFile(pathVersion, version)) {
273 if (version != std::to_string(keyInfo_.version)) {
274 LOGE("version already exist %{public}s, not expected %{public}d", version.c_str(), keyInfo_.version);
275 return false;
276 }
277 } else if (SaveStringToFileSync(pathVersion, std::to_string(keyInfo_.version)) == false) {
278 LOGE("save version failed, errno:%{public}d", errno);
279 return false;
280 }
281 ChMod(pathVersion, S_IREAD | S_IWRITE);
282 return true;
283 }
284
285 bool BaseKey::InitKeyContext(const UserAuth &auth, const std::string &keyPath, KeyContext &keyCtx)
286 {
287 LOGI("enter");
288 if (!LoadAndSaveShield(auth, keyPath + PATH_SHIELD, true, keyCtx)) {
289 LOGE("Load or save shield failed !");
290 return false;
291 }
292
293 if (!GenerateAndSaveKeyBlob(keyCtx.secDiscard, keyPath + PATH_SECDISC, CRYPTO_KEY_SECDISC_SIZE)) {
294 LOGE("Generate sec_discard failed");
295 return false;
296 }
297
298 if (!GenerateKeyBlob(keyCtx.nonce, GCM_NONCE_BYTES) ||
299 !GenerateKeyBlob(keyCtx.aad, GCM_MAC_BYTES)) {
300 LOGE("Generate nonce and aad failed !");
301 return false;
302 }
303 return true;
304 }
305
306 bool BaseKey::SaveAndCleanKeyBuff(const std::string &keyPath, KeyContext &keyCtx)
307 {
308 KeyBlob storeKey(keyCtx.nonce.size + keyCtx.rndEnc.size + keyCtx.aad.size);
309 if (!CombKeyCtx(keyCtx.nonce, keyCtx.rndEnc, keyCtx.aad, storeKey)) {
310 LOGE("CombKeyCtx failed");
311 return false;
312 }
313
314 if (!SaveKeyBlob(storeKey, keyPath + PATH_ENCRYPTED)) {
315 return false;
316 }
317
318 const std::string NEED_UPDATE_PATH = keyPath + SUFFIX_NEED_UPDATE;
319 if (!SaveStringToFile(NEED_UPDATE_PATH, KeyEncryptTypeToString(keyEncryptType_))) {
320 LOGE("Save key type file failed");
321 return false;
322 }
323
324 storeKey.Clear();
325 ClearKeyContext(keyCtx);
326 return true;
327 }
328
329 bool BaseKey::LoadAndSaveShield(const UserAuth &auth, const std::string &pathShield,
330 bool needGenerateShield, KeyContext &keyCtx)
331 {
332 #ifdef USER_CRYPTO_MIGRATE_KEY
333 if (needGenerateShield) {
334 if (!HuksMaster::GetInstance().GenerateKey(auth, keyCtx.shield)) {
335 LOGE("GenerateKey of shield failed");
336 return false;
337 }
338 } else {
339 if (!LoadKeyBlob(keyCtx.shield, dir_ + PATH_LATEST + PATH_SHIELD)) { // needcheck is update
340 keyCtx.rndEnc.Clear();
341 return false;
342 }
343 }
344 #else
345 if (!HuksMaster::GetInstance().GenerateKey(auth, keyCtx.shield)) {
346 LOGE("GenerateKey of shield failed");
347 return false;
348 }
349 #endif
350 if (!SaveKeyBlob(keyCtx.shield, pathShield)) {
351 return false;
352 }
353 return true;
354 }
355
356 // update the latest and do cleanups.
357 bool BaseKey::UpdateKey(const std::string &keypath, bool needSyncCandidate)
358 {
359 LOGI("enter");
360 if (!needSyncCandidate) {
361 LOGE("Do not update candidate file !");
362 return true;
363 }
364 auto candidate = keypath.empty() ? GetCandidateDir() : keypath;
365 if (candidate.empty() && GetTypeFromDir() == TYPE_EL5) {
366 LOGI("no uece candidate dir, do not need updateKey.");
367 return true;
368 }
369 if (candidate.empty()) {
370 LOGE("no candidate dir");
371 return false;
372 }
373 DoLatestBackUp();
374 bool hasLatest = IsDir(dir_ + PATH_LATEST);
375 OHOS::ForceRemoveDirectory(dir_ + PATH_LATEST);
376 if (rename(candidate.c_str(), (dir_ + PATH_LATEST).c_str()) != 0) { // rename {candidate} to latest
377 LOGE("rename candidate to latest fail return %{public}d", errno);
378 if (hasLatest) { // revert from the backup
379 if (rename((dir_ + PATH_LATEST_BACKUP).c_str(), (dir_ + PATH_LATEST).c_str()) != 0) {
380 LOGE("restore the latest_backup fail errno:%{public}d", errno);
381 } else {
382 LOGI("restore the latest_backup success");
383 }
384 }
385 SyncKeyDir();
386 return false;
387 }
388 LOGI("rename candidate %{public}s to latest success", candidate.c_str());
389
390 std::vector<std::string> files;
391 GetSubDirs(dir_, files);
392 for (const auto &it: files) { // cleanup backup and other versions
393 if (it != PATH_LATEST.substr(1)) {
394 OHOS::ForceRemoveDirectory(dir_ + "/" + it);
395 }
396 }
397
398 std::string backupDir;
399 KeyBackup::GetInstance().GetBackupDir(dir_, backupDir);
400 KeyBackup::GetInstance().CreateBackup(dir_, backupDir, true);
401 SyncKeyDir();
402 return true;
403 }
404
405 void BaseKey::DoLatestBackUp() const
406 {
407 // backup the latest
408 std::string pathLatest = dir_ + PATH_LATEST;
409 std::string pathLatestBak = dir_ + PATH_LATEST_BACKUP;
410 bool hasLatest = IsDir(dir_ + PATH_LATEST);
411 if (hasLatest) {
412 OHOS::ForceRemoveDirectory(pathLatestBak);
413 if (rename(pathLatest.c_str(),
414 pathLatestBak.c_str()) != 0) {
415 LOGE("backup the latest fail errno:%{public}d", errno);
416 }
417 LOGI("backup the latest success");
418 }
419 }
420
421 bool BaseKey::EncryptDe(const UserAuth &auth, const std::string &path)
422 {
423 LOGI("enter");
424 KeyContext ctxDe;
425 if (!InitKeyContext(auth, path, ctxDe)) {
426 LOGE("init key context failed !");
427 return false;
428 }
429 keyEncryptType_ = KeyEncryptType::KEY_CRYPT_HUKS;
430 if (!HuksMaster::GetInstance().EncryptKey(ctxDe, auth, keyInfo_, true)) {
431 LOGE("Encrypt by hks failed.");
432 ClearKeyContext(ctxDe);
433 return false;
434 }
435 if (!SaveKeyBlob(ctxDe.rndEnc, path + PATH_ENCRYPTED)) {
436 LOGE("SaveKeyBlob rndEnc failed.");
437 ClearKeyContext(ctxDe);
438 return false;
439 }
440 const std::string NEED_UPDATE_PATH = path + SUFFIX_NEED_UPDATE;
441 if (!SaveStringToFile(NEED_UPDATE_PATH, KeyEncryptTypeToString(keyEncryptType_))) {
442 LOGE("Save key type file failed");
443 return false;
444 }
445 LOGI("finish");
446 return true;
447 }
448
449 bool BaseKey::EncryptEceSece(const UserAuth &auth, const uint32_t keyType, KeyContext &keyCtx)
450 {
451 LOGI("enter");
452 // rnd 64 -> rndEnc 80
453 if (!HuksMaster::GetInstance().EncryptKeyEx(auth, keyInfo_.key, keyCtx)) {
454 LOGE("Encrypt by hks failed.");
455 return false;
456 }
457 LOGE("Huks encrypt end.");
458
459 UserAuth mUserAuth = auth;
460 if (auth.secret.IsEmpty()) {
461 mUserAuth.secret = KeyBlob(NULL_SECRET);
462 }
463
464 if (keyType == TYPE_EL3 || keyType == TYPE_EL4) {
465 DoTempStore(keyCtx, keyContext_);
466 }
467
468 KeyBlob rndEnc(keyCtx.rndEnc);
469 LOGI("Encrypt by openssl start"); // rndEnc 80 -> rndEncEnc 108
470 if (!OpensslCrypto::AESEncrypt(mUserAuth.secret, rndEnc, keyCtx)) {
471 LOGE("Encrypt by openssl failed.");
472 return false;
473 }
474 LOGE("Encrypt by openssl end");
475 rndEnc.Clear();
476 keyEncryptType_ = KeyEncryptType::KEY_CRYPT_HUKS_OPENSSL;
477 LOGI("finish");
478 return true;
479 }
480
481 bool BaseKey::RestoreKey(const UserAuth &auth, bool needSyncCandidate)
482 {
483 LOGW("enter");
484 auto candidate = GetCandidateDir();
485 if (candidate.empty()) {
486 // no candidate dir, just restore from the latest
487 return KeyBackup::GetInstance().TryRestoreKey(shared_from_this(), auth) == 0;
488 }
489
490 if (DoRestoreKeyEx(auth, candidate)) {
491 // update the latest with the candidate
492 UpdateKey("", needSyncCandidate);
493 return true;
494 }
495
496 LOGE("DoRestoreKey with %{public}s failed", candidate.c_str());
497 // try to restore from other versions
498 std::vector<std::string> files;
499 GetSubDirs(dir_, files);
500 std::sort(files.begin(), files.end(), [&](const std::string &a, const std::string &b) {
501 if (a.length() != b.length() ||
502 a.length() < PATH_KEY_VERSION.length() ||
503 b.length() < PATH_KEY_VERSION.length()) {
504 return a.length() > b.length();
505 }
506 // make sure a.length() >= PATH_KEY_VERSION.length() && b.length() >= PATH_KEY_VERSION.length()
507 return std::stoi(a.substr(PATH_KEY_VERSION.size() - 1)) > std::stoi(b.substr(PATH_KEY_VERSION.size() - 1));
508 });
509 for (const auto &it: files) {
510 if (it != candidate) {
511 if (DoRestoreKeyEx(auth, dir_ + "/" + it)) {
512 UpdateKey(it, needSyncCandidate);
513 return true;
514 }
515 }
516 }
517 return false;
518 }
519
520 bool BaseKey::DoRestoreKeyEx(const UserAuth &auth, const std::string &keyPath)
521 {
522 LOGI("enter restore key ex");
523 if (!DoRestoreKey(auth, keyPath)) {
524 LOGE("First restore failed !");
525 return false;
526 }
527 if (keyEncryptType_ == KeyEncryptType::KEY_CRYPT_HUKS) {
528 LOGE("Key encrypted by huks, skip !");
529 return true;
530 }
531
532 KeyBlob tempEnc(keyContext_.rndEnc.size);
533 if (!LoadKeyBlob(tempEnc, keyPath + PATH_ENCRYPTED)) {
534 LOGE("key encrypted by huks, skip !");
535 return true;
536 }
537
538 uint32_t ivSum = 0;
539 for (size_t i = 0; i < GCM_NONCE_BYTES; ++i) {
540 ivSum += tempEnc.data[i];
541 }
542 if (ivSum != 0) {
543 LOGE("key already update, skip !");
544 tempEnc.Clear();
545 return true;
546 }
547 tempEnc.Clear();
548
549 if (!StoreKey(auth)) {
550 LOGE("Store key failed !");
551 return false;
552 }
553 if (!UpdateKey()) {
554 LOGE("Update key context failed !");
555 return false;
556 }
557 if (!DoRestoreKey(auth, keyPath)) {
558 LOGE("Second restore failed !");
559 return false;
560 }
561 return true;
562 }
563
564 bool BaseKey::DoRestoreKeyOld(const UserAuth &auth, const std::string &path)
565 {
566 LOGW("enter, path = %{public}s", path.c_str());
567 const std::string NEED_UPDATE_PATH = dir_ + PATH_LATEST + SUFFIX_NEED_UPDATE;
568 if (!auth.secret.IsEmpty() && FileExists(NEED_UPDATE_PATH)) {
569 keyEncryptType_ = KeyEncryptType::KEY_CRYPT_OPENSSL;
570 LOGI("set keyEncryptType_ as KEY_CRYPT_OPENSSL success");
571 } else {
572 keyEncryptType_ = KeyEncryptType::KEY_CRYPT_HUKS;
573 LOGI("set keyEncryptType_ as KEY_CRYPT_HUKS success");
574 }
575 auto ver = KeyCtrlLoadVersion(dir_.c_str());
576 if (ver == FSCRYPT_INVALID || ver != keyInfo_.version) {
577 LOGE("RestoreKey fail. bad version loaded %{public}u not expected %{public}u", ver, keyInfo_.version);
578 return false;
579 }
580 if (!LoadKeyBlob(keyContext_.rndEnc, path + PATH_ENCRYPTED)) {
581 return false;
582 }
583 if (keyEncryptType_ == KeyEncryptType::KEY_CRYPT_HUKS) {
584 if (!LoadKeyBlob(keyContext_.shield, path + PATH_SHIELD)) {
585 keyContext_.rndEnc.Clear();
586 return false;
587 }
588 }
589 if (!LoadKeyBlob(keyContext_.secDiscard, path + PATH_SECDISC, CRYPTO_KEY_SECDISC_SIZE)) {
590 keyContext_.rndEnc.Clear();
591 keyContext_.shield.Clear();
592 return false;
593 }
594 return Decrypt(auth);
595 }
596
597 bool BaseKey::DoRestoreKeyDe(const UserAuth &auth, const std::string &path)
598 {
599 LOGI("enter");
600 KeyContext ctxNone;
601 if (!LoadKeyBlob(ctxNone.rndEnc, path + PATH_ENCRYPTED)) {
602 LOGE("Load rndEnc failed !");
603 return false;
604 }
605
606 if (!LoadKeyBlob(ctxNone.secDiscard, path + PATH_SECDISC) ||
607 !LoadKeyBlob(ctxNone.shield, path + PATH_SHIELD)) {
608 ctxNone.rndEnc.Clear();
609 LOGE("Load shield failed !");
610 return false;
611 }
612
613 LOGW("Decrypt by hks start."); // keyCtx.rndEnc 80 -> 64
614 if (!HuksMaster::GetInstance().DecryptKey(ctxNone, auth, keyInfo_, true)) {
615 LOGE("Decrypt by hks failed.");
616 ClearKeyContext(ctxNone);
617 return false;
618 }
619 ClearKeyContext(ctxNone);
620 LOGI("finish");
621 return true;
622 }
623
624 bool BaseKey::DoRestoreKeyCeEceSece(const UserAuth &auth, const std::string &path, const uint32_t keyType)
625 {
626 LOGI("enter");
627 if ((auth.secret.IsEmpty() && auth.token.IsEmpty()) ||
628 (!auth.secret.IsEmpty() && !auth.token.IsEmpty())) {
629 KeyContext ctxNone;
630 if (!LoadKeyBlob(ctxNone.rndEnc, path + PATH_ENCRYPTED)) {
631 LOGE("Load rndEnc failed !");
632 return false;
633 }
634
635 ctxNone.aad.Alloc(GCM_MAC_BYTES);
636 ctxNone.nonce.Alloc(GCM_NONCE_BYTES);
637 if (!SplitKeyCtx(ctxNone.rndEnc, ctxNone.nonce, ctxNone.rndEnc, ctxNone.aad)) {
638 ctxNone.rndEnc.Clear();
639 LOGE("Split key context failed !");
640 return false;
641 }
642 if (!LoadKeyBlob(ctxNone.secDiscard, path + PATH_SECDISC) ||
643 !LoadKeyBlob(ctxNone.shield, path + PATH_SHIELD)) {
644 ctxNone.rndEnc.Clear();
645 LOGE("Load shield failed !");
646 return false;
647 }
648 return DecryptReal(auth, keyType, ctxNone);
649 }
650
651 // face/finger (EL3 EL4)
652 if (auth.secret.IsEmpty() && !auth.token.IsEmpty()) {
653 if (!keyContext_.shield.IsEmpty() || !keyContext_.rndEnc.IsEmpty()) {
654 LOGI("Restore key by face/finger");
655 UserAuth mUserAuth = auth;
656 mUserAuth.secret = KeyBlob(NULL_SECRET);
657 KeyContext tempCtx = {};
658 DoTempStore(keyContext_, tempCtx);
659 if (!HuksMaster::GetInstance().DecryptKeyEx(tempCtx, mUserAuth, keyInfo_.key)) {
660 LOGE("Decrypt by hks failed.");
661 ClearKeyContext(tempCtx);
662 return false;
663 }
664 ClearKeyContext(tempCtx);
665 }
666 return true;
667 }
668 LOGE("Decrypt failed, invalid param !");
669 return false;
670 }
671
672 bool BaseKey::DoRestoreKey(const UserAuth &auth, const std::string &path)
673 {
674 auto ver = KeyCtrlLoadVersion(dir_.c_str());
675 if (ver == FSCRYPT_INVALID || ver != keyInfo_.version) {
676 LOGE("RestoreKey fail. bad version loaded %{public}u not expected %{public}u", ver, keyInfo_.version);
677 return false;
678 }
679
680 std::string encryptType;
681 LoadStringFromFile(path + SUFFIX_NEED_UPDATE, encryptType);
682 LOGI("encrypt type : %{public}s, keyInfo empty: %{public}u", encryptType.c_str(), keyInfo_.key.IsEmpty());
683
684 uint32_t keyType = GetTypeFromDir();
685 if (keyType == TYPE_EL1 || keyType == TYPE_GLOBAL_EL1) {
686 LOGI("Restore device key.");
687 return DoRestoreKeyDe(auth, path);
688 }
689 int ret;
690 if (encryptType == KeyEncryptTypeToString(KeyEncryptType::KEY_CRYPT_HUKS_OPENSSL)) {
691 LOGI("Restore ce ece sece key.");
692 ret = DoRestoreKeyCeEceSece(auth, path, keyType);
693 } else {
694 ret = DoUpdateRestore(auth, path);
695 }
696 LOGI("end ret %{public}u", ret);
697 return ret != 0;
698 }
699
700 bool BaseKey::DoUpdateRestore(const UserAuth &auth, const std::string &keyPath)
701 {
702 LOGI("enter");
703 if (!DoRestoreKeyOld(auth, keyPath)) {
704 LOGE("Restore old failed !");
705 return false;
706 }
707 std::error_code errCode;
708 if (std::filesystem::exists(dir_ + PATH_NEED_RESTORE_SUFFIX, errCode) && !auth.token.IsEmpty()) {
709 LOGE("Double 2 single, skip huks -> huks-openssl !");
710 return true;
711 }
712 uint64_t secureUid = { 0 };
713 if (!IamClient::GetInstance().GetSecureUid(GetIdFromDir(), secureUid)) {
714 LOGE("Get secure uid form iam failed, use default value.");
715 }
716
717 if (!StoreKey({ auth.token, auth.secret, secureUid })) {
718 LOGE("Store old failed !");
719 return false;
720 }
721 if (!UpdateKey()) {
722 LOGE("Update old failed !");
723 return false;
724 }
725 LOGI("finish");
726 return true;
727 }
728
729 bool BaseKey::DecryptReal(const UserAuth &auth, const uint32_t keyType, KeyContext &keyCtx)
730 {
731 LOGI("enter");
732 UserAuth mUserAuth = auth;
733 if (auth.secret.IsEmpty()) {
734 mUserAuth.secret = KeyBlob(NULL_SECRET);
735 }
736 KeyBlob rndEnc(keyCtx.rndEnc);
737 if (!OpensslCrypto::AESDecrypt(mUserAuth.secret, keyCtx, rndEnc)) { // rndEncEnc -> rndEnc
738 LOGE("Decrypt by openssl failed.");
739 return false;
740 }
741
742 keyCtx.rndEnc = std::move(rndEnc);
743 if (keyType == TYPE_EL3 || keyType == TYPE_EL4) {
744 DoTempStore(keyCtx, keyContext_);
745 }
746
747 if (!HuksMaster::GetInstance().DecryptKeyEx(keyCtx, auth, keyInfo_.key)) { // rndEnc -> rnd
748 LOGE("Decrypt by hks failed.");
749 return false;
750 }
751
752 rndEnc.Clear();
753 LOGI("finish");
754 return true;
755 }
756
757 bool BaseKey::Decrypt(const UserAuth &auth)
758 {
759 bool ret = false;
760 switch (keyEncryptType_) {
761 case KeyEncryptType::KEY_CRYPT_OPENSSL:
762 LOGI("Enhanced decrypt key start");
763 ret = OpensslCrypto::AESDecrypt(auth.secret, keyContext_, keyInfo_.key);
764 break;
765 case KeyEncryptType::KEY_CRYPT_HUKS:
766 LOGI("Huks decrypt key start");
767 ret = HuksMaster::GetInstance().DecryptKey(keyContext_, auth, keyInfo_, true);
768 break;
769 case KeyEncryptType::KEY_CRYPT_HUKS_OPENSSL:
770 LOGI("Huks openssl decrypt key, skip");
771 break;
772 }
773 ClearKeyContext(keyContext_);
774 return ret;
775 }
776
777 bool BaseKey::ClearKey(const std::string &mnt)
778 {
779 LOGI("enter, dir_ = %{public}s", dir_.c_str());
780 bool ret = InactiveKey(USER_DESTROY, mnt);
781 if (!ret) {
782 LOGE("InactiveKey failed.");
783 }
784 keyInfo_.key.Clear();
785 bool needClearFlag = true;
786 #ifdef USER_CRYPTO_MIGRATE_KEY
787 std::error_code errCode;
788 std::string elNeedRestorePath = PATH_USER_EL1_DIR + std::to_string(GetIdFromDir()) + PATH_NEED_RESTORE_SUFFIX;
789 if (std::filesystem::exists(elNeedRestorePath, errCode)) {
790 needClearFlag = false;
791 LOGI("needRestore flag exist, do not remove secret.");
792 }
793 #endif
794 if (needClearFlag) {
795 LOGI("do clear key.");
796 if (!IsDir(dir_)) {
797 LOGE("dir not exist, do not need to remove dir");
798 return ret;
799 }
800 WipingActionDir(dir_);
801 std::string backupDir;
802 KeyBackup::GetInstance().GetBackupDir(dir_, backupDir);
803 WipingActionDir(backupDir);
804 KeyBackup::GetInstance().RemoveNode(backupDir);
805 LOGI("force remove backupDir, %{public}s.", backupDir.c_str());
806 OHOS::ForceRemoveDirectory(backupDir);
807 LOGI("force remove dir_, %{public}s.", dir_.c_str());
808 bool removeRet = OHOS::ForceRemoveDirectory(dir_);
809 if (!removeRet) {
810 LOGI("ForceRemoveDirectory failed.");
811 return removeRet;
812 }
813 // use F2FS_IOC_SEC_TRIM_FILE
814 }
815 return ret;
816 }
817
818 void BaseKey::WipingActionDir(std::string &path)
819 {
820 std::vector<std::string> fileList;
821 LOGI("WipingActionDir path.c_str() is %{public}s", path.c_str());
822 OpenSubFile(path.c_str(), fileList);
823 for (const auto &it: fileList) {
824 int fd = open(it.c_str(), O_WRONLY | O_CLOEXEC);
825 if (fd < 0) {
826 LOGE("open %{public}s failed, errno %{public}u", it.c_str(), errno);
827 return;
828 }
829 uint32_t set = 1;
830 int ret = ioctl(fd, F2FS_IOC_SET_PIN_FILE, &set);
831 if (ret != 0) {
832 LOGE("F2FS_IOC_SET_PIN_FILE ioctl is %{public}u, errno = %{public}u", ret, errno);
833 }
834 struct F2fsSectrimRange trimRange;
835 trimRange.start = 0;
836 trimRange.len = -1;
837 trimRange.flags = F2FS_TRIM_FILE_DISCARD | F2FS_TRIM_FILE_ZEROOUT;
838 ret = ioctl(fd, F2FS_IOC_SEC_TRIM_FILE, &trimRange);
839 if (ret != 0 && errno == EOPNOTSUPP) {
840 trimRange.flags = F2FS_TRIM_FILE_ZEROOUT;
841 ret = ioctl(fd, F2FS_IOC_SEC_TRIM_FILE, &trimRange);
842 if (ret != 0) {
843 LOGE("F2FS_IOC_SEC_TRIM_FILE ioctl is %{public}u, errno = %{public}u", ret, errno);
844 }
845 }
846 set = 0;
847 ret = ioctl(fd, F2FS_IOC_SET_PIN_FILE, &set);
848 if (ret != 0) {
849 LOGE("F2FS_IOC_SET_PIN_FILE ioctl is %{public}u", ret);
850 }
851 LOGI("WipingActionDir success");
852 close(fd);
853 }
854 }
855
856 void BaseKey::SyncKeyDir() const
857 {
858 int fd = open(dir_.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC);
859 if (fd < 0) {
860 LOGE("open %{public}s failed, errno %{public}d", dir_.c_str(), errno);
861 sync();
862 return;
863 }
864 LOGW("start fsync, dir_ is %{public}s", dir_.c_str());
865 if (fsync(fd) != 0) {
866 LOGE("fsync %{public}s failed, errno %{public}d", dir_.c_str(), errno);
867 syncfs(fd);
868 }
869 LOGW("fsync end");
870 (void)close(fd);
871 }
872
873 bool BaseKey::UpgradeKeys()
874 {
875 std::vector<std::string> versions;
876 GetSubDirs(dir_, versions);
877
878 for (const auto &it : versions) {
879 std::string shieldPath = dir_ + "/" + it + PATH_SHIELD;
880 LOGI("Upgrade of %{public}s", shieldPath.c_str());
881 LoadKeyBlob(keyContext_.shield, shieldPath);
882 if (HuksMaster::GetInstance().UpgradeKey(keyContext_)) {
883 LOGI("success upgrade of %{public}s", shieldPath.c_str());
884 SaveKeyBlob(keyContext_.shield, shieldPath);
885 SyncKeyDir();
886 }
887 }
888 return true;
889 }
890
891 bool BaseKey::EncryptKeyBlob(const UserAuth &auth, const std::string &keyPath, KeyBlob &planKey,
892 KeyBlob &encryptedKey)
893 {
894 LOGI("enter");
895 KeyContext keyCtx;
896 if (!MkDirRecurse(keyPath, S_IRWXU)) {
897 LOGE("MkDirRecurse failed!");
898 }
899
900 LOGW("key path is exist : %{public}d", FileExists(keyPath));
901 if (!HuksMaster::GetInstance().GenerateKey(auth, keyCtx.shield) ||
902 !SaveKeyBlob(keyCtx.shield, keyPath + PATH_SHIELD)) {
903 LOGE("GenerateKey and save shield failed!");
904 return false;
905 }
906 if (!GenerateAndSaveKeyBlob(keyCtx.secDiscard, keyPath + PATH_SECDISC, CRYPTO_KEY_SECDISC_SIZE)) {
907 keyCtx.shield.Clear();
908 LOGE("GenerateAndSaveKeyBlob sec_discard failed!");
909 return false;
910 }
911 if (!HuksMaster::GetInstance().EncryptKey(keyCtx, auth, {.key = planKey}, false)) {
912 keyCtx.shield.Clear();
913 keyCtx.secDiscard.Clear();
914 LOGE("HUKS encrypt key failed!");
915 return false;
916 }
917 CombKeyBlob(keyCtx.rndEnc, keyCtx.nonce, encryptedKey);
918
919 ClearKeyContext(keyCtx);
920 LOGI("finish");
921 return true;
922 }
923
924 bool BaseKey::DecryptKeyBlob(const UserAuth &auth, const std::string &keyPath, KeyBlob &planKey,
925 KeyBlob &decryptedKey)
926 {
927 LOGI("enter");
928 KeyContext keyCtx;
929 auto candidate = GetCandidateDir();
930 std::string path = candidate.empty() ? keyPath : candidate;
931 if (!LoadKeyBlob(keyCtx.shield, path + PATH_SHIELD)) {
932 LOGE("Load KeyBlob shield failed!");
933 return false;
934 }
935 if (!LoadKeyBlob(keyCtx.secDiscard, path + PATH_SECDISC, CRYPTO_KEY_SECDISC_SIZE)) {
936 LOGE("Load KeyBlob secDiscard failed!");
937 keyCtx.shield.Clear();
938 return false;
939 }
940
941 KeyInfo planKeyInfo = {.key = planKey};
942 SplitKeyBlob(planKey, keyCtx.rndEnc, keyCtx.nonce, AES_256_HASH_RANDOM_SIZE + GCM_MAC_BYTES);
943 LOGE("decrypted size : %{public}d, nonce size : %{public}d", keyCtx.rndEnc.size, keyCtx.nonce.size);
944
945 if (!HuksMaster::GetInstance().DecryptKey(keyCtx, auth, planKeyInfo, false)) {
946 keyCtx.shield.Clear();
947 keyCtx.rndEnc.Clear();
948 LOGE("HUKS decrypt key failed!");
949 return false;
950 }
951
952 decryptedKey = std::move(planKeyInfo.key);
953 planKeyInfo.key.Clear();
954 ClearKeyContext(keyCtx);
955 LOGI("finish");
956 return true;
957 }
958
959 bool BaseKey::RenameKeyPath(const std::string &keyPath)
960 {
961 // rename keypath/temp/ to keypath/version_xx/
962 auto candidate = GetNextCandidateDir();
963 LOGI("rename %{public}s to %{public}s", keyPath.c_str(), candidate.c_str());
964 if (rename(keyPath.c_str(), candidate.c_str()) != 0) {
965 LOGE("rename %{public}s to %{public}s failed!", keyPath.c_str(), candidate.c_str());
966 return false;
967 }
968 SyncKeyDir();
969 return true;
970 }
971
972 void BaseKey::CombKeyBlob(const KeyBlob &encAad, const KeyBlob &end, KeyBlob &keyOut)
973 {
974 std::vector<uint8_t> startVct(encAad.data.get(), encAad.data.get() + encAad.size);
975 std::vector<uint8_t> endVct(end.data.get(), end.data.get() + end.size);
976 startVct.insert(startVct.end(), endVct.begin(), endVct.end());
977 std::copy(startVct.begin(), startVct.end(), keyOut.data.get());
978 startVct.clear();
979 endVct.clear();
980 }
981
982 void BaseKey::SplitKeyBlob(const KeyBlob &keyIn, KeyBlob &encAad, KeyBlob &nonce, uint32_t start)
983 {
984 std::vector<uint8_t> inVct(keyIn.data.get(), keyIn.data.get() + keyIn.size);
985 encAad.Alloc(start);
986 nonce.Alloc(keyIn.size - start);
987 std::copy(inVct.begin(), inVct.begin() + start, encAad.data.get());
988 std::copy(inVct.begin() + start, inVct.end(), nonce.data.get());
989 inVct.clear();
990 }
991
992 void BaseKey::ClearKeyContext(KeyContext &keyCtx)
993 {
994 LOGI("enter clear");
995 keyCtx.aad.Clear();
996 keyCtx.nonce.Clear();
997 keyCtx.shield.Clear();
998 keyCtx.rndEnc.Clear();
999 keyCtx.secDiscard.Clear();
1000 }
1001
1002 std::string BaseKey::KeyEncryptTypeToString(KeyEncryptType keyEncryptType_) const
1003 {
1004 switch (keyEncryptType_) {
1005 case KeyEncryptType::KEY_CRYPT_OPENSSL:
1006 return "KEY_CRYPT_OPENSSL";
1007 case KeyEncryptType::KEY_CRYPT_HUKS:
1008 return "KEY_CRYPT_HUKS";
1009 case KeyEncryptType::KEY_CRYPT_HUKS_OPENSSL:
1010 return "KEY_CRYPT_HUKS_OPENSSL";
1011 }
1012 }
1013
1014 bool BaseKey::CombKeyCtx(const KeyBlob &nonce, const KeyBlob &rndEnc, const KeyBlob &aad, KeyBlob &keyOut)
1015 {
1016 LOGI("enter");
1017 if (nonce.IsEmpty() || aad.IsEmpty() || rndEnc.IsEmpty()) {
1018 LOGE("Invalid param, can not combine !");
1019 return false;
1020 }
1021 LOGE("rndEncEnc: %{public}u", rndEnc.size);
1022 std::vector<uint8_t> nonceVct(nonce.data.get(), nonce.data.get() + nonce.size);
1023 std::vector<uint8_t> rndVct(rndEnc.data.get(), rndEnc.data.get() + rndEnc.size);
1024 std::vector<uint8_t> aadVct(aad.data.get(), aad.data.get() + aad.size);
1025
1026 nonceVct.insert(nonceVct.end(), rndVct.begin(), rndVct.end());
1027 nonceVct.insert(nonceVct.end(), aadVct.begin(), aadVct.end());
1028 std::copy(nonceVct.begin(), nonceVct.end(), keyOut.data.get());
1029 nonceVct.clear();
1030 rndVct.clear();
1031 aadVct.clear();
1032 return true;
1033 }
1034
1035 bool BaseKey::SplitKeyCtx(const KeyBlob &keyIn, KeyBlob &nonce, KeyBlob &rndEnc, KeyBlob &aad)
1036 {
1037 LOGI("enter");
1038 if (keyIn.size < (nonce.size + aad.size)) {
1039 LOGE("Invalid keyIn size is too small");
1040 return false;
1041 }
1042 std::vector<uint8_t> keyInVct(keyIn.data.get(), keyIn.data.get() + keyIn.size);
1043 rndEnc.Alloc(keyIn.size - nonce.size - aad.size);
1044
1045 std::copy(keyInVct.begin(), keyInVct.begin() + nonce.size, nonce.data.get());
1046 std::copy(keyInVct.begin() + nonce.size, keyInVct.begin() + nonce.size + rndEnc.size, rndEnc.data.get());
1047 std::copy(keyInVct.begin() + nonce.size + rndEnc.size, keyInVct.end(), aad.data.get());
1048 LOGI("rndEncEnc: %{public}u", rndEnc.size);
1049 keyInVct.clear();
1050 return true;
1051 }
1052
1053 uint32_t BaseKey::GetTypeFromDir()
1054 {
1055 static const std::vector<std::pair<std::string, uint32_t>> typeStrs = {
1056 {"el1", TYPE_EL1},
1057 {"el2", TYPE_EL2},
1058 {"el3", TYPE_EL3},
1059 {"el4", TYPE_EL4},
1060 {"el5", TYPE_EL5},
1061 };
1062 uint32_t type = TYPE_GLOBAL_EL1; // default to global el1
1063
1064 // fscrypt key dir is like `/data/foo/bar/el1/100`
1065 auto slashIndex = dir_.rfind('/');
1066 if (slashIndex == std::string::npos) {
1067 LOGE("bad dir %{public}s", dir_.c_str());
1068 return type;
1069 }
1070
1071 if (slashIndex == 0) {
1072 LOGE("bad dir %{public}s", dir_.c_str());
1073 return type;
1074 }
1075
1076 slashIndex = dir_.rfind('/', slashIndex - 1);
1077 if (slashIndex == std::string::npos) {
1078 LOGE("bad dir %{public}s", dir_.c_str());
1079 return type;
1080 }
1081
1082 std::string el = dir_.substr(slashIndex + 1); // el string is like `el1/100`
1083 for (const auto &it : typeStrs) {
1084 if (el.find(it.first) != std::string::npos) {
1085 type = it.second;
1086 break;
1087 }
1088 }
1089 LOGI("el string is %{public}s, parse type %{public}d", el.c_str(), type);
1090 return type;
1091 }
1092
1093 uint32_t BaseKey::GetIdFromDir()
1094 {
1095 int userId = USERID_GLOBAL_EL1; // default to global el1
1096
1097 // fscrypt key dir is like `/data/foo/bar/el1/100`
1098 auto slashIndex = dir_.rfind('/');
1099 if (slashIndex != std::string::npos) {
1100 std::string last = dir_.substr(slashIndex + 1);
1101 (void)OHOS::StrToInt(last, userId);
1102 }
1103
1104 LOGI("dir_: %{public}s, get userId is %{public}d", dir_.c_str(), userId);
1105 return static_cast<uint32_t>(userId);
1106 }
1107
1108 bool BaseKey::KeyDescIsEmpty()
1109 {
1110 return keyInfo_.keyDesc.IsEmpty();
1111 }
1112 } // namespace StorageDaemon
1113 } // namespace OHOS
1114