I'm trying to Store ECIES num0 PrivateKey with DEREncodePrivateKey to a std::string and reload it in num1 PrivateKey Object for testing.
Problem is when key is loaded with BERDecodePrivateKey in second PrivateKey object it can't be validated (also tested encryption and decrypting without validation and didn't decrypt )
here's the code
using namespace CryptoPP;
CryptoPP::AutoSeededRandomPool prng;
ECIES<ECP>::PrivateKey pp;
pp.Initialize(prng, ASN1::secp256k1());
/* returns true*/
bool val=pp.Validate(prng, 3);
std::string saves;
StringSink savesink(saves);
pp.DEREncodePrivateKey(savesink);
/*additional unnecessary steps to make sure the key is written completely */
savesink.MessageEnd();
savesink.Flush(true);
ECIES<ECP>::PrivateKey pro;
StringSource savesSource(saves, true);
pro.BERDecodePrivateKey(savesSource,true,savesSource.MaxRetrievable());
/*here the exception is thrown */
pro.ThrowIfInvalid(prng, 3);
finally found what the problem is
as #maarten-bodewes mentioned in comment the DER encoded private exponent doesn't determine the curve OID for the privateKey Object , so before BER Decoding and importing key we need to somehow determine the OID for the Object;
the simplest way is to determine it when Initializing new Object
above code changes to :
ECIES<ECP>::PrivateKey pro;
StringSource savesSource(saves, true);
auto rett = savesSource.MaxRetrievable();
pro.Initialize(prng, ASN1::secp256k1());
pro.BERDecodePrivateKey(savesSource,true,savesSource.MaxRetrievable());
also you AccessGroupParameters().Initialize(/*OID*/); or Initialize(/*OID*/) for existing object
I have been trying to use TransferClient in C++ from the official SDK following the tests in the SDK. But when I run the following code, I don't get a human readable string. Ideas?
TransferClientConfiguration transferConfig;
transferConfig.m_uploadBufferCount = 20;
static const char* ALLOCATION_TAG = "TransferTests";
ClientConfiguration config;
std::shared_ptr<S3Client> m_s3Client = Aws::MakeShared<S3Client>(ALLOCATION_TAG, config, false);
std::shared_ptr<TransferClient> m_transferClient = Aws::MakeShared<TransferClient>(ALLOCATION_TAG, m_s3Client, transferConfig);
std::string s3path = "akey";
std::shared_ptr<UploadFileRequest> requestPtr = m_transferClient->UploadFile(filepath.string(), "testbucket", s3path.c_str(), "", false, true);
requestPtr->WaitUntilDone();
if (!requestPtr->CompletedSuccessfully())
{
// requestPtr->GetFailure() returns a blank string here??
}
Figured out the problem! Turns out the bucket is in us-west-1 and for what ever reason, the transfer client with the default client option doesn't work.
I have successfully used this some lines ago in my program:
string tmp;
StringSource(msg, true, new PK_EncryptorFilter(*rng, *encryptor, new CryptoPP::HexEncoder(new StringSink(tmp))));
return tmp;
So you know that the Crypto++ objects are well created and so.
Now I want to encrypt a whole binary file and save it to an adjacent file:
FileSource(file.c_str(), true, new PK_EncryptorFilter(*rng, *encryptor, new FileSink((file+".xx").c_str(), true)),true);
But this last line crashes with a debug error stating that abort() has been called.
Hunting down the error, I tried to change the second argument to the FileSource call to false, leading to the following code:
FileSource(file.c_str(), false, new PK_EncryptorFilter(*rng, *encryptor, new FileSink((file+".xx").c_str(), true)),true);
And then the error gone, but the destination file weights 0 bytes, nothing was read/wrote.
I do not know what can can the key to the problem, so, I hope someone can help a little bit.
EDIT: I am using Visual Studio 2013 Pro.
EDIT2: I hunted the error further.
This works and the file binary content is correctly printed on screen:
string s;
FileSource file2("C:\\test.jpg", true, new StringSink(s));
std::cout << s << std::endl;
But this don't work and ends with the mentioned crash.
string s;
FileSource file2("C:\\test.jpg", true, new PK_EncryptorFilter(*rng, *encryptor, new StringSink (s)));
std::cout << s << std::endl;
This is so strange since the same PK_EncryptorFilter filter is used in another method without trouble, as I stated at the beginning of the post.
Anyway, I post here my entire class, so as to get a clear idea of what is going on:
RSASystem::RSASystem()
{
std::string pubkey = "...OMITED...";
rng = new AutoSeededRandomPool;
CryptoPP::HexDecoder decoder;
decoder.Put((byte*)pubkey.c_str(), pubkey.size());
decoder.MessageEnd();
CryptoPP::HexDecoder decoder2;
decoder2.Put((byte*)pubkey.c_str(), pubkey.size());
decoder2.MessageEnd();
verifier = new RSASSA_PKCS1v15_SHA_Verifier;
encryptor = new RSAES_OAEP_SHA_Encryptor;
verifier->AccessKey().Load(decoder);
encryptor->AccessKey().Load(decoder2);
}
string RSASystem::encrypt(string msg)
{
string tmp;
StringSource(msg, true, new PK_EncryptorFilter(*rng, *encryptor, new CryptoPP::HexEncoder(new StringSink(tmp))));
return tmp;
}
void RSASystem::encryptFile(string file)
{
FileSource(file.c_str(), true, new PK_EncryptorFilter(*rng, *encryptor, new FileSink((file+".xx").c_str(), true)),true);
}
EDIT 3: After surrounding the code with try..catch() I got this error:
RSA/OAEP-MGF1(SHA-1): message length of 490986 exceeds the maximum of 214 for this public key
Which now I think can be easily solved.
FileSource(file.c_str(), false,
new PK_EncryptorFilter(*rng, *encryptor,
new FileSink((file+".xx").c_str(), true)
),
true);
This does not look right. new FileSink((file+".xx").c_str() returns a char*, and you need a pointer to a Sink. Plus, there's an extra false in there I'm not used to seeing. Something like:
FileSource fs1(filename, true,
new PK_EncryptorFilter(rng, encryptor,
new FileSink(filename, true)
) // PK_EncryptorFilter
); // StringSource
There's a couple of examples on the Crypto++ wiki. See RSA Cryptography and RSA Encryption Schemes.
The following is an example from the Crypto++ wiki using RSA. But you can use the code for any cryptosystem that adheres to PK_Encryptor and PK_Decryptor (Sources (like StringSource and FileSource) and Sinks (like StringSink and FileSink) are also interchangeable):
////////////////////////////////////////////////
// Generate keys
AutoSeededRandomPool rng;
InvertibleRSAFunction params;
params.GenerateRandomWithKeySize( rng, 1536 );
RSA::PrivateKey privateKey( params );
RSA::PublicKey publicKey( params );
string plain="RSA Encryption", cipher, recovered;
////////////////////////////////////////////////
// Encryption
RSAES_OAEP_SHA_Encryptor e( publicKey );
StringSource ss1( plain, true,
new PK_EncryptorFilter( rng, e,
new StringSink( cipher )
) // PK_EncryptorFilter
); // StringSource
////////////////////////////////////////////////
// Decryption
RSAES_OAEP_SHA_Decryptor d( privateKey );
StringSource ss2( cipher, true,
new PK_DecryptorFilter( rng, d,
new StringSink( recovered )
) // PK_DecryptorFilter
); // StringSource
assert( plain == recovered );
Also, don't use anonymous declarations. Some versions of GCC has problems with them. That is, use:
StringSource ss1( plain, true,
...
rather than:
StringSource( plain, true,
...
I had already pending the encryption and security subject so I wasn't aware of the limitation on the length of the message of the RSA scheme.
https://security.stackexchange.com/questions/44702/whats-the-limit-on-the-size-of-the-data-that-public-key-cryptos-can-handle
So the solution passes by implementing an Integrated or Hybrid Encryption Scheme, like ECIES.
I've done this successfully with Crypto++ using: http://www.cryptopp.com/wiki/Elliptic_Curve_Integrated_Encryption_Scheme
Thanks to jww to point to the correct decision.
OK, I think I know where you might be having problems. But I'd need to see all your code and not just the encryption.
I could coax a BER Decode error by omitting encoder1.MessageEnd and encoder2.MessageEnd. Apparently, I was able to read the key before it was fully written. I assume it was fully written after leaving main (and the destructors ran) because the file sizes looked OK with ls.
In the code below, the message was encrypted under publicKey1 and then decrypted with privateKey2 to ensure the keys were round-tripping.
try {
////////////////////////////////////////////////
// Generate keys
AutoSeededRandomPool rng;
InvertibleRSAFunction params;
params.GenerateRandomWithKeySize(rng, 1024);
RSA::PrivateKey privateKey1(params);
RSA::PublicKey publicKey1(privateKey1);
////////////////////////////////////////////////
// Save/Load keys
HexEncoder encoder1(new FileSink("private-key-der.txt", true));
HexEncoder encoder2(new FileSink("public-key-der.txt", true));
privateKey1.Save(encoder1);
publicKey1.Save(encoder2);
// Must have these. Otherwise, the full key (hex encoded)
// is not written until destructors are run
encoder1.MessageEnd();
encoder2.MessageEnd();
FileSource fs1("private-key-der.txt", true, new HexDecoder);
FileSource fs2("public-key-der.txt", true, new HexDecoder);
RSA::PrivateKey privateKey2;
RSA::PublicKey publicKey2;
privateKey2.Load(fs1);
bool valid = privateKey2.Validate(rng, 3);
if(!valid)
throw Exception(Exception::OTHER_ERROR, "Failed to validate key 1");
publicKey2.Load(fs2);
valid = publicKey2.Validate(rng, 3);
if(!valid)
throw Exception(Exception::OTHER_ERROR, "Failed to validate key 2");
////////////////////////////////////////////////
// Scratch
string plain="RSA Encryption", cipher, recovered;
////////////////////////////////////////////////
// Encryption
RSAES_OAEP_SHA_Encryptor encryptor(publicKey1);
StringSource ss1(plain, true,
new PK_EncryptorFilter(rng, encryptor,
new StringSink(cipher)
) // PK_EncryptorFilter
); // StringSource
////////////////////////////////////////////////
// Decryption
RSAES_OAEP_SHA_Decryptor decryptor(privateKey2);
StringSource ss2(cipher, true,
new PK_DecryptorFilter(rng, decryptor,
new StringSink(recovered)
) // PK_DecryptorFilter
); // StringSource
cout << "Recovered plain text: " << recovered << endl;
} catch (const Exception& ex) {
cerr << ex.what() << endl;
}
I have to get ECDSA signature in variable using Crypto++.
I tried to get it after launching SignMessage but signature is empty.
How could i get it?
Have you had a look at the Crypto++ wiki? There's a lot of stuff on Elliptic Curve Digital Signature Algorithm.
Its not really clear what you are doing or where things went wrong, so here's a copy and paste from the wiki:
Signing:
ECDSA<ECP, SHA1>::PrivateKey privateKey;
privateKey.Load(...);
AutoSeededRandomPool prng;
string message = "Yoda said, Do or do not. There is no try.";
string signature;
StringSource ss1( message, true /*pump all*/,
new SignerFilter( prng,
ECDSA<ECP,SHA1>::Signer( privateKey ),
new StringSink( signature )
) // SignerFilter
); // StringSource
Verification:
ECDSA<ECP, SHA1>::PublicKey publicKey;
publicKey.Load(...);
// Result of the verification process
bool result = false;
// Exactly what was signed in the previous step
string message = ...;
// Output from the signing operation in the previous step
string signature = ...;
StringSource ss2( signature+message, true /*pump all*/,
new SignatureVerificationFilter(
ECDSA<ECP,SHA1>::Verifier(publicKey),
new ArraySink( (byte*)&result, sizeof(result) )
) // SignatureVerificationFilter
);
// Verification failure?
if( !result ) {...}
If you would like the verifcation to throw on a failure, then try:
static const int VERIFICATION_FLAGS = SIGNATURE_AT_BEGIN | THROW_EXCEPTION;
StringSource ss3( signature+message, true /*pump all*/,
new SignatureVerificationFilter(
ECDSA<ECP,SHA1>::Verifier(publicKey),
NULL, /* No need for attached filter */
VERIFICATION_FLAGS
) // SignatureVerificationFilter
);
Does anyone know how I would do the equivalent of the below C# code using unmanaged C++ i.e. query a certificate from the X509 certificate store by thumbprint?
var store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
var allCerts = store.Certificates;
foreach (var certificate in from X509Certificate2 certificate in allCerts
where certificate.Thumbprint != null
&& certificate.Thumbprint.Equals(thumbprint, StringComparison.OrdinalIgnoreCase)
select certificate)
{
return certificate;
}
Thanks in advance
Dave
In order to accomplish what you want, you'll have to look into the Win32 CryptAPI library. It won't be as easy as .NET. Look into CertOpenStore and CertFindCertificateInStore.
You'll need to open a certificate store and pass it into CertFindCertificateStore, creating a structure to hold whatever criteria you want to use to find your certificate. You can use a serial number, signature, etc.
HCERTSTORE hSysStore = NULL;
PCCERT_CONTEXT pDesiredCert = NULL;
if(hSysStore = CertOpenStore(
CERT_STORE_PROV_SYSTEM, // The store provider type
0, // The encoding type is
// not needed
NULL, // Use the default HCRYPTPROV
CERT_SYSTEM_STORE_CURRENT_USER, // Set the store location in a
// registry location
L"MY" // The store name as a Unicode
// string
))
{
//We have our store, let's do stuff with it
if (pDesiredCert = CertFindCertificateInStore(.....) { ..... }
}
else
{
//Error stuff
}
You will need to #include <Wincrypt.h> and #include <windows.h>
The code from CertFindCertificateInStore. will not work on newer systems. On newer versions of Windows the certificate's name or subject are in Unicode format which uses 2 bytes for each character. The folowing line:
LPCSTR lpszCertSubject = (LPCSTR) "Cert_subject_1";
has to be change into:
LPCWSTR lpszCertSubject = (LPCWSTR ) L"Cert_subject_1";
or
LPCTSTR lpszCertSubject = (LPCTSTR ) _T"Cert_subject_1"; // add #include <tchar.h>
depending on what you need.