先人 > 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