I'm trying to load an RSA private key from a std::string that contains the private key in PEM format, like this:
-----BEGIN RSA PRIVATE KEY-----
MIIBOgIBAAJBAK8Q+ToR4tWGshaKYRHKJ3ZmMUF6jjwCS/u1A8v1tFbQiVpBlxYB
paNcT2ENEXBGdmWqr8VwSl0NBIKyq4p0rhsCAQMCQHS1+3wL7I5ZzA8G62Exb6RE
INZRtCgBh/0jV91OeDnfQUc07SE6vs31J8m7qw/rxeB3E9h6oGi9IVRebVO+9zsC
IQDWb//KAzrSOo0P0yktnY57UF9Q3Y26rulWI6LqpsxZDwIhAND/cmlg7rUz34Pf
SmM61lJEmMEjKp8RB/xgghzmCeI1AiEAjvVVMVd8jCcItTdwyRO0UjWU4JOz0cnw
5BfB8cSIO18CIQCLVPbw60nOIpUClNxCJzmMLbsrbMcUtgVS6wFomVvsIwIhAK+A
YqT6WwsMW2On5l9di+RPzhDT1QdGyTI5eFNS+GxY
-----END RSA PRIVATE KEY-----
And I wonder if anyone can help me to use this key instead of generating a random with the following statement.
CryptoPP::RSA::PrivateKey rsaPrivate;
rsaPrivate.GenerateRandomWithKeySize (rnd, 512);
The key is PEM encoded. You need to strip the PEM header and footer, then convert from Base64 back to DER/BER, and finally use Crypto++'s BERDecodePrivateKey.
There's some reading on the subject at the Crypto++ wiki under Keys and Formats. Below is the code to perform the conversion (I don't believe Stack Overflow has a working example of it in Crypto++).
string RSA_PRIV_KEY =
"-----BEGIN RSA PRIVATE KEY-----\n"
"MIIBOgIBAAJBAK8Q+ToR4tWGshaKYRHKJ3ZmMUF6jjwCS/u1A8v1tFbQiVpBlxYB\n"
"paNcT2ENEXBGdmWqr8VwSl0NBIKyq4p0rhsCAQMCQHS1+3wL7I5ZzA8G62Exb6RE\n"
"INZRtCgBh/0jV91OeDnfQUc07SE6vs31J8m7qw/rxeB3E9h6oGi9IVRebVO+9zsC\n"
"IQDWb//KAzrSOo0P0yktnY57UF9Q3Y26rulWI6LqpsxZDwIhAND/cmlg7rUz34Pf\n"
"SmM61lJEmMEjKp8RB/xgghzmCeI1AiEAjvVVMVd8jCcItTdwyRO0UjWU4JOz0cnw\n"
"5BfB8cSIO18CIQCLVPbw60nOIpUClNxCJzmMLbsrbMcUtgVS6wFomVvsIwIhAK+A\n"
"YqT6WwsMW2On5l9di+RPzhDT1QdGyTI5eFNS+GxY\n"
"-----END RSA PRIVATE KEY-----";
static string HEADER = "-----BEGIN RSA PRIVATE KEY-----";
static string FOOTER = "-----END RSA PRIVATE KEY-----";
size_t pos1, pos2;
pos1 = RSA_PRIV_KEY.find(HEADER);
if(pos1 == string::npos)
throw runtime_error("PEM header not found");
pos2 = RSA_PRIV_KEY.find(FOOTER, pos1+1);
if(pos2 == string::npos)
throw runtime_error("PEM footer not found");
// Start position and length
pos1 = pos1 + HEADER.length();
pos2 = pos2 - pos1;
string keystr = RSA_PRIV_KEY.substr(pos1, pos2);
// Base64 decode, place in a ByteQueue
ByteQueue queue;
Base64Decoder decoder;
decoder.Attach(new Redirector(queue));
decoder.Put((const byte*)keystr.data(), keystr.length());
decoder.MessageEnd();
// Write to file for inspection
FileSink fs("decoded-key.der");
queue.CopyTo(fs);
fs.MessageEnd();
try
{
CryptoPP::RSA::PrivateKey rsaPrivate;
rsaPrivate.BERDecodePrivateKey(queue, false /*paramsPresent*/, queue.MaxRetrievable());
// BERDecodePrivateKey is a void function. Here's the only check
// we have regarding the DER bytes consumed.
ASSERT(queue.IsEmpty());
}
catch (const Exception& ex)
{
cerr << ex.what() << endl;
exit (1);
}
After loading the key, you can validate it with:
AutoSeededRandomPool prng;
bool valid = rsaPrivate.Validate(prng, 3);
if(!valid)
cerr << "RSA private key is not valid" << endl;
And print it with:
cout << "N: " << rsaPrivate.GetModulus() << endl << endl;
cout << "E: " << rsaPrivate.GetPublicExponent() << endl << endl;
cout << "D: " << rsaPrivate.GetPrivateExponent() << endl << endl;
If the key is password protected, then Crypto++ cannot decode it. The library lacks the support to perform the decryption. In this case, you can convert it to BER/DER using the following OpenSSL command. Then you can use the key material with Crypto++.
openssl pkcs8 -nocrypt -in rsa-key.pem -inform PEM -topk8 -outform DER -out rsa-key.der
The sample program wrote the key to file with this:
FileSink fs("decoded-key.der");
queue.CopyTo(fs);
fs.MessageEnd();
The CopyTo leaves the bytes in the queue for use later. You can dump the file with an ASN.1 tool, like Gutmann's dumpasn1:
$ dumpasn1 decoded-key.der
0 314: SEQUENCE {
4 1: INTEGER 0
7 65: INTEGER
: 00 AF 10 F9 3A 11 E2 D5 86 B2 16 8A 61 11 CA 27
: 76 66 31 41 7A 8E 3C 02 4B FB B5 03 CB F5 B4 56
: D0 89 5A 41 97 16 01 A5 A3 5C 4F 61 0D 11 70 46
: 76 65 AA AF C5 70 4A 5D 0D 04 82 B2 AB 8A 74 AE
: 1B
74 1: INTEGER 3
77 64: INTEGER
: 74 B5 FB 7C 0B EC 8E 59 CC 0F 06 EB 61 31 6F A4
: 44 20 D6 51 B4 28 01 87 FD 23 57 DD 4E 78 39 DF
: 41 47 34 ED 21 3A BE CD F5 27 C9 BB AB 0F EB C5
: E0 77 13 D8 7A A0 68 BD 21 54 5E 6D 53 BE F7 3B
143 33: INTEGER
: 00 D6 6F FF CA 03 3A D2 3A 8D 0F D3 29 2D 9D 8E
: 7B 50 5F 50 DD 8D BA AE E9 56 23 A2 EA A6 CC 59
: 0F
178 33: INTEGER
: 00 D0 FF 72 69 60 EE B5 33 DF 83 DF 4A 63 3A D6
: 52 44 98 C1 23 2A 9F 11 07 FC 60 82 1C E6 09 E2
: 35
213 33: INTEGER
: 00 8E F5 55 31 57 7C 8C 27 08 B5 37 70 C9 13 B4
: 52 35 94 E0 93 B3 D1 C9 F0 E4 17 C1 F1 C4 88 3B
: 5F
248 33: INTEGER
: 00 8B 54 F6 F0 EB 49 CE 22 95 02 94 DC 42 27 39
: 8C 2D BB 2B 6C C7 14 B6 05 52 EB 01 68 99 5B EC
: 23
283 33: INTEGER
: 00 AF 80 62 A4 FA 5B 0B 0C 5B 63 A7 E6 5F 5D 8B
: E4 4F CE 10 D3 D5 07 46 C9 32 39 78 53 52 F8 6C
: 58
: }
0 warnings, 0 errors.
Related
I have trouble creating signatures with OpenSSL on a Raspberry Pi. RSA, ECDSA and EdDSA fail. Here is a small example:
#pragma once
#include <vector>
#include <string>
#include <openssl/evp.h>
#include <openssl/rsa.h>
#include <openssl/err.h>
void main()
{
// message to be sign
std::string msg_str = "my messsage";
std::vector<uint8_t> msg(msg_str.begin(), msg_str.end());
// generate a key pair
EVP_PKEY* key = EVP_PKEY_Q_keygen(nullptr, nullptr, "RSA", 2048);
// signature
std::vector<uint8_t> sig_out(1024); // reserve some memory
// signing process
EVP_MD_CTX* md_ctx(EVP_MD_CTX_new());
size_t out_len = 0; // final signature length (calculated by openssl)
if (EVP_DigestSignInit(md_ctx, nullptr, EVP_sha1(), nullptr, key) == 0)
{
std::cout << "EVP_DigestSignInit error: " << ERR_error_string(ERR_get_error(), NULL) << std::endl;
}
if (EVP_DigestSign(md_ctx, sig_out.data(), &out_len, msg.data(), msg.size()) == 0)
{
std::cout << "EVP_DigestSign error: " << ERR_error_string(ERR_get_error(), NULL) << std::endl;
}
else
{
sig_out.resize(out_len);
std::cout << "signature length: " << sig_out .size() << " data: " << std::endl;
for (size_t i = 0; i < out_len; i++)
{
printf("%.2X ", sig_out[i]);
}
}
EVP_PKEY_free(key);
EVP_MD_CTX_free(md_ctx);
return;
}
On my desktop PC all signatures work but not on the Raspberry Pi. Here is the screen output:
Windows 10, AMD CPU, x64 system, OpenSSL 3.0.0:
signature length: 256 data:
59 A9 45 F5 2B 97 51 F5 53 A8 AE 17 16 7A 26 28
F5 68 3F 1F 3D B2 05 4F 0E 28 AF F2 F5 0E DA FF
37 71 50 DD DA E1 DE F0 91 05 0A 07 79 30 00 03
A4 1E F5 60 F5 7E 47 97 EF 88 9C 27 70 CE 64 63
0B 6C 2E 50 7B D7 89 48 B6 73 44 AD 7A 02 EA 49
BC D3 95 67 B8 E6 D9 E4 A1 4F 2B E8 F4 5C F8 73
B5 53 B0 A5 FB BB 7A 81 1C 25 23 6F 30 D8 8F D8
EC 9E 02 00 C2 0D 7C 9C 23 66 D7 44 62 FF 51 1A
94 3F 6F FB D7 B2 C5 2B A4 03 09 E5 10 44 D4 AE
A2 69 F3 EB 31 1B CB 2A 14 1D 76 CD 11 09 B9 76
99 59 42 5A 74 3D 14 98 B7 87 FD 98 16 17 AC 9E
DA 55 82 0B 93 3D 24 28 4F 09 EB EA AE 82 77 47
B2 E2 C8 1E 62 FF E4 90 E6 18 E8 88 94 B4 F0 AF
DF A2 2B D7 79 32 BD C5 0F B1 03 36 B6 D8 44 9A
FA DB 02 EB 7D FE D5 D7 15 34 77 72 4D 4E 44 A8
E7 DA D9 2B 49 80 43 58 1F AA F4 1D 27 80 1C EE
Raspberry Pi, ARM CPU, Debian (bullseye), x64 system, OpenSSL 3.1.0:
EVP_DigestSign error: error:1C8000B3:Provider routines::invalid signature size
does anyone have any idea what the problem may be? I am now a bit desperate.
best regards,
SBond
solved!
this error occurs (only on ARM) when out_len is smaller than the final signature length. I need to change the code as follows:
from
if (EVP_DigestSign(md_ctx, sig_out.data(), &out_len, msg.data(), msg.size()) == 0)
{
std::cout << "EVP_DigestSign error: " << ERR_error_string(ERR_get_error(), NULL) << std::endl;
}
to
EVP_DigestSign(md_ctx, nullptr, &out_len, msg.data(), msg.size()); // calculates the final length (does not perform signature; therfore a fast process)
sig_out.resize(out_len);
if (EVP_DigestSign(md_ctx, sig_out.data(), &out_len, msg.data(), msg.size()) == 0)
{
std::cout << "EVP_DigestSign error: " << ERR_error_string(ERR_get_error(), NULL) << std::endl;
}
now I'm happy :)
I'm trying to sign a file with my private key using the following function:
void Signer::SignFile(const std::string& file)
{
RSASS<PSSR, Whirlpool>::Signer signer(rsaPrivate);
// Encrypt and write
FileSource ss1(file.c_str(), true,
new SignerFilter(rng, signer,
new FileSink(file.c_str(), true)
, true));
}
As an outcome my target file gets overwritten with the signature. Why does that happen? Obviously I'd like to append it to the file, that's why I also added an extra "true" parameter for the "putMessage".
FileSource ss1(file.c_str(), true,
new SignerFilter(rng, signer,
new FileSink(file.c_str(), true), true));
I [personally] have never seen someone use the same file as a source and sink. Usually the file data and signature are separate like with a detached signature.
It looks like one file/two streams is implementation defined: C++ read and write to same file using different streams. I guess you should expect seemingly random results on different platforms.
As an outcome my target file gets overwritten with the signature. Why does that happen?
The FileSink opens with std::ios_base::tunc. Also see FileSink on the Crypto++ wiki.
You should probably do something like this. It saves the signature to an intermediate ByteQueue, and then writes the queue to the file once the file is closed.
#include "cryptlib.h"
#include "filters.h"
#include "osrng.h"
#include "files.h"
#include "pssr.h"
#include "rsa.h"
#include "whrlpool.h"
#include <iostream>
#include <fstream>
#include <string>
int main(int argc, char* argv[])
{
using namespace CryptoPP;
AutoSeededRandomPool prng;
std::string fname("test.bin");
///// Create test message /////
{
std::string msg("Yoda said, Do or do not. There is no try.");
std::ofstream out(fname.c_str());
out.write(msg.data(), msg.size());
}
///// Generate a key /////
RSASS<PSSR, Whirlpool>::Signer signer;
signer.AccessKey().GenerateRandomWithKeySize(prng, 2048);
///// Sign the message /////
ByteQueue queue;
{
FileSource source(fname.c_str(), true,
new SignerFilter(prng, signer,
new Redirector(queue)));
}
///// Append the signature /////
{
std::ofstream out(fname.c_str(), std::ios_base::out | std::ios_base::binary | std::ios_base::app);
queue.TransferTo(FileSink(out).Ref());
}
///// Create a verifier /////
RSASS<PSSR, Whirlpool>::Verifier verifier(signer);
///// Verify the message /////
{
FileSource source(fname.c_str(), true,
new SignatureVerificationFilter(verifier, NULLPTR,
SignatureVerificationFilter::THROW_EXCEPTION));
}
std::cout << "Verified signature on message" << std::endl;
return 0;
}
It does not crash and it appends the message as expected:
$ ./test.exe
Verified signature on message
$ hexdump -C test.bin
00000000 59 6f 64 61 20 73 61 69 64 2c 20 44 6f 20 6f 72 |Yoda said, Do or|
00000010 20 64 6f 20 6e 6f 74 2e 20 54 68 65 72 65 20 69 | do not. There i|
00000020 73 20 6e 6f 20 74 72 79 2e 19 f2 1c 8f f9 cb 2f |s no try......./|
00000030 f2 38 9f a8 3b a9 0b 8b 62 25 56 a8 ea 81 7e 60 |.8..;...b%V...~`|
00000040 22 55 38 ce 79 7f 32 95 a5 1a 75 c1 80 ad b2 c2 |"U8.y.2...u.....|
00000050 6f ce a5 f7 bd 4b d3 3f e4 b3 69 00 21 60 d7 09 |o....K.?..i.!`..|
00000060 a8 71 9b 5f 41 d6 66 b1 80 f1 de 00 26 19 34 01 |.q._A.f.....&.4.|
00000070 b3 65 1b 78 e2 32 71 be bc 07 25 78 36 6b 56 4e |.e.x.2q...%x6kVN|
00000080 26 4e 12 9e a8 bb 72 86 ee 0d 70 b2 f1 bd a3 2c |&N....r...p....,|
00000090 14 fd 12 61 35 98 4a 80 9f ee 3c 31 d3 70 26 0f |...a5.J...<1.p&.|
000000a0 73 a0 5d 36 ef 96 56 65 f8 ac 3a fb 44 c3 04 76 |s.]6..Ve..:.D..v|
000000b0 e5 2f ae 92 84 be 40 34 f6 4b b8 84 aa bd 67 74 |./....#4.K....gt|
000000c0 05 43 91 d2 e6 b1 50 dd 6d 64 47 cc 3e 3c 3a 9d |.C....P.mdG.><:.|
000000d0 67 ff 4f 38 c1 a5 a6 d5 92 45 bc 2d ff 96 30 3a |g.O8.....E.-..0:|
000000e0 1d 3a 42 4f 8c 13 2d 4c 3f e9 ad 08 a6 b3 5e fa |.:BO..-L?.....^.|
000000f0 46 08 24 17 43 ce ed ec f7 1a 38 62 e7 bf 42 93 |F.$.C.....8b..B.|
00000100 84 44 b6 05 22 9e e3 bd 80 a6 08 b0 34 d0 a4 89 |.D..".......4...|
00000110 78 48 20 7f 7b 33 1c 51 9d 48 b5 b7 f7 de 2f dd |xH .{3.Q.H..../.|
00000120 d7 74 7b af 04 cd 92 fc 1c |.t{......|
I was not able to get this to work. I'm pretty sure it is a dead end.
std::fstream inout(fname.c_str(), std::ios_base::in | std::ios_base::out | std::ios_base::binary | std::ios_base::app);
FileSource fs(inout, true,
new SignerFilter(prng, signer,
new FileSink(inout), true));
Obviously I'd like to append it to the file, that's why ...
Also, because you are using PSSR, you don't need the original message. PSSR is "probabilistic signature scheme with recovery". The message is include in the signature with a mask function.
You would need the original message with a SSA scheme. SSA is "signature scheme with appendix". In a SSA scheme you need to provide both the original message and the signature.
(From the comments) Here is an example that uses a Signature Scheme with Appendix (SSA). It also uses std::iftream and std::ofstream directly so FileSource and FileSink work as you expect. std::ofstream includes std::ios_base::app so the signature is appended.
#include "cryptlib.h"
#include "filters.h"
#include "osrng.h"
#include "files.h"
#include "oaep.h"
#include "rsa.h"
#include "sha.h"
#include <iostream>
#include <fstream>
#include <string>
int main(int argc, char* argv[])
{
using namespace CryptoPP;
AutoSeededRandomPool prng;
std::string fname("test.bin");
///// Create test message /////
{
std::string msg("Yoda said, Do or do not. There is no try.");
std::ofstream out(fname.c_str());
out.write(msg.data(), msg.size());
}
///// Generate a key /////
RSASS<PKCS1v15, SHA256>::Signer signer;
signer.AccessKey().GenerateRandomWithKeySize(prng, 2048);
{
///// Create fstreams for input and output /////
std::ifstream fin(fname.c_str(), std::ios_base::in | std::ios_base::binary);
std::ofstream fout(fname.c_str(), std::ios_base::out | std::ios_base::binary | std::ios_base::app);
///// Sign the message /////
FileSource source(fin, true,
new SignerFilter(prng, signer,
new FileSink(fout)));
}
///// Create a verifier /////
RSASS<PKCS1v15, SHA256>::Verifier verifier(signer);
///// Verify the message /////
{
FileSource source(fname.c_str(), true,
new SignatureVerificationFilter(verifier, NULLPTR,
SignatureVerificationFilter::THROW_EXCEPTION));
}
std::cout << "Verified signature on message" << std::endl;
return 0;
}
And then:
$ ./test.exe
Verified signature on message
$ hexdump -C test.bin
00000000 59 6f 64 61 20 73 61 69 64 2c 20 44 6f 20 6f 72 |Yoda said, Do or|
00000010 20 64 6f 20 6e 6f 74 2e 20 54 68 65 72 65 20 69 | do not. There i|
00000020 73 20 6e 6f 20 74 72 79 2e c7 b3 6f 84 1d fd bf |s no try...o....|
00000030 c7 c8 38 7c 89 b1 f3 42 ee 5e f8 10 de a8 01 7f |..8|...B.^......|
00000040 7f a5 24 3d 27 7e 55 16 bc 80 8b 21 21 75 3d ed |..$='~U....!!u=.|
00000050 41 05 84 b1 3d bf d3 ae 3a 2f a8 81 7a e7 e4 ae |A...=...:/..z...|
00000060 50 d7 9b 25 04 17 a6 a3 1d 12 e2 8e cd 7a 02 42 |P..%.........z.B|
00000070 91 c0 d7 fc 43 09 94 a2 66 d9 67 95 55 5e dc 8c |....C...f.g.U^..|
00000080 eb bc 20 af e8 5c d4 63 05 d4 2c 48 57 6d f1 fe |.. ..\.c..,HWm..|
00000090 26 16 80 c3 41 11 58 8e 8d b0 cb 48 95 b9 ed 94 |&...A.X....H....|
000000a0 84 cc 86 0f a4 7e a3 6a ff 0d 0d 24 17 82 13 94 |.....~.j...$....|
000000b0 54 cb 8a ca 04 1e 65 18 c3 ab a2 3f 4d 44 de 42 |T.....e....?MD.B|
000000c0 32 07 29 e4 95 83 cc ff 39 85 08 bf d5 61 46 db |2.).....9....aF.|
000000d0 e0 96 d6 69 25 b9 ce 1e 3e bc 63 81 e5 16 bd 12 |...i%...>.c.....|
000000e0 a0 78 02 19 60 96 80 36 7d a5 79 be 0f 45 54 f4 |.x..`..6}.y..ET.|
000000f0 92 af f0 d8 74 65 7d 45 98 c7 bb 7f 6e 9b e3 cd |....te}E....n...|
00000100 c0 60 91 0f 78 aa 7c 77 a7 f5 4e 7d 6e ed e1 4c |.`..x.|w..N}n..L|
00000110 8e 5e 96 ac cd 30 16 e0 2d be 9e 2d 68 d4 25 46 |.^...0..-..-h.%F|
00000120 86 77 87 be 68 ef 06 26 55 |.w..h..&U|
I have a strange error working with openssl in c++ with non blocking sockets.
SSL_accept return SSL_ERROR_SSL.
error string is
"error:140760FC:SSL routines:SSL23_GET_CLIENT_HELLO:unknown protocol"
as obtained from
ERR_error_string(ERR_get_error(), NULL);
ssldump:
New TCP connection #1: localhost(35677) <-> localhost(8084)
1 1 1443513828.4788 (0.0001) C>SV3.1(153) Handshake
ClientHello
Version 3.3
random[32]=
e9 fc d9 2b 25 20 77 9f 5f a4 b1 eb 5d 50 15 f2
38 7a a9 86 16 49 f8 a3 e9 00 7f 93 11 cd 7b b1
cipher suites
Unknown value 0xc02b
Unknown value 0xc02f
Unknown value 0xc00a
Unknown value 0xc009
Unknown value 0xc013
Unknown value 0xc014
Unknown value 0xc012
Unknown value 0xc007
Unknown value 0xc011
TLS_DHE_RSA_WITH_AES_128_CBC_SHA
TLS_DHE_DSS_WITH_AES_128_CBC_SHA
Unknown value 0x45
TLS_DHE_RSA_WITH_AES_256_CBC_SHA
TLS_DHE_DSS_WITH_AES_256_CBC_SHA
Unknown value 0x88
TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA
TLS_RSA_WITH_AES_128_CBC_SHA
Unknown value 0x41
TLS_RSA_WITH_AES_256_CBC_SHA
Unknown value 0x84
TLS_RSA_WITH_3DES_EDE_CBC_SHA
TLS_RSA_WITH_RC4_128_SHA
TLS_RSA_WITH_RC4_128_MD5
compression methods
NULL
1 2 1443513828.4790 (0.0002) S>CV3.3(53) Handshake
ServerHello
Version 3.3
random[32]=
aa d6 10 d1 eb b5 de b1 ed f8 6b 2f 44 fa 9f 57
14 1d c0 27 a1 e9 24 3a 20 cb 09 fa 75 33 1c c7
session_id[0]=
cipherSuite TLS_RSA_WITH_AES_128_CBC_SHA
compressionMethod NULL
1 3 1443513828.4790 (0.0000) S>CV3.3(1003) Handshake
Certificate
certificate[993]=
30 82 03 dd 30 82 02 c5 a0 03 02 01 02 02 09 00
bc 6b da c1 c3 f0 3f 14 30 0d 06 09 2a 86 48 86
f7 0d 01 01 0b 05 00 30 81 84 31 0b 30 09 06 03
55 04 06 13 02 49 4e 31 0b 30 09 06 03 55 04 08
0c 02 49 4e 31 10 30 0e 06 03 55 04 07 0c 07 67
75 72 67 61 6f 6e 31 0e 30 0c 06 03 55 04 0a 0c
05 69 72 65 78 78 31 0c 30 0a 06 03 55 04 0b 0c
03 64 65 76 31 12 30 10 06 03 55 04 03 0c 09 6c
6f 63 61 6c 68 6f 73 74 31 24 30 22 06 09 2a 86
48 86 f7 0d 01 09 01 16 15 76 69 6b 61 73 73 6f
6f 64 31 31 40 67 6d 61 69 6c 2e 63 6f 6d 30 1e
17 0d 31 35 30 39 32 39 30 38 30 32 35 36 5a 17
0d 31 36 30 39 32 38 30 38 30 32 35 36 5a 30 81
84 31 0b 30 09 06 03 55 04 06 13 02 49 4e 31 0b
30 09 06 03 55 04 08 0c 02 49 4e 31 10 30 0e 06
03 55 04 07 0c 07 67 75 72 67 61 6f 6e 31 0e 30
0c 06 03 55 04 0a 0c 05 69 72 65 78 78 31 0c 30
0a 06 03 55 04 0b 0c 03 64 65 76 31 12 30 10 06
03 55 04 03 0c 09 6c 6f 63 61 6c 68 6f 73 74 31
24 30 22 06 09 2a 86 48 86 f7 0d 01 09 01 16 15
76 69 6b 61 73 73 6f 6f 64 31 31 40 67 6d 61 69
6c 2e 63 6f 6d 30 82 01 22 30 0d 06 09 2a 86 48
86 f7 0d 01 01 01 05 00 03 82 01 0f 00 30 82 01
0a 02 82 01 01 00 e2 9e cb 0c 9a c2 a4 0a ff 81
77 23 ad 74 c6 a0 12 9f f4 a4 86 94 bf 02 57 cc
ff 13 cf 4f 13 83 6e 70 8b 2d ee 92 93 94 44 d4
db 20 e1 67 65 3a 67 c1 d5 91 67 ab f9 98 aa 59
16 b4 38 99 92 66 c2 de e7 88 82 cd a0 10 95 89
78 f5 64 6a e5 b6 75 a2 e0 d0 76 c3 57 92 03 c7
d3 7d f3 c5 18 e5 bf 8d f5 71 17 4c dd 18 fa 11
8c d1 ed 8b 0f b6 5c fb 16 bf 5a 44 23 71 c8 83
83 5a 4d ca b0 8c 15 96 66 dc cd 9a 06 33 b3 eb
71 43 25 b1 0f df 1a c6 f1 7a 4c 4d 5e 34 12 b7
70 76 b6 f9 7e 40 6c 2e 70 df 26 cd f9 c9 0b 90
57 dd 0b c3 57 b8 55 ad 63 13 16 15 bf 8d 3b 48
9d 11 cf 15 55 a1 f2 ab ff 8f 43 48 09 e7 c9 b0
21 66 e7 e4 76 14 aa d4 a9 88 ef bf e1 db 0f b3
27 95 d0 c9 50 6f 36 c8 5e 47 3f c3 a8 59 9c a6
8a 75 57 0b db 83 c6 08 13 fa 9c 64 3c 5a 4e d5
ba 4f 23 39 67 77 02 03 01 00 01 a3 50 30 4e 30
1d 06 03 55 1d 0e 04 16 04 14 29 86 80 ff 9c 14
00 5e 2e 89 81 4a 1e 3c 32 82 ec 44 35 7b 30 1f
06 03 55 1d 23 04 18 30 16 80 14 29 86 80 ff 9c
14 00 5e 2e 89 81 4a 1e 3c 32 82 ec 44 35 7b 30
0c 06 03 55 1d 13 04 05 30 03 01 01 ff 30 0d 06
09 2a 86 48 86 f7 0d 01 01 0b 05 00 03 82 01 01
00 c9 f4 f7 0f bd a4 f2 81 e4 4e c5 4d 86 9d f3
30 fe df f6 b1 b5 a3 a6 ef 41 51 fc f3 1b c5 be
e1 1f 75 fe f1 ee 94 95 54 c7 07 13 d4 b6 89 2b
a3 86 e3 7b 12 6d 0a 51 66 31 74 d5 83 67 92 79
45 b3 03 1d 77 6b b0 71 a0 07 c0 06 e6 6b 81 74
01 8e 6d a6 c1 82 8b 34 b2 6c 52 b9 3e a6 c0 c5
ce f6 c8 b2 4b 6a 8c 43 4a 20 38 61 8a 09 1f 39
cd e6 4a 0b 6c 89 b8 88 74 d7 1e fa 86 dc 0a cd
d4 73 39 5f 53 4b 13 79 f8 cd 62 ee 38 42 61 56
26 31 44 ac 5b 39 24 2b 3f f9 21 b4 59 25 14 95
69 e6 33 41 df ef b5 ea 20 7d 38 a9 f4 c3 d1 f7
c5 37 4a c9 01 cd f4 3a e7 3c a7 16 33 0f 5d 46
19 bc 50 3d 33 05 63 ee 29 51 d1 79 c4 01 04 0f
be 27 65 57 ab e5 e8 d3 bf 4d 11 55 bc 52 e4 9f
d9 0c 87 be a9 62 9d be 65 21 a8 8a 46 63 d1 91
f9 2b e1 c6 5d 33 fb ae b6 9e a0 36 0b 37 2a fa
3b
1 4 1443513828.4790 (0.0000) S>CV3.3(4) Handshake
ServerHelloDone
1 5 1443513828.4800 (0.0009) C>SV3.3(262) Handshake
ClientKeyExchange
EncryptedPreMasterSecret[256]=
76 58 13 c2 dd ed fb 6e 7b 49 aa 0c 26 40 a1 1f
8b 87 b0 f6 a5 f8 24 fe 0c 7b a9 e6 b0 51 b1 92
2c 52 33 ba af 2a d2 52 b8 80 0f ea fd 24 b7 89
15 2f 0e 90 86 ef 9c 9d 52 02 ca 56 09 b5 81 5f
e1 05 a8 9a 44 32 7f 4f ec 58 33 4a 97 96 23 15
7d a8 1d 8c bc 5d 20 13 39 54 2f 61 27 be aa 6a
ec 49 be 82 cc 2b c7 3d a3 b0 cb 4f 26 cb 14 41
d4 4b 00 57 6f 52 2b 66 aa 23 97 ed e9 e7 9c d9
ed 81 28 0c 08 9f dd 9d e4 00 b5 ba aa a4 f6 3b
23 87 f6 da 64 c0 1e 33 87 bb ef bc c3 fe 28 64
d1 c8 ff ae f9 3f 5a fe 38 e6 ab 3e 34 2c b5 96
f7 a8 99 b6 8e b3 46 d3 c9 f8 f8 94 26 97 27 85
5f 3e ff 85 15 5f c8 1f 10 53 26 e4 88 32 4f 48
62 87 ac a8 9f 14 f1 e3 f4 c4 1a 71 49 e6 33 15
16 66 66 ec 68 ee f7 91 0c 4c b3 3a 49 88 e1 31
a5 fe 4c 31 35 3d dc 01 f6 be f2 e5 65 a0 bb 78
1 6 1443513828.4800 (0.0000) C>SV3.3(1) ChangeCipherSpec
1 7 1443513828.4800 (0.0000) C>SV3.3(64) Handshake
Unknown SSL content type 72
1 1443513828.4801 (0.0001) S>C TCP RST
I am not sure why the server resets the connection.
I am using a self signed certificate to test a websocket connection using scheme wss. Client is Mozilla Firefox and websocket server is what I am trying to implement.
Any pointers on why the server is resetting the connection?
error:140760FC:SSL routines:SSL23_GET_CLIENT_HELLO:unknown protocol
What possible reason could throw unknown protocol?
Thanks
Edited: Adding code. It is not all the code but gives a fair idea of what i did.
Here is how my code looks like:
/*
this the main method that accepts incoming connection on a listening socket.
*/
SecureServer::Accept()
{
int ret = 0;
while(!mFinished) {
ret = epoll_wait(millis);
if(ret == -1) {
continue;
}
else if(ret == 0) {
idle(0);
}
else if(ret > 0) {
//some events are triggered
for(int i=0; i<ret; i++) {
//getEvent method is in the base class.
//SecureServer is derived from this class.
//Base class is just an epoll wrapper
epoll_event* ev = getEvent(i);
//check for error
if( (ev->events & EPOLLERR) || (ev->events & EPOLLHUP) || !(ev->events & EPOLLIN)) {
ERROR(Log::eSecureServer, "Error occured on fd = %d", ev->data.fd);
removeEpollFd(ev->data.fd);
continue;
}
//check if its a new incoming connection on server socket
else if(ev->data.fd == mServerSocket) {
//accept the connection
struct sockaddr peerAddress;
socklen_t socklen = sizeof(peerAddress);
int newSocket = accept(mSocket, &peerAddress, &socklen);
if(newSocket == -1) {
ERROR(Log::eSecureServer, "Error in accept, listen address = %s, port = %d epoll_wait returned = %d", mHost.c_str(), mPort, ret);
continue;
}
rxUShort port = ntohs(*((rxUShort*) &(peerAddress.sa_data[0])));
char ipPort[32] = {0};
sprintf(ipPort, "%hhu.%hhu.%hhu.%hhu:%hu", peerAddress.sa_data[2],peerAddress.sa_data[3],peerAddress.sa_data[4],
peerAddress.sa_data[5],port);
INFO(Log::eSecureServer, "SecureTCPServer received incoming client connection from = %s", ipPort);
//add epoll fd
// This method also makes the socket NON BLOCKING
addEpollFd(newSocket);
}
//check the handshake from a previously accepted connection
else {
//process the handshake
processHandshake(ev->data.fd);
}
}
}
}
}
/*
This method determines the client and server protocol
*/
int Protocol::processHandshake(int fd)
{
int length = 0;
length = recv(fd, handshake, 1024, MSG_PEEK);
if(length == 0) {
return UNKNOWN_PROTOCOL;
}
else if((bcmp(handshake, "\x16", 1) == 0) ||
(bcmp(handshake, "\x80", 1) == 0)) {
//secure connection requested on this fd
SSL* pSSL = 0;
int ret = NewSSLSocket(pSSL, fd);
if(SSL_ERROR_NON == ret) {
///success
}
else {
if(SSL_ERROR_WANT_READ == ret || SSL_ERROR_WANT_WRITE == ret) {
NFO(Log::eProtocol, "Handshake error, in progress.");
return eProtocolHandshakeInProgress;
} else if(SSL_ERROR_SSL == ret) {
INFO(Log::eProtocol, "Handshake error, library error");
return eProtocolInvalidHeader;
} else if(SSL_ERROR_SYSCALL == ret) {
INFO(Log::eProtocol, "Handshake error, possibly syscall error");
return eProtocolInvalidHeader;
}
SSL_free(pSSL);
}
}
}
int Protocol::NewSSLSocket(SSL* pSSL, rxUInt fd)
{
pSSL = SSL_new(mSSLContext);
SSL_set_fd(pSSL, fd);
int ret = SSL_accept(pSSL);
switch(SSL_get_error(pSSL, ret)) {
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
{
INFO(Log::eNetwork, "SSL Handshake is in progress on fd = %d %s", fd, ERR_error_string(ERR_get_error(), NULL));
return SSL_ERROR_WANT_READ;
}
break;
case SSL_ERROR_SYSCALL:
{
INFO(Log::eNetwork, "SSL syscall error during handshake on fd = %d %s", fd, ERR_error_string(ERR_get_error(), NULL));
return SSL_ERROR_SYSCALL;
}
break;
case SSL_ERROR_SSL:
{
INFO(Log::eNetwork, "SSL library error during handshake on fd = %d %s", fd, ERR_error_string(ERR_get_error(), NULL));
return SSL_ERROR_SSL;
}
case SSL_ERROR_NONE:
{
INFO(Log::eNetwork, "SSL handshake on fd = %d complete", fd);
return SSL_ERROR_NONE;
}
break;
default:
{
INFO(Log::eNetwork, "SSL unknown error during handshake on fd = %d %s", fd, ERR_error_string(ERR_get_error(), NULL));
return -1;
}
break;
}
return -1;
}
//Protocol Constructor Init the SSL Context
Protocol::Protocol()
{
const SSL_METHOD* pSSLMethod = SSLv23_server_method();
char err[1024] = {0};
mSSLContext = SSL_CTX_new(pSSLMethod);
if(mSSLContext == NULL) {
ERROR(Log::eNetwork, "Failed to initialize SLS_CTX. TLS Unavaliable.");
ERROR(Log::eNetwork, ERR_error_string(ERR_get_error(), err));
} else
INFO(Log::eNetwork, "Initialized SSL Context.");
SSL_CTX_set_cipher_list(mSSLContext, "ALL");
//Load the SSL Certificates
rxUInt ret = 0;
ret = SSL_CTX_use_certificate_file(mSSLContext, mCACertificateFile.c_str(), SSL_FILETYPE_PEM);
if(ret <=0 ) {
ERROR(Log::eNetwork, "Failed to read ssl sertificate. We should exit.");
ERROR(Log::eNetwork, ERR_error_string(ERR_get_error(), err));
} else
INFO(Log::eNetwork, "SSL Certificate read complete. OK!");
//Load the private key file
ret = SSL_CTX_use_PrivateKey_file(mSSLContext, mPrivateKeyFile.c_str(), SSL_FILETYPE_PEM);
if(ret <=0 ) {
ERROR(Log::eNetwork, "Failed to read private key file. We should exit.");
ERROR(Log::eNetwork, ERR_error_string(ERR_get_error(), err));
} else
INFO(Log::eNetwork, "Private Key read complete. OK!");
if(!SSL_CTX_check_private_key(mSSLContext)) {
ERROR(Log::eNetwork, "Private key does not match the SSL Certificate. We should exit.");
ERROR(Log::eNetwork, ERR_error_string(ERR_get_error(), err));
} else
INFO(Log::eNetwork, "Private Key and SSL Certificate Matched. OK!");
}
1 7 1443513828.4800 (0.0000) C>SV3.3(64) Handshake
Unknown SSL content type 72
My guess is that you are sending some plain data on the connection, i.e. write to the plain socket instead to the SSL socket. This is just a guess because you did not provide any code but looking for such error one finds issues like this.
I've generated a public key using openssl
BIGNUM* e = BN_new();
BN_set_word(e, 17);
RSA* rsa = RSA_new();
if(!RSA_generate_key_ex(rsa, 2048, e, NULL)) {
LOG(security, debug) << "failed to generate private key";
}
And these are written to files:
FILE* pubwriter = fopen("key.pub", "wb");
int err = PEM_write_RSAPublicKey(pubwriter, key);
if(!err) {
throw new std::runtime_error("Failed to store public key");
}
FILE* privwriter = fopen("key.priv", "wb");
std::string password = "password";
err = PEM_write_RSAPrivateKey(privwriter, key, EVP_des_ede3_cbc(),
(unsigned char*)password.c_str(),
password.size(), NULL, NULL);
And they seem to be stored correctly, key.pub then contains something like
-----BEGIN RSA PUBLIC KEY-----
MIIBCAKCAQEA0rG1b0g3NIsDT8HkzgTx8BUI9LhueWbH1NuAvIh9qTF57GzEXuTu
jxBcuSzWXlR83ci4oITp7VqV6KLVoJryf8orGXBVi9A73JYOQVB6FEzARKym/g8E
fSEwSmdQ4NfiTESwOCtIextdu3x8pANSYDyyqdiWsSHy0SiZmkbvdVYomIBJZOV9
jhb3mkmD0WUYie9AXziTbli97YqDiN168kMI+7ePpbNJFSVSIUkPPocSgvgcAux/
HuDqftzBgyAF3NGb3AAra1A8T7yPOqLyYyXdIJmF+/Svk5PdMbZVE/U76cjBThch
Q9AiLo25hOjkmtuEQubCuwrUDleblr93aQIBEQ==
-----END RSA PUBLIC KEY-----
Now I want to try these to make sure I haven't got anything wrong but it wont' load:
$ openssl rsautl -encrypt -inkey key.pub -pubin -in data.txt -out enc.txt
unable to load Public Key
What am I missing?
int err = PEM_write_RSAPublicKey(pubwriter, key);
PEM_write_RSAPublicKey writes just the public key. You can make the command work using PEM_write_PUBKEY. The various *_PUBKEY routines write the SubjectPublicKeyInfo, which includes the algorithm OID and public key.
When you write the SubjectPublicKeyInfo, OpenSSL calls it "traditional" format. It will also have the header -----BEGIN PUBLIC KEY----- (and not -----BEGIN RSA PUBLIC KEY-----).
Below, I used PEM_write_PUBKEY to save the public key rsa-public.pem:
$ openssl rsautl -encrypt -inkey rsa-public.pem -pubin -in data.txt -out enc.bin
$ hexdump enc.bin
0000000 45 53 31 ad 9d 6a c4 37 1e 22 4b 83 c6 27 c8 3c
0000010 df cb 87 a4 60 d8 63 9a 83 9f ee ca e5 8f 8e dd
0000020 d4 d0 98 97 1c b3 36 55 f1 84 ea 7f fe bf 22 b6
0000030 93 20 a2 d5 b2 bd 20 cc 52 8e c7 1b 33 e6 40 40
0000040 cb 7d 6f 17 f1 eb f1 d4 9d 66 fb 67 eb 67 ba 2a
0000050 44 c2 52 15 54 8d 79 76 ad 26 61 35 27 9c bb 6c
0000060 5b 0e 79 b3 d3 27 0b a9 72 17 0d 2d 19 d7 60 19
0000070 16 46 80 4b c0 ae 75 53 9e 6f f5 24 d9 1a a3 6a
0000080 2f 38 13 f6 72 19 20 94 de 40 75 20 51 f4 08 f4
0000090 74 b8 ac 49 01 d6 f8 f4 e5 79 38 88 2d 02 b7 bd
00000a0 f7 63 c1 e1 e5 ec 39 a1 fa 7c ce 0f 83 16 70 7e
00000b0 cd 7e f5 6b 51 c2 db d7 f6 c4 46 5d e5 93 d3 3d
00000c0 ab e6 3b 1a 97 d4 c9 54 e7 aa 90 2d 0a b9 c2 4b
00000d0 3c 58 fd 26 58 5a 63 c0 8c ae b9 72 24 a1 68 5d
00000e0 83 d7 5b ae 56 2a 78 46 8c f4 21 96 bd d3 0c 93
00000f0 8e 35 61 9c b8 56 2e 3a 4e 05 d9 1e 0b 59 14 11
0000100
PEM_write_PUBKEY requires a EVP_PKEY. Just use something like:
EVP_PKEY* pkey = EVP_PKEY_new();
ASSERT(pkey != NULL);
int rc = EVP_PKEY_set1_RSA(pkey, rsa);
ASSERT(rc == 1);
...
EVP_PKEY_free(pkey);
The set1 bumps the reference count on the RSA key, so you have to free it through EVP_PKEY_free.
The difference between PEM_write_RSAPublicKey and PEM_write_PUBKEY is very obvious when you save in ASN.1/DER. But it gets lost in the PEM encoding.
Here's the non-traditional key in ASN.1/DER and dumped. Its the ASN.1 equivalent of PEM_write_RSAPublicKey. Its just {n,e}:
$ dumpasn1 rsa-public-1.der
0 266: SEQUENCE {
4 257: INTEGER
: 00 D1 C8 05 BF AC 04 72 AA 0E 84 FB 47 75 59 97
: E1 81 65 0B 0A 1D 9D 2A A8 A1 E0 B1 14 5D 57 69
: D4 D2 E2 C6 64 54 94 C2 92 CC C7 99 1A 97 89 72
: F6 36 6A A7 B8 34 2C AB A9 CB 77 EB 0D A1 4E 72
: 24 9F 96 D6 1C 28 ED 44 E8 0B 22 7F F3 5B 52 E2
: 7E A6 5E F1 7C A2 29 4F F1 8B 9D 0F 94 27 05 D5
: BD 2E 1A AD B4 12 0D E0 69 3E 0B 1B A7 F8 71 B5
: AD 22 4B 18 FF 72 88 F3 C5 77 B0 CF 88 5C F4 19
: [ Another 129 bytes skipped ]
265 3: INTEGER 65537
: }
0 warnings, 0 errors.
Here's the traditional public key in ASN.1/DER and dumped. Its the ASN.1 equivalent of PEM_write_PUBKEY. Its the one that writes the SubjectPublicKeyInfo, and it includes an algorithm OID and public key:
$ dumpasn1 rsa-public-2.der
0 290: SEQUENCE {
4 13: SEQUENCE {
6 9: OBJECT IDENTIFIER rsaEncryption (1 2 840 113549 1 1 1)
17 0: NULL
: }
19 271: BIT STRING, encapsulates {
24 266: SEQUENCE {
28 257: INTEGER
: 00 D1 C8 05 BF AC 04 72 AA 0E 84 FB 47 75 59 97
: E1 81 65 0B 0A 1D 9D 2A A8 A1 E0 B1 14 5D 57 69
: D4 D2 E2 C6 64 54 94 C2 92 CC C7 99 1A 97 89 72
: F6 36 6A A7 B8 34 2C AB A9 CB 77 EB 0D A1 4E 72
: 24 9F 96 D6 1C 28 ED 44 E8 0B 22 7F F3 5B 52 E2
: 7E A6 5E F1 7C A2 29 4F F1 8B 9D 0F 94 27 05 D5
: BD 2E 1A AD B4 12 0D E0 69 3E 0B 1B A7 F8 71 B5
: AD 22 4B 18 FF 72 88 F3 C5 77 B0 CF 88 5C F4 19
: [ Another 129 bytes skipped ]
289 3: INTEGER 65537
: }
: }
: }
0 warnings, 0 errors.
err = PEM_write_RSAPrivateKey(privwriter, key, EVP_des_ede3_cbc(),
(unsigned char*)password.c_str(),
password.size(), NULL, NULL);
I believe the OpenSSL folks recommend you use PEM_write_PKCS8PrivateKey. See PEM(3) and pkcs8(1).
Now I want to try these to make sure I haven't got anything wrong but it wont' load:
$ openssl rsautl -encrypt -inkey key.pub -pubin -in data.txt -out enc.txt
You can understand the behavior by looking at <openssl src>/apps/rsautl.c. Here are the relevant lines:
else if (!strcmp(*argv, "-pubin")) {
key_type = KEY_PUBKEY;
}
...
case KEY_PUBKEY:
pkey = load_pubkey(bio_err, keyfile, keyform, 0, NULL, e, "Public Key");
break;
...
Then, in apps.c:
if (format == FORMAT_ASN1) {
pkey = d2i_PUBKEY_bio(key, NULL);
}
...
else if (format == FORMAT_PEM) {
pkey = PEM_read_bio_PUBKEY(key, NULL, ...);
}
...
The observation above is the routines are using *_PUBKEY.
There's also a code path based on format == FORMAT_PEMRSA that calls PEM_read_bio_RSAPublicKey, but I don't know how to trigger it. Looking at rsautl(1), I don't think you can because there's no switch that exposes it.
If it was going to trigger, it would be based on a combination of the -keyform option combined with format == FORMAT_PEMRSA. But apps.c's str2fmt does not return a FORMAT_PEMRSA.
I think that means your only option is to use a SubjectPublicKeyInfo. And that means using PEM_write_PUBKEY (or convert the key after the fact).
Now related: OpenSSL Bug Report, Issue 3887: rsautl and intelligent retry for Public Key parse after Traditional/Subject Public Key Info parse fails.
I faced the same problem and managed to debug by following #jww answer above. In the process I discover a simple command that does not require a EVP_PKEY.
Just use PEM_write_bio_RSA_PUBKEY(BIO * bp, RSA * x) directly. Read PEM_write documentation for details.
I am looking for an example of LUC algorithm, but I can't find anything. I know that it is in Crypto++, but I don't know C++ too well to use it.
I look for an example of algorithm of LUC...
It kind of depends on what you want to do. You might want to browse luc.h to see some of the things Crypto++ offers for LUC. There's a LUCES, a LUCSS and a LUC_IES. The *ES is encryption scheme, the *SS is a signature scheme, and the *IES is an integrated encryption scheme (which includes a key agreement algorithm and mask function).
Generally speaking, LUC is a public key encryption system. Using it is like using any other public key encryption system offered by Crypto++. That's because all the public key encryption systems inherit from the same classes (more correctly, base interfaces). You can see the design in the comments for file pubkey.h.
$ grep -R LUCES *
...
typedef LUCES<OAEP<SHA> >::Decryptor LUCES_OAEP_SHA_Decryptor;
typedef LUCES<OAEP<SHA> >::Encryptor LUCES_OAEP_SHA_Encryptor;
And that's pretty much all you need, though you may not know it.
Here's the easier problem to solve. How do you perform RSA encryption in Crypto++?
$ grep -R RSAES *
...
typedef RSAES<PKCS1v15>::Decryptor RSAES_PKCS1v15_Decryptor;
typedef RSAES<PKCS1v15>::Encryptor RSAES_PKCS1v15_Encryptor;
typedef RSAES<OAEP<SHA> >::Decryptor RSAES_OAEP_SHA_Decryptor;
typedef RSAES<OAEP<SHA> >::Encryptor RSAES_OAEP_SHA_Encryptor;
If you find an RSAES_PKCS1v15_Decryptor or RSAES_OAEP_SHA_Decryptor example, you just copy/replace with LUCES_OAEP_SHA_Decryptor and it will work just fine. And if you find an RSAES_PKCS1v15_Encryptor or RSAES_OAEP_SHA_Encryptor example, you just copy/replace with LUCES_OAEP_SHA_Encryptor and it will work just fine.
You can find the examples of using RSAES_OAEP_SHA_Encryptor and RSAES_OAEP_SHA_Decryptor on the Crypto++ wiki page for RSA Encryption Schemes. Or you can use the ECIES examples at Elliptic Curve Integrated Encryption Scheme (remember, all the public key systems inherit from the same base interfaces, so they all have the same methods and you use them the same way).
This should get you started. It creates a private key, saves it, then creates a public key, and saves it.
try
{
AutoSeededRandomPool prng;
FileSink fs1("lucs-private.der", true);
FileSink fs2("lucs-public.der", true);
InvertibleLUCFunction params;
params.GenerateRandomWithKeySize(prng, 2048);
LUC::PrivateKey privateKey(params);
privateKey.DEREncode(fs1);
LUCES_OAEP_SHA_Decryptor decryptor(privateKey);
// ...
LUC::PublicKey publicKey(params);
publicKey.DEREncode(fs2);
LUCES_OAEP_SHA_Encryptor encryptor(publicKey);
// ...
}
catch(CryptoPP::Exception& ex)
{
cerr << ex.what() << endl;
}
If you don't want to use InvertibleLUCFunction, the do something like this to generate the key. Note: RSA has an InvertibleRSAFunction.
LUC::PrivateKey privateKey;
privateKey.Initialize(prng, 2048);
...
LUC::PublicKey publicKey(privateKey);
...
An here's yet another way to do it:
FileSink fs1("lucs-private.der", true);
FileSink fs2("lucs-public.der", true);
LUCES_OAEP_SHA_Decryptor decryptor;
decryptor.AccessKey().Initialize(prng, 2048);
decryptor.AccessKey().DEREncode(fs1);
...
LUCES_OAEP_SHA_Encryptor encryptor(decryptor);
encryptor.AccessKey().DEREncode(fs2);
...
And here's a dump of the private key created by the test program:
$ dumpasn1 lucs-private.der
0 662: SEQUENCE {
4 1: INTEGER 0
7 257: INTEGER
: 00 B8 7A CA 6A 61 D9 CF 2F D8 89 5C A4 7D 74 7B
: AC F5 10 4C 3D 95 BF DD 2E F5 4E E5 F4 20 CF CD
: 44 7F C7 27 41 48 6B 83 E0 7C D9 66 16 8D 54 36
: 97 B9 CE 2D 80 A6 F6 E5 25 87 83 6E B9 41 45 DC
: 2A EB EC 4E EC D9 C0 17 B4 E0 04 F0 58 61 60 F8
: 87 18 27 16 58 BA 56 4E DD 9B C8 CD 18 46 28 38
: A2 6A A6 14 36 D0 A6 FF 9C B8 A8 B5 0F 3A 11 B5
: 00 08 44 B3 31 58 AF 01 F8 57 17 E8 FC 68 B2 5F
: [ Another 129 bytes skipped ]
268 1: INTEGER 17
271 129: INTEGER
: 00 C8 DF 47 D0 B2 6F C2 1A E4 B7 E8 3D 12 BB FF
: 04 F7 34 40 A0 0E ED DC F7 24 7B D9 46 EE 10 C4
: D5 E2 9C 93 05 CF 13 53 40 F4 50 EC 1F 6D D7 33
: FF FF 46 42 88 8D FC F4 EE 7F 0C 8B 71 71 51 D2
: 3C 32 E3 9A 11 B7 D8 CF EA 10 B2 07 49 3F 93 CD
: A0 3F 71 A9 23 27 35 1F 6A C9 1D FE CE 24 75 33
: 8F 53 71 B9 0B DE BC 05 93 98 A3 EA 94 8E 04 B1
: 29 A1 4F 4C 82 34 7A 08 3A 0E 07 98 8B 00 30 D7
: 5B
403 129: INTEGER
: 00 EB 1B D0 EF 5C 0F FC FC B7 56 A7 70 8C AA B7
: A6 90 C8 1F AA AD A0 0B 66 E5 33 75 F2 BE 68 35
: 29 2E 57 AC E0 E0 C8 04 A7 C4 13 1D 10 30 8B 50
: 20 17 0C 83 A7 14 4A 7D 25 31 77 50 66 08 36 13
: BE 9D C0 4E F4 44 74 7A BB D2 92 D0 F7 AE 7C EB
: 8E 84 5C 27 61 2C C9 7A D1 D0 C5 A0 13 98 96 E3
: 76 CD B0 E7 E8 7E 4E 0A 2D 00 86 07 57 DB 8A 51
: 1E 59 76 EA 88 44 4D DA F3 D6 AB 75 CB A6 45 F3
: F3
535 128: INTEGER
: 2E 6A AA BA B4 E8 DD 11 2D 31 A4 D5 F7 08 AB E3
: 1A 9A 15 58 AE C8 59 BE C4 75 85 90 6D 5D A4 18
: 39 27 8F FF 1C 9A FD 0F 0C 29 05 98 9C 16 FE 84
: A4 5C 85 15 F7 98 E6 D5 5B 23 CA 2F A2 27 8A 00
: 6E B1 BB 02 6E 93 53 85 30 30 61 F5 1C 49 5D 19
: EF DF CD 6F 11 7C 6D DC AE F6 A2 06 53 BB 7E 03
: C3 E5 4E E9 59 E0 D8 5F C3 28 0E E0 17 5C 63 6E
: 8E A6 18 FC AD A5 9B 08 D1 8B 7B 28 9D E2 CF E2
: }
0 warnings, 0 errors.