Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Encrypt data in ruby same as SecretKeySpec?

I am trying to encrypt a string in ruby using Cipher with AES algorithm. I have example written in Java. I have taken help from this example and written code in Java but not able to get the same output as in JAVA.

Following is the code written in java

import java.util.Base64;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.security.Key;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import java.util.Arrays;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

public class HelloWorld {
    public static final String PHONENUMBER_PARAM = "phoneNumber";
    public static final String PIN_PARAM ="pin";

    public static final String MERCHANTID_PARAM = "merchantId";

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

    String phoneNumber ="+917738995286";
    String pin ="5577";

    String merchantId ="527425858";
    String encodedKey ="vPDkdTDrcygLPROzd1829A==";

    String payLoad = PHONENUMBER_PARAM + "=" +         URLEncoder.encode(phoneNumber, "UTF-8")+ "&" + PIN_PARAM + "=" + URLEncoder.encode(pin, "UTF-8") ;

    byte[] decodedKey = Base64.getDecoder().decode(encodedKey.getBytes());

    Key encryptionKey = new SecretKeySpec(decodedKey, "AES");

    byte[] utf8Bytes = payLoad.getBytes("utf-8");

    byte[] encryptedBody = encrypt(encryptionKey, utf8Bytes);
    String encryptedData = new  String(Base64.getEncoder().encode(encryptedBody));

    System.out.println("encryptedData:" + encryptedData);
 }
private static byte[] encrypt(Key encryptionKey, byte[] data) throws Exception {
    Cipher c = Cipher.getInstance("AES");
    c.init(1, encryptionKey);
    return c.doFinal(data);
}
}

Output of this code is

encryptedData:lE40HlECbxU/mWRivF/+Szm3PprMoLW+Y7x911GczunakbG8l+A2JVEEP8gTw6xy

I tried to write the same code in ruby. Ruby Code is:

payLoad = "phoneNumber=%2B917738995286&pin=5577"

encodedKey = "vPDkdTDrcygLPROzd1829A=="

decodedKey = Base64.decode64(encodedKey)

dKey = decodedKey.each_byte.map { |b| b.to_s(16) }.join

cipher = OpenSSL::Cipher.new('aes128').encrypt
encryptionKey  = cipher.update(dKey) 
encryptionKey<< cipher.final


utf8Bytes = payLoad.bytes
uKey = utf8Bytes.map { |b| b.to_s(16) }.join

scipher = OpenSSL::Cipher.new('aes128').encrypt
scipher.key = encryptionKey  
encryptedBody = scipher.update(uKey) 
encryptedBody<< scipher.final

encryptedData  = Base64.encode64(encryptedBody)

Output of this code is

CqFmCKJ004PsoXi2tDCTBmx7/iTHVyDsFH9y8NWNrEP3k3bOQp7h8uyl/a7Z\nYi9ZmcXSspo6FCyCo6fJIwPohg==\n

Don't know where is the error. I have already worked for 2 days but not able to get any answer. Any help will be great. Thanks in advance.

like image 982
Yogesh Gupta Avatar asked May 02 '26 02:05

Yogesh Gupta


1 Answers

The following version outputs the same result as your Java code:

# crypt.rb
require 'base64'
require 'openssl'

payLoad = "phoneNumber=%2B917738995286&pin=5577"
encodedKey = "vPDkdTDrcygLPROzd1829A=="

decodedKey = Base64.decode64(encodedKey)

scipher = OpenSSL::Cipher.new('aes-128-ecb').encrypt
scipher.key = decodedKey
encryptedBody = scipher.update(payLoad)
encryptedBody << scipher.final

encryptedData  = Base64.encode64(encryptedBody)
puts encryptedData


$ ruby crypt.rb
# => lE40HlECbxU/mWRivF/+Szm3PprMoLW+Y7x911GczunakbG8l+A2JVEEP8gT
#    w6xy

Notable differences from your ruby script version:

  • You must specify the cipher mode. The problem is that Java defaults to the ECB mode whereas ruby defaults to the CBC mode. By the way, the ECB mode is considered less-secure today and you actually should not use it.

  • In ruby, you tried to re-encrypt the Base64-decoded version of your encryption key, which is something you don't do in the Java version.

  • In ruby, there is no need to do the string to byte conversions, you can encrypt strings right away.

So, although the two scripts output the same encrypted data now, I would strongly consider changing the AES mode of operation, to actually stay secure.

like image 105
Matouš Borák Avatar answered May 03 '26 14:05

Matouš Borák



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!