• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 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 //
18 // This file contains the implementation of the dm-crypt volume metadata
19 // encryption method, which is deprecated.  Devices that launched with Android
20 // 11 or higher use a different method instead.  For details, see
21 // https://source.android.com/security/encryption/metadata#configuration-on-adoptable-storage
22 //
23 
24 #define LOG_TAG "Cryptfs"
25 
26 #include "cryptfs.h"
27 
28 #include "CryptoType.h"
29 #include "Utils.h"
30 
31 #include <android-base/parseint.h>
32 #include <android-base/properties.h>
33 #include <cutils/properties.h>
34 #include <libdm/dm.h>
35 #include <log/log.h>
36 
37 #include <chrono>
38 
39 using android::base::ParseUint;
40 using android::vold::CryptoType;
41 using android::vold::KeyBuffer;
42 using android::vold::KeyGeneration;
43 using namespace android::dm;
44 using namespace android::vold;
45 using namespace std::chrono_literals;
46 
47 #define MAX_KEY_LEN 48
48 
49 #define TABLE_LOAD_RETRIES 10
50 
51 constexpr CryptoType aes_128_cbc = CryptoType()
52                                            .set_config_name("AES-128-CBC")
53                                            .set_kernel_name("aes-cbc-essiv:sha256")
54                                            .set_keysize(16);
55 
56 constexpr CryptoType supported_crypto_types[] = {aes_128_cbc, android::vold::adiantum};
57 
58 static_assert(validateSupportedCryptoTypes(MAX_KEY_LEN, supported_crypto_types,
59                                            array_length(supported_crypto_types)),
60               "We have a CryptoType with keysize > MAX_KEY_LEN or which was "
61               "incompletely constructed.");
62 
get_crypto_type()63 static const CryptoType& get_crypto_type() {
64     // We only want to parse this read-only property once.  But we need to wait
65     // until the system is initialized before we can read it.  So we use a static
66     // scoped within this function to get it only once.
67     static CryptoType crypto_type =
68             lookup_crypto_algorithm(supported_crypto_types, array_length(supported_crypto_types),
69                                     aes_128_cbc, "ro.crypto.fde_algorithm");
70     return crypto_type;
71 }
72 
cryptfs_get_keygen()73 const KeyGeneration cryptfs_get_keygen() {
74     return KeyGeneration{get_crypto_type().get_keysize(), true, false};
75 }
76 
77 /* Convert a binary key of specified length into an ascii hex string equivalent,
78  * without the leading 0x and with null termination
79  */
convert_key_to_hex_ascii(const KeyBuffer & key,char * key_ascii)80 static void convert_key_to_hex_ascii(const KeyBuffer& key, char* key_ascii) {
81     unsigned int i, a;
82     unsigned char nibble;
83 
84     for (i = 0, a = 0; i < key.size(); i++, a += 2) {
85         /* For each byte, write out two ascii hex digits */
86         nibble = (key[i] >> 4) & 0xf;
87         key_ascii[a] = nibble + (nibble > 9 ? 0x37 : 0x30);
88 
89         nibble = key[i] & 0xf;
90         key_ascii[a + 1] = nibble + (nibble > 9 ? 0x37 : 0x30);
91     }
92 
93     /* Add the null termination */
94     key_ascii[a] = '\0';
95 }
96 
97 /*
98  * If the ro.crypto.fde_sector_size system property is set, append the
99  * parameters to make dm-crypt use the specified crypto sector size and round
100  * the crypto device size down to a crypto sector boundary.
101  */
add_sector_size_param(DmTargetCrypt * target,uint64_t * nr_sec)102 static int add_sector_size_param(DmTargetCrypt* target, uint64_t* nr_sec) {
103     constexpr char DM_CRYPT_SECTOR_SIZE[] = "ro.crypto.fde_sector_size";
104     char value[PROPERTY_VALUE_MAX];
105 
106     if (property_get(DM_CRYPT_SECTOR_SIZE, value, "") > 0) {
107         unsigned int sector_size;
108 
109         if (!ParseUint(value, &sector_size) || sector_size < 512 || sector_size > 4096 ||
110             (sector_size & (sector_size - 1)) != 0) {
111             SLOGE("Invalid value for %s: %s.  Must be >= 512, <= 4096, and a power of 2\n",
112                   DM_CRYPT_SECTOR_SIZE, value);
113             return -1;
114         }
115 
116         target->SetSectorSize(sector_size);
117 
118         // With this option, IVs will match the sector numbering, instead
119         // of being hard-coded to being based on 512-byte sectors.
120         target->SetIvLargeSectors();
121 
122         // Round the crypto device size down to a crypto sector boundary.
123         *nr_sec &= ~((sector_size / 512) - 1);
124     }
125     return 0;
126 }
127 
128 /*
129  * Called by vold when it's asked to mount an encrypted external
130  * storage volume. The incoming partition has no crypto header/footer,
131  * as any metadata is been stored in a separate, small partition.  We
132  * assume it must be using our same crypt type and keysize.
133  */
cryptfs_setup_ext_volume(const char * label,const char * real_blkdev,const KeyBuffer & key,std::string * out_crypto_blkdev)134 int cryptfs_setup_ext_volume(const char* label, const char* real_blkdev, const KeyBuffer& key,
135                              std::string* out_crypto_blkdev) {
136     auto crypto_type = get_crypto_type();
137     if (key.size() != crypto_type.get_keysize()) {
138         SLOGE("Raw keysize %zu does not match crypt keysize %zu", key.size(),
139               crypto_type.get_keysize());
140         return -1;
141     }
142     uint64_t nr_sec = 0;
143     if (android::vold::GetBlockDev512Sectors(real_blkdev, &nr_sec) != android::OK) {
144         SLOGE("Failed to get size of %s: %s", real_blkdev, strerror(errno));
145         return -1;
146     }
147 
148     auto& dm = DeviceMapper::Instance();
149 
150     // We need two ASCII characters to represent each byte, and need space for
151     // the '\0' terminator.
152     char key_ascii[MAX_KEY_LEN * 2 + 1];
153     convert_key_to_hex_ascii(key, key_ascii);
154 
155     auto target = std::make_unique<DmTargetCrypt>(0, nr_sec, crypto_type.get_kernel_name(),
156                                                   key_ascii, 0, real_blkdev, 0);
157     target->AllowDiscards();
158 
159     if (fscrypt_is_native() &&
160         android::base::GetBoolProperty("ro.crypto.allow_encrypt_override", false)) {
161         target->AllowEncryptOverride();
162     }
163     if (add_sector_size_param(target.get(), &nr_sec)) {
164         SLOGE("Error processing dm-crypt sector size param\n");
165         return -1;
166     }
167 
168     DmTable table;
169     table.AddTarget(std::move(target));
170 
171     int load_count = 1;
172     while (load_count < TABLE_LOAD_RETRIES) {
173         if (dm.CreateDevice(label, table)) {
174             break;
175         }
176         load_count++;
177     }
178 
179     if (load_count >= TABLE_LOAD_RETRIES) {
180         SLOGE("Cannot load dm-crypt mapping table.\n");
181         return -1;
182     }
183     if (load_count > 1) {
184         SLOGI("Took %d tries to load dmcrypt table.\n", load_count);
185     }
186 
187     if (!dm.GetDmDevicePathByName(label, out_crypto_blkdev)) {
188         SLOGE("Cannot determine dm-crypt path for %s.\n", label);
189         return -1;
190     }
191 
192     /* Ensure the dm device has been created before returning. */
193     if (android::vold::WaitForFile(out_crypto_blkdev->c_str(), 1s) < 0) {
194         // WaitForFile generates a suitable log message
195         return -1;
196     }
197     return 0;
198 }
199