Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c00f64be authored by Siarhei Vishniakou's avatar Siarhei Vishniakou Committed by Android (Google) Code Review
Browse files

Merge "Add HmacKeyManager to InputDispatcher"

parents b2546a39 342c9270
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ cc_library_shared {
        "libinputreporter",
        "libinputreader",
        "libbinder",
        "libcrypto",
        "libcutils",
        "libhidlbase",
        "libinput",
+1 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ cc_library_static {
    ],
    shared_libs: [
        "libbase",
        "libcrypto",
        "libcutils",
        "libinput",
        "libinputreporter",
+51 −0
Original line number Diff line number Diff line
@@ -61,6 +61,8 @@ static constexpr bool DEBUG_FOCUS = false;
#include <android-base/stringprintf.h>
#include <binder/Binder.h>
#include <log/log.h>
#include <openssl/hmac.h>
#include <openssl/rand.h>
#include <powermanager/PowerManager.h>
#include <utils/Trace.h>

@@ -325,6 +327,55 @@ static std::unique_ptr<DispatchEntry> createDispatchEntry(const InputTarget& inp
    return dispatchEntry;
}

static std::array<uint8_t, 128> getRandomKey() {
    std::array<uint8_t, 128> key;
    if (RAND_bytes(key.data(), key.size()) != 1) {
        LOG_ALWAYS_FATAL("Can't generate HMAC key");
    }
    return key;
}

// --- HmacKeyManager ---

HmacKeyManager::HmacKeyManager() : mHmacKey(getRandomKey()) {}

std::array<uint8_t, 32> HmacKeyManager::sign(const VerifiedInputEvent& event) const {
    size_t size;
    switch (event.type) {
        case VerifiedInputEvent::Type::KEY: {
            size = sizeof(VerifiedKeyEvent);
            break;
        }
        case VerifiedInputEvent::Type::MOTION: {
            size = sizeof(VerifiedMotionEvent);
            break;
        }
    }
    std::vector<uint8_t> data;
    const uint8_t* start = reinterpret_cast<const uint8_t*>(&event);
    data.assign(start, start + size);
    return sign(data);
}

std::array<uint8_t, 32> HmacKeyManager::sign(const std::vector<uint8_t>& data) const {
    // SHA256 always generates 32-bytes result
    std::array<uint8_t, 32> hash;
    unsigned int hashLen = 0;
    uint8_t* result = HMAC(EVP_sha256(), mHmacKey.data(), mHmacKey.size(), data.data(), data.size(),
                           hash.data(), &hashLen);
    if (result == nullptr) {
        ALOGE("Could not sign the data using HMAC");
        return INVALID_HMAC;
    }

    if (hashLen != hash.size()) {
        ALOGE("HMAC-SHA256 has unexpected length");
        return INVALID_HMAC;
    }

    return hash;
}

// --- InputDispatcher ---

InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy)
+10 −0
Original line number Diff line number Diff line
@@ -56,6 +56,16 @@ namespace android::inputdispatcher {

class Connection;

class HmacKeyManager {
public:
    HmacKeyManager();
    std::array<uint8_t, 32> sign(const VerifiedInputEvent& event) const;

private:
    std::array<uint8_t, 32> sign(const std::vector<uint8_t>& data) const;
    const std::array<uint8_t, 128> mHmacKey;
};

/* Dispatches events to input targets.  Some functions of the input dispatcher, such as
 * identifying input targets, are controlled by a separate policy object.
 *
+75 −0
Original line number Diff line number Diff line
@@ -43,6 +43,18 @@ struct PointF {
    float y;
};

/**
 * Return a DOWN key event with KEYCODE_A.
 */
static KeyEvent getTestKeyEvent() {
    KeyEvent event;

    event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE, INVALID_HMAC,
                     AKEY_EVENT_ACTION_DOWN, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME,
                     ARBITRARY_TIME);
    return event;
}

// --- FakeInputDispatcherPolicy ---

class FakeInputDispatcherPolicy : public InputDispatcherPolicyInterface {
@@ -197,6 +209,69 @@ private:
    }
};

// --- HmacKeyManagerTest ---

class HmacKeyManagerTest : public testing::Test {
protected:
    HmacKeyManager mHmacKeyManager;
};

/**
 * Ensure that separate calls to sign the same data are generating the same key.
 * We avoid asserting against INVALID_HMAC. Since the key is random, there is a non-zero chance
 * that a specific key and data combination would produce INVALID_HMAC, which would cause flaky
 * tests.
 */
TEST_F(HmacKeyManagerTest, GeneratedHmac_IsConsistent) {
    KeyEvent event = getTestKeyEvent();
    VerifiedKeyEvent verifiedEvent = verifiedKeyEventFromKeyEvent(event);

    std::array<uint8_t, 32> hmac1 = mHmacKeyManager.sign(verifiedEvent);
    std::array<uint8_t, 32> hmac2 = mHmacKeyManager.sign(verifiedEvent);
    ASSERT_EQ(hmac1, hmac2);
}

/**
 * Ensure that changes in VerifiedKeyEvent produce a different hmac.
 */
TEST_F(HmacKeyManagerTest, GeneratedHmac_ChangesWhenFieldsChange) {
    KeyEvent event = getTestKeyEvent();
    VerifiedKeyEvent verifiedEvent = verifiedKeyEventFromKeyEvent(event);
    std::array<uint8_t, 32> initialHmac = mHmacKeyManager.sign(verifiedEvent);

    verifiedEvent.deviceId += 1;
    ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent));

    verifiedEvent.source += 1;
    ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent));

    verifiedEvent.eventTimeNanos += 1;
    ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent));

    verifiedEvent.displayId += 1;
    ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent));

    verifiedEvent.action += 1;
    ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent));

    verifiedEvent.downTimeNanos += 1;
    ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent));

    verifiedEvent.flags += 1;
    ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent));

    verifiedEvent.keyCode += 1;
    ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent));

    verifiedEvent.scanCode += 1;
    ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent));

    verifiedEvent.metaState += 1;
    ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent));

    verifiedEvent.repeatCount += 1;
    ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent));
}

// --- InputDispatcherTest ---