blob: fdc07f1f1e3ec21c1a1fdbc3efaed77c773b3010 [file] [log] [blame]
/*
* 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