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