I've been working on a system that uses asymmetric encryption in a large number of files. I'm currently using RSA with 4096-bit keys to encrypt a 256-bit randomly generated AES key for each file, but performance is somewhat lacking, as one required operation is to scan through all the files (estimated number when the system is in use is around 10,000) and identify which ones can be decrypted using a specific private key. While I don't expect this operation to be instant, it is taking too long at the moment (~2 files processed per second). I considered reducing the key length, but even taking it down to 2048 bits doesn't provide the level of performance I need. 512 bits would just about cut it, but as such keys can now be cracked trivially that is out of the question.
Can anybody point me in the direction of a system that is faster but of similar cryptographic strength? It would need to be implemented via a Java JCA provider (e.g. something like bouncycastle) in order to plug in to my existing application neatly. I know bouncy castle supports El Gamal, but I can't find any details on how strong this algorithm is, or if it is even likely to be any faster than RSA. I also hear about elliptic curve systems that only need relatively short keys (384 bits or the like), but don't know where to find an implementation of one of these.
For your question as asked, try Diffie-Hellman over elliptic curves, also known as "ECDH". Estimating security is a bit difficult once we deal with sizes that cannot be cracked with current technology, since this depends on how we bet on future technological evolutions. Yet one can say that ECDH over the P-256 curve provides "128 bits" of security, a level which is similar to what you would get from 2048-bit RSA. That level is widely sufficient for all current usages, or, more appropriately said, if P-256 is not enough for you then your problem has very special needs and cryptographic strength is likely to be the least of your worries.
On my PC (a 2.4 Ghz Intel Core2, 64-bit mode, running Linux), OpenSSL claims to crunch out about 900 ECDH instances per second, using a single core.
Edit: for estimation of key security, depending on the length, for several algorithms, see this site.
Why don't you calculate a cryptographically strong hash of each key, and then store that in the clear with each filename? Then, given a key that you need to match against all the files, you can simply hash the key and look it up in the table.
I'd go for an approach that requires less RSA operations. SSL/TLS, although they use RSA etc for encrypting AES etc keys, do not use AES for the data simply because it is a computationally expensive operation at sufficiently large key sizes for security to be done on a per-packet, or in your case, per-file basis.
Another public key system is: http://en.wikipedia.org/wiki/ElGamal_encryption. Security-wise I believe it has yet to be broken but would personally put my trust in RSA for now. I do not know if there are any elliptic curve encryption algorithms currently available - that is to say I know they are being researched but understand they may not be ready for production use and I heard there were patent issues.
Related
I need to decrypt messages via RSA in order to send it over an unsecured channel, but I'm afraid of the Padding Oracle Attack. Therefore I already have asked the follwoing questions:
How to verify the integrity of RSA encrypted messages?
How to ensure message integrity for RSA ciphers by using javax.crypto.Cipher
Like suggested in the first question,
However, since you are using a high level cryptographic library, this is something you shouldn't have to worry about. The writers of that library should have taken care of it.
I shouldn't consider about. As far I know, the RSA implementation of PKCS#1 v1.5 is vulnerable to the Padding Oracale Attack whereby OAEP isn't (assumed it's implemented correctly)
Hence I want to know which padding implementation is used by javax.crypt.Cipher by Java 7
It depends on the chosen or default provider which padding is actually used when you instantiate a Cipher without fully qualifying it like:
Cipher.getInstance("RSA")
Doing so is a bad practice, because if you switch Java implementations, there might be different defaults and suddenly, you won't be compatible with the old ciphertexts anymore. Always fully qualify the cipher.
As I said before, the default will probably (there are many providers, one can't be sure) be PKCS#1 v1.5 padding. If you need another, you would have to specify it. If you want to use OAEP, here is a fully qualified cipher string from here:
Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
That's not a good advice given in the first link to the cryptography site. You should never rely on the defaults of cryptographic libraries cryptographic algorithms. There are quite a few reasons for this:
Different implementations, different defaults (there are no requirements for cryptography providers concerning defaults, although most will copy the Oracle/Sun defaults);
What's secure now may not be considered secure tomorrow, and because for backwards compatibility, you can never change the default;
It's unclear to anybody reading your software what the default is (you could document it, but in that case you might as well write it out).
The SunJCEProvider provided by Oracle defaults to PKCS#1 padding ("PKCS1Padding") for historical reasons (see reason #2 above). This is not well documented.
At that time that default was set you basically had just the insecure textbook RSA ("NoPadding") and the PKCS#1 v1.5 version ("PKCS1Padding" or RSAES-PKCS1-v1_5 in the PKCS#1 v2.1 standard). At that time RSAES-PKCS1-v1_5 was definitely the more secure choice. Changing the default now to OAEP would break every RSA implementation out there that uses the default.
The advice of otus (in the first link within this answer) is be better suited to protocol implementations in libraries than to cryptographic algorithms. In the end you should be able to defend the security of the choices made, whatever you choose.
The default for bouncy-castle when you just specify RSA is RSA/NONE/NOPADDING
This is the same result as RSA/ECB/NOPADDING as well.
I'm creating a web service that stores a list of users with their public keys online, as well as encrypted messages. My end goal was end-to-end encryption.
I initially thought this would be pretty easy -- "Oh, OpenSSL and RSA private/public key asymmetric encryption is great." False. RSA will only encrypt a tiny bit of data, presumably to pass a regular, symmetric key back and forth.
Okay, so I tried to find solutions online. Most of them either ended without a functioning example or pointed at using the command line, all of which seemed excessive and incomplete.
Is there a way to use end-to-end encryption on data with asymmetric keys, or is it all a personal pipe dream? OpenSSL in PHP has a way to do this already, and it's kludgy but it works.
Is there some method I'm missing here?
The common way to encrypt larger amount of data with a asymmetric keys (eg. RSA) is by use of hybrid encryption. In hybrid encryption you mix symmetric and asymmetric encryption. First you generated a random symmetric key, that is used to encrypt the data. Then you encrypt the symmetric key with the asymmetric key. The encrypted data + the encrypted random key are then put together and makes up the full encrypted data.
The openssl_seal() in PHP you refer to, uses hybrid encryption where the symmetric algorithm is RC4. How data is encoded and put together in the encrypted files have been defined by the openssl implementation, and might not necessarily be the way you would want to do it. PGP, as an other example of hybrid encryption, uses it's own way of packing the data.
In any case, hybrid encryption is not something you get out of the box in java, and you typically need to implement each of the encryption + packaging steps yourself, or use one of the libraries that implements there version of this. An example of doing it yourself is this Java code I found that can decrypt messages encrypted with the above mentioned openssl_seal().
An example of using a library for hybrid encryption, could be using the PGP support in Bouncy Castle.
Ebbe's answer is very good, however this question was highly ranked in Google in my attempt to try and find a decent hybrid encryption library (Bouncy Castle's documentation is non-existent and not straight-forward, and GnuPG for Java relies on the OS and is not fully tested). So I thought I'd add on to Ebbe's answer for the weary traveller.
If you can use them, JWTs (JavaScript Web Tokens) could be handy for this. It's also an IETF Standard. There are two different types:
JWS, which is a signed JWT. Plain-text message, but you can verify its authenticity. Which has its own IETF Standard
JWE, which is an encrypted JWT. Which also has its own IETF Standard
Support for JWEs are unfortunately a bit poor at this point in time. However this should hopefully improve. At this point in time (2017-04-11), the only Java JWT library that supports JWEs is BitBucket's Jose4j.
I'm not really sure what you're trying to en- and decrypt, but GnuPG for Java might be a good choice.
It supports public and private keys and can en- and decrypt bigger files and data.
I have just watched a crypto 101 talk which said if you are typing the letters "AES" into your code, you're doing it wrong! The solution was to "just use GPG".
If you are storing your data on the cloud, all readers and writers need to know the key. If the key is a public private key, that's just a slow key but not a more secure key than just having a good password?
What standard alternatives are there to GPG that properly encrypt data at rest but use a shared secret instead of public keys?
I use Java, and would like to use a library, but want interchange with other platforms.
The solution is wrong in terms - you don't use "GPG" but OpenPGP.
Indeed for encryption using shared secrets (passphrases and alike) OpenPGP is optimal, as it supports multiple methods at the same time and includes compression.
The alternative would be to use CMS encryption with keypairs derived (in some predetermined way) from the shared secret. However such scheme is not standard.
I can remember also XML encryption that supports encryption with symmetric keys, but it has certain security flaws.
So OpenPGP is probably the best way to go.
Regarding compatibility - OpenPGP-compliant library should create packets that can be later processed by any other OpenPGP-compliant library or application. Unfortunately OpenPGP implementation in popular BouncyCastle library sometimes produces not compliant packets - we came across its issues several times when packets created with BouncyCastle could not be processed by GnuPG or our SecureBlackbox due to issues in the packet created.
I am looking for a good library that can perform pairing based cryptography (PBC).
One I could find is jPBC
What have others used? and their experiences?
The idea is to test the performance of algorithms using standard pairings (Weil, Tate) as well as some of the newer proposals without getting my hands too much dirty in the math.
I do work in this space as well. The best thing we could find in java was jPBC. Its not very good.
Non java alternatives:
MIRACL: I believe this is the current
fastest c implementation.
charm crypto: a python framework for
rapidly prototyping crypto systems. Full disclosure, I am a dev on
it. It has bindings to some subset of MIRACL and Lynn's PBC lib.
These are more than enough to impliment most schemes.These subsets
are expanding and probably can be readily expanded without getting
into the math involved. Given specific requests, we might even be willing to do those
extensions
Furthermore, it already has support for benchmarking that can
give specific time spent in cryptographic operations, the number of operations (e.g.
pairings and exponentiations), and other stats.
An open-source java implementation of Miracl is at
https://dsl-external.bbn.com/tracsvr/openP3S/wiki/jmiracl
Includes benchmarks
MIRACL is the gold standard for Elliptic Curve Cryptography over GF(p) and GF(2m) and additionally supports even more esoteric Elliptic Curves and Lucas function-based schemes. It also includes over twenty protocols based on the new paradigm of Pairing-Based Cryptography. Using MIRACL means that AES encryption, RSA public key cryptography, Diffie-Hellman Key exchange and DSA digital signature are all just a few procedure calls away.
You can read more about MIRACL here and download the SDK: https://github.com/miracl/MIRACL
I want to encrypt/decrypt lots of small (2-10kB) pieces of data. The performance is ok for now: On a Core2Duo, I get about 90 MBytes/s AES256 (when using 2 threads). But I may need to improve that in the future - or at least reduce the impact on the CPU.
Is it possible to use dedicated AES encryption hardware with Java (using JCE, or maybe a different API)?
Would Java take advantage of special CPU features (SSE5?!), if I get a better CPU?
Or are there faster JCE providers? (I tried SunJCE and BouncyCastle - no big difference.)
Other possiblilities?
The JVM will not, by itself, take advantage of special CPU features when executing code which happens to be an AES encryption: recognizing some code as being an implementation of AES is beyond the abilities of the JIT compiler. To use special hardware (e.g. the "Padlock" on VIA processors, or the AES-NI instructions on the newer Intel processors), you must go, at some point, through "native code".
Possibly, a JCE provider could do that for you. I am not aware of any readily available JCE provider which includes optimized native code for AES (there was a project called Apache JuiCE, but it seems to be stalled and I do not know its status). However it is conceivable that SunJCE will do that in a future version (but with Oracle buying Sun and the overfeaturism of OpenJDK 7, it is unclear when the next Java version will be released). Alternatively, bite the bullet and use native code yourself. Native code is invoked through JNI, and for the native AES code, a popular implementation is the one from Brian Gladman. When you get a bigger and newer processor with the AES-NI instruction, replace that native code with some code which knows about these instructions, as Intel describes.
By using AES-128 instead of AES-256 you should get a +40% speed boost. Breaking AES-128 is currently beyond the technological reach of Mankind, and should stay so for the next few decades. Do you really need a 256-bit key for AES ?
Just in case people run into this. JAVA 8 now uses AES-NI. See this: AES-NI intrinsics enabled by default?
You can benefit from improved AES speeds by using SunPKCS11 security provider together with mozilla-nss library.
Setup is described at
Improved Advanced Encryption Standard (AES) Crypto performance on Java with NSS using IntelĀ® AES-NI Instructions
and JavaTM PKCS#11 Reference Guide
A simple google search will identify some JCE providers which claim hardware acceleration Solaris Crypto Framework. I have heard the break-even point is 4K (where under 4k its faster to perform using in JVM java providers).
I might look at using the NSS implementation, it might have some compiler optimizations for your platform (and you can certainly build from source with them enabled); though I have not used it myself. The big benefit with hardware a provider is probably the fact that the keys can be stored in hardware in a way that supports using them without exposing them to the OS.
Update: I should probably mention that the Keyczar source had some helpful insight (somewhere in source or surrounding docs) about reducing the overhead for initializing the Cipher. It also does exactly what you want (see Encrypter), and seems to implement asynchronous encryption (using a thread pool).
I would also suggest using AES-128 rather than 256. If the code is loosely coupled, and is still around in however many years it takes for AES-128 to become archaic, my guess is that it will be much easier to update the encryption at that point (when hardware will be more powerful) than it would be to try to optimize performance via hardware now.
Of course, that is assuming it is loosely coupled :D
Usually the step which consumes more time is Initiating the KeyGenerator.
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(256); // This step takes more time
KeyGenerator aesKey = keyGen.generateKey();
The way I solved it is by generating a pool of KeyGenerator instances before the server statup and reusing them for just for Key Generation