PHPでSHA256変換を実装する方法

このQ&Aのポイント
  • C#のロジックをPHPで実装する際に、同じ結果を得ることができない問題に困っています。
  • 質問者は、引数の値とエンコードの指定が適切であることを前提に、PHP側でSHA256変換を正しく行いたいとのことです。
  • 質問者が実装しているPHPのコードを確認すると、base64エンコードとhash_hmacを使用しています。
回答を見る
  • ベストアンサー

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
  • 回答数2
  • ありがとう数3

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

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

C#はSHA256を計算しているのにPHPはHMAC-SHA256を計算しているのですから,異なるのは当然です。 HMACはハッシュ関数を使ってメッセージ認証コードを作成するための方法です。 PHPでハッシュを計算するのであれば,hash関数を利用します。 ref) http://php.net/manual/ja/function.hash.php # MD5とSHA1は専用関数がありますが,現時点においてこれらのハッシュ関数の使用は推奨されません。 もし,C#で実はHMAC-SHA256が欲しいのであれば,HMACSHA256クラスを利用します。 ref) http://msdn.microsoft.com/ja-jp/library/system.security.cryptography.hmacsha256.aspx

bugz1977
質問者

お礼

始めはhashを使用して処理をしていたのですが、結果が合わず、hash_hmac関数を使用しました。 hashを使用することはわかりましたので、再度、確認します。

その他の回答 (1)

noname#212058
noname#212058
回答No.1

『同じことをしたいコード』に全く見えないのですが、 とりあえず気になる点だけ。 ・C# :string tmp = salt.Substring(0, m) + data + salt.Substring(m);  PHP:$tmp = substr($salt,0,$m).$id.substr($salt,$m);  この2行は同じ処理を想定しているのでしょうか? ・PHP の $tmp = base64_encode(utf8_encode($tmp));  は不要な処理では。少なくとも、ここで base64_encode を実行  するのは誤りでしょう。C# 側にはそんな処理入っていませんので。

bugz1977
質問者

お礼

ご回答ありがとうございます。 >・C# :string tmp = salt.Substring(0, m) + data + salt.Substring(m); >PHP:$tmp = substr($salt,0,$m).$id.substr($salt,$m); >この2行は同じ処理を想定しているのでしょうか? 同じ処理を想定しております。 >PHP の $tmp = base64_encode(utf8_encode($tmp)); >は不要な処理では。少なくとも、ここで base64_encode を実行 >するのは誤りでしょう。C# 側にはそんな処理入っていませんので ありがとうございます。 情報ありがとうございます。

関連する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と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
  • 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
  • ファンゲートの作り方を教えてください

    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 ?>

  • 現在フェイスブックのファンゲートを作成しています

    いいねボタンを押すと違うページに推移するものです。いいねを押すと、ページ上でもフェイスブック上でも反映されますが 何故か押されたか判別するシステムではいいねボタンを押した事が上手くうけとれていません。何がわるいのでしょうか?? function parse_signed_request($signed_request, $secret) { list($encoded_sig, $payload) = explode('.', $signed_request, 2); // decode the data $sig = base64_url_decode($encoded_sig); $data = json_decode(base64_url_decode($payload), true); if (strtoupper($data['algorithm']) !== 'HMAC-SHA256') { error_log('Unknown algorithm. Expected HMAC-SHA256'); return null; } // check sig $expected_sig = hash_hmac('sha256', $payload, $secret, $raw = true); if ($sig !== $expected_sig) { error_log('Bad Signed JSON signature!'); return null; } return $data; } function base64_url_decode($input) { return base64_decode(strtr($input, '-_', '+/')); }

    • 締切済み
    • PHP
  • 配列の配列をmemcpyやmemcmpしたいです

    【環境】WindowsXP(SP2)、VisualStudio2005++(MFC) タイトルの通りなんですが、配列の配列を比較したりコピーしたいのですが、以下に質問を3つ記載させていただきますので、どなたかご教授お願いいたしますm(__)m 1.宣言と初期化について char **buf; buf = new char*[3200]; for(int i=0; i < 3200; i++) { buf[i] = new char[4]; } これで、buf[1]、buf[2]、buf[3]、buf[4]に、それぞれ3200のchar型の配列が宣言された事になりますでしょうか? ※buf[4][3200] なのか buf[3200][4]なのかよく分からないです。 2.上記の方法で定義した2つの配列(bufとtmp)の比較 for(int i =0; i < 4; i++) { memcmp (buf[i], tmp[i], sizeof(tmp[i])); } これで比較出来ますでしょうか? 3.上記の方法で定義した2つの配列(bufとtmp)のコピー for(int i =0; i < 4; i++) { memcpy_s(buf[i], sizeof(buf[i]), tmp[i], 3200 * sizeof(char)); } これではバッファオーバーランエラーが発生してしまうのですが、どこがおかしいでしょうか? 以上3点、初心者の質問なので意味が分からないような箇所があるとは思いますが、どうかご教授お願いいたしますm(__)m  

  • 3進数を10進数に変換

    3進数や5進数のように2の階乗ではない任意の進数の文字列を、C言語のビットシフトを使って10進数に変換するプログラムについて、質問させていただきます。 ビットシフトを使わないで、任意の進数の文字列を10進数に変換する方法は分かっていますが、ビットシフトを使った方が非常に計算が高速で出来るので、ビットシフトを使いたいと思っています。 下記のプログラムは4進文字列を10進整数に変換するものです。2進、8進文字列の場合は、シフトするビット数を1ビット、3ビット(つまり、ans <<= 1、ans <<= 3)にすれば計算することが可能です。しかし、3進数や5進数の場合、いろいろと考えたのですが、どのようにすれば良いのか分かりません。 下記のプログラムのようにビットシフトを使って3進数や5進数の文字列を10進数に変換するには、どのように工夫すれば良いでしょうか? どなたかご教授をお願いいたします。 #define STRING_NUM 2 /* 文字列の長さ */ int main(void) { int i; int ans = 0; /* 10進数の整数 */ char buf[STRING_NUM]; /* 4進数の文字列 */ buf[0] = '3'; buf[1] = '1'; for ( i = 0 ; i < STRING_NUM; i++ ){ printf(" %c", buf[i]); } printf("\n"); for ( i = 0 ; i < STRING_NUM; i++ ){ if ( buf[i] == '0' ){ ans <<= 2; /* シフトするビット数 */ ans |= 0; } if ( buf[i] == '1' ){ ans <<= 2; ans |= 1; } if ( buf[i] == '2' ){ ans <<= 2; ans |= 2; } if ( buf[i] == '3' ){ ans <<= 2; ans |= 3; } } printf( "ans = %d\n", ans ); return 0; }

  • java

    Base64にエンコードしたものをデコードするプログラムです。(汎用性が低いのは仕様です)コンパイルは通ったのですが、実行したら以下のエラーが出てきました。 C:\Users\Owner\Documents\javadev>java Base64Decode2 hello.dat hello2.txt java.lang.ArrayIndexOutOfBoundsException: 97 at Base64Decode2.decode(Base64Decode2.java:51) at Base64Decode2.main(Base64Decode2.java:23) 指定の行を見ても原因がよく分かりません。とても初歩的な質問なのかもしれませんが、お願いします。 以下がプログラムコードです import java.io.*; public class Base64Decode2 { public static void main(String[] args) { // 変換テーブル char[] table = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'}; InputStream in = null; // 入力データ OutputStream out = null; // 出力先 try { in = new FileInputStream(args[0]); out = new FileOutputStream(args[1]); char[] cs; while ((cs=read4(in)) != null) { int[] buf = decode(cs, table);//ここが問題? for (int i=0; i<buf.length; i++) { System.out.print(buf[i]+", "); } System.out.println(); int[] buf2 = convert6to8(buf); write3(out, buf2); } } catch (Exception e) { e.printStackTrace(); // 例外の情報を表示する } finally { // in, out を閉じる try { in.close(); out.close(); } catch (Exception e) { } } } /** * 8ビットの2進数の列を復号化する. * @param cs * @param table 符号テーブル * @return */ public static int[] decode(char[] cs, char[] table) { int[] buf = new int[cs.length]; for (int i=0; i<buf.length; i++) { buf[i] = table[cs[i]];//ここが問題? } return buf; } public static int[] convert6to8(int[] buf) { String b; int[] buf2; if (buf.length == 2) { b = toBinary(buf[0], 6); buf2 = new int[1]; buf2[0] = fromBinary(b.substring(0, 8)); } else if (buf.length == 3) { b = toBinary(buf[0], 6) + toBinary(buf[1], 6); buf2 = new int[2]; buf2[0] = fromBinary(b.substring(0, 8)); buf2[1] = fromBinary(b.substring(8, 16)); } else { b = toBinary(buf[0], 6) + toBinary(buf[1], 6) + toBinary(buf[2], 6); buf2 = new int[3]; buf2[0] = fromBinary(b.substring(0, 8)); buf2[1] = fromBinary(b.substring(8, 16)); buf2[2] = fromBinary(b.substring(16, 24)); } return buf2; } /** * バイト列 bt の数を順に出力する. * @param bt 数の配列。長さは 3以下. 各数は8ビットの整数 */ public static void write3(OutputStream out, int[] bt) throws IOException { for (int i=0; i<3; i++) { if (i<bt.length) { out.write(bt[i]); } } } /** * in から文字を最大4つ読み出す. * @param in 入力ストリーム * @return 文字の配列。配列長は最大4. 入力終了したときには null を返す. */ public static char[] read4(InputStream in) throws IOException { char[] bs; int n0=in.read(); int n1=in.read(); int n2=in.read(); int n3=in.read(); if (n0 < 0) { // 読み込み終了 bs = null; } else if (n2 < 0 || (char) n2=='=') { bs = new char[2]; bs[0] = (char) n0; bs[1] = (char) n1; } else if (n3 < 0 || (char) n3=='=') { bs = new char[3]; bs[0] = (char) n0; bs[1] = (char) n1; bs[2] = (char) n2; } else { bs = new char[4]; bs[0] = (char) n0; bs[1] = (char) n1; bs[2] = (char) n2; bs[3] = (char) n3; } return bs; } /** * 数を読み取って、nビットの2進数を表す文字列に変換する * @param bt 1バイトの数 * @param n 2進数のビット数 * @return 2進数を表す文字列 */ public static String toBinary(int bt, int n) { String s = Integer.toBinaryString(bt); for (int i=s.length(); i<n; i++) { s = "0" + s; } return s; } /** * 2進数を表す文字列を数に変換する * @param b 2進数を表す文字列 * @return b が表す数 */ public static int fromBinary(String b) { return Integer.parseInt(b, 2); } }

    • ベストアンサー
    • Java
  • c言語で配列を返したい

    自分がc言語で書いているプログラムの関数で次のようなものがあるのですが、 int CTR(int data[], int* key, long long t){ int buf[sizeof(data)]; int tmp[16]; int bytesoft[128]; int i,j; KeyExpansion(key); for(i=0;i<sizeof(data);i+=16){ for(j=0;j<16;j++){ if(j<sizeof(bytesoft)) tmp[16-j-1]=bytesoft[sizeof(bytesoft)-j-1]; else tmp[16-j-1]=0; } Cipher(data); for(j=0;j<16;j++){ buf[i+j] ^= data[i+j]; } t=t+1; } return buf; } 配列bufを返すためには、ポインタを用いればいいということは調べて分かったのですが具体的にどのように書き換えればいいかよくわかりません。 どなたかご教授いただけないでしょうか?

  • ファイル読み込みを配列に入れる方法

    ファイルから数字を読み込んで 並び替えて出力するプログラムを作成しているのですが ファイルから一度に配列に取り込んで、その配列で並び変えたいのですが取り込みができないのです、int型の配列に一度に取り込むのは可能なのでしょうか? import java.io.*; class Sort { public static void main(String[] args) { String path = args[0]; File file = new File(path); FileReader fr = null; int[] buf = new int[(int)file.length()]; try { fr = new FileReader(file); fr.read(buf); for (int i=0; i<buf.length-1;i++) { int mini=buf[i]; int miniIndex = i; for(int j = i+1; j<buf.length;j++){ if(buf[j] < mini){ mini = buf[j]; miniIndex = j; } } buf[miniIndex] = buf[i]; buf[i] = mini; } for(int i =0; i<buf.length;i++) { System.out.print( buf[i]+","); } } catch (IOException e) { System.out.println("ファイル入力エラー"); } } } と作ってみたのですが‥ ご教授お願いいたします。

    • ベストアンサー
    • Java