【问题标题】:RSA Signature: Java to RubyRSA 签名:Java 到 Ruby
【发布时间】:2021-11-11 18:04:30
【问题描述】:

我正在尝试编写 Ruby 代码来复制我作为工作示例收到的 Java 代码的功能。我相信我得到了大部分内容,但最后当我尝试使用服务器验证签名时,我得到了这个:

IAM Exception: IAM-1000:Signature length not correct: got 256 but was expecting 384

这是 Java 示例:

import java.io.ObjectStreamException;
import java.security.KeyRep;
import java.security.PrivateKey;
import java.security.Signature;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;

import org.apache.commons.codec.binary.Base64;

public class SignatureGenerator {

    public static void main(String[] args) {
        SignatureGenerator generator = new SignatureGenerator();

        String consumerId = "xxxxxx";
        String priviateKeyVersion = "1";
        String privateKey = ""; // omitted for security reasons

        long intimestamp = System.currentTimeMillis();

        System.out.println("consumerId: " + consumerId);
        System.out.println("intimestamp: " + intimestamp);

        Map<String, String> map = new HashMap<>();
        map.put("AA_CONSUMER.ID", consumerId);
        map.put("AA_CONSUMER.INTIMESTAMP", Long.toString(intimestamp));
        map.put("AA_SEC.KEY_VERSION", priviateKeyVersion);

        String[] array = canonicalize(map);

        String data = null;

        try {
            data = generator.generateSignature(privateKey, array[1]);
        } catch(Exception e) { }
        System.out.println("Signature: " + data);
    }
    public String generateSignature(String key, String stringToSign) throws Exception {
        Signature signatureInstance = Signature.getInstance("SHA256WithRSA");

        ServiceKeyRep keyRep = new ServiceKeyRep(KeyRep.Type.PRIVATE, "RSA", "PKCS#8", Base64.decodeBase64(key));

        PrivateKey resolvedPrivateKey = (PrivateKey) keyRep.readResolve();

        signatureInstance.initSign(resolvedPrivateKey);

        byte[] bytesToSign = stringToSign.getBytes("UTF-8");
        signatureInstance.update(bytesToSign);
        byte[] signatureBytes = signatureInstance.sign();

        String signatureString = Base64.encodeBase64String(signatureBytes);

        return signatureString;
    }
    protected static String[] canonicalize(Map<String, String> headersToSign) {
        StringBuffer canonicalizedStrBuffer=new StringBuffer();
        StringBuffer parameterNamesBuffer=new StringBuffer();
        Set<String> keySet=headersToSign.keySet();

        // Create sorted key set to enforce order on the key names
        SortedSet<String> sortedKeySet=new TreeSet<String>(keySet);
        for (String key :sortedKeySet) {
            Object val=headersToSign.get(key);
            parameterNamesBuffer.append(key.trim()).append(";");
            canonicalizedStrBuffer.append(val.toString().trim()).append("\n");
        }
        return new String[] {parameterNamesBuffer.toString(), canonicalizedStrBuffer.toString()};
    }

    class ServiceKeyRep extends KeyRep  {
        private static final long serialVersionUID = -7213340660431987616L;
        public ServiceKeyRep(Type type, String algorithm, String format, byte[] encoded) {
            super(type, algorithm, format, encoded);
        }
        protected Object readResolve() throws ObjectStreamException {
            return super.readResolve();
        }
    }
}

这是我的 Ruby 代码,它最终尝试执行相同的 + 请求

consumer_id = 'xxxxx'
key_version = '1'
private_key = '' # omitted for security
to_encrypt = {
  "AA_CONSUMER.ID" => consumer_id,
  "AA_CONSUMER.INTIMESTAMP" => DateTime.now.strftime('%Q'),
  "AA_SEC.KEY_VERSION" => key_version
}

names = ''
canstr = ''

# sort
sorted_keys = to_encrypt.keys.sort
sorted_keys.each do |key|
  value = to_encrypt[key]
  names += "#{key};"
  canstr += "#{value}\n"
end

final_arr = [names, canstr]
key = OpenSSL::PKey::RSA.new(Base64.decode64(private_key))
signature = key.sign('SHA256', final_arr[1])
signature_string = Base64.urlsafe_encode64(signature)

headers = to_encrypt.merge("AA_SEC.AUTH_SIGNATURE" => signature_string)
response = Faraday.send(:get, url, {}, headers)

有什么建议吗?

【问题讨论】:

  • 请显示您收到的错误的堆栈跟踪。
  • 我没有堆栈跟踪错误。我正在向 API 发送 GET 请求,他们希望签名为 384 而不是 256。如果我调用 signature.size,我得到的数字是 256。
  • ...但最后当我尝试使用服务器验证签名时...您发布的代码都没有尝试验证签名。 Java 和 Ruby 代码似乎都会生成签名。
  • 我知道。 Ruby 代码最终通过使用 Faraday 来完成。唯一的验证点是服务器,它需要 384 字节的签名。

标签: java ruby openssl rsa


【解决方案1】:

似乎服务器需要一个 384 字节长的签名,而您正在发送一个 256 字节长的签名。

值得一试

key.sign('SHA384', final_arr[1])

为了让您的摘要为 384 字节。

【讨论】:

  • 我仍然收到关于 ```IAM 异常的相同错误:IAM-1000:Signature length not correct: got 256 but was expected 384
  • 当我调用 signature.size 它说 256 字节
  • SHA384 不是 384 字节,而是 384 位。签名的大小是 RSA 模数大小的函数,而不是散列函数。
猜你喜欢
  • 1970-01-01
  • 2023-03-06
  • 2021-03-22
  • 1970-01-01
  • 2010-12-02
  • 1970-01-01
  • 2011-10-03
  • 2018-02-18
  • 1970-01-01
相关资源
最近更新 更多