HMAC-SHA1ハッシュ関数について

このQ&Aのポイント
  • HMAC-SHA1ハッシュ関数についての質問です。HMAC-SHA1によってダイジェスト値を生成し、BASE64でエンコードしてシグニチャを生成したいと思っています。
  • 参考サイトでは、GETメソッドとURL、パラメータを使ってダイジェスト値を生成しています。例示されているPHPコードを試してみましたが、期待通りのシグニチャが得られません。
  • 正しいPHPコードでHMAC-SHA1ハッシュ関数を使ってダイジェスト値とシグニチャを生成する方法を教えてください。
回答を見る
  • ベストアンサー

HMAC-SHA1ハッシュ関数について

HMAC-SHA1ハッシュ関数について質問です。 HMAC-SHA1 によってダイジェスト値を生成し、BASE64 でエンコードすることによってシグニチャを生成したいと考えました。 参考サイト http://weboo-returns.com/blog/php-oauth-consumer-request-2-legged-oauth/ 上記の例では、 ●ダイジェスト値 GET&http%3A%2F%2Fapi.gu3.jp%2Fv1%2Ftest%2Fauth&oauth_consumer_key%3Dyamashita.dyndns.org%26oauth_nonce%3Dc83b1847200bd25d918c3fb077aca16f%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1219931263%26oauth_version%3D1.0 ●共有キー kd94hf93k423kf44& とした場合、ここから得られる、シグニチャは以下のようになりますと書かれています。 M32qYtcaUD8b1Kb/AponRG5hrwI= 上記を下記のPHPで試してみました。 ********************************************* <?php $key2 = 'kd94hf93k423kf44&'; $Base_String2 = 'GET&http%3A%2F%2Fapi.gu3.jp%2Fv1%2Ftest%2Fauth&oauth_consumer_key%3Dyamashita.dyndns.org%26oauth_nonce%3Dc83b1847200bd25d918c3fb077aca16f%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1219931263%26oauth_version%3D1.0'; $OAuthSignature2 = base64_encode(hash_hmac('sha1', $Base_String2, $key2, true)); echo $OAuthSignature2."\n"; ?> ************************************** ここから得られたシグニチャは以下のようになりました。 /j6JriS6FRFbKat4X3pJg4hO1Po= 残念ながら例示であるM32qYtcaUD8b1Kb/AponRG5hrwI=と一致しません。 私のPHPの書き方に誤りがあるようです。 質問 HMAC-SHA1 によってダイジェスト値を生成し、BASE64 でエンコードすることによってシグニチャを生成するPHPはどのように書けばよいのでしょうか?

  • PHP
  • 回答数1
  • ありがとう数1

質問者が選んだベストアンサー

  • ベストアンサー
回答No.1

このサイトに誤りがあると自分は判断します。 このサイトから参照されているサイトを見たら、このサイトの元になった説明が書かれています。 http://oauth.googlecode.com/svn/spec/ext/consumer_request/1.0/drafts/1/spec.html この説明通りにダイジェストを作ると、説明通りの結果が出ます。 $sigbase = 'GET&http%3A%2F%2Fprovider.example.net%2Fprofile&oauth_consumer_key%3 Ddpf43f3p2l4k3l03%26oauth_nonce%3Dkllo9940pd9333jh%26oauth_signature_method%3DHM AC-SHA1%26oauth_timestamp%3D1191242096%26oauth_version%3D1.0'; $key = 'kd94hf93k423kf44&'; $hmac = base64_encode(hash_hmac('sha1', $sigbase, $key, true)); echo "$hmac\n"; 当然、エンコードするところからやっても同じです。 $method = 'GET'; $url = 'http://provider.example.net/profile'; $contents = 'oauth_consumer_key=dpf43f3p2l4k3l03&oauth_nonce=kllo9940pd9333jh&oa uth_signature_method=HMAC-SHA1&oauth_timestamp=1191242096&oauth_version=1.0'; $sigbase = urlencode($method).'&'.urlencode($url).'&'.urlencode($contents); $hmac = base64_encode(hash_hmac('sha1', $sigbase, $key, true)); echo "$hmac\n"; しかし、リンクされていたサイトのとおりにやってもあなたと同じ結果しかでません。 $sigbase = 'GET&http%3A%2F%2Fapi.gu3.jp%2Fv1%2Ftest%2Fauth&oauth_consumer_key%3D yamashita.dyndns.org%26oauth_nonce%3Dc83b1847200bd25d918c3fb077aca16f%26oauth_si gnature_method%3DHMAC-SHA1%26oauth_timestamp%3D1219931263%26oauth_version%3D1.0' ; $key = 'kd94hf93k423kf44&'; $hmac = base64_encode(hash_hmac('sha1', $sigbase, $key, true)); echo "$hmac\n"; URLエンコードのところから作っても同じです。 $method = 'GET'; $url = 'http://api.gu3.jp/v1/test/auth'; $contents = 'oauth_consumer_key=yamashita.dyndns.org&oauth_nonce=c83b1847200bd25 d918c3fb077aca16f&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1219931263&oa uth_version=1.0'; $sigbase = urlencode($method).'&'.urlencode($url).'&'.urlencode($contents); $hmac = base64_encode(hash_hmac('sha1', $sigbase, $key, true)); echo "$hmac\n"; オリジナルのサイトの通りやってオリジナルのサイトで説明した通りの結果が出るのに対し、日本語で説明しているサイトのとおりにやってそのとおりの結果が出ていないというところから、翻訳をした人がsecretをミスって作ったのではないかと予想します。 参考までに誰かが書いたOAuth1のライブラリーを見た感じだと同じようにコードが書いてあるように見えます。 https://github.com/jrconlin/oauthsimple/blob/master/php/OAuthSimple.php というわけで、この日本語サイトを書いた人が参考にした英語版のサイトを参考にして作ることをおすすめします。

tajix14
質問者

お礼

有難うございました。私のPHPでも大元のホームページの結果と同じものが確認できました。 これで安心して作成できます。 大変お世話になりました。御礼申し上げます。

関連するQ&A

  • Perlモジュールを使わずにsha256変換を使う方法

    下記のPHPと同じ結果をPerlで出したいです。 ■PHPデータ <?php // HMAC-SHA256 $hash = hash_hmac('sha256', hogedata, hogekey, 'true'); // BASE64エンコード print base64_encode($hash); ?> 検索エンジンで調べたところ、 「Digest::SHA256」などのPerlモジュールを使用すれば可能なようですが、 新しいPerlモジュールをインストールする権限のないため、 直接、Perlに式を記述したいと思いました。 ■Perlデータ(途中) #!/usr/bin/perl use MIME::Base64; print "Content-type: text/html\n\n"; # HMAC-SHA256 ~ここに変換式が入ります~ # BASE64エンコード $enhash = encode_base64($hash); print "$enhash"; PHPで書き直せば同じサイトを作ることは可能ですが、 できればPerlのままで継続したいです。 お分かりの方がいらっしゃいましたら、 ご教授いただけますでしょうか。 どうぞよろしくお願いいたします。

    • ベストアンサー
    • Perl
  • PHPとObjective-Cでハッシュが違う結果

    Objective-Cでハッシュ値を生成し、PHPに送って、 PHP側でもハッシュ値を生成し、この2つを比較したいと思っています。 PHPでは、以下の関数でSHA256が取得できることがわかりました。 hash_hmac('sha256', $text, false) Objective-Cは自分で実装する必要があるようなので、以下のページのコードを使わせてもらいました。 http://zak-za-k.blogspot.jp/2011/09/objective-csha256.html この2つの関数それぞれで、同じ文字列を使ってSHA256のハッシュ値を出したのですが、 結果が違ってしまいます。 2つの関数で同じ結果を得られるようにするにはどうすればよいでしょうか。 参考にした上記URLのコードの内容は、ほとんど理解できていません。 よろしくお願いいたします。

    • ベストアンサー
    • PHP
  • PHPとJavaでSHA256の結果を同じにしたい

    PHPから JavaServletにアクセスするシステムを作っています。 その際にパラメーターの改ざん対策にハッシュを渡すようにしたいのですが PHPでSHA-256でハッシュ化した値と JavaでSHA-256でハッシュかした値が異なってしまいます。 PHPだとハッシュ化する際の秘密鍵を指定する項目がありますが Javaでは見つかりませんでしたので この項目が違うために結果が違うのだと予想していますが Javaが内部的に使っている秘密鍵はどこか取得できるのでしょうか? やりたいこととしてはPHPとJavaで同じハッシュが取得できるようにしたいのですが 良い案とかやり方あったら教えてください。 ◆php string hash_hmac ( string $algo , string $data , string $key [, bool $raw_output = false ] ) ◆Java DigestUtils.sha256Hex(string data) わかる方いましたら教えてください。よろしくお願いいたします。

    • ベストアンサー
    • Java
  • ツイッターのAPIでOAUTH認証を使用してのAPIリクエストについて

    ツイッターのAPIでOAUTH認証を使用してのAPIリクエストについて ツイッターのAPIを利用してアプリケーションを開発しています。 OAUTH認証でアクセストークンの取得まではできたのですが、 アクセストークンを使ってAPIにアクセスしたところページが 存在しないとの旨を伝えられました。 ↓実際のソース https://twitter.com/1/statuses/update.xml?in_reply_to_status_id=自分のID(アクセストークンで取得したもの)&oauth_consumer_key=OAUTHコンシューマキー&oauth_nonce=ランダム文字列&oauth_signature_method=HMAC-SHA1&oauth_timestamp=タイムスタンプ&oauth_token=アクセストークン&oauth_version=1.0&status=つぶやきたい内容&oauth_signature=署名 上記URLにheader()(リダイレクト)でアクセスしています。simplexml_load_file()や file_get_contents();だと何も取得できませんでした。 特に不安なのがin_reply_to_status_idの指定先と実際のリクエストの仕方が良く わからない事です。何とかして呟きたいのでご教示よろしくお願いいたします。

  • javaでTwitterのOAuth認証を用いたつぶやきのポストを実現

    javaでTwitterのOAuth認証を用いたつぶやきのポストを実現したいと考えています。アクセストークンとアクセストークンシークレットは取得できたのですがそれを用いてつぶやきをポストすることができません。OAuthのライブラリを使えばポストすることは出来たのですができればライブラリを使わずに実現したいと思っています。おそらくポストのやりかたがおかしいと思うのですが何が悪いのかわかりません。javaはあまり得意ではないためお見せするのも恥ずかしいソースですがおかしなところを指摘していただけるとありがたいです。ポストの部分を載せます。 String url="http://twitter.com/statuses/update.xml"; URL urlObj=new URL(url); HttpURLConnecton urlCon=(HttpURLConnection)urlObj.openConnection();urlCon.setRequestMethod("POST"); urlCon.setDoOutput(true); urlCon.setRequestProperty("Content-Type","application/x-www-form-urlencoded"); urlCon.setRequestProperty("Authorization",header); //変数headerには以下のような文字列が入っています //OAuth oauth_nonce="****", oauth_signature_method="HMAC-SHA1", oauth_timestamp="****", oauth_consumer_key="****", oauth_token="****", oauth_signature="****", oauth_version="1.0" String body="status=test"; PrintWriter pw=new PrintWriter(urlCon.getOutputStream()); pw.print(body); pw.flush(); pw.close(); //ここでエラー BufferedReader inStr=new BufferedReader(new InputStreamReader(urlCon.getInputStream()));

    • ベストアンサー
    • Java
  • PHPのSHA256変換について

    C#で以下のロジックがあるのですが、 using System.Text; using System.Security.Cryptography; private static string getHash(string data, string salt, int stretchingcount, Encoding encode) {     int m = salt.Length / 2;     string tmp = salt.Substring(0, m) + data + salt.Substring(m);     byte[] buf = encode.GetBytes(tmp);     SHA256CryptoServiceProvider algorithm = new SHA256CryptoServiceProvider();     for (int i = 0; i < stretchingcount; ++i)     {         buf = algorithm.ComputeHash(buf);     }     return BitConverter.ToString(buf).Replace("-", string.Empty); } こちらのソースをPHPで同じ結果になるように実装したいのですが、 同じ結果にならず、困っています。 PHP側のソースは以下の通りです。 public static function funcPrivacyCheck($data,$salt,$stretchingcount){ $m = strlen($salt) / 2; $tmp = substr($salt,0,$m).$id.substr($salt,$m); $tmp = base64_encode(utf8_encode($tmp)); $hash = ''; for ($i = 0; $i < $stretchingcount; $i++) { if($hash <> ''){ $hash = hash_hmac('sha256' ,$hash, false); }else{ $hash = hash_hmac('sha256' ,$tmp, false); } } return $hash; } エンコードは、UTF-8を指定することが前提です。 ご教授頂きますようよろしくお願いいたします。

    • ベストアンサー
    • PHP
  • TwitterのAPI制限について

    OAuthを使ってログインしたいと思い色々調べているのですが APIの実行回数の制限についてよく分かりません。 例えば下記のコードでログイン用のURLを取得しています。 TwitterのAPIの制限が1時間に150回となっているのですが 下記のログインURL呼び出しのリクエストはAPI実行回数制限にカウントされるのか? カウントされるのであれば サーバーIP等での実行回数制限になるのか クライアントIP等での実行回数制限になるのか どちらなのでしょうか? サーバーIPでの制限であればまともにサービス展開できませんし 調べてみたのですが確認できませんでした。 ご存知の方がいらっしゃいましたらご教授下さい。 よろしくお願いします。 <? session_start(); require_once("oauth/twitteroauth/twitteroauth.php"); if($_SESSION['oauth_token']===NULL && $_SESSION['oauth_token_secret']===NULL){ $consumer_key = "xxxxxxxxxxxxxxxxxxxxxx"; $consumer_secret = "xxxxxxxxxxxxxxxxxxxxxx"; // OAuthオブジェクト生成 $to = new TwitterOAuth($consumer_key,$consumer_secret); // callbackURLを指定してRequest tokenを取得 $tok = $to->getRequestToken("http://xxxxxxxxx/callback.php"); // セッションに保存 $_SESSION['request_token']=$token=$tok['oauth_token']; $_SESSION['request_token_secret'] = $tok['oauth_token_secret']; // サインインするためのURLを取得 $url = $to->getAuthorizeURL($token); print "<a href=\"$url\">サインイン</a>"; } else{ //サインインしていればヘッダーを出力 include("user_header.php"); } ?>

    • ベストアンサー
    • PHP
  • ファンゲートの作り方を教えてください

    Facebookページに付けるファンゲートの簡単な作り方を教えてくださいませんか。 これを入れればいいらしいですが、なかなかうまく行きません。 <?php 02 function parse_signed_request($signed_request, $secret) { 03 list($encoded_sig, $payload) = explode('.', $signed_request, 2); 04 // decode the data 05 $sig = base64_url_decode($encoded_sig); 06 $data = json_decode(base64_url_decode($payload), true); 07 if (strtoupper($data['algorithm']) !== 'HMAC-SHA256') { 08 error_log('Unknown algorithm. Expected HMAC-SHA256'); 09 return null; 10 } 11 // check sig 12 $expected_sig = hash_hmac('sha256', $payload, $secret, $raw = true); 13 if ($sig !== $expected_sig) { 14 error_log('Bad Signed JSON signature!'); 15 return null; 16 } 17 return $data; 18 } 19 function base64_url_decode($input) { 20 return base64_decode(strtr($input, '-_', '+/')); 21 } 22 ?>

  • mixiアプリモバイルOAuth Signatur

    mixiアプリモバイルにて、 gpsから位置情報を取得した際のOAuth Signatureの検証方法 について、ご存じの方がおられましたら、ご教授お願い致します。 言語はjavaで書いております。 まず、gpsにて位置情報取得のため、 mixi Developer Centerの記述サンプル(http://developer.mixi.co.jp/appli/spec/mob/get_gps_info/)に従い、 以下のようなURLでリンクを張りました。 (guid=ONもです。) <a href="location:gps?url=http%3A%2F%2Fexample.com%2Ffoo%2F">位置情報を取得する</a> その祭、 mixi側から来るリクエストとAuthorizationヘッダの内容をソートして並べ替えると、 以下のものがありました。(XXの部分は英数字) datum=wgs84 guid=ON lat=XX.XX.XX.XX lon=XX.XX.XX.XX oauth_consumer_key=XXXXXXX oauth_nonce=XXXXXXX oauth_signature_method=XXXXXXX oauth_timestamp=XXXXXXX oauth_version=XXXXXXX opensocial_app_id=XXXXXXX opensocial_owner_id=XXXXXXX あとは、OAuth Signatureの検証方法について (http://developer.mixi.co.jp/appli/spec/mob/validate-oauth-signature/) を参考にして、Signatureを作成したのですが、 Authorizationヘッダのoauth_signatureと生成したsignatureの値が一致しません。 現在、gpsからのコールバックでなければ、 oauth_signatureと生成したsignature値が一致するので、 gpsからのコールバック時は、何か過不足の処理があるのかと思っています。 もし、この辺りの事で、お詳しい方がおられましたら、 ご教授のほど、よろしくお願い致します。

    • ベストアンサー
    • Java
  • ライブドアブログにPHPスクリプトで投稿したい

    お世話になります。 ライブドアブログにPHPスクリプトで 投稿するためのコードを あるブログで見つけましたが、 下記のコードを実行すると 「<?xml version="1.0" encoding="utf-8" ?> <error>Invalid login</error>」 というメッセージが表示します。 id 、パスワードはあっています。 エンコード方法が、間違っているんでしょうか? 「curl_setopt($ch, CURLOPT_POST, true);」 でのメッセージだと推測します。 そのブログの管理人との連絡方法が ありません。 どなたか、お手数をおかけしますが、 アドバイスをいただけると幸いです。 <?php $livedoor_id = "id"; // livedoorID $password = "APIKEY"; // パスワード $title = "english"; // 記事タイトル $text = "this is a pen"; // 記事本文 $atomapi_url = "http://cms.blog.livedoor.com/atom/"; $created = date('Y-m-d\TH:i:s\Z'); $nonce = pack('H*', sha1(md5(time()))); $pass_digest = base64_encode(pack('H*', sha1($nonce.$created.$password))); //$pass_digest = base64_encode(pack('H*', sha1($nonce.$created.strtolower(md5($password))))); $wsse = 'UsernameToken Username="'.$livedoor_id.'", '. 'PasswordDigest="'.$pass_digest.'", '. 'Nonce="'.base64_encode($nonce).'", '. 'Created="'.$created.'"'; $text64= base64_encode($text); $rawdata = '<?xml version="1.0"?>'. '<entry xmlns="http://purl.org/atom/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">'. '<title type="text/html" mode="escaped">'.$title.'</title>'. '<dc:subject type="text/html" mode="escaped">'.$category.'</dc:subject>'. '<content type="application/xhtml+xml" mode="base64">'.$text64.'</content>'. '</entry>'; //echo $rawdata; $headers =array( 'X-WSSE: ' . $wsse, 'Expect:' ); $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $atomapi_url); curl_setopt($ch, CURLOPT_HEADER, false); curl_setopt($ch, CURLOPT_HTTPHEADER,$headers); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS,$rawdata); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $res = curl_exec($ch); curl_close($ch); //出力結果確認用 echo $res; ?>

    • ベストアンサー
    • PHP