无法使用HMAC在Ruby中生成正确的加密密钥
我试图按照文档和询问代码进行操作,但我无法这样做 我收到以下错误:401 Unauthorized:{“code”:“Unauthorized”,“message”:“输入授权令牌无法为请求提供服务。请检查预期的有效负载是否按照协议生成,并检查正在使用的密钥。服务器使用以下有效负载进行签名:'post\ndbs\n\n13 april 2015 18:21:05 gmt\n\n'\r\nActivityId: 我的ruby代码如下所示:无法使用HMAC在Ruby中生成正确的加密密钥,ruby,azure,hmac,sha256,azure-cosmosdb,Ruby,Azure,Hmac,Sha256,Azure Cosmosdb,我试图按照文档和询问代码进行操作,但我无法这样做 我收到以下错误:401 Unauthorized:{“code”:“Unauthorized”,“message”:“输入授权令牌无法为请求提供服务。请检查预期的有效负载是否按照协议生成,并检查正在使用的密钥。服务器使用以下有效负载进行签名:'post\ndbs\n\n13 april 2015 18:21:05 gmt\n\n'\r\nActivityId: 我的ruby代码如下所示: require 'openssl' require 're
require 'openssl'
require 'rest-client'
require 'base64'
require 'uri'
require 'json'
require 'time'
def get_databases url, master_key
time = Time.now.httpdate
authorization = get_master_auth_token "get", "", "dbs", time, master_key
header = { "authorization" => authorization, "x-ms-date" => time, "x-ms-version" => "2015-04-08" }
RestClient.get url, header
end
def get_master_auth_token verb, resource_id, resource_type, date, master_key
digest = OpenSSL::Digest::SHA256.new
key = Base64.decode64 master_key
text = verb + "\n" +
resource_type + "\n" +
resource_id + "\n" +
date + "\n" +
"\n"
hmac = OpenSSL::HMAC.digest digest, key, text.downcase
auth_string = "type=" + "master" + "&ver=" + "1.0" + "&sig=" + hmac
URI.escape auth_string
end
var crypto = require("crypto")
function encode_message(masterKey, message) {
var key = new Buffer(masterKey, "base64"); // encode/decode? base64 the masterKey
var body = new Buffer(message.toLowerCase(), "utf8"); // convert message to "utf8" and lower case
return crypto.createHmac("sha256", key).update(body).digest("base64"); // encrypt the message using key
}
require 'base64'
require 'openssl'
def encode_message master_key, message
key = Base64.urlsafe_decode64 master_key
hmac = OpenSSL::HMAC.digest 'sha256', key, message
Base64.urlsafe_encode64 hmac
end
2.2.1 :021 > encode_message("blah", "get\ncolls\n\nTue, 14 Apr 2015 13:34:22 GMT\n\n")
=> "N6BL3n4eSvYA8dIL1KzlTIvR3TcYpdqW2UNPtKWrjP8="
谢谢
编辑:根据Ryan的建议和示例,我将代码简化为以下snippit,这应该与他发布的节点代码相匹配,但在ruby中仍然失败:
def hard_coded_get_databases master_key, url
verb = "get"
resource_type = "dbs"
resource_id = ""
date = Time.now.httpdate
serv_version = '2014-08-21'
master_token = "master"
token_version = "1.0"
key = Base64.decode64 master_key
text = verb + "\n" + resource_type + "\n" + resource_id + "\n" + date + "\n\n"
body = text.downcase.force_encoding "utf-8"
signature = OpenSSL::HMAC.digest OpenSSL::Digest::SHA256.new, key, body
auth_token = URI.escape("type="+master_token + "&ver="+token_version + "&sig="+signature)
header = { "accept" => "application/json", "x-ms-version" => serv_version, "x-ms-date" => date, "authorization" => auth_token }
RestClient.get url, header
end
EDIT2:我相信我已经将问题隔离到如何进行主密钥身份验证
以Ryan为例,我们可以将他的节点代码缩减如下:
require 'openssl'
require 'rest-client'
require 'base64'
require 'uri'
require 'json'
require 'time'
def get_databases url, master_key
time = Time.now.httpdate
authorization = get_master_auth_token "get", "", "dbs", time, master_key
header = { "authorization" => authorization, "x-ms-date" => time, "x-ms-version" => "2015-04-08" }
RestClient.get url, header
end
def get_master_auth_token verb, resource_id, resource_type, date, master_key
digest = OpenSSL::Digest::SHA256.new
key = Base64.decode64 master_key
text = verb + "\n" +
resource_type + "\n" +
resource_id + "\n" +
date + "\n" +
"\n"
hmac = OpenSSL::HMAC.digest digest, key, text.downcase
auth_string = "type=" + "master" + "&ver=" + "1.0" + "&sig=" + hmac
URI.escape auth_string
end
var crypto = require("crypto")
function encode_message(masterKey, message) {
var key = new Buffer(masterKey, "base64"); // encode/decode? base64 the masterKey
var body = new Buffer(message.toLowerCase(), "utf8"); // convert message to "utf8" and lower case
return crypto.createHmac("sha256", key).update(body).digest("base64"); // encrypt the message using key
}
require 'base64'
require 'openssl'
def encode_message master_key, message
key = Base64.urlsafe_decode64 master_key
hmac = OpenSSL::HMAC.digest 'sha256', key, message
Base64.urlsafe_encode64 hmac
end
2.2.1 :021 > encode_message("blah", "get\ncolls\n\nTue, 14 Apr 2015 13:34:22 GMT\n\n")
=> "N6BL3n4eSvYA8dIL1KzlTIvR3TcYpdqW2UNPtKWrjP8="
如果调用此节点代码,我可以生成以下键:
encode_message("blah", 'get\ncolls\n\nTue, 14 Apr 2015 13:34:22 GMT\n\n')
'IYlLuyZtVLx5ANkGMAxviDHgC/DJJXSj1gUGLvN0oM8='
如果我生成等效的ruby代码来创建身份验证,我的ruby代码如下所示:
require 'openssl'
require 'rest-client'
require 'base64'
require 'uri'
require 'json'
require 'time'
def get_databases url, master_key
time = Time.now.httpdate
authorization = get_master_auth_token "get", "", "dbs", time, master_key
header = { "authorization" => authorization, "x-ms-date" => time, "x-ms-version" => "2015-04-08" }
RestClient.get url, header
end
def get_master_auth_token verb, resource_id, resource_type, date, master_key
digest = OpenSSL::Digest::SHA256.new
key = Base64.decode64 master_key
text = verb + "\n" +
resource_type + "\n" +
resource_id + "\n" +
date + "\n" +
"\n"
hmac = OpenSSL::HMAC.digest digest, key, text.downcase
auth_string = "type=" + "master" + "&ver=" + "1.0" + "&sig=" + hmac
URI.escape auth_string
end
var crypto = require("crypto")
function encode_message(masterKey, message) {
var key = new Buffer(masterKey, "base64"); // encode/decode? base64 the masterKey
var body = new Buffer(message.toLowerCase(), "utf8"); // convert message to "utf8" and lower case
return crypto.createHmac("sha256", key).update(body).digest("base64"); // encrypt the message using key
}
require 'base64'
require 'openssl'
def encode_message master_key, message
key = Base64.urlsafe_decode64 master_key
hmac = OpenSSL::HMAC.digest 'sha256', key, message
Base64.urlsafe_encode64 hmac
end
2.2.1 :021 > encode_message("blah", "get\ncolls\n\nTue, 14 Apr 2015 13:34:22 GMT\n\n")
=> "N6BL3n4eSvYA8dIL1KzlTIvR3TcYpdqW2UNPtKWrjP8="
如果我调用此代码,我会得到以下结果:
require 'openssl'
require 'rest-client'
require 'base64'
require 'uri'
require 'json'
require 'time'
def get_databases url, master_key
time = Time.now.httpdate
authorization = get_master_auth_token "get", "", "dbs", time, master_key
header = { "authorization" => authorization, "x-ms-date" => time, "x-ms-version" => "2015-04-08" }
RestClient.get url, header
end
def get_master_auth_token verb, resource_id, resource_type, date, master_key
digest = OpenSSL::Digest::SHA256.new
key = Base64.decode64 master_key
text = verb + "\n" +
resource_type + "\n" +
resource_id + "\n" +
date + "\n" +
"\n"
hmac = OpenSSL::HMAC.digest digest, key, text.downcase
auth_string = "type=" + "master" + "&ver=" + "1.0" + "&sig=" + hmac
URI.escape auth_string
end
var crypto = require("crypto")
function encode_message(masterKey, message) {
var key = new Buffer(masterKey, "base64"); // encode/decode? base64 the masterKey
var body = new Buffer(message.toLowerCase(), "utf8"); // convert message to "utf8" and lower case
return crypto.createHmac("sha256", key).update(body).digest("base64"); // encrypt the message using key
}
require 'base64'
require 'openssl'
def encode_message master_key, message
key = Base64.urlsafe_decode64 master_key
hmac = OpenSSL::HMAC.digest 'sha256', key, message
Base64.urlsafe_encode64 hmac
end
2.2.1 :021 > encode_message("blah", "get\ncolls\n\nTue, 14 Apr 2015 13:34:22 GMT\n\n")
=> "N6BL3n4eSvYA8dIL1KzlTIvR3TcYpdqW2UNPtKWrjP8="
显然,这两个编码的auth令牌是不一样的。(Ryan再次感谢您的帮助。)首先,我要为我有限的Ruby知识道歉,但让我在这里尝试帮助 在get_master_auth_token函数中,您似乎在使用密钥之前解码密钥。这是否正确?如果正确,原因是什么 下面是一个node.js示例,它使用主密钥,构建auth头值,并执行一个简单的http调用来列出数据库中的集合
var crypto = require("crypto");
var https = require("https");
https.globalAgent.options.secureProtocol = "TLSv1_client_method";
var verb = 'get';
var resourceType = 'dbs'; //the resource you are trying to get. dbs, colls, docs etc.
var resourceId = ''; //the parent resource id. note: not the id, but the _rid. but for you, because you are trying to lookup list of databases there is no parent
var masterKey = '...'; //your masterkey
var date = new Date().toUTCString();
var auth = getAuthorizationTokenUsingMasterKey(verb, resourceId, resourceType, date, masterKey);
var options = {
hostname: '...', //your hostname (without https://)
port: 443,
path: '/dbs/',
method: 'GET',
headers: {
accept: 'application/json',
'x-ms-version': '2014-08-21',
'x-ms-date': date,
authorization: auth,
}
};
for (var i = 0; i < 1000; i++) {
var req = https.request(options, function (res) {
process.stdout.write(new Date().toUTCString() + " - statusCode: " + res.statusCode + "\n");
res.on('data', function (d) {
}).on('error', function (e) {
})
});
//console.log(req);
req.end();
}
function getAuthorizationTokenUsingMasterKey(verb, resourceId, resourceType, date, masterKey) {
var key = new Buffer(masterKey, "base64");
var text = (verb || "") + "\n" +
(resourceType || "") + "\n" +
(resourceId || "") + "\n" +
(date || "") + "\n" +
("") + "\n";
var body = new Buffer(text.toLowerCase(), "utf8");
var signature = crypto.createHmac("sha256", key).update(body).digest("base64");
var MasterToken = "master";
var TokenVersion = "1.0";
return encodeURIComponent("type=" + MasterToken + "&ver=" + TokenVersion + "&sig=" + signature);
}
var crypto=require(“crypto”);
var https=要求(“https”);
https.globalAgent.options.secureProtocol=“TLSv1\u client\u method”;
var动词='get';
var resourceType='dbs';//您试图获取的资源。dbs、colls、docs等。
var resourceId='';//父资源id。注意:不是id,而是_rid。但是对于您来说,因为您试图查找数据库列表,所以没有父资源id
var masterKey='…';//您的masterKey
var date=new date().toutString();
var auth=getAuthorizationTokenUsingMasterKey(动词、资源ID、资源类型、日期、masterKey);
变量选项={
主机名:“…”,//您的主机名(不带https://)
港口:443,
路径:'/dbs/',
方法:“GET”,
标题:{
接受:'application/json',
“x-ms-version”:“2014-08-21”,
“x-ms-date”:日期,
授权:auth,
}
};
对于(变量i=0;i<1000;i++){
var req=https.request(选项、函数(res){
process.stdout.write(new Date().toutString()+”-statusCode:“+res.statusCode+”\n”);
res.on('数据',功能(d){
}).on('error',函数(e){
})
});
//控制台日志(req);
请求结束();
}
函数getAuthorizationTokenUsingMasterKey(动词、resourceId、resourceType、日期、masterKey){
var key=新的缓冲区(masterKey,“base64”);
变量text=(动词| |“”)+“\n”+
(resourceType | |“”)+“\n”+
(resourceId | |“”)+“\n”+
(日期| |“”)+“\n”+
(“”)+“\n”;
var body=新缓冲区(text.toLowerCase(),“utf8”);
var signature=crypto.createHmac(“sha256”,key).update(body.digest)(“base64”);
var MasterToken=“master”;
var TokenVersion=“1.0”;
返回encodeURIComponent(“type=“+MasterToken+”&ver=“+TokenVersion+”&sig=“+signature”);
}
在您的示例中,传递给getAuthorizationTokenUsingMasterKey方法的resourceId应该是“”,resourceType应该是“dbs”
我确实注意到,在某些情况下,您必须对值进行URI编码,但我认为您已经在func的最后一行这样做了
我能在你的代码和我的代码中发现的唯一区别是,你似乎在解码主密钥,而我没有这样做
我建议您运行此节点示例,并将body&signature中的字符串值与your值进行比较。它们需要匹配。我找到了答案。感谢Magnus Stahre…他是帮助我解决问题的人 正如我所想,这是编码,诀窍是:
def encode_message master_key, message
key = Base64.urlsafe_decode64 master_key
hmac = OpenSSL::HMAC.digest 'sha256', key, message.downcase
Base64.encode64(hmac).strip
end
我过早地对代码进行了降级,我的Base64.encode64未能去掉ruby在末尾添加的换行符。作为说明,我还引用了msdn的以下帖子:非常感谢您的帮助。我的理解是,当您这样做时:var key=new Buffer(masterkey,“Base64”)您正在解码主密钥,这不对吗?是的,字符串末尾的换行符就可以了。捕捉得好!