1*4d7e907cSAndroid Build Coastguard Worker /* 2*4d7e907cSAndroid Build Coastguard Worker * Copyright 2015 The Android Open Source Project 3*4d7e907cSAndroid Build Coastguard Worker * 4*4d7e907cSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*4d7e907cSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*4d7e907cSAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*4d7e907cSAndroid Build Coastguard Worker * 8*4d7e907cSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*4d7e907cSAndroid Build Coastguard Worker * 10*4d7e907cSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*4d7e907cSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*4d7e907cSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*4d7e907cSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*4d7e907cSAndroid Build Coastguard Worker * limitations under the License. 15*4d7e907cSAndroid Build Coastguard Worker * 16*4d7e907cSAndroid Build Coastguard Worker */ 17*4d7e907cSAndroid Build Coastguard Worker 18*4d7e907cSAndroid Build Coastguard Worker #ifndef SOFT_GATEKEEPER_H_ 19*4d7e907cSAndroid Build Coastguard Worker #define SOFT_GATEKEEPER_H_ 20*4d7e907cSAndroid Build Coastguard Worker 21*4d7e907cSAndroid Build Coastguard Worker extern "C" { 22*4d7e907cSAndroid Build Coastguard Worker #include <openssl/rand.h> 23*4d7e907cSAndroid Build Coastguard Worker #include <openssl/sha.h> 24*4d7e907cSAndroid Build Coastguard Worker 25*4d7e907cSAndroid Build Coastguard Worker #include <crypto_scrypt.h> 26*4d7e907cSAndroid Build Coastguard Worker } 27*4d7e907cSAndroid Build Coastguard Worker 28*4d7e907cSAndroid Build Coastguard Worker #include <android-base/memory.h> 29*4d7e907cSAndroid Build Coastguard Worker #include <gatekeeper/gatekeeper.h> 30*4d7e907cSAndroid Build Coastguard Worker 31*4d7e907cSAndroid Build Coastguard Worker #include <iostream> 32*4d7e907cSAndroid Build Coastguard Worker #include <memory> 33*4d7e907cSAndroid Build Coastguard Worker #include <unordered_map> 34*4d7e907cSAndroid Build Coastguard Worker 35*4d7e907cSAndroid Build Coastguard Worker namespace gatekeeper { 36*4d7e907cSAndroid Build Coastguard Worker 37*4d7e907cSAndroid Build Coastguard Worker struct fast_hash_t { 38*4d7e907cSAndroid Build Coastguard Worker uint64_t salt; 39*4d7e907cSAndroid Build Coastguard Worker uint8_t digest[SHA256_DIGEST_LENGTH]; 40*4d7e907cSAndroid Build Coastguard Worker }; 41*4d7e907cSAndroid Build Coastguard Worker 42*4d7e907cSAndroid Build Coastguard Worker class SoftGateKeeper : public GateKeeper { 43*4d7e907cSAndroid Build Coastguard Worker public: 44*4d7e907cSAndroid Build Coastguard Worker static const uint32_t SIGNATURE_LENGTH_BYTES = 32; 45*4d7e907cSAndroid Build Coastguard Worker 46*4d7e907cSAndroid Build Coastguard Worker // scrypt params 47*4d7e907cSAndroid Build Coastguard Worker static const uint64_t N = 16384; 48*4d7e907cSAndroid Build Coastguard Worker static const uint32_t r = 8; 49*4d7e907cSAndroid Build Coastguard Worker static const uint32_t p = 1; 50*4d7e907cSAndroid Build Coastguard Worker 51*4d7e907cSAndroid Build Coastguard Worker static const int MAX_UINT_32_CHARS = 11; 52*4d7e907cSAndroid Build Coastguard Worker SoftGateKeeper()53*4d7e907cSAndroid Build Coastguard Worker SoftGateKeeper() { 54*4d7e907cSAndroid Build Coastguard Worker key_.reset(new uint8_t[SIGNATURE_LENGTH_BYTES]); 55*4d7e907cSAndroid Build Coastguard Worker memset(key_.get(), 0, SIGNATURE_LENGTH_BYTES); 56*4d7e907cSAndroid Build Coastguard Worker } 57*4d7e907cSAndroid Build Coastguard Worker ~SoftGateKeeper()58*4d7e907cSAndroid Build Coastguard Worker virtual ~SoftGateKeeper() {} 59*4d7e907cSAndroid Build Coastguard Worker GetAuthTokenKey(const uint8_t ** auth_token_key,uint32_t * length)60*4d7e907cSAndroid Build Coastguard Worker virtual bool GetAuthTokenKey(const uint8_t** auth_token_key, uint32_t* length) const { 61*4d7e907cSAndroid Build Coastguard Worker if (auth_token_key == NULL || length == NULL) return false; 62*4d7e907cSAndroid Build Coastguard Worker *auth_token_key = key_.get(); 63*4d7e907cSAndroid Build Coastguard Worker *length = SIGNATURE_LENGTH_BYTES; 64*4d7e907cSAndroid Build Coastguard Worker return true; 65*4d7e907cSAndroid Build Coastguard Worker } 66*4d7e907cSAndroid Build Coastguard Worker GetPasswordKey(const uint8_t ** password_key,uint32_t * length)67*4d7e907cSAndroid Build Coastguard Worker virtual void GetPasswordKey(const uint8_t** password_key, uint32_t* length) { 68*4d7e907cSAndroid Build Coastguard Worker if (password_key == NULL || length == NULL) return; 69*4d7e907cSAndroid Build Coastguard Worker *password_key = key_.get(); 70*4d7e907cSAndroid Build Coastguard Worker *length = SIGNATURE_LENGTH_BYTES; 71*4d7e907cSAndroid Build Coastguard Worker } 72*4d7e907cSAndroid Build Coastguard Worker ComputePasswordSignature(uint8_t * signature,uint32_t signature_length,const uint8_t *,uint32_t,const uint8_t * password,uint32_t password_length,salt_t salt)73*4d7e907cSAndroid Build Coastguard Worker virtual void ComputePasswordSignature(uint8_t* signature, uint32_t signature_length, 74*4d7e907cSAndroid Build Coastguard Worker const uint8_t*, uint32_t, const uint8_t* password, 75*4d7e907cSAndroid Build Coastguard Worker uint32_t password_length, salt_t salt) const { 76*4d7e907cSAndroid Build Coastguard Worker if (signature == NULL) return; 77*4d7e907cSAndroid Build Coastguard Worker crypto_scrypt(password, password_length, reinterpret_cast<uint8_t*>(&salt), sizeof(salt), N, 78*4d7e907cSAndroid Build Coastguard Worker r, p, signature, signature_length); 79*4d7e907cSAndroid Build Coastguard Worker } 80*4d7e907cSAndroid Build Coastguard Worker GetRandom(void * random,uint32_t requested_length)81*4d7e907cSAndroid Build Coastguard Worker virtual void GetRandom(void* random, uint32_t requested_length) const { 82*4d7e907cSAndroid Build Coastguard Worker if (random == NULL) return; 83*4d7e907cSAndroid Build Coastguard Worker RAND_pseudo_bytes((uint8_t*)random, requested_length); 84*4d7e907cSAndroid Build Coastguard Worker } 85*4d7e907cSAndroid Build Coastguard Worker ComputeSignature(uint8_t * signature,uint32_t signature_length,const uint8_t *,uint32_t,const uint8_t *,const uint32_t)86*4d7e907cSAndroid Build Coastguard Worker virtual void ComputeSignature(uint8_t* signature, uint32_t signature_length, const uint8_t*, 87*4d7e907cSAndroid Build Coastguard Worker uint32_t, const uint8_t*, const uint32_t) const { 88*4d7e907cSAndroid Build Coastguard Worker if (signature == NULL) return; 89*4d7e907cSAndroid Build Coastguard Worker memset(signature, 0, signature_length); 90*4d7e907cSAndroid Build Coastguard Worker } 91*4d7e907cSAndroid Build Coastguard Worker GetMillisecondsSinceBoot()92*4d7e907cSAndroid Build Coastguard Worker virtual uint64_t GetMillisecondsSinceBoot() const { 93*4d7e907cSAndroid Build Coastguard Worker struct timespec time; 94*4d7e907cSAndroid Build Coastguard Worker int res = clock_gettime(CLOCK_BOOTTIME, &time); 95*4d7e907cSAndroid Build Coastguard Worker if (res < 0) return 0; 96*4d7e907cSAndroid Build Coastguard Worker return (time.tv_sec * 1000) + (time.tv_nsec / 1000 / 1000); 97*4d7e907cSAndroid Build Coastguard Worker } 98*4d7e907cSAndroid Build Coastguard Worker IsHardwareBacked()99*4d7e907cSAndroid Build Coastguard Worker virtual bool IsHardwareBacked() const { return false; } 100*4d7e907cSAndroid Build Coastguard Worker GetFailureRecord(uint32_t uid,secure_id_t user_id,failure_record_t * record,bool)101*4d7e907cSAndroid Build Coastguard Worker virtual bool GetFailureRecord(uint32_t uid, secure_id_t user_id, failure_record_t* record, 102*4d7e907cSAndroid Build Coastguard Worker bool /* secure */) { 103*4d7e907cSAndroid Build Coastguard Worker failure_record_t* stored = &failure_map_[uid]; 104*4d7e907cSAndroid Build Coastguard Worker if (user_id != stored->secure_user_id) { 105*4d7e907cSAndroid Build Coastguard Worker stored->secure_user_id = user_id; 106*4d7e907cSAndroid Build Coastguard Worker stored->last_checked_timestamp = 0; 107*4d7e907cSAndroid Build Coastguard Worker stored->failure_counter = 0; 108*4d7e907cSAndroid Build Coastguard Worker } 109*4d7e907cSAndroid Build Coastguard Worker memcpy(record, stored, sizeof(*record)); 110*4d7e907cSAndroid Build Coastguard Worker return true; 111*4d7e907cSAndroid Build Coastguard Worker } 112*4d7e907cSAndroid Build Coastguard Worker ClearFailureRecord(uint32_t uid,secure_id_t user_id,bool)113*4d7e907cSAndroid Build Coastguard Worker virtual bool ClearFailureRecord(uint32_t uid, secure_id_t user_id, bool /* secure */) { 114*4d7e907cSAndroid Build Coastguard Worker failure_record_t* stored = &failure_map_[uid]; 115*4d7e907cSAndroid Build Coastguard Worker stored->secure_user_id = user_id; 116*4d7e907cSAndroid Build Coastguard Worker stored->last_checked_timestamp = 0; 117*4d7e907cSAndroid Build Coastguard Worker stored->failure_counter = 0; 118*4d7e907cSAndroid Build Coastguard Worker return true; 119*4d7e907cSAndroid Build Coastguard Worker } 120*4d7e907cSAndroid Build Coastguard Worker WriteFailureRecord(uint32_t uid,failure_record_t * record,bool)121*4d7e907cSAndroid Build Coastguard Worker virtual bool WriteFailureRecord(uint32_t uid, failure_record_t* record, bool /* secure */) { 122*4d7e907cSAndroid Build Coastguard Worker failure_map_[uid] = *record; 123*4d7e907cSAndroid Build Coastguard Worker return true; 124*4d7e907cSAndroid Build Coastguard Worker } 125*4d7e907cSAndroid Build Coastguard Worker ComputeFastHash(const SizedBuffer & password,uint64_t salt)126*4d7e907cSAndroid Build Coastguard Worker fast_hash_t ComputeFastHash(const SizedBuffer& password, uint64_t salt) { 127*4d7e907cSAndroid Build Coastguard Worker fast_hash_t fast_hash; 128*4d7e907cSAndroid Build Coastguard Worker size_t digest_size = password.size() + sizeof(salt); 129*4d7e907cSAndroid Build Coastguard Worker std::unique_ptr<uint8_t[]> digest(new uint8_t[digest_size]); 130*4d7e907cSAndroid Build Coastguard Worker memcpy(digest.get(), &salt, sizeof(salt)); 131*4d7e907cSAndroid Build Coastguard Worker memcpy(digest.get() + sizeof(salt), password.Data<uint8_t>(), password.size()); 132*4d7e907cSAndroid Build Coastguard Worker 133*4d7e907cSAndroid Build Coastguard Worker SHA256(digest.get(), digest_size, (uint8_t*)&fast_hash.digest); 134*4d7e907cSAndroid Build Coastguard Worker 135*4d7e907cSAndroid Build Coastguard Worker fast_hash.salt = salt; 136*4d7e907cSAndroid Build Coastguard Worker return fast_hash; 137*4d7e907cSAndroid Build Coastguard Worker } 138*4d7e907cSAndroid Build Coastguard Worker VerifyFast(const fast_hash_t & fast_hash,const SizedBuffer & password)139*4d7e907cSAndroid Build Coastguard Worker bool VerifyFast(const fast_hash_t& fast_hash, const SizedBuffer& password) { 140*4d7e907cSAndroid Build Coastguard Worker fast_hash_t computed = ComputeFastHash(password, fast_hash.salt); 141*4d7e907cSAndroid Build Coastguard Worker return memcmp(computed.digest, fast_hash.digest, SHA256_DIGEST_LENGTH) == 0; 142*4d7e907cSAndroid Build Coastguard Worker } 143*4d7e907cSAndroid Build Coastguard Worker DoVerify(const password_handle_t * expected_handle,const SizedBuffer & password)144*4d7e907cSAndroid Build Coastguard Worker bool DoVerify(const password_handle_t* expected_handle, const SizedBuffer& password) { 145*4d7e907cSAndroid Build Coastguard Worker uint64_t user_id = android::base::get_unaligned<secure_id_t>(&expected_handle->user_id); 146*4d7e907cSAndroid Build Coastguard Worker FastHashMap::const_iterator it = fast_hash_map_.find(user_id); 147*4d7e907cSAndroid Build Coastguard Worker if (it != fast_hash_map_.end() && VerifyFast(it->second, password)) { 148*4d7e907cSAndroid Build Coastguard Worker return true; 149*4d7e907cSAndroid Build Coastguard Worker } else { 150*4d7e907cSAndroid Build Coastguard Worker if (GateKeeper::DoVerify(expected_handle, password)) { 151*4d7e907cSAndroid Build Coastguard Worker uint64_t salt; 152*4d7e907cSAndroid Build Coastguard Worker GetRandom(&salt, sizeof(salt)); 153*4d7e907cSAndroid Build Coastguard Worker fast_hash_map_[user_id] = ComputeFastHash(password, salt); 154*4d7e907cSAndroid Build Coastguard Worker return true; 155*4d7e907cSAndroid Build Coastguard Worker } 156*4d7e907cSAndroid Build Coastguard Worker } 157*4d7e907cSAndroid Build Coastguard Worker 158*4d7e907cSAndroid Build Coastguard Worker return false; 159*4d7e907cSAndroid Build Coastguard Worker } 160*4d7e907cSAndroid Build Coastguard Worker 161*4d7e907cSAndroid Build Coastguard Worker private: 162*4d7e907cSAndroid Build Coastguard Worker typedef std::unordered_map<uint32_t, failure_record_t> FailureRecordMap; 163*4d7e907cSAndroid Build Coastguard Worker typedef std::unordered_map<uint64_t, fast_hash_t> FastHashMap; 164*4d7e907cSAndroid Build Coastguard Worker 165*4d7e907cSAndroid Build Coastguard Worker std::unique_ptr<uint8_t[]> key_; 166*4d7e907cSAndroid Build Coastguard Worker FailureRecordMap failure_map_; 167*4d7e907cSAndroid Build Coastguard Worker FastHashMap fast_hash_map_; 168*4d7e907cSAndroid Build Coastguard Worker }; 169*4d7e907cSAndroid Build Coastguard Worker } // namespace gatekeeper 170*4d7e907cSAndroid Build Coastguard Worker 171*4d7e907cSAndroid Build Coastguard Worker #endif // SOFT_GATEKEEPER_H_ 172