-1

I have this code in my rails app:

require 'openssl'
require 'digest/sha1'
require 'base64'

KEY="secret_key"
data  = "secret message"

 def encrypt_value(data)
    cipher = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
    cipher.encrypt
    cipher.key = Digest::SHA256.digest(KEY)
    encrypted = cipher.update(data)+cipher.final
    return encrypted
 end

def decrypt_value1(data)
    cipher = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
    cipher.decrypt
    cipher.key = Digest::SHA256.digest(KEY)
    decrypted = cipher.update(data)+cipher.final
    data = Base64.decode64(decrypted)
    return data
end

And java code:

import java.security.AlgorithmParameters; 
import java.security.NoSuchAlgorithmException; 
import java.security.SecureRandom; 

import javax.crypto.BadPaddingException; 
import javax.crypto.Cipher; 
import javax.crypto.IllegalBlockSizeException; 
import javax.crypto.SecretKey; 
import javax.crypto.SecretKeyFactory; 
import javax.crypto.spec.IvParameterSpec; 
import javax.crypto.spec.PBEKeySpec; 
import javax.crypto.spec.SecretKeySpec; 
import javax.xml.bind.DatatypeConverter; 

public class EncryptionDecryption { 

    private static String salt; 
    private static int iterations = 65536  ; 
    private static int keySize = 256; 
    private static byte[] ivBytes; 

   // private static SecretKey secretKey; 
    private static final byte[] secretKey = "secret_key".getBytes(); 

    public static void main(String []args) throws Exception { 

        salt = getSalt(); 

        char[] message = "secret message".toCharArray(); 
        System.out.println("Message: " + String.valueOf(message)); 
        System.out.println("Encrypted: " + encrypt(message)); 
        System.out.println("Decrypted: " + decrypt(encrypt(message).toCharArray())); 
    } 

    public static String encrypt(char[] plaintext) throws Exception { 
        byte[] saltBytes = salt.getBytes(); 

        SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); 
        PBEKeySpec spec = new PBEKeySpec(plaintext, saltBytes, iterations, keySize); 
        //secretKey = skf.generateSecret(spec); 
        SecretKeySpec secretSpec = new SecretKeySpec(secretKey, "AES"); 

        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
        cipher.init(Cipher.ENCRYPT_MODE, secretSpec); 
        AlgorithmParameters params = cipher.getParameters(); 
        ivBytes = params.getParameterSpec(IvParameterSpec.class).getIV(); 
        byte[] encryptedTextBytes = cipher.doFinal(String.valueOf(plaintext).getBytes("UTF-8")); 

        return DatatypeConverter.printBase64Binary(encryptedTextBytes); 
    } 

    public static String decrypt(char[] encryptedText) throws Exception { 

        System.out.println(encryptedText); 

        byte[] encryptedTextBytes = DatatypeConverter.parseBase64Binary(new String(encryptedText)); 
        SecretKeySpec secretSpec = new SecretKeySpec(secretKey, "AES"); 

        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
        cipher.init(Cipher.DECRYPT_MODE, secretSpec, new IvParameterSpec(ivBytes)); 

        byte[] decryptedTextBytes = null; 

        try { 
            decryptedTextBytes = cipher.doFinal(encryptedTextBytes); 
        }   catch (IllegalBlockSizeException e) { 
            e.printStackTrace(); 
        }   catch (BadPaddingException e) { 
            e.printStackTrace(); 
        } 

        return new String(decryptedTextBytes); 

    } 

    public static String getSalt() throws Exception { 

        SecureRandom sr = SecureRandom.getInstance("SHA1PRNG"); 
        byte[] salt = new byte[20]; 
        sr.nextBytes(salt); 
        return new String(salt); 
    } 
}

How can I have both of them work with each other, for example if I send an encrypted data to java app from rails app it should be able to decode it and vice-versa.

Sahil
  • 3,338
  • 1
  • 21
  • 43
  • 1
    and which of those 2 versions should be the one that stays? – zapl Jun 23 '16 at 12:02
  • you have a simple encryption in ruby and vs PBKDF with salt in java. You can use either version in either language but you'll have to specify which one you want. – zapl Jun 23 '16 at 12:15
  • Ok, I guess therefore I am unable to get the desired result. If I use PBKDF in ruby, will there will be a need to send iv key value to the java application? – Sahil Jun 23 '16 at 12:18
  • 2
    Both salt & IV are not secret and need to be known by both en- and de-crypting sides. They can be sent in plain text without compromising security. If you chose either one or both you'll have to transfer them (or chose fixed ones but that makes them basically unnecessary). – zapl Jun 23 '16 at 12:44
  • How does sending one or both does not compromise security as if someone records the request, he will get both the keys and then he just has to guess the algo? – Sahil Jun 24 '16 at 04:17
  • 1
    You need to know the secretkey / encryption password. Using salt / iv makes it harder to calculate that because the resulting encrypted data is randomized further. You can without (different each time) iv for example identify identical messages just by comparing the encrypted data – zapl Jun 24 '16 at 05:30
  • @zapl, I know the secret key used in Java program, but it's salt and iv which I am not doing it in ruby, plus it also has iterations count. So the end result is not same in both. – Sahil Jun 24 '16 at 05:32
  • @zapl, can you give me an idea, how can I extract salt and iv value from javascript, because, I have tried doing it and setting it in my ruby code, which gives me an error saying that iv value is too short. – Sahil Jun 24 '16 at 07:41
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/115484/discussion-between-zapl-and-sahil). – zapl Jun 24 '16 at 07:41
  • Hi @zapl, I have implemented the functionality, however whenever I run the standalone java decryption code in my ubuntu machine, everything seems fine, whereas when I run this same code in Windows machine in standalone mode it decrypts it but appends this at the end `{count:0,val:1467022962315}`, and if I post the encrypted code from my rails app to Java app which is running in dev mode on Windows, it fails at `cipher.init(Cipher.DECRYPT_MODE, KEY, new IvParameterSpec(ivBytes));` error:`Exception Inside getEncryptedByteArrayForfile Method java.security.InvalidKeyException: Illegal key size` – Sahil Jun 27 '16 at 11:46
  • I am unable to show those characters[square shaped icons with 000E] over here. – Sahil Jun 27 '16 at 11:52
  • Just one small doubt, is it possible that the security jce file loads from one location if I run the encryption file directly where as when I include this in my Java app, the secuirty.jar file loads from some other location. After googling I found out [this](http://stackoverflow.com/a/6481658/3863146) which I have already done and works for standalone java file. – Sahil Jun 27 '16 at 12:59
  • 2
    `InvalidKeyException: Illegal key size` happens when you don't have the unlimited strength crypto because default java installs allow only aes-128 and below key sizes. The files you install are always loaded when you use that java install to run your program, whether that's a standalone or server app. You're probably using different java versions installed side by side when it works only in one. What that `count:0, ..` thing is, I don't know you must have put it into the encrypted blob if it comes out of there. Encryption does not alter data and it's not OS dependent either. – zapl Jun 27 '16 at 13:19

1 Answers1

0

As far as you are using the same cypher algorithms and message padding characters, they should work just fine.

Also, it is better to use some key exchange protocol, like Diffie-Hellman. Both Ruby's OpenSSL wrapper and Java's Crypto lib support it. It is a safer way to generate per session keys.

PS. Your code as you have it, seems to be written for a standalone execution. For example, your Java code for decoding assumes that your string was encoded with the same instance's encode method. Because, your decode method is using IV that was initialized in encode method (ivBytes).

Uzbekjon
  • 11,655
  • 3
  • 37
  • 54
  • Thanks @Uzbekjon, I have to try the key exchange protocol, as of now if I try to decode an encrypted message received from the Java App, I get an error saying that wrong final block. I am unable to find out how both of them give the same encoded msg. Will try your approach and update it over here. – Sahil Jun 24 '16 at 04:21
  • If the problem is in the final block, then it might be caused by the different padding characters used in ruby and java. You should look into that. – Uzbekjon Jun 24 '16 at 04:26
  • There's one more thing which I am not sure of which is, in java it uses iv key, so I tried getting the iv value and used it in ruby as, cipher.iv = same_key, plus even the key used in ruby it says it's too short, so I converted it to 256 bit using SHA256, which I am not sure is being done in Java. – Sahil Jun 24 '16 at 04:53
  • Just debug your app and check it to rule it out. Or just look into docs. Java docs are quite detailed. I'd say too detailed ) – Uzbekjon Jun 24 '16 at 04:56
  • Is there a way, I can write a similar program in ruby as the one written in Java above? I have been trying to sync it up since yesterday. Because there are many things in happening the java code such as, iv, salt, iterations and secret key which is not there in my current code. – Sahil Jun 24 '16 at 05:29