Skip to content

Commit 9109752

Browse files
sergkaprovichturuslan
authored andcommitted
RSA provider (#29)
Signed-off-by: turuslan <[email protected]>
1 parent a93e615 commit 9109752

File tree

10 files changed

+490
-13
lines changed

10 files changed

+490
-13
lines changed
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/**
2+
* Copyright Soramitsu Co., Ltd. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
#ifndef LIBP2P_CRYPTO_RSA_PROVIDER_HPP
7+
#define LIBP2P_CRYPTO_RSA_PROVIDER_HPP
8+
9+
#include <gsl/span>
10+
#include <libp2p/outcome/outcome.hpp>
11+
#include <libp2p/crypto/rsa_types.hpp>
12+
13+
namespace libp2p::crypto::rsa {
14+
15+
/**
16+
* @class RSA provider interface
17+
*/
18+
class RsaProvider {
19+
public:
20+
/**
21+
* Sign a message using private key. Message digest calculated as SHA512
22+
* @param message - the source message as bytes sequence
23+
* @param private_key - private key bytes
24+
* @return signature as bytes sequence
25+
*/
26+
virtual outcome::result<Signature> sign(gsl::span<uint8_t> message,
27+
const PrivateKey &private_key) const = 0;
28+
29+
/**
30+
* @brief Verify signature for a message
31+
* @param message - signed data
32+
* @param signature - target for verifying
33+
* @param key - key for signature verifying
34+
* @return Result of the verification or error code
35+
*/
36+
virtual outcome::result<bool> verify(gsl::span<uint8_t> message,
37+
const Signature &signature,
38+
const PublicKey &key) const = 0;
39+
40+
virtual ~RsaProvider() = default;
41+
};
42+
}; // namespace libp2p::crypto::rsa
43+
44+
#endif // LIBP2P_CRYPTO_RSA_PROVIDER_HPP
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/**
2+
* Copyright Soramitsu Co., Ltd. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
#ifndef LIBP2P_CRYPTO_RSA_PROVIDER_IMPL_HPP
7+
#define LIBP2P_CRYPTO_RSA_PROVIDER_IMPL_HPP
8+
9+
#include <memory>
10+
11+
#include <openssl/rsa.h>
12+
#include <libp2p/crypto/error.hpp>
13+
#include <libp2p/crypto/rsa_provider.hpp>
14+
15+
namespace libp2p::crypto::rsa {
16+
17+
/**
18+
* @class RSA provider implementation declaration
19+
*/
20+
class RsaProviderImpl : public RsaProvider {
21+
public:
22+
outcome::result<Signature> sign(gsl::span<uint8_t> message,
23+
const PrivateKey &private_key) const override;
24+
25+
outcome::result<bool> verify(gsl::span<uint8_t> message,
26+
const Signature &signature,
27+
const PublicKey &key) const override;
28+
29+
private:
30+
/**
31+
* @brief Convert key to OpenSSL type
32+
* @param input_key - public key bytes
33+
* @return Converted key or error code
34+
*/
35+
static outcome::result<std::shared_ptr<X509_PUBKEY>> getPublicKeyFromBytes(
36+
const PublicKey &input_key);
37+
};
38+
}; // namespace libp2p::crypto::rsa
39+
40+
#endif // LIBP2P_CRYPTO_RSA_PROVIDER_IMPL_HPP

include/libp2p/crypto/rsa_types.hpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/**
2+
* Copyright Soramitsu Co., Ltd. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
#ifndef LIBP2P_CRYPTO_RSA_TYPES_HPP
7+
#define LIBP2P_CRYPTO_RSA_TYPES_HPP
8+
9+
#include <vector>
10+
11+
namespace libp2p::crypto::rsa {
12+
/**
13+
* @brief Common types
14+
*/
15+
using PrivateKey = std::vector<uint8_t>; /**< RSA private key */
16+
using PublicKey = std::vector<uint8_t>; /**< RSA public key */
17+
using Signature = std::vector<uint8_t>; /**< RSA signature of a message */
18+
19+
struct KeyPair {
20+
PrivateKey private_key; /**< RSA private key */
21+
PublicKey public_key; /**< RSA public key */
22+
23+
/**
24+
* @brief Comparing keypairs
25+
* @param other - second keypair to compare
26+
* @return true, if keypairs are equal
27+
*/
28+
bool operator==(const KeyPair &other) {
29+
return other.private_key == private_key && other.public_key == public_key;
30+
}
31+
32+
/**
33+
* @brief Comparing keypairs
34+
* @param other - second keypair to compare
35+
* @return true, if keypairs aren't equal
36+
*/
37+
bool operator!=(const KeyPair &other) {
38+
return !operator==(other);
39+
}
40+
};
41+
}; // namespace libp2p::crypto::rsa
42+
43+
#endif // LIBP2P_CRYPTO_RSA_TYPES_HPP

src/crypto/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ add_subdirectory(key_marshaller)
1212
add_subdirectory(key_validator)
1313
add_subdirectory(protobuf)
1414
add_subdirectory(random_generator)
15+
add_subdirectory(rsa_provider)
1516
add_subdirectory(secp256k1_provider)
1617
add_subdirectory(sha)
1718

src/crypto/crypto_provider/crypto_provider_impl.cpp

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -77,22 +77,14 @@ namespace libp2p::crypto {
7777
}
7878

7979
outcome::result<PublicKey> deriveRsa(const PrivateKey &key) {
80-
BIO *bio_private = BIO_new_mem_buf(
81-
static_cast<const void *>(key.data.data()), key.data.size());
82-
if (nullptr == bio_private) {
83-
return KeyGeneratorError::KEY_DERIVATION_FAILED;
84-
}
85-
auto free_bio =
86-
gsl::finally([bio_private]() { BIO_free_all(bio_private); });
87-
8880
const unsigned char *data_pointer = key.data.data();
8981
RSA *rsa = d2i_RSAPrivateKey(nullptr, &data_pointer, key.data.size());
9082
if (nullptr == rsa) {
9183
return KeyGeneratorError::KEY_DERIVATION_FAILED;
9284
}
9385
auto cleanup_rsa = gsl::finally([rsa]() { RSA_free(rsa); });
9486

95-
OUTCOME_TRY(public_bytes, detail::encodeKeyDer(rsa, i2d_RSAPublicKey));
87+
OUTCOME_TRY(public_bytes, detail::encodeKeyDer(rsa, i2d_RSA_PUBKEY));
9688

9789
return PublicKey{{key.type, std::move(public_bytes)}};
9890
}
@@ -170,10 +162,10 @@ namespace libp2p::crypto {
170162
* We encode the private key as a PKCS1 key using ASN.1 DER.
171163
*
172164
* according to openssl manual:
173-
* https://www.openssl.org/docs/man1.0.2/man3/i2d_RSAPublicKey.html
174-
* d2i_RSAPublicKey() and i2d_RSAPublicKey() decode and encode a PKCS#1
165+
* https://www.openssl.org/docs/man1.1.1/man3/i2d_RSA_PUBKEY.html
166+
* d2i_RSA_PUBKEY() and i2d_RSA_PUBKEY() decode and encode a PKIX
175167
*
176-
* https://www.openssl.org/docs/man1.0.2/man3/i2d_RSAPrivateKey.html
168+
* https://www.openssl.org/docs/man1.1.1/man3/i2d_RSAPrivateKey.html
177169
* d2i_RSAPrivateKey(), i2d_RSAPrivateKey() decode and encode a PKCS#1
178170
*/
179171
outcome::result<std::pair<CryptoProvider::Buffer, CryptoProvider::Buffer>>
@@ -207,7 +199,7 @@ namespace libp2p::crypto {
207199
return KeyGeneratorError::KEY_GENERATION_FAILED;
208200
}
209201

210-
OUTCOME_TRY(public_bytes, detail::encodeKeyDer(rsa, i2d_RSAPublicKey));
202+
OUTCOME_TRY(public_bytes, detail::encodeKeyDer(rsa, i2d_RSA_PUBKEY));
211203
OUTCOME_TRY(private_bytes, detail::encodeKeyDer(rsa, i2d_RSAPrivateKey));
212204

213205
return {std::move(public_bytes), std::move(private_bytes)};
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#
2+
# Copyright Soramitsu Co., Ltd. All Rights Reserved.
3+
# SPDX-License-Identifier: Apache-2.0
4+
#
5+
6+
add_library(p2p_rsa
7+
rsa_provider_impl.cpp
8+
)
9+
10+
target_link_libraries(p2p_rsa
11+
p2p_sha
12+
p2p_crypto_error
13+
OpenSSL::Crypto
14+
)
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/**
2+
* Copyright Soramitsu Co., Ltd. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
#include "libp2p/crypto/rsa_provider/rsa_provider_impl.hpp"
7+
8+
#include "libp2p/crypto/sha/sha256.hpp"
9+
#include <memory>
10+
#include <openssl/err.h>
11+
#include <openssl/rsa.h>
12+
#include <openssl/x509.h>
13+
14+
using Hash256 = libp2p::common::Hash256;
15+
16+
namespace libp2p::crypto::rsa {
17+
18+
outcome::result<std::shared_ptr<RSA>> rsaFromPrivateKey(
19+
const PrivateKey &private_key) {
20+
const unsigned char *data_pointer = private_key.data();
21+
std::shared_ptr<RSA> rsa{
22+
d2i_RSAPrivateKey(nullptr, &data_pointer, private_key.size()),
23+
RSA_free};
24+
if (nullptr == rsa) {
25+
return KeyValidatorError::INVALID_PRIVATE_KEY;
26+
}
27+
return rsa;
28+
}
29+
30+
outcome::result<Signature> RsaProviderImpl::sign(
31+
gsl::span<uint8_t> message, const PrivateKey &private_key) const {
32+
OUTCOME_TRY(rsa, rsaFromPrivateKey(private_key));
33+
Hash256 digest = sha256(message);
34+
Signature signature(RSA_size(rsa.get()));
35+
unsigned int signature_size;
36+
if (1
37+
!= RSA_sign(NID_sha256, digest.data(), digest.size(), signature.data(),
38+
&signature_size, rsa.get())) {
39+
return CryptoProviderError::SIGNATURE_GENERATION_FAILED;
40+
}
41+
42+
return signature;
43+
}
44+
45+
outcome::result<bool> RsaProviderImpl::verify(gsl::span<uint8_t> message,
46+
const Signature &signature,
47+
const PublicKey &public_key) const {
48+
OUTCOME_TRY(x509_key, RsaProviderImpl::getPublicKeyFromBytes(public_key));
49+
EVP_PKEY *key = X509_PUBKEY_get0(x509_key.get());
50+
std::unique_ptr<RSA, void (*)(RSA *)> rsa{EVP_PKEY_get1_RSA(key), RSA_free};
51+
Hash256 digest = sha256(message);
52+
int result = RSA_verify(NID_sha256, digest.data(), digest.size(),
53+
signature.data(), signature.size(), rsa.get());
54+
return result == 1 ? true : false;
55+
}
56+
57+
outcome::result<std::shared_ptr<X509_PUBKEY>>
58+
RsaProviderImpl::getPublicKeyFromBytes(const PublicKey &input_key) {
59+
const uint8_t *bytes = input_key.data();
60+
std::shared_ptr<X509_PUBKEY> key{X509_PUBKEY_new(), X509_PUBKEY_free};
61+
X509_PUBKEY *key_ptr = key.get();
62+
if (d2i_X509_PUBKEY(&key_ptr, &bytes, input_key.size()) == nullptr) {
63+
return KeyValidatorError::INVALID_PUBLIC_KEY;
64+
}
65+
return key;
66+
}
67+
68+
}; // namespace libp2p::crypto::rsa

test/libp2p/crypto/CMakeLists.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,13 @@ target_link_libraries(key_validator_test
6161
p2p_key_validator
6262
)
6363

64+
addtest(rsa_provider_test
65+
rsa_provider_test.cpp
66+
)
67+
target_link_libraries(rsa_provider_test
68+
p2p_rsa
69+
)
70+
6471
addtest(secp256k1_test
6572
secp256k1_test.cpp
6673
)

test/libp2p/crypto/key_generator_test.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,18 @@ class KeyGoCompatibility : public ::testing::Test {
150150
std::shared_ptr<CryptoProvider> crypto_provider_;
151151
};
152152

153+
TEST_F(KeyGoCompatibility, RSA) {
154+
PrivateKey privateKey{
155+
{Key::Type::RSA,
156+
"3082025e02010002818100bcaf3ee0f2bc3ac58ab3fcb3c23b2386230564331653ae34e9e09ea6fb0b9cfcf9c6ef76c9337d9b8ed29b4505c8e57a06a9a008ecb89ece3a6e809af64342be4367e06ba1bec131c8944465ba1f5cead836e84932097aea1f6aefc97e84f76219b9dec8afd7a1d0fa90802bd84b1d021112daf026c60ad958db4247e56dc39d0203010001028180407fdb8bc40e6a3ccafc59ff0cff705653346d9b351fa7e678a88b33639005bb489b2392c496b07273b134d8b47087595e5bafd43d2fa341b621be1ebade253b149ba6df498b94269b708547406aeb5da7d71e4fa52fff331cfbae3db55c51ed896d914e93bc0a703aaafed6fe83e7f9af20c2fcfd7207d34426b6b4ed8283b5024100e678fb31b2489505bdb0cf16c23fd6e4ff5069de71f72c12e5a1b0c295aa4fa6e2b691fd5c5ea98473d0884dd969a258f48e5593bdc15f8c72f9da775ca0aeff024100d1955ed85222b96e55e1f9d7865dcb78467a12839f0a3f5b17791b15a1d5b14c20e96bb6d352988f628030282a1c44027e168bb79dac7eb858c1bb3c6ffce963024100d298a808203dfc96336055cb1912d69d87c3060a729f0651fa2cc664f7f7993308a5053fbb60f08b8c7c77a09352d83b6ab488f428878374c63712eed0e02f27024100b94ed2ef7da00a488e5321aef8b511e4a49be6a6ce062782893ca13ffd398e6bfb65a7c19d1398a49eb92cdb36708b8990a6aa9e8d21296221c8199f147d9075024100a7abd450a0c8fe8f3cb2c0d8fca3f15094b512dce328ce543977c14f80dcb7e41ac4ae7fb2925fae724b6e2494231d0c51572ae89510b4ce6e984623ddf2c923"_unhex}};
157+
158+
auto derivedPublicKey = crypto_provider_->derivePublicKey(privateKey).value();
159+
160+
EXPECT_EQ(
161+
derivedPublicKey.data,
162+
"30819f300d06092a864886f70d010101050003818d0030818902818100bcaf3ee0f2bc3ac58ab3fcb3c23b2386230564331653ae34e9e09ea6fb0b9cfcf9c6ef76c9337d9b8ed29b4505c8e57a06a9a008ecb89ece3a6e809af64342be4367e06ba1bec131c8944465ba1f5cead836e84932097aea1f6aefc97e84f76219b9dec8afd7a1d0fa90802bd84b1d021112daf026c60ad958db4247e56dc39d0203010001"_unhex);
163+
}
164+
153165
TEST_F(KeyGoCompatibility, ECDSA) {
154166
PrivateKey privateKey{
155167
{Key::Type::ECDSA,

0 commit comments

Comments
 (0)