【问题标题】:Java to ruby AES/ECB/PKCS5Padding encryptionJava 到 Ruby AES/ECB/PKCS5Padding 加密
【发布时间】:2017-11-11 08:08:33
【问题描述】:

我有一个使用第三方支付门户的在线电子商务网站。在第三方支付门户要求所有人开始使用带有其他支付参数的哈希键之前,支付门户一直运行良好。

现在的问题是第三方支付门户只提供了一页文档来实现哈希键。

这是提供的文档:-

加密算法

为了在传输和发布数据时减轻参数的修改/修改,商家可以使用 Telenor POC 提供的哈希密钥对请求进行加密。该加密请求与主请求一起发送,然后在 OPS 端进行协调以检测参数是否更改。可以使用以下算法进行加密:

  1. 创建请求中所有字段的映射 映射字段 = new HashMap();

    fields.put("数量", "10");

    fields.put("storeId", "28");

    fields.put("orderRefNum", "11001");

    fields.put("expiryDate", "20150101 151515");

    fields.put("postBackURL", "http://localhost:9081/local/status.php");

  2. 从第一步创建的地图中获取字段名列表

    List fieldNames = new ArrayList(fields.keySet());

  3. 根据地图键按字母顺序对地图字段进行排序

    Collections.sort(fieldNames);

  4. 创建以下格式的字符串: 金额=10&expiryDate=20150101151515&orderRefNum=11001&postBackURL=http://localhost:9081/local/status.php&storeId=28

  5. 使用 AES/ECB/PKCS5Padding 算法,使用上一步生成的密钥和字符串进行加密

    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");

    SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(), "AES");

    cipher.init(Cipher.ENCRYPT_MODE, secretKey);

    加密值 = 新 String(Base64.encodeBase64(cipher.doFinal(value.getBytes())));

现在另一个问题是我没有任何Java经验。

我拨打了第三方支付门户帮助热线,他们只是帮我告诉了我钥匙。

如果有人能帮助我告诉我第 5 步的 Ruby 等价物是什么,我将不胜感激。谢谢

刚刚在在线java编译器上尝试了提供的代码:-

import java.security.Key;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;

public class encryptData {
  public static void main(String[] args) {

    String data="amount=10&expiryDate=20150101 151515&orderRefNum=11001&postBackURL=http://localhost:9081/local/status.php&storeId=28";
    String key="89OUITUPRL3I8H3G";

    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
    SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(), "AES");
    cipher.init(Cipher.ENCRYPT_MODE, secretKey);
    encryptedValue = new String(Base64.encodeBase64(cipher.doFinal(data.getBytes())));
  }
}

这是错误:-

/tmp/java_Ramvov/encryptData.java:16: 错误:找不到符号

encryptedValue = new String(Base64.encodeBase64(cipher.doFinal(data.getBytes())));
^

符号:变量 encryptedValue

位置:加密数据类

/tmp/java_Ramvov/encryptData.java:16: 错误:找不到符号

encryptedValue = new String(Base64.encodeBase64(cipher.doFinal(data.getBytes())));
                                  ^

符号:方法 encodeBase64(byte[])

位置:Base64 类

2 个错误

任何帮助将不胜感激

我也尝试在 ruby​​ 中重现这个 java 代码:-

data = "amount=10&expiryDate=20150101151515&orderRefNum=11001&postBackURL=http://localhost:9081/local/status.php&storeId=28"                                                                                                                                            
cipher = OpenSSL::Cipher.new("AES-128-ECB")
cipher.encrypt()
cipher.key = "89OUITUPRL4I9H3G"
crypt = cipher.update(data) + cipher.final()
crypt_string = (Base64.encode64(crypt))

但生成的加密被支付门户拒绝

【问题讨论】:

  • 他们有示例输出吗?这样您就可以验证实现的正确性
  • @Srgio Tulentsev 没有提供。他们刚刚给我的另一个信息是,最后一步中的“value”变量是这个字符串“amount=10&expiryDate=20150101151515&orderRefNum=11001&postBackURL=localhost:9081/local/status.php&storeId=28
  • 好吧,你怎么能确定你正确地实现了密码呢?向他们询问示例输出。或者运行那个 java 代码。
  • @Srgio Tulentsev 我已经编辑了这个问题,但我在编译 Java 代码时遇到了错误

标签: java ruby encryption


【解决方案1】:

使用ECB模式进行防篡改输入是非常愚蠢的。

话虽如此,但知道这不是你的错,因为这不是你的想法,而你只是想让代码工作,让我们请独立方给我们一个参考点:

echo -n "amount=10&expiryDate=20150101151515&orderRefNum=11001&postBackURL=http://localhost:9081/local/status.php&storeId=28" | openssl enc -K 38394f5549545550524c334938483347 -aes-128-ecb -base64

请注意,openssl 将密钥作为十六进制字符串,因此 89OUITUPRL4I9H3G 应写为其 ASCII 序列 38394f5549545550524c334938483347

输出是:

r7N11xE4HdbJyTByiTDifI1vifvZyNcNfKF+Jo7jEq4rN7c3EiOJxdWOUlCtVXeH
FBTdPSROSmTkUTWfAuOQnHWqe/q/Msd1ykUDIz9eP5L6X6RI0R5UtUXmaakr4klz
1kxEJOjR/WJ5xgd2clBh4iLcYi3caDrCkbD0kRDLQE4=

让我们尝试在 Java 中复制它。为此,我们必须更改代码中的一些内容:

  1. 您的 expiryDate 在 Java 代码中是 20150101 151515,但在其他任何地方都是 20150101151515。所以让我们标准化20150101151515
  2. Base64.encodeBase64() 不存在。 Java 8内置Base64编码,代码应为Base64.getEncoder().encodeToString(data)
  3. 返回类型已经是字符串,所以不需要encryptedValue = new String(Base64...)
  4. 另外,需要先声明encryptedValue的类型才能使用。

综上所述,这可以在 Java 8 中编译:

import java.security.Key;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;

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

    String data="amount=10&expiryDate=20150101151515&orderRefNum=11001&postBackURL=http://localhost:9081/local/status.php&storeId=28";
    String key="89OUITUPRL3I8H3G";

    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
    SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(), "AES");
    cipher.init(Cipher.ENCRYPT_MODE, secretKey);

    byte[] plaintext = data.getBytes();
    byte[] ciphertext = cipher.doFinal(plaintext);
    String encryptedValue = Base64.getEncoder().encodeToString(ciphertext);

    System.out.println(encryptedValue);
  }
}

并打印(我添加的换行符):

r7N11xE4HdbJyTByiTDifI1vifvZyNcNfKF+Jo7jEq4rN7c3EiOJxdWOUlCtVXeH
FBTdPSROSmTkUTWfAuOQnHWqe/q/Msd1ykUDIz9eP5L6X6RI0R5UtUXmaakr4klz
1kxEJOjR/WJ5xgd2clBh4iLcYi3caDrCkbD0kRDLQE4=

到目前为止还可以。红宝石呢?

#!/usr/bin/ruby

require 'openssl'
require 'base64'

data = "amount=10&expiryDate=20150101151515&orderRefNum=11001&postBackURL=http://localhost:9081/local/status.php&storeId=28"

key = "89OUITUPRL4I9H3G"
cipher = OpenSSL::Cipher.new("AES-128-ECB")
cipher.encrypt()
cipher.key = key
crypt = cipher.update(data) + cipher.final

crypt_string = (Base64.encode64(crypt))
puts crypt_string

打印出来:

mp8WVhyUHFDqvJKaRXbYKbZT1920TNboRpFLUdPaYsWTkiQ2fhN/tCL6wvtI
B9/Mu08McaKTVIWYeQAfVR5XcUKdeQ+CBcJJRs5krLBjtjiMNlBUq9JpCUaC
0eclfDMaGTE+Z4XSafjPictWzTG/Ye+vkJWC23yxW1zSjBnYBfg=

为什么 ruby​​ 代码不起作用?好吧,我怀疑 ruby​​ 需要与 openssl 相同的密钥,因为 ruby​​ crypto 通常在引擎盖下使用 openssl。所以将键定义更改为

key = "38394f5549545550524c334938483347"
key = [key].pack('H*')

现在打印:

r7N11xE4HdbJyTByiTDifI1vifvZyNcNfKF+Jo7jEq4rN7c3EiOJxdWOUlCt
VXeHFBTdPSROSmTkUTWfAuOQnHWqe/q/Msd1ykUDIz9eP5L6X6RI0R5UtUXm
aakr4klz1kxEJOjR/WJ5xgd2clBh4iLcYi3caDrCkbD0kRDLQE4=

除了换行位置之外,其他两个位置的输出相同。希望你能与对方正确沟通,切记:

使用ECB模式进行防篡改输入是非常愚蠢的。

【讨论】:

  • 这个问题无法得到更好的解决和解释。谢谢@wallenborn
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-03-01
  • 2017-04-07
  • 1970-01-01
  • 2019-05-14
  • 2019-04-18
  • 1970-01-01
  • 2011-10-19
相关资源
最近更新 更多