1 /*
2 * Copyright (c) 2018-present, Facebook, Inc.
3 * All rights reserved.
4 *
5 * This source code is licensed under the BSD-style license found in the
6 * LICENSE file in the root directory of this source tree.
7 */
8
9 #include <folly/portability/GTest.h>
10
11 #include <fizz/crypto/signature/Signature.h>
12 #include <fizz/crypto/signature/test/EdSignatureTest.h>
13 #include <fizz/crypto/test/TestUtil.h>
14 #include <folly/String.h>
15
16 #define ED25519_FIXTURE(num) \
17 Params { \
18 kEd25519PrivateKey##num, kEd25519PublicKey##num, kEd25519Message##num, \
19 kEd25519Signature##num \
20 }
21
22 using namespace folly;
23
24 namespace fizz {
25 namespace testing {
26
27 #if FIZZ_OPENSSL_HAS_ED25519
TEST_P(EdDSATest,TestSignature)28 TEST_P(EdDSATest, TestSignature) {
29 auto privateKey = fizz::test::getPrivateKey(GetParam().privateKey);
30 auto message = unhexlify(GetParam().hexMessage);
31 auto generatedSignature =
32 detail::edSign(IOBuf::copyBuffer(message)->coalesce(), privateKey);
33 EXPECT_EQ(hexlify(generatedSignature->coalesce()), GetParam().hexSignature);
34 }
35
TEST_P(EdDSATest,TestVerify)36 TEST_P(EdDSATest, TestVerify) {
37 auto publicKey = fizz::test::getPublicKey(GetParam().publicKey);
38 auto message = unhexlify(GetParam().hexMessage);
39 auto signature = unhexlify(GetParam().hexSignature);
40
41 // 1. Verification should pass for the message-signature pair in our fixtures
42 detail::edVerify(
43 IOBuf::copyBuffer(message)->coalesce(),
44 folly::ByteRange(folly::StringPiece(signature)),
45 publicKey);
46
47 // 2. Verification should fail if the message is modified
48 auto modifiedMessage = modifyMessage(message);
49 EXPECT_THROW(
50 detail::edVerify(
51 IOBuf::copyBuffer(modifiedMessage)->coalesce(),
52 folly::ByteRange(folly::StringPiece(signature)),
53 publicKey),
54 std::runtime_error);
55
56 // 3. Verification should fail if the signature is modified
57 auto modifiedSignature = modifySignature(signature);
58 EXPECT_THROW(
59 detail::edVerify(
60 IOBuf::copyBuffer(message)->coalesce(),
61 folly::ByteRange(folly::StringPiece(modifiedSignature)),
62 publicKey),
63 std::runtime_error);
64 }
65
TEST_P(Ed25519Test,TestOpenSSLSignature)66 TEST_P(Ed25519Test, TestOpenSSLSignature) {
67 auto privateKey = fizz::test::getPrivateKey(GetParam().privateKey);
68 auto message = unhexlify(GetParam().hexMessage);
69 auto signature = unhexlify(GetParam().hexSignature);
70
71 // 1. Test instantiation of OpenSSLSignature for Ed25519
72 OpenSSLSignature<KeyType::ED25519> eddsa;
73
74 // 2. Test setting key
75 eddsa.setKey(std::move(privateKey));
76
77 // 3. Test sign method
78 auto generatedSignature = eddsa.sign<SignatureScheme::ed25519>(
79 IOBuf::copyBuffer(message)->coalesce());
80 EXPECT_EQ(hexlify(generatedSignature->coalesce()), GetParam().hexSignature);
81
82 // 4. Test verify method succeeds when it should
83 eddsa.verify<SignatureScheme::ed25519>(
84 IOBuf::copyBuffer(message)->coalesce(),
85 folly::ByteRange(folly::StringPiece(signature)));
86
87 // 5. Test verify method fails if the message is modified
88 auto modifiedMessage = modifyMessage(message);
89 EXPECT_THROW(
90 eddsa.verify<SignatureScheme::ed25519>(
91 IOBuf::copyBuffer(modifiedMessage)->coalesce(),
92 folly::ByteRange(folly::StringPiece(signature))),
93 std::runtime_error);
94
95 // 6. Test verify method fails if the signature is modified
96 auto modifiedSignature = modifySignature(signature);
97 EXPECT_THROW(
98 eddsa.verify<SignatureScheme::ed25519>(
99 IOBuf::copyBuffer(message)->coalesce(),
100 folly::ByteRange(folly::StringPiece(modifiedSignature))),
101 std::runtime_error);
102 }
103
104 // Test vectors from RFC8032
105 INSTANTIATE_TEST_CASE_P(
106 TestVectors,
107 EdDSATest,
108 ::testing::Values(
109 ED25519_FIXTURE(1),
110 ED25519_FIXTURE(2),
111 ED25519_FIXTURE(3),
112 ED25519_FIXTURE(4),
113 ED25519_FIXTURE(5)));
114
115 // Test vectors from RFC8032
116 INSTANTIATE_TEST_CASE_P(
117 TestVectors,
118 Ed25519Test,
119 ::testing::Values(
120 ED25519_FIXTURE(1),
121 ED25519_FIXTURE(2),
122 ED25519_FIXTURE(3),
123 ED25519_FIXTURE(4),
124 ED25519_FIXTURE(5)));
125 #endif
126
modifyMessage(const std::string & input)127 std::string modifyMessage(const std::string& input) {
128 if (input.size() == 0) {
129 return "a";
130 }
131 auto modifiedMessage = std::string(input);
132 modifiedMessage[0] ^= 1; // Flip a bit in the first character
133 return modifiedMessage;
134 }
135
modifySignature(const std::string & input)136 std::string modifySignature(const std::string& input) {
137 CHECK_GT(input.size(), 0) << "Signatures should have positive length";
138 auto modifiedMessage = std::string(input);
139 modifiedMessage[0] ^= 1; // Flip a bit in the first character
140 return modifiedMessage;
141 }
142 } // namespace testing
143 } // namespace fizz
144