1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "VolumeEncryption.h"
18 
19 #include <string>
20 
21 #include <android-base/logging.h>
22 #include <android-base/properties.h>
23 
24 #include "KeyBuffer.h"
25 #include "KeyUtil.h"
26 #include "MetadataCrypt.h"
27 #include "cryptfs.h"
28 
29 namespace android {
30 namespace vold {
31 
32 enum class VolumeMethod { kFailed, kCrypt, kDefaultKey };
33 
lookup_volume_method()34 static VolumeMethod lookup_volume_method() {
35     constexpr uint64_t pre_gki_level = 29;
36     auto first_api_level =
37             android::base::GetUintProperty<uint64_t>("ro.product.first_api_level", 0);
38     auto method = android::base::GetProperty("ro.crypto.volume.metadata.method", "default");
39     if (method == "default") {
40         return first_api_level > pre_gki_level ? VolumeMethod::kDefaultKey : VolumeMethod::kCrypt;
41     } else if (method == "dm-default-key") {
42         return VolumeMethod::kDefaultKey;
43     } else if (method == "dm-crypt") {
44         if (first_api_level > pre_gki_level) {
45             LOG(ERROR) << "volume encryption method dm-crypt cannot be used, "
46                           "ro.product.first_api_level = "
47                        << first_api_level;
48             return VolumeMethod::kFailed;
49         }
50         return VolumeMethod::kCrypt;
51     } else {
52         LOG(ERROR) << "Unknown volume encryption method: " << method;
53         return VolumeMethod::kFailed;
54     }
55 }
56 
volume_method()57 static VolumeMethod volume_method() {
58     static VolumeMethod method = lookup_volume_method();
59     return method;
60 }
61 
generate_volume_key(android::vold::KeyBuffer * key)62 bool generate_volume_key(android::vold::KeyBuffer* key) {
63     KeyGeneration gen;
64     switch (volume_method()) {
65         case VolumeMethod::kFailed:
66             LOG(ERROR) << "Volume encryption setup failed";
67             return false;
68         case VolumeMethod::kCrypt:
69             gen = cryptfs_get_keygen();
70             break;
71         case VolumeMethod::kDefaultKey:
72             if (!defaultkey_volume_keygen(&gen)) return false;
73             break;
74     }
75     if (!generateStorageKey(gen, key)) return false;
76     return true;
77 }
78 
setup_ext_volume(const std::string & label,const std::string & blk_device,const android::vold::KeyBuffer & key,std::string * out_crypto_blkdev)79 bool setup_ext_volume(const std::string& label, const std::string& blk_device,
80                       const android::vold::KeyBuffer& key, std::string* out_crypto_blkdev) {
81     switch (volume_method()) {
82         case VolumeMethod::kFailed:
83             LOG(ERROR) << "Volume encryption setup failed";
84             return false;
85         case VolumeMethod::kCrypt:
86             return cryptfs_setup_ext_volume(label.c_str(), blk_device.c_str(), key,
87                                             out_crypto_blkdev) == 0;
88         case VolumeMethod::kDefaultKey:
89             return defaultkey_setup_ext_volume(label, blk_device, key, out_crypto_blkdev);
90     }
91 }
92 
93 }  // namespace vold
94 }  // namespace android
95