blob: 84393c980373981b425398232bcff227f0f70611 [file] [log] [blame]
Paul Lawrence707fd6c2015-04-28 22:14:15 +00001#include "Ext4Crypt.h"
2
3#include <string>
4#include <fstream>
5#include <map>
6
7#include <errno.h>
8#include <sys/mount.h>
9#include <cutils/properties.h>
10
11#include "unencrypted_properties.h"
12#include "key_control.h"
13#include "cryptfs.h"
14
15#define LOG_TAG "Ext4Crypt"
16#include "cutils/log.h"
17#include <cutils/klog.h>
18
19namespace {
20 // Key length in bits
21 const int key_length = 128;
22
23 // How is device encrypted
24 struct keys {
25 std::string master_key;
26 std::string password;
27 };
28 std::map<std::string, keys> s_key_store;
29
30 // ext4enc:TODO Include structure from somewhere sensible
31 // MUST be in sync with ext4_crypto.c in kernel
32 const int EXT4_MAX_KEY_SIZE = 76;
33 struct ext4_encryption_key {
34 uint32_t mode;
35 char raw[EXT4_MAX_KEY_SIZE];
36 uint32_t size;
37 };
38
39 namespace tag {
40 const char* magic = "magic";
41 const char* major_version = "major_version";
42 const char* minor_version = "minor_version";
43 const char* flags = "flags";
44 const char* crypt_type = "crypt_type";
45 const char* failed_decrypt_count = "failed_decrypt_count";
46 const char* crypto_type_name = "crypto_type_name";
47 const char* master_key = "master_key";
48 const char* salt = "salt";
49 const char* kdf_type = "kdf_type";
50 const char* N_factor = "N_factor";
51 const char* r_factor = "r_factor";
52 const char* p_factor = "p_factor";
53 const char* keymaster_blob = "keymaster_blob";
54 const char* scrypted_intermediate_key = "scrypted_intermediate_key";
55 }
56}
57
58static int put_crypt_ftr_and_key(const crypt_mnt_ftr& crypt_ftr,
59 UnencryptedProperties& props)
60{
61 SLOGI("Putting crypt footer");
62
63 bool success = props.Set<int>(tag::magic, crypt_ftr.magic)
64 && props.Set<int>(tag::major_version, crypt_ftr.major_version)
65 && props.Set<int>(tag::minor_version, crypt_ftr.minor_version)
66 && props.Set<int>(tag::flags, crypt_ftr.flags)
67 && props.Set<int>(tag::crypt_type, crypt_ftr.crypt_type)
68 && props.Set<int>(tag::failed_decrypt_count,
69 crypt_ftr.failed_decrypt_count)
70 && props.Set<std::string>(tag::crypto_type_name,
71 std::string(reinterpret_cast<const char*>(crypt_ftr.crypto_type_name)))
72 && props.Set<std::string>(tag::master_key,
73 std::string((const char*) crypt_ftr.master_key,
74 crypt_ftr.keysize))
75 && props.Set<std::string>(tag::salt,
76 std::string((const char*) crypt_ftr.salt,
77 SALT_LEN))
78 && props.Set<int>(tag::kdf_type, crypt_ftr.kdf_type)
79 && props.Set<int>(tag::N_factor, crypt_ftr.N_factor)
80 && props.Set<int>(tag::r_factor, crypt_ftr.r_factor)
81 && props.Set<int>(tag::p_factor, crypt_ftr.p_factor)
82 && props.Set<std::string>(tag::keymaster_blob,
83 std::string((const char*) crypt_ftr.keymaster_blob,
84 crypt_ftr.keymaster_blob_size))
85 && props.Set<std::string>(tag::scrypted_intermediate_key,
86 std::string((const char*) crypt_ftr.scrypted_intermediate_key,
87 SCRYPT_LEN));
88 return success ? 0 : -1;
89}
90
91static int get_crypt_ftr_and_key(crypt_mnt_ftr& crypt_ftr,
92 const UnencryptedProperties& props)
93{
94 memset(&crypt_ftr, 0, sizeof(crypt_ftr));
95 crypt_ftr.magic = props.Get<int>(tag::magic);
96 crypt_ftr.major_version = props.Get<int>(tag::major_version);
97 crypt_ftr.minor_version = props.Get<int>(tag::minor_version);
98 crypt_ftr.flags = props.Get<int>(tag::flags);
99 crypt_ftr.crypt_type = props.Get<int>(tag::crypt_type);
100 crypt_ftr.failed_decrypt_count = props.Get<int>(tag::failed_decrypt_count);
101 std::string crypto_type_name = props.Get<std::string>(tag::crypto_type_name);
102 strlcpy(reinterpret_cast<char*>(crypt_ftr.crypto_type_name),
103 crypto_type_name.c_str(),
104 sizeof(crypt_ftr.crypto_type_name));
105 std::string master_key = props.Get<std::string>(tag::master_key);
106 crypt_ftr.keysize = master_key.size();
107 if (crypt_ftr.keysize > sizeof(crypt_ftr.master_key)) {
108 SLOGE("Master key size too long");
109 return -1;
110 }
111 memcpy(crypt_ftr.master_key, &master_key[0], crypt_ftr.keysize);
112 std::string salt = props.Get<std::string>(tag::salt);
113 if (salt.size() != SALT_LEN) {
114 SLOGE("Salt wrong length");
115 return -1;
116 }
117 memcpy(crypt_ftr.salt, &salt[0], SALT_LEN);
118 crypt_ftr.kdf_type = props.Get<int>(tag::kdf_type);
119 crypt_ftr.N_factor = props.Get<int>(tag::N_factor);
120 crypt_ftr.r_factor = props.Get<int>(tag::r_factor);
121 crypt_ftr.p_factor = props.Get<int>(tag::p_factor);
122 std::string keymaster_blob = props.Get<std::string>(tag::keymaster_blob);
123 crypt_ftr.keymaster_blob_size = keymaster_blob.size();
124 if (crypt_ftr.keymaster_blob_size > sizeof(crypt_ftr.keymaster_blob)) {
125 SLOGE("Keymaster blob too long");
126 return -1;
127 }
128 memcpy(crypt_ftr.keymaster_blob, &keymaster_blob[0],
129 crypt_ftr.keymaster_blob_size);
130 std::string scrypted_intermediate_key = props.Get<std::string>(tag::scrypted_intermediate_key);
131 if (scrypted_intermediate_key.size() != SCRYPT_LEN) {
132 SLOGE("scrypted intermediate key wrong length");
133 return -1;
134 }
135 memcpy(crypt_ftr.scrypted_intermediate_key, &scrypted_intermediate_key[0],
136 SCRYPT_LEN);
137
138 return 0;
139}
140
141static UnencryptedProperties GetProps(const char* path)
142{
143 return UnencryptedProperties(path);
144}
145
146static UnencryptedProperties GetAltProps(const char* path)
147{
148 return UnencryptedProperties((std::string() + path + "/tmp_mnt").c_str());
149}
150
151static UnencryptedProperties GetPropsOrAltProps(const char* path)
152{
153 UnencryptedProperties props = GetProps(path);
154 if (props.OK()) {
155 return props;
156 }
157 return GetAltProps(path);
158}
159
160int e4crypt_enable(const char* path)
161{
162 // Already enabled?
163 if (s_key_store.find(path) != s_key_store.end()) {
164 return 0;
165 }
166
167 // Not an encryptable device?
168 UnencryptedProperties key_props = GetProps(path).GetChild(properties::key);
169 if (!key_props.OK()) {
170 return 0;
171 }
172
173 if (key_props.Get<std::string>(tag::master_key).empty()) {
174 crypt_mnt_ftr ftr;
175 if (cryptfs_create_default_ftr(&ftr, key_length)) {
176 SLOGE("Failed to create crypto footer");
177 return -1;
178 }
179
180 if (put_crypt_ftr_and_key(ftr, key_props)) {
181 SLOGE("Failed to write crypto footer");
182 return -1;
183 }
184
185 crypt_mnt_ftr ftr2;
186 if (get_crypt_ftr_and_key(ftr2, key_props)) {
187 SLOGE("Failed to read crypto footer back");
188 return -1;
189 }
190
191 if (memcmp(&ftr, &ftr2, sizeof(ftr)) != 0) {
192 SLOGE("Crypto footer not correctly written");
193 // ex4enc:TODO why is this failing?
194 //return -1;
195 }
196 }
197
198 if (!UnencryptedProperties(path).Remove(properties::ref)) {
199 SLOGE("Failed to remove key ref");
200 return -1;
201 }
202
203 return e4crypt_check_passwd(path, "");
204}
205
206int e4crypt_change_password(const char* path, int crypt_type,
207 const char* password)
208{
209 SLOGI("e4crypt_change_password");
210
211 UnencryptedProperties key_props = GetProps(path).GetChild(properties::key);
212
213 crypt_mnt_ftr ftr;
214 if (get_crypt_ftr_and_key(ftr, key_props)) {
215 SLOGE("Failed to read crypto footer back");
216 return -1;
217 }
218
219 auto mki = s_key_store.find(path);
220 if (mki == s_key_store.end()) {
221 SLOGE("No stored master key - can't change password");
222 return -1;
223 }
224
225 const unsigned char* master_key
226 = reinterpret_cast<const unsigned char*>(&mki->second.master_key[0]);
227
228 if (cryptfs_set_password(&ftr, password, master_key)) {
229 SLOGE("Failed to set password");
230 return -1;
231 }
232
233 ftr.crypt_type = crypt_type;
234
235 if (put_crypt_ftr_and_key(ftr, key_props)) {
236 SLOGE("Failed to write crypto footer");
237 return -1;
238 }
239
240 if (!UnencryptedProperties(path).Set(properties::is_default,
241 crypt_type == CRYPT_TYPE_DEFAULT)) {
242 SLOGE("Failed to update default flag");
243 return -1;
244 }
245
246 return 0;
247}
248
249int e4crypt_crypto_complete(const char* path)
250{
251 SLOGI("ext4 crypto complete called on %s", path);
252 UnencryptedProperties key_props
253 = GetPropsOrAltProps(path).GetChild(properties::key);
254 if (key_props.Get<std::string>(tag::master_key).empty()) {
255 SLOGI("No master key, so not ext4enc");
256 return -1;
257 }
258
259 return 0;
260}
261
262int e4crypt_check_passwd(const char* path, const char* password)
263{
264 SLOGI("e4crypt_check_password");
265
266 // ext4enc:TODO once we have password checking, fix this to be
267 // GetKeyOrAltKey
268 UnencryptedProperties props = *password ? GetAltProps(path)
269 : GetProps(path);
270 UnencryptedProperties key_props = props.GetChild(properties::key);
271
272 crypt_mnt_ftr ftr;
273 if (get_crypt_ftr_and_key(ftr, key_props)) {
274 SLOGE("Failed to read crypto footer back");
275 return -1;
276 }
277
278 unsigned char master_key[key_length / 8];
279 if (cryptfs_get_master_key (&ftr, password, master_key)){
280 SLOGI("Incorrect password");
281 return -1;
282 }
283
284 s_key_store[path] = keys{std::string(reinterpret_cast<char*>(master_key),
285 sizeof(master_key)),
286 password};
287
288 // Install password into global keyring
289 ext4_encryption_key ext4_key = {0, {0}, key_length / 8};
290 memcpy(ext4_key.raw, master_key, ext4_key.size);
291
292 // ext4enc:TODO Use better reference not 1234567890
293 key_serial_t device_keyring = keyctl_search(KEY_SPEC_SESSION_KEYRING,
294 "keyring", "e4crypt", 0);
295
296 SLOGI("Found device_keyring - id is %d", device_keyring);
297
298 key_serial_t key_id = add_key("logon", "ext4-key:1234567890",
299 (void*)&ext4_key, sizeof(ext4_key),
300 device_keyring);
301
302 if (key_id == -1) {
303 SLOGE("Failed to insert key into keyring with error %s",
304 strerror(errno));
305 return -1;
306 }
307
308 SLOGI("Added key %d to keyring %d in process %d",
309 key_id, device_keyring, getpid());
310
311 // ext4enc:TODO set correct permissions
312 long result = keyctl_setperm(key_id, 0x3f3f3f3f);
313 if (result) {
314 SLOGE("KEYCTL_SETPERM failed with error %ld", result);
315 return -1;
316 }
317
318 // Save reference to key so we can set policy later
319 if (!props.Set(properties::ref, "@s.ext4-key:1234567890")) {
320 SLOGE("Cannot save key reference");
321 return -1;
322 }
323
324 return 0;
325}
326
327int e4crypt_restart(const char* path)
328{
329 SLOGI("e4crypt_restart");
330
331 int rc = 0;
332
333 SLOGI("ext4 restart called on %s", path);
334 property_set("vold.decrypt", "trigger_reset_main");
335 SLOGI("Just asked init to shut down class main");
336 sleep(2);
337
338 std::string tmp_path = std::string() + path + "/tmp_mnt";
339
340 // ext4enc:TODO add retry logic
341 rc = umount(tmp_path.c_str());
342 if (rc) {
343 SLOGE("umount %s failed with rc %d, msg %s",
344 tmp_path.c_str(), rc, strerror(errno));
345 return rc;
346 }
347
348 // ext4enc:TODO add retry logic
349 rc = umount(path);
350 if (rc) {
351 SLOGE("umount %s failed with rc %d, msg %s",
352 path, rc, strerror(errno));
353 return rc;
354 }
355
356 return 0;
357}
358
359const char* e4crypt_get_password(const char* path)
360{
361 SLOGI("e4crypt_get_password");
362
363 // ext4enc:TODO scrub password after timeout
364 auto i = s_key_store.find(path);
365 if (i == s_key_store.end()) {
366 return 0;
367 } else {
368 return i->second.password.c_str();
369 }
370}
371
372int e4crypt_get_password_type(const char* path)
373{
374 SLOGI("e4crypt_get_password_type");
375 return GetPropsOrAltProps(path).GetChild(properties::key)
376 .Get<int>(tag::crypt_type, CRYPT_TYPE_DEFAULT);
377}