331 lines
14 KiB
C++
331 lines
14 KiB
C++
/*
|
|
* Copyright 2020 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#define LOG_TAG "AdbPairingAuthTest"
|
|
|
|
#include <gtest/gtest.h>
|
|
|
|
#include <adb/pairing/pairing_auth.h>
|
|
#include <android-base/endian.h>
|
|
|
|
namespace adb {
|
|
namespace pairing {
|
|
|
|
static void PairingAuthDeleter(PairingAuthCtx* p) {
|
|
pairing_auth_destroy(p);
|
|
}
|
|
|
|
class AdbPairingAuthTest : public testing::Test {
|
|
protected:
|
|
virtual void SetUp() override {}
|
|
|
|
virtual void TearDown() override {}
|
|
|
|
using PairingAuthUniquePtr = std::unique_ptr<PairingAuthCtx, decltype(&PairingAuthDeleter)>;
|
|
|
|
PairingAuthUniquePtr makeClient(std::vector<uint8_t> pswd) {
|
|
return PairingAuthUniquePtr(pairing_auth_client_new(pswd.data(), pswd.size()),
|
|
PairingAuthDeleter);
|
|
}
|
|
|
|
PairingAuthUniquePtr makeServer(std::vector<uint8_t> pswd) {
|
|
return PairingAuthUniquePtr(pairing_auth_server_new(pswd.data(), pswd.size()),
|
|
PairingAuthDeleter);
|
|
}
|
|
};
|
|
|
|
TEST_F(AdbPairingAuthTest, EmptyPassword) {
|
|
// Context creation should fail if password is empty
|
|
PairingAuthUniquePtr client(nullptr, PairingAuthDeleter);
|
|
ASSERT_DEATH(
|
|
{
|
|
client = PairingAuthUniquePtr(pairing_auth_client_new(nullptr, 0),
|
|
PairingAuthDeleter);
|
|
},
|
|
"");
|
|
ASSERT_DEATH(
|
|
{
|
|
client = PairingAuthUniquePtr(pairing_auth_client_new(nullptr, 2),
|
|
PairingAuthDeleter);
|
|
},
|
|
"");
|
|
ASSERT_DEATH(
|
|
{
|
|
uint8_t p;
|
|
client = PairingAuthUniquePtr(pairing_auth_client_new(&p, 0), PairingAuthDeleter);
|
|
},
|
|
"");
|
|
}
|
|
|
|
TEST_F(AdbPairingAuthTest, ValidPassword) {
|
|
const char* kPswd = "password";
|
|
std::vector<uint8_t> pswd(kPswd, kPswd + sizeof(kPswd));
|
|
auto client = makeClient(pswd);
|
|
auto server = makeServer(pswd);
|
|
|
|
ASSERT_NE(nullptr, client);
|
|
ASSERT_NE(nullptr, server);
|
|
|
|
// msg should not be empty.
|
|
{
|
|
size_t msg_size = pairing_auth_msg_size(client.get());
|
|
std::vector<uint8_t> buf(msg_size);
|
|
ASSERT_GT(msg_size, 0);
|
|
pairing_auth_get_spake2_msg(client.get(), buf.data());
|
|
}
|
|
{
|
|
size_t msg_size = pairing_auth_msg_size(server.get());
|
|
std::vector<uint8_t> buf(msg_size);
|
|
ASSERT_GT(msg_size, 0);
|
|
pairing_auth_get_spake2_msg(server.get(), buf.data());
|
|
}
|
|
}
|
|
|
|
TEST_F(AdbPairingAuthTest, NoInitCipher) {
|
|
// Register a non-empty password, but not the peer's msg.
|
|
// You should not be able to encrypt/decrypt messages.
|
|
const char* kPswd = "password";
|
|
std::vector<uint8_t> pswd(kPswd, kPswd + sizeof(kPswd));
|
|
std::vector<uint8_t> data{0x01, 0x02, 0x03};
|
|
uint8_t outbuf[256];
|
|
size_t outsize;
|
|
|
|
// All other functions should crash if cipher hasn't been initialized.
|
|
ASSERT_DEATH(
|
|
{
|
|
auto server = makeServer(pswd);
|
|
pairing_auth_init_cipher(server.get(), nullptr, 0);
|
|
},
|
|
"");
|
|
ASSERT_DEATH(
|
|
{
|
|
auto server = makeServer(pswd);
|
|
pairing_auth_encrypt(server.get(), data.data(), data.size(), outbuf, &outsize);
|
|
},
|
|
"");
|
|
ASSERT_DEATH(
|
|
{
|
|
auto server = makeServer(pswd);
|
|
pairing_auth_decrypt(server.get(), data.data(), data.size(), outbuf, &outsize);
|
|
},
|
|
"");
|
|
ASSERT_DEATH(
|
|
{
|
|
auto server = makeServer(pswd);
|
|
pairing_auth_safe_decrypted_size(server.get(), data.data(), data.size());
|
|
},
|
|
"");
|
|
ASSERT_DEATH(
|
|
{
|
|
auto server = makeServer(pswd);
|
|
pairing_auth_safe_encrypted_size(server.get(), data.size());
|
|
},
|
|
"");
|
|
}
|
|
|
|
TEST_F(AdbPairingAuthTest, DifferentPasswords) {
|
|
// Register different passwords and then exchange the msgs. The
|
|
// encryption should succeed, but the decryption should fail, since the
|
|
// ciphers have been initialized with different keys.
|
|
auto client = makeClient({0x01, 0x02, 0x03});
|
|
std::vector<uint8_t> client_msg(pairing_auth_msg_size(client.get()));
|
|
ASSERT_FALSE(client_msg.empty());
|
|
pairing_auth_get_spake2_msg(client.get(), client_msg.data());
|
|
|
|
auto server = makeServer({0x01, 0x02, 0x04});
|
|
std::vector<uint8_t> server_msg(pairing_auth_msg_size(server.get()));
|
|
ASSERT_FALSE(server_msg.empty());
|
|
pairing_auth_get_spake2_msg(server.get(), server_msg.data());
|
|
|
|
EXPECT_TRUE(pairing_auth_init_cipher(client.get(), server_msg.data(), server_msg.size()));
|
|
EXPECT_TRUE(pairing_auth_init_cipher(server.get(), client_msg.data(), client_msg.size()));
|
|
|
|
// We shouldn't be able to decrypt.
|
|
std::vector<uint8_t> msg{0x2a, 0x2b, 0x2c};
|
|
// Client encrypts, server can't decrypt
|
|
size_t out_size;
|
|
client_msg.resize(pairing_auth_safe_encrypted_size(client.get(), msg.size()));
|
|
ASSERT_GT(client_msg.size(), 0);
|
|
ASSERT_TRUE(pairing_auth_encrypt(client.get(), msg.data(), msg.size(), client_msg.data(),
|
|
&out_size));
|
|
ASSERT_GT(out_size, 0);
|
|
client_msg.resize(out_size);
|
|
|
|
server_msg.resize(
|
|
pairing_auth_safe_decrypted_size(server.get(), client_msg.data(), client_msg.size()));
|
|
ASSERT_GT(server_msg.size(), 0);
|
|
ASSERT_FALSE(pairing_auth_decrypt(server.get(), client_msg.data(), client_msg.size(),
|
|
server_msg.data(), &out_size));
|
|
|
|
// Server encrypts, client can't decrypt
|
|
server_msg.resize(pairing_auth_safe_encrypted_size(server.get(), msg.size()));
|
|
ASSERT_GT(server_msg.size(), 0);
|
|
ASSERT_TRUE(pairing_auth_encrypt(server.get(), msg.data(), msg.size(), server_msg.data(),
|
|
&out_size));
|
|
ASSERT_GT(out_size, 0);
|
|
server_msg.resize(out_size);
|
|
|
|
client_msg.resize(
|
|
pairing_auth_safe_decrypted_size(client.get(), server_msg.data(), server_msg.size()));
|
|
ASSERT_GT(client_msg.size(), 0);
|
|
ASSERT_FALSE(pairing_auth_decrypt(client.get(), server_msg.data(), server_msg.size(),
|
|
client_msg.data(), &out_size));
|
|
}
|
|
|
|
TEST_F(AdbPairingAuthTest, SamePasswords) {
|
|
// Register same password and then exchange the msgs. The
|
|
// encryption and decryption should succeed and have the same, unencrypted
|
|
// values.
|
|
std::vector<uint8_t> pswd{0x4f, 0x5a, 0x01, 0x46};
|
|
auto client = makeClient(pswd);
|
|
std::vector<uint8_t> client_msg(pairing_auth_msg_size(client.get()));
|
|
ASSERT_FALSE(client_msg.empty());
|
|
pairing_auth_get_spake2_msg(client.get(), client_msg.data());
|
|
|
|
auto server = makeServer(pswd);
|
|
std::vector<uint8_t> server_msg(pairing_auth_msg_size(server.get()));
|
|
ASSERT_FALSE(server_msg.empty());
|
|
pairing_auth_get_spake2_msg(server.get(), server_msg.data());
|
|
|
|
EXPECT_TRUE(pairing_auth_init_cipher(client.get(), server_msg.data(), server_msg.size()));
|
|
EXPECT_TRUE(pairing_auth_init_cipher(server.get(), client_msg.data(), client_msg.size()));
|
|
|
|
// We should be able to decrypt.
|
|
std::vector<uint8_t> msg{0x2a, 0x2b, 0x2c, 0xff, 0x45, 0x12, 0x33};
|
|
// Client encrypts, server decrypts
|
|
size_t out_size;
|
|
client_msg.resize(pairing_auth_safe_encrypted_size(client.get(), msg.size()));
|
|
ASSERT_GT(client_msg.size(), 0);
|
|
ASSERT_TRUE(pairing_auth_encrypt(client.get(), msg.data(), msg.size(), client_msg.data(),
|
|
&out_size));
|
|
ASSERT_GT(out_size, 0);
|
|
client_msg.resize(out_size);
|
|
|
|
server_msg.resize(
|
|
pairing_auth_safe_decrypted_size(server.get(), client_msg.data(), client_msg.size()));
|
|
ASSERT_GT(server_msg.size(), 0);
|
|
ASSERT_TRUE(pairing_auth_decrypt(server.get(), client_msg.data(), client_msg.size(),
|
|
server_msg.data(), &out_size));
|
|
ASSERT_EQ(out_size, msg.size());
|
|
EXPECT_EQ(memcmp(msg.data(), server_msg.data(), out_size), 0);
|
|
|
|
// Server encrypts, client decrypt
|
|
server_msg.resize(pairing_auth_safe_encrypted_size(server.get(), msg.size()));
|
|
ASSERT_GT(server_msg.size(), 0);
|
|
ASSERT_TRUE(pairing_auth_encrypt(server.get(), msg.data(), msg.size(), server_msg.data(),
|
|
&out_size));
|
|
ASSERT_GT(out_size, 0);
|
|
server_msg.resize(out_size);
|
|
|
|
client_msg.resize(
|
|
pairing_auth_safe_decrypted_size(client.get(), server_msg.data(), server_msg.size()));
|
|
ASSERT_GT(client_msg.size(), 0);
|
|
ASSERT_TRUE(pairing_auth_decrypt(client.get(), server_msg.data(), server_msg.size(),
|
|
client_msg.data(), &out_size));
|
|
ASSERT_EQ(out_size, msg.size());
|
|
EXPECT_EQ(memcmp(msg.data(), client_msg.data(), out_size), 0);
|
|
}
|
|
|
|
TEST_F(AdbPairingAuthTest, CorruptedPayload) {
|
|
// Do a matching password for both server/client, but let's fudge with the
|
|
// header payload field. The decryption should fail.
|
|
std::vector<uint8_t> pswd{0x4f, 0x5a, 0x01, 0x46};
|
|
auto client = makeClient(pswd);
|
|
std::vector<uint8_t> client_msg(pairing_auth_msg_size(client.get()));
|
|
ASSERT_FALSE(client_msg.empty());
|
|
pairing_auth_get_spake2_msg(client.get(), client_msg.data());
|
|
|
|
auto server = makeServer(pswd);
|
|
std::vector<uint8_t> server_msg(pairing_auth_msg_size(server.get()));
|
|
ASSERT_FALSE(server_msg.empty());
|
|
pairing_auth_get_spake2_msg(server.get(), server_msg.data());
|
|
|
|
EXPECT_TRUE(pairing_auth_init_cipher(client.get(), server_msg.data(), server_msg.size()));
|
|
EXPECT_TRUE(pairing_auth_init_cipher(server.get(), client_msg.data(), client_msg.size()));
|
|
|
|
std::vector<uint8_t> msg{0x2a, 0x2b, 0x2c, 0xff, 0x45, 0x12,
|
|
0x33, 0x45, 0x12, 0xea, 0xf2, 0xdb};
|
|
{
|
|
// Client encrypts whole msg, server decrypts msg. Should be fine.
|
|
size_t out_size;
|
|
client_msg.resize(pairing_auth_safe_encrypted_size(client.get(), msg.size()));
|
|
ASSERT_GT(client_msg.size(), 0);
|
|
ASSERT_TRUE(pairing_auth_encrypt(client.get(), msg.data(), msg.size(), client_msg.data(),
|
|
&out_size));
|
|
ASSERT_GT(out_size, 0);
|
|
client_msg.resize(out_size);
|
|
|
|
server_msg.resize(pairing_auth_safe_decrypted_size(server.get(), client_msg.data(),
|
|
client_msg.size()));
|
|
ASSERT_GT(server_msg.size(), 0);
|
|
ASSERT_TRUE(pairing_auth_decrypt(server.get(), client_msg.data(), client_msg.size(),
|
|
server_msg.data(), &out_size));
|
|
ASSERT_EQ(out_size, msg.size());
|
|
EXPECT_EQ(memcmp(msg.data(), server_msg.data(), out_size), 0);
|
|
}
|
|
{
|
|
// 1) Client encrypts msg
|
|
// 2) append some data to the encrypted msg
|
|
// 3) change the payload field
|
|
// 4) server tries to decrypt. It should fail.
|
|
size_t out_size;
|
|
client_msg.resize(pairing_auth_safe_encrypted_size(client.get(), msg.size()));
|
|
ASSERT_GT(client_msg.size(), 0);
|
|
ASSERT_TRUE(pairing_auth_encrypt(client.get(), msg.data(), msg.size(), client_msg.data(),
|
|
&out_size));
|
|
ASSERT_GT(out_size, 0);
|
|
client_msg.resize(out_size);
|
|
client_msg.push_back(0xaa);
|
|
// This requires knowledge of the layout of the data. payload is the
|
|
// first four bytes of the client_msg.
|
|
uint32_t* payload = reinterpret_cast<uint32_t*>(client_msg.data());
|
|
*payload = ntohl(*payload);
|
|
*payload = htonl(*payload + 1);
|
|
|
|
server_msg.resize(pairing_auth_safe_decrypted_size(server.get(), client_msg.data(),
|
|
client_msg.size()));
|
|
ASSERT_GT(server_msg.size(), 0);
|
|
ASSERT_FALSE(pairing_auth_decrypt(server.get(), client_msg.data(), client_msg.size(),
|
|
server_msg.data(), &out_size));
|
|
}
|
|
{
|
|
// 1) Client encrypts msg
|
|
// 3) decrement the payload field
|
|
// 4) server tries to decrypt. It should fail.
|
|
size_t out_size;
|
|
client_msg.resize(pairing_auth_safe_encrypted_size(client.get(), msg.size()));
|
|
ASSERT_GT(client_msg.size(), 0);
|
|
ASSERT_TRUE(pairing_auth_encrypt(client.get(), msg.data(), msg.size(), client_msg.data(),
|
|
&out_size));
|
|
ASSERT_GT(out_size, 0);
|
|
client_msg.resize(out_size);
|
|
// This requires knowledge of the layout of the data. payload is the
|
|
// first four bytes of the client_msg.
|
|
uint32_t* payload = reinterpret_cast<uint32_t*>(client_msg.data());
|
|
*payload = ntohl(*payload);
|
|
*payload = htonl(*payload - 1);
|
|
|
|
server_msg.resize(pairing_auth_safe_decrypted_size(server.get(), client_msg.data(),
|
|
client_msg.size()));
|
|
ASSERT_GT(server_msg.size(), 0);
|
|
ASSERT_FALSE(pairing_auth_decrypt(server.get(), client_msg.data(), client_msg.size(),
|
|
server_msg.data(), &out_size));
|
|
}
|
|
}
|
|
|
|
} // namespace pairing
|
|
} // namespace adb
|