blob: df163b450bb011dbc83369212a9d86406257072e [file] [log] [blame]
Paul Lawrence707fd6c2015-04-28 22:14:15 +00001#include "Ext4Crypt.h"
2
Paul Lawrence5e7f0042015-04-10 07:48:51 -07003#include <iomanip>
Paul Lawrence707fd6c2015-04-28 22:14:15 +00004#include <map>
Paul Lawrence5e7f0042015-04-10 07:48:51 -07005#include <fstream>
6#include <string>
7#include <sstream>
Paul Lawrence707fd6c2015-04-28 22:14:15 +00008
9#include <errno.h>
10#include <sys/mount.h>
11#include <cutils/properties.h>
Paul Lawrence5e7f0042015-04-10 07:48:51 -070012#include <openssl/sha.h>
Paul Lawrence707fd6c2015-04-28 22:14:15 +000013
14#include "unencrypted_properties.h"
15#include "key_control.h"
16#include "cryptfs.h"
17
18#define LOG_TAG "Ext4Crypt"
19#include "cutils/log.h"
20#include <cutils/klog.h>
21
22namespace {
23 // Key length in bits
24 const int key_length = 128;
Paul Lawrence5e7f0042015-04-10 07:48:51 -070025 static_assert(key_length % 8 == 0,
26 "Key length must be multiple of 8 bits");
Paul Lawrence707fd6c2015-04-28 22:14:15 +000027
28 // How is device encrypted
29 struct keys {
30 std::string master_key;
31 std::string password;
32 };
33 std::map<std::string, keys> s_key_store;
34
Paul Lawrence5e7f0042015-04-10 07:48:51 -070035 // ext4enc:TODO get these consts from somewhere good
36 const int SHA512_LENGTH = 64;
37 const int EXT4_KEY_DESCRIPTOR_SIZE = 8;
38
Paul Lawrence707fd6c2015-04-28 22:14:15 +000039 // ext4enc:TODO Include structure from somewhere sensible
40 // MUST be in sync with ext4_crypto.c in kernel
Paul Lawrence5e7f0042015-04-10 07:48:51 -070041 const int EXT4_MAX_KEY_SIZE = 64;
42 const int EXT4_ENCRYPTION_MODE_AES_256_XTS = 1;
Paul Lawrence707fd6c2015-04-28 22:14:15 +000043 struct ext4_encryption_key {
Paul Lawrence5e7f0042015-04-10 07:48:51 -070044 uint32_t mode;
45 char raw[EXT4_MAX_KEY_SIZE];
46 uint32_t size;
Paul Lawrence707fd6c2015-04-28 22:14:15 +000047 };
48
Paul Lawrence5e7f0042015-04-10 07:48:51 -070049 // ext4enc:TODO Get from somewhere good
50 struct ext4_encryption_policy {
51 char version;
52 char contents_encryption_mode;
53 char filenames_encryption_mode;
54 char master_key_descriptor[EXT4_KEY_DESCRIPTOR_SIZE];
55 } __attribute__((__packed__));
56
Paul Lawrence707fd6c2015-04-28 22:14:15 +000057 namespace tag {
58 const char* magic = "magic";
59 const char* major_version = "major_version";
60 const char* minor_version = "minor_version";
61 const char* flags = "flags";
62 const char* crypt_type = "crypt_type";
63 const char* failed_decrypt_count = "failed_decrypt_count";
64 const char* crypto_type_name = "crypto_type_name";
65 const char* master_key = "master_key";
66 const char* salt = "salt";
67 const char* kdf_type = "kdf_type";
68 const char* N_factor = "N_factor";
69 const char* r_factor = "r_factor";
70 const char* p_factor = "p_factor";
71 const char* keymaster_blob = "keymaster_blob";
72 const char* scrypted_intermediate_key = "scrypted_intermediate_key";
73 }
74}
75
76static int put_crypt_ftr_and_key(const crypt_mnt_ftr& crypt_ftr,
77 UnencryptedProperties& props)
78{
79 SLOGI("Putting crypt footer");
80
81 bool success = props.Set<int>(tag::magic, crypt_ftr.magic)
82 && props.Set<int>(tag::major_version, crypt_ftr.major_version)
83 && props.Set<int>(tag::minor_version, crypt_ftr.minor_version)
84 && props.Set<int>(tag::flags, crypt_ftr.flags)
85 && props.Set<int>(tag::crypt_type, crypt_ftr.crypt_type)
86 && props.Set<int>(tag::failed_decrypt_count,
87 crypt_ftr.failed_decrypt_count)
88 && props.Set<std::string>(tag::crypto_type_name,
89 std::string(reinterpret_cast<const char*>(crypt_ftr.crypto_type_name)))
90 && props.Set<std::string>(tag::master_key,
91 std::string((const char*) crypt_ftr.master_key,
92 crypt_ftr.keysize))
93 && props.Set<std::string>(tag::salt,
94 std::string((const char*) crypt_ftr.salt,
95 SALT_LEN))
96 && props.Set<int>(tag::kdf_type, crypt_ftr.kdf_type)
97 && props.Set<int>(tag::N_factor, crypt_ftr.N_factor)
98 && props.Set<int>(tag::r_factor, crypt_ftr.r_factor)
99 && props.Set<int>(tag::p_factor, crypt_ftr.p_factor)
100 && props.Set<std::string>(tag::keymaster_blob,
101 std::string((const char*) crypt_ftr.keymaster_blob,
102 crypt_ftr.keymaster_blob_size))
103 && props.Set<std::string>(tag::scrypted_intermediate_key,
104 std::string((const char*) crypt_ftr.scrypted_intermediate_key,
105 SCRYPT_LEN));
106 return success ? 0 : -1;
107}
108
109static int get_crypt_ftr_and_key(crypt_mnt_ftr& crypt_ftr,
110 const UnencryptedProperties& props)
111{
112 memset(&crypt_ftr, 0, sizeof(crypt_ftr));
113 crypt_ftr.magic = props.Get<int>(tag::magic);
114 crypt_ftr.major_version = props.Get<int>(tag::major_version);
115 crypt_ftr.minor_version = props.Get<int>(tag::minor_version);
116 crypt_ftr.flags = props.Get<int>(tag::flags);
117 crypt_ftr.crypt_type = props.Get<int>(tag::crypt_type);
118 crypt_ftr.failed_decrypt_count = props.Get<int>(tag::failed_decrypt_count);
119 std::string crypto_type_name = props.Get<std::string>(tag::crypto_type_name);
120 strlcpy(reinterpret_cast<char*>(crypt_ftr.crypto_type_name),
121 crypto_type_name.c_str(),
122 sizeof(crypt_ftr.crypto_type_name));
123 std::string master_key = props.Get<std::string>(tag::master_key);
124 crypt_ftr.keysize = master_key.size();
125 if (crypt_ftr.keysize > sizeof(crypt_ftr.master_key)) {
126 SLOGE("Master key size too long");
127 return -1;
128 }
129 memcpy(crypt_ftr.master_key, &master_key[0], crypt_ftr.keysize);
130 std::string salt = props.Get<std::string>(tag::salt);
131 if (salt.size() != SALT_LEN) {
132 SLOGE("Salt wrong length");
133 return -1;
134 }
135 memcpy(crypt_ftr.salt, &salt[0], SALT_LEN);
136 crypt_ftr.kdf_type = props.Get<int>(tag::kdf_type);
137 crypt_ftr.N_factor = props.Get<int>(tag::N_factor);
138 crypt_ftr.r_factor = props.Get<int>(tag::r_factor);
139 crypt_ftr.p_factor = props.Get<int>(tag::p_factor);
140 std::string keymaster_blob = props.Get<std::string>(tag::keymaster_blob);
141 crypt_ftr.keymaster_blob_size = keymaster_blob.size();
142 if (crypt_ftr.keymaster_blob_size > sizeof(crypt_ftr.keymaster_blob)) {
143 SLOGE("Keymaster blob too long");
144 return -1;
145 }
146 memcpy(crypt_ftr.keymaster_blob, &keymaster_blob[0],
147 crypt_ftr.keymaster_blob_size);
148 std::string scrypted_intermediate_key = props.Get<std::string>(tag::scrypted_intermediate_key);
149 if (scrypted_intermediate_key.size() != SCRYPT_LEN) {
150 SLOGE("scrypted intermediate key wrong length");
151 return -1;
152 }
153 memcpy(crypt_ftr.scrypted_intermediate_key, &scrypted_intermediate_key[0],
154 SCRYPT_LEN);
155
156 return 0;
157}
158
159static UnencryptedProperties GetProps(const char* path)
160{
161 return UnencryptedProperties(path);
162}
163
164static UnencryptedProperties GetAltProps(const char* path)
165{
166 return UnencryptedProperties((std::string() + path + "/tmp_mnt").c_str());
167}
168
169static UnencryptedProperties GetPropsOrAltProps(const char* path)
170{
171 UnencryptedProperties props = GetProps(path);
172 if (props.OK()) {
173 return props;
174 }
175 return GetAltProps(path);
176}
177
178int e4crypt_enable(const char* path)
179{
180 // Already enabled?
181 if (s_key_store.find(path) != s_key_store.end()) {
182 return 0;
183 }
184
185 // Not an encryptable device?
186 UnencryptedProperties key_props = GetProps(path).GetChild(properties::key);
187 if (!key_props.OK()) {
188 return 0;
189 }
190
191 if (key_props.Get<std::string>(tag::master_key).empty()) {
192 crypt_mnt_ftr ftr;
193 if (cryptfs_create_default_ftr(&ftr, key_length)) {
194 SLOGE("Failed to create crypto footer");
195 return -1;
196 }
197
198 if (put_crypt_ftr_and_key(ftr, key_props)) {
199 SLOGE("Failed to write crypto footer");
200 return -1;
201 }
202
203 crypt_mnt_ftr ftr2;
204 if (get_crypt_ftr_and_key(ftr2, key_props)) {
205 SLOGE("Failed to read crypto footer back");
206 return -1;
207 }
208
209 if (memcmp(&ftr, &ftr2, sizeof(ftr)) != 0) {
210 SLOGE("Crypto footer not correctly written");
211 // ex4enc:TODO why is this failing?
212 //return -1;
213 }
214 }
215
216 if (!UnencryptedProperties(path).Remove(properties::ref)) {
217 SLOGE("Failed to remove key ref");
218 return -1;
219 }
220
221 return e4crypt_check_passwd(path, "");
222}
223
224int e4crypt_change_password(const char* path, int crypt_type,
225 const char* password)
226{
227 SLOGI("e4crypt_change_password");
228
229 UnencryptedProperties key_props = GetProps(path).GetChild(properties::key);
230
231 crypt_mnt_ftr ftr;
232 if (get_crypt_ftr_and_key(ftr, key_props)) {
233 SLOGE("Failed to read crypto footer back");
234 return -1;
235 }
236
237 auto mki = s_key_store.find(path);
238 if (mki == s_key_store.end()) {
239 SLOGE("No stored master key - can't change password");
240 return -1;
241 }
242
243 const unsigned char* master_key
244 = reinterpret_cast<const unsigned char*>(&mki->second.master_key[0]);
245
246 if (cryptfs_set_password(&ftr, password, master_key)) {
247 SLOGE("Failed to set password");
248 return -1;
249 }
250
251 ftr.crypt_type = crypt_type;
252
253 if (put_crypt_ftr_and_key(ftr, key_props)) {
254 SLOGE("Failed to write crypto footer");
255 return -1;
256 }
257
258 if (!UnencryptedProperties(path).Set(properties::is_default,
259 crypt_type == CRYPT_TYPE_DEFAULT)) {
260 SLOGE("Failed to update default flag");
261 return -1;
262 }
263
264 return 0;
265}
266
267int e4crypt_crypto_complete(const char* path)
268{
269 SLOGI("ext4 crypto complete called on %s", path);
270 UnencryptedProperties key_props
271 = GetPropsOrAltProps(path).GetChild(properties::key);
272 if (key_props.Get<std::string>(tag::master_key).empty()) {
273 SLOGI("No master key, so not ext4enc");
274 return -1;
275 }
276
277 return 0;
278}
279
Paul Lawrence5e7f0042015-04-10 07:48:51 -0700280static std::string generate_key_ref(const char* key, int length)
281{
282 SHA512_CTX c;
283
284 SHA512_Init(&c);
285 SHA512_Update(&c, key, length);
286 unsigned char key_ref1[SHA512_LENGTH];
287 SHA512_Final(key_ref1, &c);
288
289 SHA512_Init(&c);
290 SHA512_Update(&c, key_ref1, SHA512_LENGTH);
291 unsigned char key_ref2[SHA512_LENGTH];
292 SHA512_Final(key_ref2, &c);
293
294 return std::string((char*)key_ref2, EXT4_KEY_DESCRIPTOR_SIZE);
295}
296
Paul Lawrence707fd6c2015-04-28 22:14:15 +0000297int e4crypt_check_passwd(const char* path, const char* password)
298{
299 SLOGI("e4crypt_check_password");
300
301 // ext4enc:TODO once we have password checking, fix this to be
302 // GetKeyOrAltKey
303 UnencryptedProperties props = *password ? GetAltProps(path)
304 : GetProps(path);
305 UnencryptedProperties key_props = props.GetChild(properties::key);
306
307 crypt_mnt_ftr ftr;
308 if (get_crypt_ftr_and_key(ftr, key_props)) {
309 SLOGE("Failed to read crypto footer back");
310 return -1;
311 }
312
313 unsigned char master_key[key_length / 8];
314 if (cryptfs_get_master_key (&ftr, password, master_key)){
315 SLOGI("Incorrect password");
316 return -1;
317 }
318
319 s_key_store[path] = keys{std::string(reinterpret_cast<char*>(master_key),
320 sizeof(master_key)),
321 password};
322
323 // Install password into global keyring
Paul Lawrence5e7f0042015-04-10 07:48:51 -0700324 // ext4enc:TODO Currently raw key is required to be of length
325 // sizeof(ext4_key.raw) == EXT4_MAX_KEY_SIZE, so zero pad to
326 // this length. Change when kernel bug is fixed.
327 ext4_encryption_key ext4_key = {EXT4_ENCRYPTION_MODE_AES_256_XTS,
328 {0},
329 sizeof(ext4_key.raw)};
330 memset(ext4_key.raw, 0, sizeof(ext4_key.raw));
331 static_assert(key_length / 8 <= sizeof(ext4_key.raw),
332 "Key too long!");
333 memcpy(ext4_key.raw, master_key, key_length / 8);
Paul Lawrence707fd6c2015-04-28 22:14:15 +0000334
Paul Lawrence5e7f0042015-04-10 07:48:51 -0700335 // Get raw keyref - used to make keyname and to pass to ioctl
336 auto raw_ref = generate_key_ref(ext4_key.raw, ext4_key.size);
337
338 // Generate keyname
339 std::ostringstream o;
340 for (auto i = raw_ref.begin(); i != raw_ref.end(); ++i) {
341 o << std::hex << std::setw(2) << std::setfill('0') << (int)*i;
342 }
343 auto ref = std::string("ext4:") + o.str();
344
345 // Find existing keyring
Paul Lawrence707fd6c2015-04-28 22:14:15 +0000346 key_serial_t device_keyring = keyctl_search(KEY_SPEC_SESSION_KEYRING,
347 "keyring", "e4crypt", 0);
348
349 SLOGI("Found device_keyring - id is %d", device_keyring);
350
Paul Lawrence5e7f0042015-04-10 07:48:51 -0700351 // Add key ...
352 key_serial_t key_id = add_key("logon", ref.c_str(),
Paul Lawrence707fd6c2015-04-28 22:14:15 +0000353 (void*)&ext4_key, sizeof(ext4_key),
354 device_keyring);
355
356 if (key_id == -1) {
357 SLOGE("Failed to insert key into keyring with error %s",
358 strerror(errno));
359 return -1;
360 }
361
Paul Lawrence5e7f0042015-04-10 07:48:51 -0700362 SLOGI("Added key %d (%s) to keyring %d in process %d",
363 key_id, ref.c_str(), device_keyring, getpid());
Paul Lawrence707fd6c2015-04-28 22:14:15 +0000364
365 // ext4enc:TODO set correct permissions
366 long result = keyctl_setperm(key_id, 0x3f3f3f3f);
367 if (result) {
368 SLOGE("KEYCTL_SETPERM failed with error %ld", result);
369 return -1;
370 }
371
372 // Save reference to key so we can set policy later
Paul Lawrence5e7f0042015-04-10 07:48:51 -0700373 if (!props.Set(properties::ref, raw_ref)) {
Paul Lawrence707fd6c2015-04-28 22:14:15 +0000374 SLOGE("Cannot save key reference");
375 return -1;
376 }
377
378 return 0;
379}
380
381int e4crypt_restart(const char* path)
382{
383 SLOGI("e4crypt_restart");
384
385 int rc = 0;
386
387 SLOGI("ext4 restart called on %s", path);
388 property_set("vold.decrypt", "trigger_reset_main");
389 SLOGI("Just asked init to shut down class main");
390 sleep(2);
391
392 std::string tmp_path = std::string() + path + "/tmp_mnt";
393
394 // ext4enc:TODO add retry logic
395 rc = umount(tmp_path.c_str());
396 if (rc) {
397 SLOGE("umount %s failed with rc %d, msg %s",
398 tmp_path.c_str(), rc, strerror(errno));
399 return rc;
400 }
401
402 // ext4enc:TODO add retry logic
403 rc = umount(path);
404 if (rc) {
405 SLOGE("umount %s failed with rc %d, msg %s",
406 path, rc, strerror(errno));
407 return rc;
408 }
409
410 return 0;
411}
412
413const char* e4crypt_get_password(const char* path)
414{
415 SLOGI("e4crypt_get_password");
416
417 // ext4enc:TODO scrub password after timeout
418 auto i = s_key_store.find(path);
419 if (i == s_key_store.end()) {
420 return 0;
421 } else {
422 return i->second.password.c_str();
423 }
424}
425
426int e4crypt_get_password_type(const char* path)
427{
428 SLOGI("e4crypt_get_password_type");
429 return GetPropsOrAltProps(path).GetChild(properties::key)
430 .Get<int>(tag::crypt_type, CRYPT_TYPE_DEFAULT);
431}