Prevent prompting for PEM passphrase - c++

I am building a Qt-based application that will communicate through https with a webserver. The setup should allow client-authentication with a local certificate and private key. The application must run without any user interaction.
Now I have a problem when the private key file is protected by a passphrase:
OpenSSL will prompt for a password, blocking the whole application!
The openSSL API allows to pass a callback for getting the passphrase, but this is not accessible though the Qt Wrapper. Is there another way to prevent openSSL from prompting for a password? Or can this somehow be interrupted?

On looking at the online documentation, I don't see any callback options when decrypting the private key.
The simplest way is to make the private key password-free. Here's how you could do it (assuming you have password-protected RSA keys):
openssl rsa -in privateKey.pem -out newPrivateKey.pem
Here privateKey.pem is password protected but newPrivateKey.pem is not. Note that while this means the private key is unprotected, this is a common technique to do uninterrupted SSL communication (even used in stunnel for instance). The assumption is that the private key is stored in a directory which has restricted permissions and is protected by the operating system access policy.
The harder way is to write your application by directly linking with OpenSSL instead of going through the wrapper. That way, you have a fine-grained control on the password callbacks.

You can specify the password when you construct the QSslKey. The constructor takes a passphrase which will be used to decrypt the key, see the docs at the link below:
http://qt-project.org/doc/qt-4.8/qsslkey.html#QSslKey-2

I came up with a solution:
OpenSSL will only prompt for a password, when none is specified in the decode function. As Richard Moore pointed out in his answer, QSslKey has a constructor where you can pass the passphrase.
As long as an non-empty string is passed here, OpenSSL won't prompt for a password. Plus: If the key is not protected, the password is ignored. Therefore, I simply make sure that a non-empty string is passed, so this is my solution:
// Never use empty PWD, as this blocks. (Use null-string)
// PLUS: setting a password for a non-protected key still correctly loads the key!
QByteArray thePwd = pwd.isEmpty() ? QByteArray("\0", 1) : pwd.toUtf8();
// Try all encodings
QList<QSslKey> keys = QList<QSslKey>()
<< QSslKey( theKey, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey, thePwd )
<< QSslKey( theKey, QSsl::Rsa, QSsl::Der, QSsl::PrivateKey, thePwd )
<< QSslKey( theKey, QSsl::Dsa, QSsl::Pem, QSsl::PrivateKey, thePwd )
<< QSslKey( theKey, QSsl::Dsa, QSsl::Der, QSsl::PrivateKey, thePwd );
// Find a valid encoding
foreach ( QSslKey k, keys ) {
if ( !k.isNull() ) {
ret = k;
break;
}
}

Related

How to store my key for encryption on aws?

I am developing rest api system running on ec2 service.
My requirement is
encrypt/decrypt on plain text with AES256
generate key with pbkdf2
Store key on aws cloud system
Java
I tried to used KMS & Crypto sdk but it’s not working. (ex) result of encryption value is changed every time When I called method with same plaint text.
Do you have any ideas?
public String encrypt(String text) {
String plaintext = text;
try {
ByteBuffer byteBuffer = getByteBuffer(plaintext);
EncryptRequest encryptRequest = new EncryptRequest().withKeyId(key_arn).withPlaintext(byteBuffer);
EncryptResult encryptResult = client.encrypt(encryptRequest);
String ciphertext = getString(java.util.Base64.getEncoder().encode(encryptResult.getCiphertextBlob()));
plaintext = ciphertext;
} catch (Exception e) {
e.printStackTrace();
}
return plaintext;
}
public String decrypt(String text) {
String bb = null;
try {
byte[] ciphertextBytes = text.getBytes();
DecryptRequest request = new DecryptRequest();
request.setCiphertextBlob(ByteBuffer.wrap(ciphertextBytes));
DecryptResult result = client.decrypt(request);
// Convert to byte array
byte[] plaintext = new byte[result.getPlaintext().remaining()];
ByteBuffer a = result.getPlaintext().get(plaintext);
bb = getString(a);
} catch (Exception e) {
e.printStackTrace();
}
return bb;
}
This is a hard question to answer succinctly because there are a lot of details and background knowledge that go into crypto and using the AWS crypto capabilities correctly.
First to your specific question - different values from the same plaintext is ok and expected. Encrypt returns different values for the same plain text because it attaches additional data to the plain text, such as an Initialization Vector (IV). This is a way to include non-deterministic data in the plain text precisely so that you don't end up with the exact same cipher text from the same plain text when using the same key.
More importantly, though, note that Encrypt and Decrypt are not general-purpose tools - they are designed to handle small payloads (< 8KB), specifically Data Keys. So where you go from here will depend on what kind of data you are encrypting. If you just need to decrypt a small value like a password, you can continue with Encrypt/Decrypt, and don't worry that two Encrypt operations produce different cipher texts. If you need to encrypt files or other arbitrary chunks of data, read on.
AWS promotes the idea of Envelope Encryption, which is the notion that the key used to actually en/decrypt is stored alongside data it protects, and is itself en/decrypted via a separate master key. In the AWS case, that's Customer Master Key (CMK), which never leaves KMS.
So you can use Encrypt to encrypt an encryption key that you generate, or you could use the AWS method GenerateDataKey to 1) create a key and 2) encrypt it for you. That will return both a plaintext (base64) and cipher text version of the key. Use the plaintext in memory, store the cipher text to disk.
A more typical workflow would be something like:
Call GenerateDataKey - you need to specify the KeyId and a KeySpec (AES_128 or AES_256). There are also options to generate asymmetric keys.
The result includes both a plain text and encrypted version of the generated key. Store the encrypted version.
At some later time, call Decrypt when you need to use the key.
Use the plaintext from that Decrypt method as the key in your local crypto code.
AWS actually provides a separate library to do all that for you - the AWS Encryption SDK, with support for a range of languages including Java. I've not used it extensively, but it provides the framework to do envelope encryption via best practices (which algorithms, master vs. data keys, etc). Take a look (link below).
Hope this helps; encryption is tough to get right.
For more info:
https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#enveloping
https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/introduction.html
https://en.wikipedia.org/wiki/Initialization_vector

wc_RsaSSL_Verify returns BAD_FUNC_ARG, and I can't tell why

I am trying to RSA public key decrypt a signed file using wolfcrypt - yes, I may or may not be abusing the "sign/verify" power of RSA to encrypt a separate AES key using the private key and decrypt using the public key.
Unfortunately, I am stuck at wc_RsaSSL_Verify() - for the life of me I can't figure out why it is returning BAD_FUNC_ARG - I figured an error like that should be immediately visible to somebody else so I'm deciding to call upon the collective powers of StackOverflow.
As far as I can tell, I'm giving the function what it's asking for - an input buffer, an output buffer, the size of each, and a pointer to the RsaKey struct. Here is a code snippet from the function in question:
bool VerifyWorker::GetAESKey()
{
bool result = true;
uint8_t en_aes_file_buff[VerifyWorkerLocal::RSA_KEY_SIZE];
uint8_t de_aes_file_buff[VerifyWorkerLocal::RSA_KEY_SIZE];
uint8_t* aes_iv_ptr = NULL;
// keyfile filestream
std::fstream aes_file;
// rsa_key must be initialized
if(rsa_key == NULL)
{
result = false;
}
// Open the key file and read it into a local buffer, then decrypt it and use it to initialize the
// aes struct
if(result)
{
aes_file.open(this->aes_key_file, std::ios_base::in | std::ios_base::binary);
if(aes_file.fail())
{
// Unable to open file - perror?
perror("GetAESKey");
result = false;
}
else
{
aes_file.read(reinterpret_cast<char*>(en_aes_file_buff), VerifyWorkerLocal::RSA_KEY_SIZE + 1);
if(!aes_file.eof())
{
// we didn't have enough space to read the whole signature!
std::cerr << "aes_file read failed! " << aes_file.rdstate() << std::endl;
result = false;
}
}
}
// "Unsign" the aes key file with RSA verify, and load the aes struct with the result
if(result)
{
int wc_ret = 0;
wc_ret = wc_RsaSSL_Verify(const_cast<const byte*>(en_aes_file_buff),
VerifyWorkerLocal::RSA_KEY_SIZE, reinterpret_cast<byte*>(&de_aes_file_buff),
VerifyWorkerLocal::RSA_KEY_SIZE, rsa_key);
The rsa_key is a private member initialized (successfully, using wc_PublicKeyDecode()) in a separate function with a public key DER file. I generated both the public and private key using OpenSSL - which should properly pad my AES key and iv file using PKCS#1 v1.5 b default.
I should also mention that I am using wolfssl version 3.9.8. Thanks!
The issue, I found, was that the file that I had signed with my RSA key was not signed correctly. When I signed the file using OpenSSL, my cli invocation was
openssl rsautl -in keyfile -out keyfile -inkey private.pem -sign
Apparently, openssl does not like you to specify the same file for -in and -out. When I changed it to something like
openssl rsautl -in keyfile -out keyfile_signed -inkey private.pem -sign
I was actually able to verify the file using wc_RsaSSL_Verify.
So, like most stupid late-night, last hour software problems, I was looking in the wrong place entirely. I was a bit thrown off by the BAD_FUNC_ARG being returned and thought that it had to do explicitly with the format of the function arguments, not necessarily their content. Hopefully this answer is useful for somebody else, too.
It sounds like you are trying to use RSA_Sign to perform an "Encrypt" of an AES key. Then I assume you are sending to a remote partner or computer who will then run an RSA_Verify operation to decrypt the AES key do I understand the scenario correctly?
If so I apologize it did not show up if you searched on how to do this initially but we actually have an example of doing exactly that here:
https://github.com/wolfSSL/wolfssl-examples/tree/master/signature/encryption-through-signing
That example includes two separate applications. The first app, "rsa-private-encrypt-app.c", will sign (encrypt) the "fake Aes Key" and output the result to a file. The second app, "rsa-public-decrypt-app.c", then opens the file that was output and does a verify (decrypt) on the data contained in the file to recover the original "fake Aes Key".
I may or may not be abusing the "sign/verify" power of RSA to encrypt a separate AES key using the private key and decrypt using the public key.
No not at all, that is a valid use of RSA sign/verify ASSUMING you are working with fixed-length inputs such as an AES key.
That's why we created the example! We actually had a user ask a very similar question on our forums awhile back which led to us making the example.
One thing to make note of though on the issues you encountered with openssl and wolfssl is actually talked about in the README:
https://github.com/wolfSSL/wolfssl-examples/blob/master/signature/encryption-through-signing/README.md
... Keep in mind this is not a TRUE RSA ENCRYPT and will likely not inter-op with other libraries that offer a RSA_PRIVATE_ENCRYPT type API.
This is a true SIGN operation.
If you have any other questions feel free to post them here (and add the wolfssl tag of course) or you can also send us an email anytime at support#wolfssl.com
Disclaimer: I work for wolfSSL Inc.

Openssl X509 cert get string human readable

I have a client/server architecture in which I use the openssl library to implement an encrypted communication (TLSv1.2).
Since I'm using "self signed" certificates, in order to verify server's identity, my idea is to put in the client side a physical copy of the server's public key (server_public_key.pem) and then verify if it is equals to which received in the handshake phase of TLS.
On the client, I can retrieve the latter with:
X509 *cert = SSL_get_peer_certificate(ssl);
Now, I would extract the human readable string of the public key contained in this object.
I know that I can print it in this way:
EVP_PKEY *pkey = X509_get_pubkey(cert);
PEM_write_PUBKEY(stdout, pkey);
But I need to keep it as a string (instead of send it to stdout). How can I do this ?
Use BIO_new() to create a new BIO backed by an internal memory buffer (initially empty).
Then use PEM_write_bio_PUBKEY() to write the public key to the BIO, at which point use the functions documented in the BIO's manual page to retrieve the public key.
See the cited documentation for a simple example of creating a BIO, writing to it, then reading from it. Replacing the sample write operation with PEM_write_bio_PUBKEY() should be sufficient.

RSA encrypt for C++ (BB10)

Resolved (look for my answer). I need help encrypting a password with RSA in C++. I'm working for Blackberry10 in C++ and I've been looking for a RSA tutorial or something that walk me through the encrypting process but sadly I haven't found anything consistant.
I've been told that the process consist basicaly in three steps:
1)Generate the RSA public key with the module and exponent.
2)Encrypt the text with the public key.
3)Encrypt the text again in base640.
If you are wondering why I need to follow this three steps is because I'm working in a banking app, and those are their requirements.
I've been searching all over and I haven't found even how to make the first step, generate the public key with the module and the exponent (I already have both).
Any help will be appreciated.
Thanks.
Is not that I'm building the whole app by myself. We are a team and I need to encrypt just the client password with RSA and send it to the next step of the process. I do have experiencie working with Blackberry and RSA but in Java, where the process is a little bit easier, e.g: In java the first step once you got the module and public exponent is create the RSA Public Key Object through a very simple syntaxis: RSAPublicKey publicKey = new RSAPublicKey(new RSACryptoSystem(2048),ebytes, mbytes);. In this part is where I'm little bit lost because I haven't found the proper BB10 documentation. I'm sorry if I created the illusion that I'm creating a whole encryption API by myself. BB10 has this security API based in hursa.h (https://developer.blackberry.com/native/beta/reference/com.qnx.doc.crypto/topic/about_rsa_raw.html) I'm trying to implement it, but I haven't been successful. #owlstead #dajames #bta
I highly recommend that you take advantage of an existing encryption library to handle all of this for you. OpenSSL is widely used, and the LibTom libraries include an encryption lib as well. Encryption is not an easy thing to implement from scratch, and you will save a considerable amount of time and frustration by using an existing implementation. OpenSSL in particular is a good choice, as it has passed FIPS certification tests multiple times. Since you're working on a banking app, you (and your customers) will most likely want to use an implementation that has been certified.
Even if you insist on implementing your own encryption libraries from scratch, I encourage you to check out the aforementioned libraries as examples.
It seems to me that you know even less than you think you do about how this cryptography works.
One doesn't usually use RSA encryption to encrypt data. It can be done for something short like a PIN or password, but what is usually done is to generate a symmetric key and to encrypt the data with the symmetric key and then use RSA to encrypt the symmetric key.
If you are sending a password to a bank then what you are probably supposed to be doing is to use the RSA key supplied by the bank in their own key certificate. Only the bank has the private key, so only they can decrypt the password. If that's right then you don't need to generate an RSA key, but you do need to verify that the certificate is trusted.
I don't program Blackberries, so I don't know what cryptography APIs they support, but I would expect everything you need to be built-in. This is all pretty standard stuff.
I recommend that you start by reading up on public key cryptography (e.g. on Wikipedia here and here) before starting to design your solution.
Resolved. After doing some research and getting to know better with BB10 coding and RSA, I finally came out with the solution to successfuly encrypt a plain text with RSA and Base64 in C/C++ for BB10 or any other platform. Please take in consideration that I have the modulus and the public exponent of the rsa object from the services that I'm working with.
The code:
QByteArray answer;
RSA* rsa = RSA_new();
BIGNUM *modulus = BN_new();
BIGNUM *exponent = BN_new();
const char *modulusString = rsaObj->getM(); //My Modulus
const char *exponentString = rsaObj->getE(); //My exponent
BN_hex2bn(&modulus, modulusString);
BN_hex2bn(&exponent, exponentString);
rsa->n = BN_new();
BN_copy(rsa->n, modulus);
rsa->e = BN_new();
BN_copy(rsa->e, exponent);
int maxSize = RSA_size(rsa);
qDebug() << "maxSize:" << maxSize;
const char *inn = "1234";
unsigned char *encrypted = (unsigned char*) malloc(maxSize);
int bufferSize = RSA_public_encrypt(strlen(inn), (unsigned char *) inn,
encrypted, rsa, RSA_PKCS1_PADDING);
if (bufferSize == -1) {
RSA_free(rsa);
qDebug() << "Error";
}
QByteArray enc = QByteArray::fromRawData((const char*) encrypted, 256);
answer = enc.toBase64();
return answer;
Thanks and I expect this helps to the new BB10 developers

Load PEM encoded private RSA key in Crypto++

Often times, user will have PEM encoded RSA private keys. Crypto++ requires that these keys be in DER format to load. I've been asking people to manually convert their PEM files to DER beforehand using openssl like this:
openssl pkcs8 -in in_file.pem -out out_file.der -topk8 -nocrypt -outform der
That works fine, but some people don't understand how to do that nor do they want to. So I would like to convert PEM files to DER files automatically within the program.
Is it as simple as striping the "-----BEGIN CERTIFICATE-----" and "-----END CERTIFICATE-----" from the PEM or is some other transformation required as well? I've been told that between those markers that it's just b64 encoded DER. Here's some code that demonstrates the issue:
// load the private key
CryptoPP::RSA::PrivateKey PK;
CryptoPP::ByteQueue bytes;
try
{
CryptoPP::FileSource File( rsa.c_str(), true, new CryptoPP::Base64Decoder() );
File.TransferTo( bytes );
bytes.MessageEnd();
// This line Causes BERDecodeError when a PEM encoded file is used
PK.Load( bytes );
}
catch ( CryptoPP::BERDecodeErr )
{
// Convert PEM to DER and try to load the key again
}
I'd like to avoid making system calls to openssl and do the transformation entirely in Crypto++ so that users can provide either format and things "just work". Thanks for any advice.
Yes, it's a DER stream encoded with Base64. Note though, in addition to striping both BEGIN and END markers, in case of RSA key format you also need to strip any flags that may be inserted between the BEGIN marker and the encoded data. Only the remaining part can be successfully Base64 decoded. It appears that you feed the full certificate file to the decoder and that needs fixing.
... I would like to convert PEM files to DER files automatically within the program.
In July 2014, a PEM Pack was provided for the Crypto++ library. The PEM Pack is a partial implementation of message encryption which allows you to read and write PEM encoded keys and parameters, including encrypted private keys. The additional files include support for RSA, DSA, EC, ECDSA keys and Diffie-Hellman parameters.
Its an add-on to the library, and not part of the library proper. You download a ZIP and add five source files to the library. Then you build the library (Crypto++ automatically picks them up). The ZIP contains five additional source files, a script to create test keys using OpenSSL, a C++ program to test reading and writing the keys, and a script to verify the keys written by Crypto++ using OpenSSL.
Here's how you would use it:
CryptoPP::RSA::PrivateKey pk;
CryptoPP::FileSource file("<rsa-key-file.pem>", true);
CryptoPP::PEM_Load(file, pk);
CryptoPP::AutoSeededRandomPool prng;
bool = pk.Validate(prng, 3);
if (! valid)
throw ...
If the keys is encrypted, then here's how you would load it. The PEM Pack re-implement's OpenSSL's EVP_BytesToKey, so the key derivation will work and you can interop:
CryptoPP::RSA::PrivateKey pk;
CryptoPP::FileSource file("<rsa-key-file.pem>", true);
std::string pass = "<super secret password>";
CryptoPP::PEM_Load(file, pk, pass.data(), pass.size());
CryptoPP::AutoSeededRandomPool prng;
bool = pk.Validate(prng, 3);
if (! valid)
throw ...
There's also a PEM_Save, so you can write the keys directly from Crypto++. For example:
// Generate it or load it from somewhere
CryptoPP::RSA::PrivateKey pk = ...;
CryptoPP::FileSink file("<rsa-key-file.pem>", true);
CryptoPP::PEM_Save(file, pk);
And PEM_Save for an encrypted key (or key you intend to encrypt):
// Generate it or load it from somewhere
CryptoPP::RSA::PrivateKey pk = ...;
CryptoPP::FileSink file("<rsa-key-file.pem>", true);
std::string pass = "<super secret password>";
CryptoPP::PEM_Save(file, pk, "AES-128-CBC", pass.data(), pass.size());
PEM_Load does not need an algorithm because its encoded in the encapsulated header. PEM_Save needs an algorithm because there is no default algorithm.
I know this is an old question but other's might find this useful. Once you strip the markers you're left with the 'inner' key material. According to http://www.cryptopp.com/wiki/Keys_and_Formats#BER_and_DER_Encoding you can use BERDecodePrivateKey to load this. So, to load an openssl key that has had its markers stripped you can do something like
bool LoadKey(RandomNumberGenerator& rng, const std::string& file,
RSA::PrivateKey& key)
{
ByteQueue q;
FileSource KeyFile(file.c_str(), true, new Base64Decoder);
KeyFile.TransferTo(q);
key.BERDecodePrivateKey(q,false,0); // last 2 params unused
return key.Validate(rng, 2);
}