1 /* 2 * Copyright (C) 2016 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 "KeyStorage.h" 18 19 #include "Keymaster.h" 20 #include "ScryptParameters.h" 21 #include "Utils.h" 22 23 #include <vector> 24 25 #include <errno.h> 26 #include <sys/stat.h> 27 #include <sys/types.h> 28 #include <sys/wait.h> 29 #include <unistd.h> 30 31 #include <openssl/sha.h> 32 33 #include <android-base/file.h> 34 #include <android-base/logging.h> 35 36 #include <cutils/properties.h> 37 38 #include <hardware/hw_auth_token.h> 39 40 #include <keymaster/authorization_set.h> 41 42 extern "C" { 43 44 #include "crypto_scrypt.h" 45 } 46 47 namespace android { 48 namespace vold { 49 50 const KeyAuthentication kEmptyAuthentication{"", ""}; 51 52 static constexpr size_t AES_KEY_BYTES = 32; 53 static constexpr size_t GCM_NONCE_BYTES = 12; 54 static constexpr size_t GCM_MAC_BYTES = 16; 55 static constexpr size_t SALT_BYTES = 1 << 4; 56 static constexpr size_t SECDISCARDABLE_BYTES = 1 << 14; 57 static constexpr size_t STRETCHED_BYTES = 1 << 6; 58 59 static constexpr uint32_t AUTH_TIMEOUT = 30; // Seconds 60 61 static const char* kCurrentVersion = "1"; 62 static const char* kRmPath = "/system/bin/rm"; 63 static const char* kSecdiscardPath = "/system/bin/secdiscard"; 64 static const char* kStretch_none = "none"; 65 static const char* kStretch_nopassword = "nopassword"; 66 static const std::string kStretchPrefix_scrypt = "scrypt "; 67 static const char* kFn_encrypted_key = "encrypted_key"; 68 static const char* kFn_keymaster_key_blob = "keymaster_key_blob"; 69 static const char* kFn_salt = "salt"; 70 static const char* kFn_secdiscardable = "secdiscardable"; 71 static const char* kFn_stretching = "stretching"; 72 static const char* kFn_version = "version"; 73 74 static bool checkSize(const std::string& kind, size_t actual, size_t expected) { 75 if (actual != expected) { 76 LOG(ERROR) << "Wrong number of bytes in " << kind << ", expected " << expected << " got " 77 << actual; 78 return false; 79 } 80 return true; 81 } 82 83 static std::string hashSecdiscardable(const std::string& secdiscardable) { 84 SHA512_CTX c; 85 86 SHA512_Init(&c); 87 // Personalise the hashing by introducing a fixed prefix. 88 // Hashing applications should use personalization except when there is a 89 // specific reason not to; see section 4.11 of https://www.schneier.com/skein1.3.pdf 90 std::string secdiscardableHashingPrefix = "Android secdiscardable SHA512"; 91 secdiscardableHashingPrefix.resize(SHA512_CBLOCK); 92 SHA512_Update(&c, secdiscardableHashingPrefix.data(), secdiscardableHashingPrefix.size()); 93 SHA512_Update(&c, secdiscardable.data(), secdiscardable.size()); 94 std::string res(SHA512_DIGEST_LENGTH, '\0'); 95 SHA512_Final(reinterpret_cast<uint8_t*>(&res[0]), &c); 96 return res; 97 } 98 99 static bool generateKeymasterKey(Keymaster& keymaster, const KeyAuthentication& auth, 100 const std::string& appId, std::string* key) { 101 auto paramBuilder = keymaster::AuthorizationSetBuilder() 102 .AesEncryptionKey(AES_KEY_BYTES * 8) 103 .Authorization(keymaster::TAG_BLOCK_MODE, KM_MODE_GCM) 104 .Authorization(keymaster::TAG_MIN_MAC_LENGTH, GCM_MAC_BYTES * 8) 105 .Authorization(keymaster::TAG_PADDING, KM_PAD_NONE); 106 addStringParam(¶mBuilder, keymaster::TAG_APPLICATION_ID, appId); 107 if (auth.token.empty()) { 108 LOG(DEBUG) << "Creating key that doesn't need auth token"; 109 paramBuilder.Authorization(keymaster::TAG_NO_AUTH_REQUIRED); 110 } else { 111 LOG(DEBUG) << "Auth token required for key"; 112 if (auth.token.size() != sizeof(hw_auth_token_t)) { 113 LOG(ERROR) << "Auth token should be " << sizeof(hw_auth_token_t) << " bytes, was " 114 << auth.token.size() << " bytes"; 115 return false; 116 } 117 const hw_auth_token_t* at = reinterpret_cast<const hw_auth_token_t*>(auth.token.data()); 118 paramBuilder.Authorization(keymaster::TAG_USER_SECURE_ID, at->user_id); 119 paramBuilder.Authorization(keymaster::TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD); 120 paramBuilder.Authorization(keymaster::TAG_AUTH_TIMEOUT, AUTH_TIMEOUT); 121 } 122 return keymaster.generateKey(paramBuilder.build(), key); 123 } 124 125 static keymaster::AuthorizationSetBuilder beginParams(const KeyAuthentication& auth, 126 const std::string& appId) { 127 auto paramBuilder = keymaster::AuthorizationSetBuilder() 128 .Authorization(keymaster::TAG_BLOCK_MODE, KM_MODE_GCM) 129 .Authorization(keymaster::TAG_MAC_LENGTH, GCM_MAC_BYTES * 8) 130 .Authorization(keymaster::TAG_PADDING, KM_PAD_NONE); 131 addStringParam(¶mBuilder, keymaster::TAG_APPLICATION_ID, appId); 132 if (!auth.token.empty()) { 133 LOG(DEBUG) << "Supplying auth token to Keymaster"; 134 addStringParam(¶mBuilder, keymaster::TAG_AUTH_TOKEN, auth.token); 135 } 136 return paramBuilder; 137 } 138 139 static bool encryptWithKeymasterKey(Keymaster& keymaster, const std::string& key, 140 const KeyAuthentication& auth, const std::string& appId, 141 const std::string& message, std::string* ciphertext) { 142 auto params = beginParams(auth, appId).build(); 143 keymaster::AuthorizationSet outParams; 144 auto opHandle = keymaster.begin(KM_PURPOSE_ENCRYPT, key, params, &outParams); 145 if (!opHandle) return false; 146 keymaster_blob_t nonceBlob; 147 if (!outParams.GetTagValue(keymaster::TAG_NONCE, &nonceBlob)) { 148 LOG(ERROR) << "GCM encryption but no nonce generated"; 149 return false; 150 } 151 // nonceBlob here is just a pointer into existing data, must not be freed 152 std::string nonce(reinterpret_cast<const char*>(nonceBlob.data), nonceBlob.data_length); 153 if (!checkSize("nonce", nonce.size(), GCM_NONCE_BYTES)) return false; 154 std::string body; 155 if (!opHandle.updateCompletely(message, &body)) return false; 156 157 std::string mac; 158 if (!opHandle.finishWithOutput(&mac)) return false; 159 if (!checkSize("mac", mac.size(), GCM_MAC_BYTES)) return false; 160 *ciphertext = nonce + body + mac; 161 return true; 162 } 163 164 static bool decryptWithKeymasterKey(Keymaster& keymaster, const std::string& key, 165 const KeyAuthentication& auth, const std::string& appId, 166 const std::string& ciphertext, std::string* message) { 167 auto nonce = ciphertext.substr(0, GCM_NONCE_BYTES); 168 auto bodyAndMac = ciphertext.substr(GCM_NONCE_BYTES); 169 auto params = addStringParam(beginParams(auth, appId), keymaster::TAG_NONCE, nonce).build(); 170 auto opHandle = keymaster.begin(KM_PURPOSE_DECRYPT, key, params); 171 if (!opHandle) return false; 172 if (!opHandle.updateCompletely(bodyAndMac, message)) return false; 173 if (!opHandle.finish()) return false; 174 return true; 175 } 176 177 static bool readFileToString(const std::string& filename, std::string* result) { 178 if (!android::base::ReadFileToString(filename, result)) { 179 PLOG(ERROR) << "Failed to read from " << filename; 180 return false; 181 } 182 return true; 183 } 184 185 static bool writeStringToFile(const std::string& payload, const std::string& filename) { 186 if (!android::base::WriteStringToFile(payload, filename)) { 187 PLOG(ERROR) << "Failed to write to " << filename; 188 return false; 189 } 190 return true; 191 } 192 193 static std::string getStretching() { 194 char paramstr[PROPERTY_VALUE_MAX]; 195 196 property_get(SCRYPT_PROP, paramstr, SCRYPT_DEFAULTS); 197 return std::string() + kStretchPrefix_scrypt + paramstr; 198 } 199 200 static bool stretchingNeedsSalt(const std::string& stretching) { 201 return stretching != kStretch_nopassword && stretching != kStretch_none; 202 } 203 204 static bool stretchSecret(const std::string& stretching, const std::string& secret, 205 const std::string& salt, std::string* stretched) { 206 if (stretching == kStretch_nopassword) { 207 if (!secret.empty()) { 208 LOG(WARNING) << "Password present but stretching is nopassword"; 209 // Continue anyway 210 } 211 stretched->clear(); 212 } else if (stretching == kStretch_none) { 213 *stretched = secret; 214 } else if (std::equal(kStretchPrefix_scrypt.begin(), kStretchPrefix_scrypt.end(), 215 stretching.begin())) { 216 int Nf, rf, pf; 217 if (!parse_scrypt_parameters(stretching.substr(kStretchPrefix_scrypt.size()).c_str(), &Nf, 218 &rf, &pf)) { 219 LOG(ERROR) << "Unable to parse scrypt params in stretching: " << stretching; 220 return false; 221 } 222 stretched->assign(STRETCHED_BYTES, '\0'); 223 if (crypto_scrypt(reinterpret_cast<const uint8_t*>(secret.data()), secret.size(), 224 reinterpret_cast<const uint8_t*>(salt.data()), salt.size(), 225 1 << Nf, 1 << rf, 1 << pf, 226 reinterpret_cast<uint8_t*>(&(*stretched)[0]), stretched->size()) != 0) { 227 LOG(ERROR) << "scrypt failed with params: " << stretching; 228 return false; 229 } 230 } else { 231 LOG(ERROR) << "Unknown stretching type: " << stretching; 232 return false; 233 } 234 return true; 235 } 236 237 static bool generateAppId(const KeyAuthentication& auth, const std::string& stretching, 238 const std::string& salt, const std::string& secdiscardable, 239 std::string* appId) { 240 std::string stretched; 241 if (!stretchSecret(stretching, auth.secret, salt, &stretched)) return false; 242 *appId = hashSecdiscardable(secdiscardable) + stretched; 243 return true; 244 } 245 246 bool storeKey(const std::string& dir, const KeyAuthentication& auth, const std::string& key) { 247 if (TEMP_FAILURE_RETRY(mkdir(dir.c_str(), 0700)) == -1) { 248 PLOG(ERROR) << "key mkdir " << dir; 249 return false; 250 } 251 if (!writeStringToFile(kCurrentVersion, dir + "/" + kFn_version)) return false; 252 std::string secdiscardable; 253 if (ReadRandomBytes(SECDISCARDABLE_BYTES, secdiscardable) != OK) { 254 // TODO status_t plays badly with PLOG, fix it. 255 LOG(ERROR) << "Random read failed"; 256 return false; 257 } 258 if (!writeStringToFile(secdiscardable, dir + "/" + kFn_secdiscardable)) return false; 259 std::string stretching = auth.secret.empty() ? kStretch_nopassword : getStretching(); 260 if (!writeStringToFile(stretching, dir + "/" + kFn_stretching)) return false; 261 std::string salt; 262 if (stretchingNeedsSalt(stretching)) { 263 if (ReadRandomBytes(SALT_BYTES, salt) != OK) { 264 LOG(ERROR) << "Random read failed"; 265 return false; 266 } 267 if (!writeStringToFile(salt, dir + "/" + kFn_salt)) return false; 268 } 269 std::string appId; 270 if (!generateAppId(auth, stretching, salt, secdiscardable, &appId)) return false; 271 Keymaster keymaster; 272 if (!keymaster) return false; 273 std::string kmKey; 274 if (!generateKeymasterKey(keymaster, auth, appId, &kmKey)) return false; 275 if (!writeStringToFile(kmKey, dir + "/" + kFn_keymaster_key_blob)) return false; 276 std::string encryptedKey; 277 if (!encryptWithKeymasterKey(keymaster, kmKey, auth, appId, key, &encryptedKey)) return false; 278 if (!writeStringToFile(encryptedKey, dir + "/" + kFn_encrypted_key)) return false; 279 return true; 280 } 281 282 bool retrieveKey(const std::string& dir, const KeyAuthentication& auth, std::string* key) { 283 std::string version; 284 if (!readFileToString(dir + "/" + kFn_version, &version)) return false; 285 if (version != kCurrentVersion) { 286 LOG(ERROR) << "Version mismatch, expected " << kCurrentVersion << " got " << version; 287 return false; 288 } 289 std::string secdiscardable; 290 if (!readFileToString(dir + "/" + kFn_secdiscardable, &secdiscardable)) return false; 291 std::string stretching; 292 if (!readFileToString(dir + "/" + kFn_stretching, &stretching)) return false; 293 std::string salt; 294 if (stretchingNeedsSalt(stretching)) { 295 if (!readFileToString(dir + "/" + kFn_salt, &salt)) return false; 296 } 297 std::string appId; 298 if (!generateAppId(auth, stretching, salt, secdiscardable, &appId)) return false; 299 std::string kmKey; 300 if (!readFileToString(dir + "/" + kFn_keymaster_key_blob, &kmKey)) return false; 301 std::string encryptedMessage; 302 if (!readFileToString(dir + "/" + kFn_encrypted_key, &encryptedMessage)) return false; 303 Keymaster keymaster; 304 if (!keymaster) return false; 305 return decryptWithKeymasterKey(keymaster, kmKey, auth, appId, encryptedMessage, key); 306 } 307 308 static bool deleteKey(const std::string& dir) { 309 std::string kmKey; 310 if (!readFileToString(dir + "/" + kFn_keymaster_key_blob, &kmKey)) return false; 311 Keymaster keymaster; 312 if (!keymaster) return false; 313 if (!keymaster.deleteKey(kmKey)) return false; 314 return true; 315 } 316 317 static bool runSecdiscard(const std::string& dir) { 318 if (ForkExecvp( 319 std::vector<std::string>{kSecdiscardPath, "--", 320 dir + "/" + kFn_encrypted_key, 321 dir + "/" + kFn_keymaster_key_blob, 322 dir + "/" + kFn_secdiscardable, 323 }) != 0) { 324 LOG(ERROR) << "secdiscard failed"; 325 return false; 326 } 327 return true; 328 } 329 330 static bool recursiveDeleteKey(const std::string& dir) { 331 if (ForkExecvp(std::vector<std::string>{kRmPath, "-rf", dir}) != 0) { 332 LOG(ERROR) << "recursive delete failed"; 333 return false; 334 } 335 return true; 336 } 337 338 bool destroyKey(const std::string& dir) { 339 bool success = true; 340 // Try each thing, even if previous things failed. 341 success &= deleteKey(dir); 342 success &= runSecdiscard(dir); 343 success &= recursiveDeleteKey(dir); 344 return success; 345 } 346 347 } // namespace vold 348 } // namespace android 349