1

My main concern comes from: I have a spring boot app,A, that calls another spring boot app,B, using rest template. The response from B contains an encrypted fields that needs to be decrypted.

In order to decrypt it a RSA private key is loaded in app A a single time.

The decryption code looks like this:

Cipher rsaCipher2 = 
Cipher.getInstance("RSA/ECB/PKCS1Padding");
rsaCipher2.init(Cipher.DECRYPT_MODE, Test.privateKey);
rsaCipher2.update(encryptMessage);
byte[] decryptedMessage = rsaCipher2.doFinal();

If i submit multiple requests, one after another , I see that the responses are proceeses by the app A in different times and the decryption (only those 4 lines above) takes different times each run, from 5ms to 20ms even if the same test, with the same data, is executed. Is this something normal? I would have expected to have more similar duration times.

Any idea on how I can keep the decryption time at a minimum? I tried a pool of Ciphers but didn't went to well.

In order to see if i could replicate the behaviour outside the app I did the following:

I generated a pair of keys using RSA algorithm, I encrypted a string. I run the decryption multiple times, one after another, in a main method, on a single thread, and a decryption is made on average in 5 ms

If i do the same thing, but add a timeout of 100ms before the decryption, the decryption is made on average in 20 ms. (in case you ask i did not take the timeout into consideration when calculating the average).

Can someone please shine some light on why is this happening, and how can I avoid it. I tried to initialize the cipher before the for statement, but I saw no improvement, I tried to run the decrypt on a separate thread and a slightly improvement was seen, but yet far from the original results.

generated a pair of keys using RSA

KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(2048);the same thing, but add a timeout of 100ms before the decryption, the decryption is made on average in 20 ms. (in case you ask i did not take the timeou
KeyPair keyPair = keyGen.genKeyPair();
PrivateKey privateKey = keyPair.getPrivate();
PublicKey publicKey = keyPair.getPublic();

encoded a random string

Cipher rsaCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
rsaCipher.init(Cipher.ENCRYPT_MODE, publicKey);
rsaCipher.update("randomString".getBytes());
encryptMessage = rsaCipher.doFinal();

run the decript 1000 times

for (int i  =  0 ; i < 1000 ; i++ ) {
  //Thread.sleep(100);
    Long time =  System.currentTimeMillis();    
    Cipher rsaCipher2 = Cipher.getInstance("RSA/ECB/PKCS1Padding");
    rsaCipher2.init(Cipher.DECRYPT_MODE, privateKey);
    rsaCipher2.update(encryptMessage);
    byte[] decryptedMessage = rsaCipher2.doFinal();
    System.out.println((System.currentTimeMillis() - time)   + " ms ");
}

Just in case of someone asking about my entropy:

cat /proc/sys/kernel/random/entropy_avail
3795
user745671
  • 41
  • 5

1 Answers1

1

First you need to test properly: How do I write a correct micro-benchmark in Java?

If proper benchmarking shows similar results, it can be due to sleeping causing a context switch, caches flushing and all kinds of other things that happen on the lower levels of the CPU. Sleeping causes a lot more than just a delay.

That's why we don't put random sleeps in our code.

Kayaman
  • 72,141
  • 5
  • 83
  • 121
  • i get similar results if the decryption is made after a http response is received. – user745671 Jul 03 '18 at 06:42
  • @user745671 well running code in a tight loop vs. running it after a HTTP response (and possibly measuring it with wallclock time) are quite different things. – Kayaman Jul 03 '18 at 07:50
  • they are different, but the Cipher behaves the same (same text is decrypted in different times ), the loop was an easier way to trigger it – user745671 Jul 03 '18 at 10:40
  • It's not entirely clear what your **actual** code does or looks like, but if it's a case of the JVM not being warmed up, you *might* get some benefits by extracting the decryption into its own private method so the JVM can inline it effectively. – Kayaman Jul 03 '18 at 11:24