【发布时间】: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 字节的签名。