Cryptographically secure RNG in C++ for RSA PKCS#1 (key generation) - c++

I'm trying to re-implement the RSA key generation in C++ (as a hobby/learning playground) and by far my biggest problem seems to be generating a random number in range x,y which is also cryptographically secure (the primes p and q, for example).
I suppose using mt19937 or std::rand with a secure random seed (e.g. /dev/urandom or OpenSSL RAND_bytes etc) would not be considered 'cryptographically secure' in this case (RSA)?
ISAAC looked promising but I have zero clue on how to use it since I wasn't able to find any documentation at all.
Notably, this is also my first C++ project (I've done some C, Rust etc before... So C++ at least feels somewhat familiar and I'm not a complete newbie, mind you).

I suppose using mt19937 or std::rand with a secure random seed (e.g. /dev/urandom or OpenSSL RAND_bytes etc) would not be considered 'cryptographically secure' in this case (RSA)?
No, those are not cryptographically secure for basically any purpose.
ISAAC looked promising but I have zero clue on how to use it since I wasn't able to find any documentation at all.
Well, it stood the time I suppose. But I'd simply use a C++ library such as Crypto++ or Botan or something similar and then just implement the RSA key pair generation bit, borrowing one of their secure random generators. With a bit of luck they also have a bignum library so that you don't have to implement that either.

Related

OpenSSL get deterministic random keys

For the sake of ease of deployment of a prototype of a distributed application I want to generate a list of openSSL keys that are deterministic based on some random seed.
I do already know that using srand(seed) does not work because openSSL uses a different soruce of randomness. I've checked out RAND_pseudo_bytes, but it seems to be using the same random source as the non-pseudo method so that one doesn't seem to be doing it either.
Is there a way to generate the SSL keys deterministically?

Is srand a reliable source of encryption pads?

I'm looking to encrypt license keys on an audio software plugin. The biggest risk to the integrity of the license keys is small-time crackers decompiling the code and looking for the encryption key. My solution is to store an arbitrary number in the code and feed it to an algorithm that will obfuscate the encryption key while still allowing me to differ the key between projects (I'm a freelancer).
My question is - will seeding the C++ random number generator create the same psuedo-random encryption key every time, or will it differ between runs, libraries, etcetera. It's fine if it differs between operating systems, I just need it to not differ between SDKs and hosting softwares on the same computer.
srand and rand will produce the same sequence of numbers when you use the same implementation. Change compilers, even to a newer version of the same compiler, and there are no guarantees,
But the new random number generators, introduced in C++11 and defined in <random>, are requires to generate the same sequence of numbers on all implementations.

Is std::random_device cryptographic secure?

I see many people talk about security and std::random_device together.
For example, here slide 22.
According to cppreference, std::random_device :
std::random_device is a uniformly-distributed integer random number generator that produces non-deterministic random numbers.
It does not talk about security explicitly.
Is there any valid reference that explicitly mentions std::random_device is secure for cryptography?
No, because that's not what std::random_device is designed for; it's designed to generate random numbers, not to be secure.
In the context of security, randomness is something that is useful for key generation, but randomness is not something that is absolutely needed. For example, AES does not use any randomness, yet AES-256 is what is used to encrypt top secret information in the US.
One area where randomness and security cross, is when a random key is generated and used; if I can guess the seed and know the random protocol used, there's a good chance I can then use that same seed value to generate the same "random" value and thus the same key.
std::random_device will use a hardware module (like a hardware TPM) if one is available, otherwise it will use whatever the OS has as a RNG (like CryptGenRandom in Windows, or /dev/random in *nix systems), which might even be a PRNG (pseudo-random number generator), which might generate the same number depending on the random number algorithm used. As a side note: much like how the AES instruction set was incorporated into chipsets to speed up encryption and decryption, hardware RNG's help to give a larger entropy pool and faster random number generation as the algorithms are moved into hardware.
So if you are using std::random_device in any sort of cryptographic key generation, you'll need to be aware what random number generator is being used on the system being deployed to, otherwise you can have collisions and thus your encrypted system can be susceptible to duplicate key types of attack.
Hope that can help.
TL;DR: only use std::random_device to generate seeds for the defined PRNG's within this library. Otherwise use a cryptographic library such as Crypto++, Bothan, OpenSSL etc. to generate secure random numbers.
To have an idea why std::random_device is required it is important to see it in the light of the context for which it was defined.
std::random_device is part of a set of classes and methods that are used to generate deterministic/pseudo random number sequences fast. One example - also shown in the slides - is the Mersenne twister algorithm, which is certainly not cryptographically secure.
Now this is all very nice, but as the defined algorithms are all deterministic, this is arguably not what the users may be after: they want a fast random number generator that doesn't produce the same stream all of the time. Some kind of entropy source is required to seed the insecure PRNG. This is where std::random_device comes into action, it is used to seed the Mersenne twister (as shown in the slides referred to in the answer).
The slides show a speed difference of about 250 times for the Mersenne twister and the slow system provided non-deterministic random number generator. This clearly demonstrates why local, deterministic PRNG's can help to speed up random number generation.
Also note that local PRNG's won't slow down much when used from multiple threads. The system generator could be speedy when accessed by multiple threads, but this is certainly not a given. Sometimes system RNG's may even block or have latency or related issues.
As mentioned in the comments below the question, the contract for std::random_device is rather weak. It talks about using a "deterministic" generator if a system generator is not avialable. Of course, on most desktop / server configurations such a device (e.g. /dev/random or the non-blocking /dev/urandom device) is available. In that case std:random_device is rather likely to return a secure random number generator. However, you cannot rely on this to happen on all system configurations.
If you require a relatively fast secure random number generator I would recommend you use a cryptographic library such as OpenSSL or Crypto++ instead of using an insecure fast one the relatively slow system random generator. OpenSSL - for instance - will use the system random generator (as well as other entropy sources) to seed a more secure algorithm.

Should I use randint?

The randint proposal is supposed to provide an intuitive interface for getting random integral numbers. The problem however is that it uses default_random_engine and so far has no way of letting you specify the engine it uses. libstdc++ and libc++ both use minstd_rand which is a LCG, which I've read creates poor quality numbers. MSVC uses mt19937 which seems to be the most common on this site.
Is this a big negative of randint?

Strongest cipher available to use with C/C++?

I am just wondering if you are supposed to write a sort of really secure application with data being transmitted over insecure networks, what kind of encryption algorithm will you use it in order to make it safe ? I know several c++ libraries for encryption providing nice functions with different algorithms, but i'm not quite sure which cipher to use - AES, DES, RSA, Blowfish or maybe something more different ?
Please provide your ideas and suggestions.
While some encryption algorithms are easier to break then others, the weak spot is more about key generation. If your key generation algorithm is predictable, it will be easier to figure out your key and decrypt the packet.
So, I wouldn't sweat which encryption algorithm (AES is fine). But make sure you have a good source of real randomness to generate your keys.
If you are on any of the common POSIX OS, look into using /dev/random to generate your key.
use AES for data encryption and use RSA to exchange AES key between parties
You have listed too few requirements for your encryption needs. It depends on circumstances.
For example, if both end-points of the communication link are trusted, you could just worry about encryption and have both of them produce public-keys for the other end to encrypt information with. In this case, RSA would be my personal choice.
However, if you do not trust the other end-point, and am using the encryption to determine whether it "has the key", then you would be counting on preset keys, rather than private/public encryption. In this case, Triple DES (DES is considered a little weak these days) may be a good choice.
Hope this helps!
Any of the well know ciphers have well understood levels of security so that part is easy. I'd be more concerned about the quality and trust level of the library you use and bugs in your use of it. Have you considered using external programs like ssh to do the key gen and handle the connection, and drive that with an API library?
Crypto++, perhaps the best known, largest, and best crypto library for C++, contains several algorithms you can use. It can also give you a good cryptographically secure random library for use with these algorithms.
According to their FAQ, that depends quite a bit on what you want to do. From their recommended list of algorithms:
block cipher: DES-EDE3, AES, Serpent (Serpent is slower than AES but has a larger security margin and is not vulnerable to timing attacks.)
stream cipher: any of the above block ciphers in CTR mode
fast stream cipher: Salsa20, Panama, Sosemanuk (available in version 5.5)
hash function: SHA-256, SHA-512, Whirlpool
message authentication code: HMAC/SHA1 or HMAC with one of the above hash functions
public key encryption: RSA/OAEP/SHA1, ECIES
signature: RSA/PSS/H, ECDSA/H, which H one of the above hash functions
key agreement: DH, ECDH
random number generator: RandomPool, AutoSeededRandomPool
We can't give an exact answer because there isn't one without knowing more about what you're trying to accomplish.
First of all you have to split up symmetric block ciphers with public key ciphers:
they have really different performances
their implementation is really different
their strenghts/weaknesses are based upon different factors
By the way:
DES is not considered secure anymore, you should always avoid using it
AES is still considered safe (you could use 256 bits keys)
RSA's (and other public key algorithms like ElGamal, Ellipctic Curve) security is based on the hardness of the mathematical problems on which these algorithms are based. For example: number factorization. If the number of bits you use to store the keys are big enough you can consider them enough safe.
However things can change according to the power of CPUs in few years so you shouldn't consider them safe forever..
One thing to consider is that public key ciphers are usually slower than block ciphers, that's why commong protocols usually use the first ones to exchange a simmetric key that then is used with an algorithm like AES.
The answer is: don't. If it has to be secure and you ask this question it means that you need to find a security expert to do it. You are not going to design a secure protocol by asking for help on SO. You can [maybe] use an existing protocol such as ssh or TLS, but if you roll your own you will fail.
If you want to transmit data over an insecure network, you need more than a cipher, you need a secure protocol, potentially including key distribution and authentication.
If you're really serious about crypto implementation, not just doing it to understand the basic mathematics of cryptography, then you need to do more than implement the number-crunching correctly. You also need to worry about side-channel attacks. For example, if your implementation takes a different amount of time depending on the key, as is common, then an attacker can deduce information about the key from your various response times. And that's just the basic algorithm, never mind putting it all together.
This is in general an unsolved problem and an area of ongoing research. Most or all implementations are flawed, although for the latest versions of well-used libraries probably not in a way that anyone has publicly announced they can exploit. Timing-based attacks on OpenSSL have been demonstrated in the past, albeit only on a highly predictable local network AFAIK. You can basically spend as long as you like on it, up to and including your entire career.
In practice, just use SSL, in whatever implementation comes with your platform.
Actually, we may not need to know all the details. But, IMHO, cascade these algorithms with Chain Of Responsibility Pattern, or Composite + Strategy.