先人 > Amazon Product Advertising APIの認証の件 - zorioの日記
Ruby-1.8.7と Ruby-1.8.6では String#force_encoding("ASCII-8BIT")ができず、String#ordもない(ないのはエンコーディングの概念がないからと、String#[]で代替できるからだと思われる)。それらを使い分けるために 2種類のメソッドを用意するくらいなら、unpackで配列経由でいいです。
require 'digest/sha2'
def hmac_sha256(key, message)
hash = Digest::SHA256
hash_block_size = 64 # bytes (= hash.new.block_length)
key = hash.digest( key ) if hash_block_size < (key.bytesize rescue key.size)
ikey = Array.new( hash_block_size, 0x36 )
okey = Array.new( hash_block_size, 0x5c )
key.unpack("C*").each_with_index{|key_byte, i|
ikey[i] ^= key_byte
okey[i] ^= key_byte
}
inner_hash = hash.new.update( ikey.pack("C*") )
outer_hash = hash.new.update( okey.pack("C*") )
digest = outer_hash.update( inner_hash.update( message ).digest ).digest
return digest
end
短い秘密鍵は 0を補うって書いてあった。その処理が見あたらないのになぜうまくいくのかと考えたら、0を相手に排他的論理和をとったって何も変わらないのねん。
class Digest::Base
- update(str)
- self << str
- 文字列を追加する。self を返す。複数回updateを呼ぶことは文字列を連結してupdateを呼ぶことと等しい。すなわち m.update(a); m.update(b) は m.update(a + b) と、 m << a << b は m << a + b とそれぞれ等価である。
Ruby-1.9で文字列の連結は怖いので m.update(a + b) と m << a + b と Digest::SHA256.digest(ipad + message) は避けたい。
302 Foundはわかる。リバースプロキシは何するもの?
require 'uri'
require 'base64'
def amazon_authenticated_query_string( host, params )
re_rfc3986_unreserved = /[^A-Za-z0-9\-_.~]/
query_string = params.to_a.sort_by{|x| x.first }.map{|key, value|
URI.encode(key, re_rfc3986_unreserved) +'='+ URI.encode(value, re_rfc3986_unreserved)
}.join("&")
string_to_sign = <<-"STRING_TO_SIGN".gsub(/^\t\t/, '').chomp
GET
#{host.downcase}
/onca/xml
#{query_string}
STRING_TO_SIGN
amazon_secret_access_key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
signature = Base64.encode64( hmac_sha256( amazon_secret_access_key, string_to_sign ) ).chomp
return "#{query_string}&Signature=#{URI.encode(signature, re_rfc3986_unreserved)}"
end