如何使用与SecretKeySpec相同的方式加密ruby中的数据?

时间:2016-04-29 13:10:40

标签: java ruby-on-rails ruby encryption

我正在尝试使用Cipher和AES算法加密ruby中的字符串。我有用Java编写的示例。我已经从这个示例中获得了帮助,并用Java编写了代码,但是无法获得与JAVA相同的输出。

以下是用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);
}
}

此代码的输出

  

的EncryptedData:lE40HlECbxU / mWRivF / + + Szm3PprMoLW + Y7x911GczunakbG8l A2JVEEP8gTw6xy

我试着在ruby中编写相同的代码。 Ruby代码是:

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)

此代码的输出

  

CqFmCKJ004PsoXi2tDCTBmx7 / iTHVyDsFH9y8NWNrEP3k3bOQp7h8uyl / A7Z \ nYi9ZmcXSspo6FCyCo6fJIwPohg == \ n

不知道错误在哪里。我已经工作了2天但没有得到任何答案。任何帮助都会很棒。提前谢谢。

1 个答案:

答案 0 :(得分:2)

以下版本输出与Java代码相同的结果:

# 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

与ruby脚本版本存在显着差异:

  • 必须指定密码模式。问题是Java defaults to the ECB mode而ruby默认为CBC模式。顺便说一句,今天ECB模式被认为不太安全,而实际上should not use it

  • 在ruby中,您尝试重新加密Base64解码版本的加密密钥,这是您在Java版本中没有做到的。

  • 在ruby中,不需要进行字符串到字节的转换,您可以立即加密字符串。

因此,虽然这两个脚本现在输出相同的加密数据,但我会强烈考虑更改AES操作模式,以实际保持安全。