mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-14 22:56:12 -04:00
Add ED25519 Keypair generator utilities to signer
PiperOrigin-RevId: 538034774
This commit is contained in:
committed by
Copybara-Service
parent
4835ae4293
commit
5917c87e73
@@ -14,12 +14,15 @@
|
||||
|
||||
#include "internal/crypto/ed25519.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/strings/str_format.h"
|
||||
#include "internal/crypto/random.h"
|
||||
#include <openssl/base.h>
|
||||
#include <openssl/evp.h>
|
||||
|
||||
namespace crypto {
|
||||
@@ -27,6 +30,13 @@ namespace crypto {
|
||||
constexpr size_t kEd25519SignatureSize = 64;
|
||||
constexpr size_t kEd25519PrivateKeySize = 32;
|
||||
constexpr size_t kEd25519PublicKeySize = 32;
|
||||
constexpr size_t kEd25519KeySeedSize = 32;
|
||||
|
||||
// Keypair
|
||||
Ed25519KeyPair::~Ed25519KeyPair() {
|
||||
memset(private_key.data(), 0, private_key.size());
|
||||
memset(public_key.data(), 0, public_key.size());
|
||||
}
|
||||
|
||||
// Signer
|
||||
absl::StatusOr<Ed25519Signer> Ed25519Signer::Create(std::string private_key) {
|
||||
@@ -47,6 +57,51 @@ absl::StatusOr<Ed25519Signer> Ed25519Signer::Create(std::string private_key) {
|
||||
return Ed25519Signer(std::move(priv_key));
|
||||
}
|
||||
|
||||
absl::StatusOr<Ed25519KeyPair> Ed25519Signer::CreateNewKeyPair(
|
||||
absl::string_view key_seed) {
|
||||
if (key_seed.length() != kEd25519KeySeedSize) {
|
||||
return absl::InvalidArgumentError(absl::StrFormat(
|
||||
"Only acceptable key seed length is %d", kEd25519KeySeedSize));
|
||||
}
|
||||
CryptoKeyUniquePtr priv_key(EVP_PKEY_new_raw_private_key(
|
||||
EVP_PKEY_ED25519, /*unused=*/nullptr,
|
||||
reinterpret_cast<const uint8_t *>(key_seed.data()), kEd25519KeySeedSize));
|
||||
if (priv_key == nullptr) {
|
||||
return absl::InternalError("EVP_PKEY_new_raw_private_key failed");
|
||||
}
|
||||
Ed25519KeyPair key_pair;
|
||||
key_pair.private_key.resize(kEd25519PrivateKeySize);
|
||||
key_pair.public_key.resize(kEd25519PublicKeySize);
|
||||
uint8_t *priv_key_ptr = reinterpret_cast<uint8_t *>(&key_pair.private_key[0]);
|
||||
uint8_t *pub_key_ptr = reinterpret_cast<uint8_t *>(&key_pair.public_key[0]);
|
||||
size_t len = kEd25519PrivateKeySize;
|
||||
if (EVP_PKEY_get_raw_private_key(priv_key.get(), priv_key_ptr, &len) != 1) {
|
||||
return absl::InternalError("EVP_PKEY_get_raw_private_key failed");
|
||||
}
|
||||
if (len != kEd25519PrivateKeySize) {
|
||||
return absl::InternalError(
|
||||
absl::StrCat("Invalid private key size; expected ",
|
||||
kEd25519PrivateKeySize, " got ", len));
|
||||
}
|
||||
len = kEd25519PublicKeySize;
|
||||
if (EVP_PKEY_get_raw_public_key(priv_key.get(), pub_key_ptr, &len) != 1) {
|
||||
return absl::InternalError("EVP_PKEY_get_raw_public_key failed");
|
||||
}
|
||||
if (len != kEd25519PublicKeySize) {
|
||||
return absl::InternalError(
|
||||
absl::StrCat("Invalid public key size; expected ",
|
||||
kEd25519PublicKeySize, " got ", len));
|
||||
}
|
||||
return key_pair;
|
||||
}
|
||||
|
||||
absl::StatusOr<Ed25519KeyPair> Ed25519Signer::CreateNewKeyPair() {
|
||||
uint8_t key_seed[kEd25519KeySeedSize] = {0};
|
||||
RandBytes(key_seed, kEd25519KeySeedSize);
|
||||
return CreateNewKeyPair(
|
||||
std::string(reinterpret_cast<char *>(key_seed), kEd25519KeySeedSize));
|
||||
}
|
||||
|
||||
Ed25519Signer::Ed25519Signer(CryptoKeyUniquePtr private_key) {
|
||||
private_key_ = std::move(private_key);
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#ifndef THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_ED25519_H_
|
||||
#define THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_ED25519_H_
|
||||
|
||||
#include <cstring>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
@@ -41,9 +42,18 @@ using CryptoKeyUniquePtr = std::unique_ptr<EVP_PKEY, Ed25519KeyFree>;
|
||||
using CryptoMdCtxUniquePtr = std::unique_ptr<EVP_MD_CTX, Ed25519MdCtxFree>;
|
||||
#endif
|
||||
|
||||
struct Ed25519KeyPair {
|
||||
~Ed25519KeyPair();
|
||||
std::string private_key;
|
||||
std::string public_key;
|
||||
};
|
||||
|
||||
class CRYPTO_EXPORT Ed25519Signer {
|
||||
public:
|
||||
static absl::StatusOr<Ed25519Signer> Create(std::string private_key);
|
||||
static absl::StatusOr<Ed25519KeyPair> CreateNewKeyPair(
|
||||
absl::string_view key_seed);
|
||||
static absl::StatusOr<Ed25519KeyPair> CreateNewKeyPair();
|
||||
std::optional<std::string> Sign(absl::string_view data);
|
||||
|
||||
private:
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
namespace crypto {
|
||||
namespace {
|
||||
|
||||
using ::absl::StatusCode;
|
||||
using ::testing::status::StatusIs;
|
||||
|
||||
// From
|
||||
@@ -82,8 +83,55 @@ TEST(Ed25519SignerTest, RejectsBadKeyLength) {
|
||||
"6218a1a38da47ed00230f0580816ed13ba3303ac5deb91154890802570");
|
||||
ASSERT_EQ(priv.size(), 65);
|
||||
auto signer = Ed25519Signer::Create(priv);
|
||||
EXPECT_THAT(signer,
|
||||
testing::status::StatusIs(absl::StatusCode::kInvalidArgument));
|
||||
EXPECT_THAT(signer, StatusIs(StatusCode::kInvalidArgument));
|
||||
}
|
||||
|
||||
// Wycheproof vectors
|
||||
TEST(Ed25519SignerTest, NewEd25519KeyValidSeed1) {
|
||||
std::string private_key = absl::HexStringToBytes(
|
||||
"add4bb8103785baf9ac534258e8aaf65f5f1adb5ef5f3df19bb80ab989c4d64b");
|
||||
std::string public_key = absl::HexStringToBytes(
|
||||
"7d4d0e7f6153a69b6242b522abbee685fda4420f8834b108c3bdae369ef549fa");
|
||||
auto key = Ed25519Signer::CreateNewKeyPair(private_key);
|
||||
ASSERT_OK(key);
|
||||
EXPECT_EQ(key->public_key, public_key);
|
||||
EXPECT_EQ(key->private_key, private_key);
|
||||
}
|
||||
|
||||
TEST(Ed25519SignerTest, NewEd25519KeyValidSeed2) {
|
||||
std::string private_key = absl::HexStringToBytes(
|
||||
"0a23a20072891237aa0864b5765139514908787878cd77135a0059881d313f00");
|
||||
std::string public_key = absl::HexStringToBytes(
|
||||
"a12c2beb77265f2aac953b5009349d94155a03ada416aad451319480e983ca4c");
|
||||
auto key = Ed25519Signer::CreateNewKeyPair(private_key);
|
||||
ASSERT_OK(key);
|
||||
EXPECT_EQ(key->public_key, public_key);
|
||||
EXPECT_EQ(key->private_key, private_key);
|
||||
}
|
||||
|
||||
TEST(Ed25519SignerTest, NewEd25519KeyValidSeed3) {
|
||||
std::string private_key = absl::HexStringToBytes(
|
||||
"4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb");
|
||||
std::string public_key = absl::HexStringToBytes(
|
||||
"3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c");
|
||||
auto key = Ed25519Signer::CreateNewKeyPair(private_key);
|
||||
ASSERT_OK(key);
|
||||
EXPECT_EQ(key->public_key, public_key);
|
||||
EXPECT_EQ(key->private_key, private_key);
|
||||
}
|
||||
|
||||
TEST(Ed25519SignerTest, NewEd25519KeyInvalidSeed) {
|
||||
std::string valid_seed = absl::HexStringToBytes(
|
||||
"000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f");
|
||||
// Seed that is too small.
|
||||
for (int i = 0; i < 32; i++) {
|
||||
EXPECT_THAT(Ed25519Signer::CreateNewKeyPair(valid_seed.substr(0, i)),
|
||||
StatusIs(StatusCode::kInvalidArgument));
|
||||
}
|
||||
// Seed that is too large.
|
||||
std::string large_seed = absl::StrCat(valid_seed, "a");
|
||||
EXPECT_THAT(Ed25519Signer::CreateNewKeyPair(large_seed),
|
||||
StatusIs(StatusCode::kInvalidArgument));
|
||||
}
|
||||
|
||||
TEST(Ed25519VerifierTest, CanVerifyCorrect1) {
|
||||
@@ -138,7 +186,7 @@ TEST(Ed25519VerifierTest, DoesNotVerifyBadSignature) {
|
||||
"8a284743a445e3680d7db5ac3ac18ff"
|
||||
"9b538d16f290ae67f760984dc6594a7c15e97"
|
||||
"16ed28dc027beceea1ec40a80")),
|
||||
StatusIs(absl::StatusCode::kInvalidArgument));
|
||||
StatusIs(StatusCode::kInvalidArgument));
|
||||
}
|
||||
|
||||
TEST(Ed25519VerifierTest, RejectsBadKeyLength) {
|
||||
@@ -146,7 +194,20 @@ TEST(Ed25519VerifierTest, RejectsBadKeyLength) {
|
||||
"fc51cd8e6218a1a38da47ed00230f0580816ed13ba3303ac5deb91154890802570");
|
||||
ASSERT_EQ(pub.size(), 33);
|
||||
auto verifier = Ed25519Verifier::Create(pub);
|
||||
EXPECT_THAT(verifier, StatusIs(absl::StatusCode::kInvalidArgument));
|
||||
EXPECT_THAT(verifier, StatusIs(StatusCode::kInvalidArgument));
|
||||
}
|
||||
|
||||
TEST(Ed25519SignerVerifierTest, NewKeypairFromRandomSeedRoundtrip) {
|
||||
auto key_pair = Ed25519Signer::CreateNewKeyPair();
|
||||
ASSERT_NE(key_pair->private_key, std::string(32, 0));
|
||||
auto signer = Ed25519Signer::Create(
|
||||
absl::StrCat(key_pair->private_key, key_pair->public_key));
|
||||
ASSERT_OK(signer);
|
||||
auto verifier = Ed25519Verifier::Create(key_pair->public_key);
|
||||
ASSERT_OK(verifier);
|
||||
auto signature = signer->Sign("hello world");
|
||||
ASSERT_TRUE(signature.has_value());
|
||||
EXPECT_OK(verifier->Verify("hello world", *signature));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Reference in New Issue
Block a user