Skip to content

Commit aaa23c5

Browse files
committed
Move RSA signing code from PublicKey to Signing
Backs out the changes made to PublicKey.
1 parent 741a9b2 commit aaa23c5

File tree

5 files changed

+150
-104
lines changed

5 files changed

+150
-104
lines changed

Crypto/PublicKey.cc

Lines changed: 0 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212

1313
#include "mbedtls/config.h"
1414
#include "PublicKey.hh"
15-
#include "SecureRandomize.hh"
1615
#include "TLSContext.hh"
1716
#include "Logging.hh"
1817
#include "StringUtil.hh"
@@ -79,36 +78,11 @@ namespace litecore { namespace crypto {
7978
}
8079

8180

82-
#pragma mark - PUBLIC KEY:
83-
84-
8581
PublicKey::PublicKey(slice data) {
8682
parsePEMorDER(data, "public key", context(), &mbedtls_pk_parse_public_key);
8783
}
8884

8985

90-
static int rngFunction(void *ctx, unsigned char *dst, size_t size) {
91-
SecureRandomize({dst, size});
92-
return 0;
93-
}
94-
95-
96-
bool PublicKey::verifySignature(const SHA256 &inputDigest, slice signature) {
97-
int result = mbedtls_pk_verify(context(),
98-
MBEDTLS_MD_SHA256, // declares that input is a SHA256 digest.
99-
(const uint8_t*)inputDigest.asSlice().buf,
100-
inputDigest.asSlice().size,
101-
(const uint8_t*)signature.buf, signature.size);
102-
if (result == MBEDTLS_ERR_RSA_VERIFY_FAILED)
103-
return false;
104-
TRY(result); // other error codes throw exceptions
105-
return true;
106-
}
107-
108-
109-
#pragma mark - PRIVATE KEY:
110-
111-
11286
PrivateKey::PrivateKey(slice data, slice password) {
11387
if (password.size == 0)
11488
password = nullslice; // interpret empty password as 'no password'
@@ -149,19 +123,7 @@ namespace litecore { namespace crypto {
149123
default:
150124
Assert(false, "Invalid key format received (%d)", (int)format);
151125
}
152-
}
153-
154126

155-
alloc_slice PrivateKey::sign(const SHA256 &inputDigest) {
156-
alloc_slice signature(MBEDTLS_PK_SIGNATURE_MAX_SIZE);
157-
size_t sigLen = 0;
158-
TRY(mbedtls_pk_sign(context(),
159-
MBEDTLS_MD_SHA256, // declares that input is a SHA256 digest.
160-
(const uint8_t*)inputDigest.asSlice().buf, inputDigest.asSlice().size,
161-
(uint8_t*)signature.buf, &sigLen,
162-
rngFunction, nullptr));
163-
signature.shorten(sigLen);
164-
return signature;
165127
}
166128

167129

Crypto/PublicKey.hh

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -75,16 +75,6 @@ namespace litecore { namespace crypto {
7575

7676
virtual bool isPrivate() override {return false;}
7777

78-
/** Checks whether `signature` is a valid signature, created by my matching private key,
79-
of the given SHA256 digest. */
80-
virtual bool verifySignature(const SHA256 &inputDigest, fleece::slice signature);
81-
82-
/** Checks whether `signature` is a valid signature, created by my matching private key,
83-
of a SHA256 digest of the input data. */
84-
bool verifySignature(fleece::slice inputData, fleece::slice signature) {
85-
return verifySignature(SHA256(inputData), signature);
86-
}
87-
8878
protected:
8979
friend class CertBase;
9080

@@ -124,12 +114,6 @@ namespace litecore { namespace crypto {
124114
return new PublicKey(publicKeyData(KeyFormat::Raw));
125115
}
126116

127-
/** Generates a signature of a SHA256 digest. */
128-
virtual fleece::alloc_slice sign(const SHA256 &inputDigest);
129-
130-
/** Generates a signature of a SHA256 digest of the input data. */
131-
fleece::alloc_slice sign(fleece::slice inputData) {return sign(SHA256(inputData));}
132-
133117
protected:
134118
PrivateKey() =default;
135119
};

Crypto/SignatureTest.cc

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -25,54 +25,60 @@ using namespace std;
2525
using namespace fleece;
2626

2727

28-
TEST_CASE("RSA Signatures", "[Signatures]") {
28+
TEST_CASE("Signatures", "[Signatures]") {
2929
static constexpr slice kDataToSign = "The only thing we learn from history"
3030
" is that people do not learn from history. --Hegel";
31-
Retained<PrivateKey> key = PrivateKey::generateTemporaryRSA(2048);
32-
alloc_slice signature = key->sign(kDataToSign);
31+
32+
const char *alg = GENERATE(kRSAAlgorithmName, kEd25519AlgorithmName);
33+
cerr << "\t---- " << alg << endl;
34+
35+
auto signingKey = SigningKey::generate(alg);
36+
alloc_slice signature = signingKey->sign(kDataToSign);
3337
cout << "Signature is " << signature.size << " bytes: " << base64::encode(signature) << endl;
3438

3539
// Verify:
36-
CHECK(key->publicKey()->verifySignature(kDataToSign, signature));
40+
auto verifyingKey = signingKey->verifyingKey();
41+
CHECK(verifyingKey->verifySignature(kDataToSign, signature));
3742

3843
// Verification fails with wrong public key:
39-
auto key2 = PrivateKey::generateTemporaryRSA(2048);
40-
CHECK(!key2->publicKey()->verifySignature(kDataToSign, signature));
44+
auto key2 = SigningKey::generate(kRSAAlgorithmName);
45+
CHECK(!key2->verifyingKey()->verifySignature(kDataToSign, signature));
4146

4247
// Verification fails with incorrect digest:
4348
auto badDigest = SHA256(kDataToSign);
4449
((uint8_t*)&badDigest)[10]++;
45-
CHECK(!key->publicKey()->verifySignature(badDigest, signature));
50+
CHECK(!verifyingKey->verifySignature(badDigest, signature));
4651

4752
// Verification fails with altered signature:
48-
((uint8_t&)signature[100])++;
49-
CHECK(!key->publicKey()->verifySignature(kDataToSign, signature));
53+
((uint8_t&)signature[30])++;
54+
CHECK(!verifyingKey->verifySignature(kDataToSign, signature));
5055
}
5156

5257

5358
TEST_CASE("Signed Document", "[Signatures]") {
59+
const char *algorithm = GENERATE(kRSAAlgorithmName, kEd25519AlgorithmName);
5460
bool embedKey = GENERATE(false, true);
55-
cout << "---- Embed key in signature = " << embedKey << endl;
61+
cerr << "\t---- " << algorithm << "; embed key in signature = " << embedKey << endl;
5662

5763
// Create a signed doc and convert to JSON:
5864
alloc_slice publicKeyData;
5965
string json;
6066
{
61-
auto priv = Ed25519SigningKey::generate();
62-
auto pub = priv.publicKey();
63-
publicKeyData = pub.data();
67+
auto priv = SigningKey::generate(algorithm);
68+
auto pub = priv->verifyingKey();
69+
publicKeyData = pub->data();
6470

6571
MutableDict doc = MutableDict::newDict();
6672
doc["name"] = "Oliver Bolliver Butz";
6773
doc["age"] = 6;
6874
cout << "Document: " << doc.toJSONString() << endl;
6975

70-
MutableDict sig = makeSignature(doc, priv, 5 /*minutes*/, embedKey);
76+
MutableDict sig = makeSignature(doc, *priv, 5 /*minutes*/, embedKey);
7177
REQUIRE(sig);
7278
string sigJson = sig.toJSONString();
7379
cout << "Signature, " << sigJson.size() << " bytes: " << sigJson << endl;
7480

75-
CHECK(verifySignature(doc, sig, &pub) == VerifyResult::Valid);
81+
CHECK(verifySignature(doc, sig, pub.get()) == VerifyResult::Valid);
7682

7783
doc["(sig)"] = sig; // <-- add signature to doc, in "(sig)" property
7884
json = doc.toJSONString();
@@ -86,13 +92,13 @@ TEST_CASE("Signed Document", "[Signatures]") {
8692
Dict sig = doc["(sig)"].asDict();
8793
REQUIRE(sig);
8894

89-
auto parsedKey = getSignaturePublicKey(sig, "Ed25519");
95+
auto parsedKey = getSignaturePublicKey(sig, algorithm);
9096
if (embedKey) {
9197
REQUIRE(parsedKey);
9298
CHECK(parsedKey->data() == publicKeyData);
9399
} else {
94100
CHECK(!parsedKey);
95-
parsedKey = make_unique<Ed25519VerifyingKey>(publicKeyData);
101+
parsedKey = VerifyingKey::instantiate(publicKeyData, algorithm);
96102
}
97103

98104
MutableDict unsignedDoc = doc.mutableCopy();

Crypto/Signing.cc

Lines changed: 73 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,30 @@
1919
#include "Signing.hh"
2020
#include "Error.hh"
2121
#include "SecureRandomize.hh"
22+
#include "mbedUtils.hh"
2223
#include "monocypher.h"
2324
#include "monocypher-ed25519.h"
2425

26+
#pragma clang diagnostic push
27+
#pragma clang diagnostic ignored "-Wdocumentation-deprecated-sync"
28+
#include "mbedtls/pk.h"
29+
#pragma clang diagnostic pop
30+
2531
namespace litecore::crypto {
2632
using namespace std;
2733

2834

35+
std::unique_ptr<SigningKey> SigningKey::generate(const char *algorithm) {
36+
if (0 == strcmp(algorithm, kRSAAlgorithmName)) {
37+
return make_unique<RSASigningKey>(PrivateKey::generateTemporaryRSA(2048));
38+
} else if (0 == strcmp(algorithm, kEd25519AlgorithmName)) {
39+
return make_unique<Ed25519SigningKey>();
40+
} else {
41+
error::_throw(error::CryptoError, "Unknown signature algorithm '%s'", algorithm);
42+
}
43+
}
44+
45+
2946
unique_ptr<VerifyingKey> VerifyingKey::instantiate(slice data, const char *algorithm) {
3047
if (0 == strcmp(algorithm, kRSAAlgorithmName)) {
3148
return make_unique<RSAVerifyingKey>(data);
@@ -37,9 +54,54 @@ namespace litecore::crypto {
3754
}
3855

3956

57+
#pragma mark - RSA:
58+
59+
60+
static int rngFunction(void *ctx, unsigned char *dst, size_t size) {
61+
SecureRandomize({dst, size});
62+
return 0;
63+
}
64+
65+
66+
alloc_slice RSASigningKey::sign(slice data) const {
67+
SHA256 inputDigest(data);
68+
alloc_slice signature(MBEDTLS_PK_SIGNATURE_MAX_SIZE);
69+
size_t sigLen = 0;
70+
TRY(mbedtls_pk_sign(_key->context(),
71+
MBEDTLS_MD_SHA256, // declares that input is a SHA256 digest.
72+
(const uint8_t*)inputDigest.asSlice().buf, inputDigest.asSlice().size,
73+
(uint8_t*)signature.buf, &sigLen,
74+
rngFunction, nullptr));
75+
signature.shorten(sigLen);
76+
return signature;
77+
}
78+
79+
80+
unique_ptr<VerifyingKey> RSASigningKey::verifyingKey() const {
81+
return make_unique<RSAVerifyingKey>(_key->publicKey());
82+
}
83+
84+
85+
bool RSAVerifyingKey::verifySignature(slice data, slice signature) const {
86+
SHA256 inputDigest(data);
87+
int result = mbedtls_pk_verify(_key->context(),
88+
MBEDTLS_MD_SHA256, // declares that input is a SHA256 digest.
89+
(const uint8_t*)inputDigest.asSlice().buf,
90+
inputDigest.asSlice().size,
91+
(const uint8_t*)signature.buf, signature.size);
92+
if (result == MBEDTLS_ERR_RSA_VERIFY_FAILED)
93+
return false;
94+
TRY(result); // other error codes throw exceptions
95+
return true;
96+
}
97+
98+
99+
#pragma mark - Ed25519:
100+
101+
40102
Ed25519Base::Ed25519Base(slice bytes) {
41103
if (bytes.size != sizeof(_bytes))
42-
error::_throw(error::CryptoError, "Invalid data for Ed25519 key");
104+
error::_throw(error::CryptoError, "Invalid data size for Ed25519 key");
43105
bytes.copyTo(_bytes.data());
44106
}
45107

@@ -56,13 +118,20 @@ namespace litecore::crypto {
56118
}
57119

58120

121+
unique_ptr<VerifyingKey> Ed25519SigningKey::verifyingKey() const {
122+
unique_ptr<Ed25519VerifyingKey> pub(new Ed25519VerifyingKey());
123+
crypto_ed25519_public_key(pub->_bytes.data(), _bytes.data());
124+
return pub;
125+
}
126+
127+
59128
alloc_slice Ed25519SigningKey::verifyingKeyData() const {
60129
return publicKey().data();
61130
}
62131

63132

64133
alloc_slice Ed25519SigningKey::sign(slice data) const {
65-
alloc_slice signature(64);
134+
alloc_slice signature(kSignatureSize);
66135
crypto_ed25519_sign((uint8_t*)signature.buf,
67136
(const uint8_t*)_bytes.data(), nullptr,
68137
(const uint8_t*)data.buf, data.size);
@@ -76,7 +145,8 @@ namespace litecore::crypto {
76145
}
77146

78147
bool Ed25519VerifyingKey::verifySignature(slice inputData, slice signature) const {
79-
return 0 == crypto_ed25519_check((const uint8_t*)signature.buf,
148+
return signature.size == kSignatureSize
149+
&& 0 == crypto_ed25519_check((const uint8_t*)signature.buf,
80150
(const uint8_t*)_bytes.data(),
81151
(const uint8_t*)inputData.buf,
82152
inputData.size);

0 commit comments

Comments
 (0)