Skip to content

Commit 96d25a0

Browse files
committed
added test_crypto.cpp with first code for rsa blinding
1 parent f385ad9 commit 96d25a0

File tree

3 files changed

+259
-2
lines changed

3 files changed

+259
-2
lines changed

CMakeLists.txt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ else()
1818
endif()
1919

2020

21+
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
22+
2123
include(FetchContent)
2224

2325
#
@@ -99,7 +101,10 @@ add_executable(${PROJECT_NAME} src/main.cpp)
99101
target_link_libraries(${PROJECT_NAME} PRIVATE oc-mint-lib INTERFACE tl::expected::expected)
100102

101103
## these are unittests that can be run on any platform
102-
add_executable(tests test/test_big_int.cpp test/test.cpp)
104+
add_executable(tests test/test_big_int.cpp
105+
test/test_json_s8n.cpp
106+
test/test_crypto.cpp)
107+
103108
target_link_libraries(tests
104109
oc-mint-lib
105110
Catch2::Catch2WithMain)

test/test_crypto.cpp

Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
2+
#include <catch2/catch_test_macros.hpp>
3+
4+
#include "cryptlib.h"
5+
#include "integer.h"
6+
#include "nbtheory.h"
7+
#include "osrng.h"
8+
#include "rsa.h"
9+
#include "sha.h"
10+
11+
#include <iostream>
12+
#include <stdexcept>
13+
14+
15+
CryptoPP::Integer blind_signature(const CryptoPP::SecByteBlock& orig,
16+
CryptoPP::Integer& r,
17+
const CryptoPP::RSA::PublicKey& pub_key,
18+
const CryptoPP::RSA::PrivateKey& priv_key) {
19+
using namespace CryptoPP;
20+
using std::cout;
21+
using std::endl;
22+
23+
// Convenience
24+
const Integer &n = pub_key.GetModulus();
25+
const Integer &e = pub_key.GetPublicExponent();
26+
const Integer &d = priv_key.GetPrivateExponent();
27+
28+
// For sizing the hashed message buffer. This should be SHA256 size.
29+
const size_t sig_size = UnsignedMin(SHA256::BLOCKSIZE, n.ByteCount());
30+
// Scratch
31+
SecByteBlock buff_1, buff_2, buff_3;
32+
33+
Integer m(orig.data(), orig.size());
34+
cout << "Message: " << std::hex << m << endl;
35+
36+
// Hash message per Rabin (1979)
37+
buff_1.resize(sig_size);
38+
SHA256 hash_1;
39+
hash_1.CalculateTruncatedDigest(buff_1, buff_1.size(), orig, orig.size());
40+
41+
// H(m) as Integer
42+
Integer hm(buff_1.data(), buff_1.size());
43+
cout << "H(m): " << std::hex << hm << endl;
44+
45+
// Blinding factor
46+
Integer b = a_exp_b_mod_c(r, e, n);
47+
cout << "Random: " << std::hex << b << endl;
48+
49+
// Alice blinded message
50+
Integer mm = a_times_b_mod_c(hm, b, n);
51+
cout << "Blind msg: " << std::hex << mm << endl;
52+
53+
AutoSeededRandomPool prng;
54+
55+
// Bob sign
56+
Integer ss = priv_key.CalculateInverse(prng, mm);
57+
cout << "Blind sign: " << ss << endl;
58+
59+
return ss;
60+
}
61+
62+
CryptoPP::Integer unblind_signature(CryptoPP::Integer const & ss,
63+
CryptoPP::Integer& r,
64+
65+
const CryptoPP::RSA::PublicKey& pub_key)
66+
{
67+
68+
const CryptoPP::Integer &n = pub_key.GetModulus();
69+
CryptoPP::Integer s = a_times_b_mod_c(ss, r.InverseMod(n), n);
70+
return s;
71+
}
72+
73+
CryptoPP::Integer verify(CryptoPP::Integer const & ss,
74+
CryptoPP::Integer& r,
75+
76+
const CryptoPP::RSA::PublicKey& pub_key)
77+
{
78+
CryptoPP::Integer s = unblind_signature(ss,r,pub_key);
79+
CryptoPP::Integer v = pub_key.ApplyFunction(s);
80+
return v;
81+
}
82+
83+
TEST_CASE("cryptopp1", "[crypto]") {
84+
using namespace CryptoPP;
85+
using std::cout;
86+
using std::endl;
87+
using std::runtime_error;
88+
89+
// Bob artificially small key pair
90+
AutoSeededRandomPool prng;
91+
RSA::PrivateKey priv_key;
92+
93+
priv_key.GenerateRandomWithKeySize(prng, 64U);
94+
RSA::PublicKey pub_key(priv_key);
95+
96+
// Convenience
97+
const Integer &n = pub_key.GetModulus();
98+
const Integer &e = pub_key.GetPublicExponent();
99+
const Integer &d = priv_key.GetPrivateExponent();
100+
101+
// Print params
102+
cout << "Pub mod: " << std::hex << pub_key.GetModulus() << endl;
103+
cout << "Pub exp: " << std::hex << e << endl;
104+
cout << "Priv mod: " << std::hex << priv_key.GetModulus() << endl;
105+
cout << "Priv exp: " << std::hex << d << endl;
106+
const char* MESSAGE = "secret";
107+
SecByteBlock orig((const byte *)MESSAGE, 6U);
108+
109+
// Alice blinding
110+
Integer r;
111+
do {
112+
r.Randomize(prng, Integer::One(), n - Integer::One());
113+
} while (!RelativelyPrime(r, n));
114+
CryptoPP::Integer ss = blind_signature(orig,
115+
r,
116+
pub_key,
117+
priv_key);
118+
// Alice checks s(s'(x)) = x. This is from Chaum's paper
119+
Integer c = pub_key.ApplyFunction(ss);
120+
cout << "Check sign: " << c << endl;
121+
//if (c != mm) {
122+
// throw runtime_error("Alice cross-check failed");
123+
// }
124+
// Alice remove blinding
125+
Integer s = unblind_signature(ss, r, pub_key);
126+
cout << "Unblind sign: " << s << endl;
127+
128+
// Eve verifies
129+
Integer v = verify(ss, r, pub_key);
130+
cout << "Verify: " << std::hex << v << endl;
131+
132+
// Scratch
133+
SecByteBlock buff_2, buff_3;
134+
135+
// Convert to a string
136+
size_t req = v.MinEncodedSize();
137+
buff_2.resize(req);
138+
v.Encode(&buff_2[0], buff_2.size());
139+
140+
// Hash message per Rabin (1979)
141+
const size_t sig_size = UnsignedMin(SHA256::BLOCKSIZE, n.ByteCount());
142+
buff_3.resize(sig_size);
143+
SHA256 hash_2;
144+
hash_2.CalculateTruncatedDigest(buff_3, buff_3.size(), orig, orig.size());
145+
146+
// Constant time compare
147+
bool equal = buff_2.size() == buff_3.size() &&
148+
VerifyBufsEqual(buff_2.data(), buff_3.data(), buff_3.size());
149+
150+
if (!equal) {
151+
throw runtime_error("Eve verified failed");
152+
}
153+
cout << "Verified signature" << endl;
154+
155+
156+
}
157+
158+
TEST_CASE("cryptopp", "[crypto]") {
159+
using namespace CryptoPP;
160+
using std::cout;
161+
using std::endl;
162+
using std::runtime_error;
163+
164+
// Bob artificially small key pair
165+
AutoSeededRandomPool prng;
166+
RSA::PrivateKey priv_key;
167+
168+
priv_key.GenerateRandomWithKeySize(prng, 64U);
169+
RSA::PublicKey pub_key(priv_key);
170+
171+
// Convenience
172+
const Integer &n = pub_key.GetModulus();
173+
const Integer &e = pub_key.GetPublicExponent();
174+
const Integer &d = priv_key.GetPrivateExponent();
175+
176+
// Print params
177+
cout << "Pub mod: " << std::hex << pub_key.GetModulus() << endl;
178+
cout << "Pub exp: " << std::hex << e << endl;
179+
cout << "Priv mod: " << std::hex << priv_key.GetModulus() << endl;
180+
cout << "Priv exp: " << std::hex << d << endl;
181+
182+
// For sizing the hashed message buffer. This should be SHA256 size.
183+
const size_t sig_size = UnsignedMin(SHA256::BLOCKSIZE, n.ByteCount());
184+
185+
// Scratch
186+
SecByteBlock buff_1, buff_2, buff_3;
187+
188+
// Alice original message to be signed by Bob
189+
SecByteBlock orig((const byte *)"secret", 6U);
190+
Integer m(orig.data(), orig.size());
191+
cout << "Message: " << std::hex << m << endl;
192+
193+
// Hash message per Rabin (1979)
194+
buff_1.resize(sig_size);
195+
SHA256 hash_1;
196+
hash_1.CalculateTruncatedDigest(buff_1, buff_1.size(), orig, orig.size());
197+
198+
// H(m) as Integer
199+
Integer hm(buff_1.data(), buff_1.size());
200+
cout << "H(m): " << std::hex << hm << endl;
201+
202+
// Alice blinding
203+
Integer r;
204+
do {
205+
r.Randomize(prng, Integer::One(), n - Integer::One());
206+
} while (!RelativelyPrime(r, n));
207+
208+
// Blinding factor
209+
Integer b = a_exp_b_mod_c(r, e, n);
210+
cout << "Random: " << std::hex << b << endl;
211+
212+
// Alice blinded message
213+
Integer mm = a_times_b_mod_c(hm, b, n);
214+
cout << "Blind msg: " << std::hex << mm << endl;
215+
216+
// Bob sign
217+
Integer ss = priv_key.CalculateInverse(prng, mm);
218+
cout << "Blind sign: " << ss << endl;
219+
220+
// Alice checks s(s'(x)) = x. This is from Chaum's paper
221+
Integer c = pub_key.ApplyFunction(ss);
222+
cout << "Check sign: " << c << endl;
223+
if (c != mm) {
224+
throw runtime_error("Alice cross-check failed");
225+
}
226+
// Alice remove blinding
227+
Integer s = a_times_b_mod_c(ss, r.InverseMod(n), n);
228+
cout << "Unblind sign: " << s << endl;
229+
230+
// Eve verifies
231+
Integer v = pub_key.ApplyFunction(s);
232+
cout << "Verify: " << std::hex << v << endl;
233+
234+
// Convert to a string
235+
size_t req = v.MinEncodedSize();
236+
buff_2.resize(req);
237+
v.Encode(&buff_2[0], buff_2.size());
238+
239+
// Hash message per Rabin (1979)
240+
buff_3.resize(sig_size);
241+
SHA256 hash_2;
242+
hash_2.CalculateTruncatedDigest(buff_3, buff_3.size(), orig, orig.size());
243+
244+
// Constant time compare
245+
bool equal = buff_2.size() == buff_3.size() &&
246+
VerifyBufsEqual(buff_2.data(), buff_3.data(), buff_3.size());
247+
248+
if (!equal) {
249+
throw runtime_error("Eve verified failed");
250+
}
251+
cout << "Verified signature" << endl;
252+
}

test/test.cpp renamed to test/test_json_s8n.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ TEST_CASE( "PublicKey::to_json", "[to_json]" ) {
1212
REQUIRE( json["modulus"].dump() == "\"" + k.modulus.to_string() + "\"" );
1313
REQUIRE( json["public_exponent"].dump() == "\"" + k.public_exponent.to_string()+"\"" );
1414
REQUIRE( json["type"].dump() == "\"rsa public key\"" );
15-
REQUIRE( json.keys().size() == 3 );
15+
REQUIRE( json.keys().size() == 3U );
1616
}
1717

1818
TEST_CASE("RequestCDDCSerial::from_string", "[from_string]") {

0 commit comments

Comments
 (0)