mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-15 15:16:12 -04:00
250 lines
7.4 KiB
C++
250 lines
7.4 KiB
C++
// Copyright 2022 Google LLC
|
|
//
|
|
// 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
|
|
//
|
|
// https://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.
|
|
|
|
#include <openssl/bn.h>
|
|
#include <openssl/ec.h>
|
|
#include <openssl/evp.h>
|
|
#include <openssl/sha.h>
|
|
|
|
#include <cerrno>
|
|
#include <iomanip>
|
|
#include <iostream>
|
|
#include <memory>
|
|
#include <queue>
|
|
#include <sstream>
|
|
#include <string>
|
|
|
|
#include "fakes.h"
|
|
#include "nearby_platform_se.h"
|
|
|
|
static unsigned int random_value = 0;
|
|
static std::queue<uint8_t> random_sequence;
|
|
|
|
static std::unique_ptr<EVP_PKEY, void (*)(EVP_PKEY *)> anti_spoofing_key(
|
|
NULL, EVP_PKEY_free);
|
|
|
|
static std::string ArrayToString(const uint8_t *data, size_t length) {
|
|
std::stringstream output;
|
|
output << "0x" << std::hex << std::setfill('0') << std::setw(2);
|
|
for (int i = 0; i < length; i++) {
|
|
output << (unsigned)data[i];
|
|
}
|
|
return output.str();
|
|
}
|
|
|
|
// Generates a random number.
|
|
uint8_t nearby_platform_Rand() {
|
|
if (random_sequence.empty()) {
|
|
return random_value;
|
|
} else {
|
|
uint8_t v = random_sequence.front();
|
|
random_sequence.pop();
|
|
return v;
|
|
}
|
|
}
|
|
|
|
#ifdef NEARBY_FP_ENABLE_ADDITIONAL_DATA
|
|
static SHA256_CTX sha256_context;
|
|
|
|
nearby_platform_status nearby_platform_Sha256Start() {
|
|
SHA256_Init(&sha256_context);
|
|
return kNearbyStatusOK;
|
|
}
|
|
|
|
nearby_platform_status nearby_platform_Sha256Update(const void *data,
|
|
size_t length) {
|
|
SHA256_Update(&sha256_context, data, length);
|
|
return kNearbyStatusOK;
|
|
}
|
|
|
|
nearby_platform_status nearby_platform_Sha256Finish(uint8_t out[32]) {
|
|
SHA256_Final(out, &sha256_context);
|
|
return kNearbyStatusOK;
|
|
}
|
|
#endif /* NEARBY_FP_ENABLE_ADDITIONAL_DATA */
|
|
|
|
// Encrypts a data block with AES128 in ECB mode.
|
|
nearby_platform_status nearby_platform_Aes128Encrypt(const uint8_t input[16],
|
|
uint8_t output[16],
|
|
const uint8_t key[16]) {
|
|
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
|
|
int input_length = 16;
|
|
int output_length = 16;
|
|
|
|
EVP_EncryptInit(ctx, EVP_aes_128_ecb(), key, NULL);
|
|
|
|
if (1 !=
|
|
EVP_EncryptUpdate(ctx, output, &output_length, input, input_length)) {
|
|
return kNearbyStatusError;
|
|
}
|
|
|
|
EVP_CIPHER_CTX_free(ctx);
|
|
return kNearbyStatusOK;
|
|
}
|
|
|
|
// Encrypts a data block with AES128 in ECB mode.
|
|
nearby_platform_status nearby_platform_Aes128Decrypt(const uint8_t input[16],
|
|
uint8_t output[16],
|
|
const uint8_t key[16]) {
|
|
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
|
|
int input_length = 16;
|
|
int output_length = 16;
|
|
|
|
EVP_DecryptInit(ctx, EVP_aes_128_ecb(), key, NULL);
|
|
|
|
if (1 !=
|
|
EVP_DecryptUpdate(ctx, output, &output_length, input, input_length)) {
|
|
return kNearbyStatusError;
|
|
}
|
|
|
|
EVP_CIPHER_CTX_free(ctx);
|
|
return kNearbyStatusOK;
|
|
}
|
|
|
|
static EC_POINT *load_public_key(const uint8_t public_key[64]) {
|
|
BN_CTX *bn_ctx;
|
|
EC_KEY *key;
|
|
EC_POINT *point;
|
|
const EC_GROUP *group;
|
|
uint8_t oct_key[65];
|
|
|
|
oct_key[0] = 0x04;
|
|
memcpy(oct_key + 1, public_key, 64);
|
|
bn_ctx = BN_CTX_new();
|
|
key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
|
|
group = EC_KEY_get0_group(key);
|
|
point = EC_POINT_new(group);
|
|
if (1 != EC_POINT_oct2point(group, point, oct_key, sizeof(oct_key), bn_ctx))
|
|
return NULL;
|
|
BN_CTX_free(bn_ctx);
|
|
EC_KEY_free(key);
|
|
return point;
|
|
}
|
|
|
|
// Generates a shared sec256p1 secret using remote party public key and this
|
|
// device's private key.
|
|
nearby_platform_status nearby_platform_GenSec256r1Secret(
|
|
const uint8_t remote_party_public_key[64], uint8_t secret[32]) {
|
|
EVP_PKEY_CTX *ctx;
|
|
EVP_PKEY *peerkey;
|
|
EC_POINT *peer_point;
|
|
EC_KEY *ec_peer_key;
|
|
size_t secret_len;
|
|
|
|
/* Create the context for the shared secret derivation */
|
|
if (NULL == (ctx = EVP_PKEY_CTX_new(anti_spoofing_key.get(), NULL)))
|
|
return kNearbyStatusError;
|
|
|
|
/* Initialise */
|
|
if (1 != EVP_PKEY_derive_init(ctx)) return kNearbyStatusError;
|
|
|
|
if (NULL == (peer_point = load_public_key(remote_party_public_key)))
|
|
return kNearbyStatusError;
|
|
|
|
ec_peer_key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
|
|
|
|
if (1 != EC_KEY_set_public_key(ec_peer_key, peer_point))
|
|
return kNearbyStatusError;
|
|
|
|
peerkey = EVP_PKEY_new();
|
|
if (1 != EVP_PKEY_assign_EC_KEY(peerkey, ec_peer_key))
|
|
return kNearbyStatusError;
|
|
|
|
/* Provide the peer public key */
|
|
if (1 != EVP_PKEY_derive_set_peer(ctx, peerkey)) return kNearbyStatusError;
|
|
|
|
/* Determine buffer length for shared secret */
|
|
if (1 != EVP_PKEY_derive(ctx, NULL, &secret_len)) return kNearbyStatusError;
|
|
|
|
if (secret_len != 32) return kNearbyStatusError;
|
|
|
|
/* Derive the shared secret */
|
|
if (1 != (EVP_PKEY_derive(ctx, secret, &secret_len)))
|
|
return kNearbyStatusError;
|
|
|
|
EVP_PKEY_CTX_free(ctx);
|
|
EC_POINT_free(peer_point);
|
|
EVP_PKEY_free(peerkey);
|
|
|
|
std::cout << "Secret: " << ArrayToString(secret, 32) << std::endl;
|
|
return kNearbyStatusOK;
|
|
}
|
|
|
|
// Initializes secure element module
|
|
nearby_platform_status nearby_platform_SecureElementInit() {
|
|
random_value = 0;
|
|
random_sequence = std::queue<uint8_t>();
|
|
return kNearbyStatusOK;
|
|
}
|
|
|
|
void nearby_test_fakes_SetRandomNumber(unsigned int value) {
|
|
random_value = value;
|
|
}
|
|
|
|
void nearby_test_fakes_SetRandomNumberSequence(std::vector<uint8_t> &value) {
|
|
for (auto &v : value) random_sequence.push(v);
|
|
}
|
|
|
|
static BIGNUM *load_private_key(const uint8_t private_key[32]) {
|
|
uint8_t buffer[37];
|
|
buffer[0] = buffer[1] = buffer[2] = 0;
|
|
buffer[3] = 33;
|
|
buffer[4] = 0;
|
|
memcpy(buffer + 5, private_key, 32);
|
|
return BN_mpi2bn(buffer, sizeof(buffer), NULL);
|
|
}
|
|
|
|
nearby_platform_status nearby_test_fakes_SetAntiSpoofingKey(
|
|
const uint8_t private_key[32], const uint8_t public_key[64]) {
|
|
EC_KEY *key;
|
|
BIGNUM *prv;
|
|
EC_POINT *pub;
|
|
|
|
prv = load_private_key(private_key);
|
|
if (prv == NULL) return kNearbyStatusError;
|
|
pub = load_public_key(public_key);
|
|
if (pub == NULL) return kNearbyStatusError;
|
|
|
|
key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
|
|
|
|
if (1 != EC_KEY_set_private_key(key, prv)) return kNearbyStatusError;
|
|
if (1 != EC_KEY_set_public_key(key, pub)) return kNearbyStatusError;
|
|
|
|
anti_spoofing_key.reset(EVP_PKEY_new());
|
|
if (1 != EVP_PKEY_assign_EC_KEY(anti_spoofing_key.get(), key))
|
|
return kNearbyStatusError;
|
|
BN_free(prv);
|
|
EC_POINT_free(pub);
|
|
return kNearbyStatusOK;
|
|
}
|
|
|
|
nearby_platform_status nearby_test_fakes_GenSec256r1Secret(
|
|
const uint8_t remote_party_public_key[64], uint8_t secret[32]) {
|
|
return nearby_platform_GenSec256r1Secret(remote_party_public_key, secret);
|
|
}
|
|
|
|
nearby_platform_status nearby_test_fakes_Aes128Decrypt(
|
|
const uint8_t input[AES_MESSAGE_SIZE_BYTES],
|
|
uint8_t output[AES_MESSAGE_SIZE_BYTES],
|
|
const uint8_t key[AES_MESSAGE_SIZE_BYTES]) {
|
|
return nearby_platform_Aes128Decrypt(input, output, key);
|
|
}
|
|
|
|
nearby_platform_status nearby_test_fakes_Aes128Encrypt(
|
|
const uint8_t input[AES_MESSAGE_SIZE_BYTES],
|
|
uint8_t output[AES_MESSAGE_SIZE_BYTES],
|
|
const uint8_t key[AES_MESSAGE_SIZE_BYTES]) {
|
|
return nearby_platform_Aes128Encrypt(input, output, key);
|
|
}
|