OpenSSLでPHPとコマンドでの挙動

なんていうかPHPでopensslコマンドと相互運用できる暗号を作成したいんだけど、成功しない

http://y-stream.blogspot.jp/2015/05/php-openssl.html

このブログで紹介してるけど成功しなった。

紹介されているcreate_key_iv($password, $salt)で塩がNullでしか返ってこなかった。

でも将来成功させたいからちょっと引用して保存

暗号化を構成する要素の関係性を理解する

まずは簡単に暗号化の手順や内部のロジックを図解してくれているサイトがあったので、そちらでサラっと概要を確認します。 → 図説:PKCS#5秘密鍵をパスワード保護する共通鍵とIVの作り方(記事修正)

相互運用できるAES-256-CBC形式暗号の作成

色々やってみた結果、思ったのは、opensslの暗号は脆い、という事です。
どの部分が脆いかと言うと、コード内にもコメントを残しておりますが、「key、iv」のセットを作成する際のハッシュ化を1回しか回していない部分ですね。
なので、実際の運用においては、コマンドラインからも暗号化、復号化できるツールも合わせて作成した方が暗号強度も上がるし、自由度も上がるかと思います。

今回使った暗号形式は「AES-256-CBC」という今現在強度的にも問題ないだろうと言われている形式「AES-256」とCBCというモードで暗号化するやり方です。

最終的な暗号化を行う部分は、openssl_encrypt関数で問題ないですが、php.netにはろくな情報が載っていないので、正直困りました。

キモになるのは、「key、iv」のセットを作成する部分をopensslコマンド相当の実装で用意する部分になります。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
 * @param string $password 任意の文字列
 * @param string $salt 16進数に変換可能な文字列(暗号形式によって長さは異なる)
 */
function create_key_iv($password, $salt){
 $salt_bin = hex2bin($salt);
 $hash_str = $hash = '';
 // opensslはハッシュを1回しかしないが、セキュリティの事を考えると複数回ハッシュ化させた方がよい
 for ($i=0; $i<1; $i++){
  $hash = md5($hash. $password. $salt_bin, true);
  $hash_str .= $hash;
 }
 // 取り急ぎ AES-256-CBCに寄せておく
 $key = substr($hash_str, 0, 32);
 $iv = substr($hash_str, 32, 16);
  
 return array($key, $iv);
}
 
list($key, $iv) = create_key_iv("hogehoge", "12345678");

md5でハッシュ生成している辺りが気になりますが、openssl標準のやり方はこのようになっているみたいです。

チューニングのポイントはハッシュ回数とハッシュ形式でしょうか。
回数は数千回回しても不安が残る人たちからすると、1回なんてありえないでしょうね。
ハッシュ形式も、今はsha256なども選べますし、ミックスする事もできますね。

頑張って理解しようー

和暦から西暦へ

 

和暦のぐちゃぐちゃなStringからSQL様の日付フォーマットに変換するやつでまあまあな出来なのが出来た。

ほんとはstrftimeてきなのでやりたかったけどWindowsには対応してないから自作

正規表現は偉大だった。

public static function convNumStringtoDate($src) {
    	$outputArray=array();
    	//昭和とかを西暦にだけ変換 複数はアレイに
    	$src=mb_convert_kana($src, "ah", "UTF-8");//	「全角」英数字を「半角」に変換します。
 
    	//注意!JavaScriptでやる場合は最後のUをとる! UTF8のUです
    	$RegularExpressionM='/(^[mMmM明])\D*(0[1-9]|[123][0-9]|4[012345]|[1-9])\D*(0[1-9]|1[0-2]|[1-9])?\D*(0[1-9]|[12][0-9]|3[01]|[1-9])?.*$/u';//
    	$RegularExpressionT='/(^[tTtT大])\D*(0[1-9]|1[012345]|[1-9])\D*(0[1-9]|1[0-2]|[1-9])?\D*(0[1-9]|[12][0-9]|3[01]|[1-9])?.*$/u';
    	$RegularExpressionS='/(^[sSsS昭])\D*(0[1-9]|[12345][0-9]|6[01234]|[1-9])\D*(0[1-9]|1[0-2]|[1-9])?\D*(0[1-9]|[12][0-9]|3[01]|[1-9])?.*$/u';
    	$RegularExpressionH='/(^[hHhH平])\D*(0[1-9]|[12345][0-9]|6[01234]|[1-9])\D*(0[1-9]|1[0-2]|[1-9])?\D*(0[1-9]|[12][0-9]|3[01]|[1-9])?.*$/u';//heisei64まで
    	if(preg_match($RegularExpressionM,$src,$match)){
    		//echo $match[1];
    		$y=null;
    		$m=null;
    		$d=null;
    		$y = 1868+$match[2];
    		if(isset($match[3]))$m = $match[3];
    		if(isset($match[4]))$d = $match[4];
    		$outputArray[]=DatetimeUtility::GArraytoString($y,$m,$d);
    	}else if(preg_match($RegularExpressionT,$src,$match)){
    		$y=null;
    		$m=null;
    		$d=null;
    		$y = 1911+$match[2];
    		if(isset($match[3]))$m = $match[3];
    		if(isset($match[4]))$d = $match[4];
    		$outputArray[]=DatetimeUtility::GArraytoString($y,$m,$d);
 
    	}else if(preg_match($RegularExpressionS,$src,$match)){
    		$y=null;
    		$m=null;
    		$d=null;
    		$y = 1925+$match[2];
    		if(isset($match[3]))$m = $match[3];
    		if(isset($match[4]))$d = $match[4];
    		$outputArray[]= DatetimeUtility::GArraytoString($y,$m,$d);
 
    	}else if(preg_match($RegularExpressionH,$src,$match)){
    		$y=null;
    		$m=null;
    		$d=null;
    		$y = 1988+$match[2];
    		if(isset($match[3]))$m = $match[3];
    		if(isset($match[4]))$d = $match[4];
    		$outputArray[]=DatetimeUtility::GArraytoString($y,$m,$d);
 
    	}
 
    	$RegularExpressionS4_2_2='/^()(19[0-9][0-9]|20[0-9][0-9])\D*(0[1-9]|1[0-2]|[1-9])?\D*(0[1-9]|[12][0-9]|3[01]|[1-9])?.*$/';//
    	if(preg_match($RegularExpressionS4_2_2,$src,$match)){
    		$y=null;
    		$m=null;
    		$d=null;
    		$y = $match[2];
    		if(isset($match[3]))$m = $match[3];
    		if(isset($match[4]))$d = $match[4];
    		$outputArray[]=DatetimeUtility::GArraytoString($y,$m,$d);
 
    	}
 
 
    	$RegularExpressionM2_2_2='/^()(0[1-9]|[123][0-9]|4[012345]|[1-9])\D*(0[1-9]|1[0-2]|[1-9])?\D*(0[1-9]|[12][0-9]|3[01]|[1-9])?$/';//
    	if(preg_match($RegularExpressionM2_2_2,$src,$match)){
    		$y=null;
    		$m=null;
    		$d=null;
    		$y = 1868+$match[2];
    		if(isset($match[3]))$m = $match[3];
    		if(isset($match[4]))$d = $match[4];
    		$outputArray[]=DatetimeUtility::GArraytoString($y,$m,$d);
 
    	}
    	$RegularExpressionT2_2_2='/^()(0[1-9]|1[012345]|[1-9])\D*(0[1-9]|1[0-2]|[1-9])?\D*(0[1-9]|[12][0-9]|3[01]|[1-9])?$/';//
    	if(preg_match($RegularExpressionT2_2_2,$src,$match)){
    		$y=null;
    		$m=null;
    		$d=null;
    		$y = 1911+$match[2];
    		if(isset($match[3]))$m = $match[3];
    		if(isset($match[4]))$d = $match[4];
    		$outputArray[]=DatetimeUtility::GArraytoString($y,$m,$d);
 
    	}
    	$RegularExpressionS2_2_2='/^()(0[1-9]|[12345][0-9]|6[01234]|[1-9])\D*(0[1-9]|1[0-2]|[1-9])?\D*(0[1-9]|[12][0-9]|3[01]|[1-9])?$/';//
    	if(preg_match($RegularExpressionS2_2_2,$src,$match)){
    		$y=null;
    		$m=null;
    		$d=null;
    		$y = 1925+$match[2];
    		if(isset($match[3]))$m = $match[3];
    		if(isset($match[4]))$d = $match[4];
    		$outputArray[]=DatetimeUtility::GArraytoString($y,$m,$d);
 
    	}
    	$RegularExpressionH2_2_2='/^()(0[1-9]|[12345][0-9]|6[01234]|[1-9])\D*(0[1-9]|1[0-2]|[1-9])?\D*(0[1-9]|[12][0-9]|3[01]|[1-9])?$/';//
    	if(preg_match($RegularExpressionH2_2_2,$src,$match)){
    		$y=null;
    		$m=null;
    		$d=null;
    		$y = 1988+$match[2];
    		if(isset($match[3]))$m = $match[3];
    		if(isset($match[4]))$d = $match[4];
    		$outputArray[]=DatetimeUtility::GArraytoString($y,$m,$d);
 
    	}
    	return $outputArray;
 
    }
    private static function GArraytoString($y,$m,$d) {
 
    	if(isset($m)){
    		$m=str_pad($m, 2, 0, STR_PAD_LEFT); // 01
    		if(isset($d)){
    			$d=str_pad($d, 2, 0, STR_PAD_LEFT); // 01
    			return $y."-".$m."-".$d;
    		}
    		return $y."-".$m;
    	}
    	return $y;
    }

これで綺麗にSQLとばせるはず。

よかったよかった

lsolesen/pel(PHP Exif Library)の使い方

PHPでEXIFを使いたいと思ってたんだけど、公式の通りやっても動かない。
set_include_path(‘library\lsolesen-pel-308f226\src’ . PATH_SEPARATOR . get_include_path());

とかやれって書いてるのに動かないぞ!と

Fatal error: Class 'PelJpeg' not found in

がでる

結論として

require_once "pel/autoload.php";
use lsolesen\pel\PelJpeg;
use lsolesen\pel\PelTag;
use lsolesen\pel\PelIfd;

で動いた。

バージョンが古かったらしい。たぶん。

 

謎なカメラのorientation

今までintentで内部のカメラアプリを起動さしてjpgをgetしてたけど、今回シャッターの制御が必要になったので自作カメラアプリを作った。

なぜか一番悩んだのが画像の向きだ。

横にしたり縦にしたりしても、Exif情報がなんか1に固定されている。

仕方ないので

protected void configureCameraParameters(Camera.Parameters cameraParams, boolean portrait) {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.FROYO) { // for 2.1 and before
        if (portrait) {
            cameraParams.set(CAMERA_PARAM_ORIENTATION, CAMERA_PARAM_PORTRAIT);
        } else {
            cameraParams.set(CAMERA_PARAM_ORIENTATION, CAMERA_PARAM_LANDSCAPE);
        }
    } else { // for 2.2 and later
        int angle;
        int angle2;
        Display display = mActivity.getWindowManager().getDefaultDisplay();
        switch (display.getRotation()) {
            case Surface.ROTATION_0: // This is display orientation
                angle = 90; // This is camera orientation
                angle2=0;
                break;
            case Surface.ROTATION_90:
                angle = 0;
                angle2=270;
                break;
            case Surface.ROTATION_180:
                angle = 270;
                angle2=180;
                break;
            case Surface.ROTATION_270:
                angle = 180;
                angle2=0;
                break;
            default:
                angle = 90;
                angle2=90;
                break;
        }
        Log.v(LOG_TAG, "angle: " + angle);
        onOrientationChanged(angle2);
        mCamera.setDisplayOrientation(angle);
    }

 

public void onOrientationChanged(int orientation) {
    //if (orientation == ORIENTATION_UNKNOWN) return;
    android.hardware.Camera.CameraInfo info =
            new android.hardware.Camera.CameraInfo();
    android.hardware.Camera.getCameraInfo(mCameraId, info);
    orientation = (orientation + 45) / 90 * 90;
    int rotation = 0;
    if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
        rotation = (info.orientation - orientation + 360) % 360;
    } else {  // back-facing camera
        rotation = (info.orientation + orientation) % 360;
    }
    Camera.Parameters cameraParams = mCamera.getParameters();
    cameraParams.setRotation(rotation);
    mCamera.setParameters(cameraParams);
}

で対応さした。

謎なのがDisplayのangleとカメラのangleが違うところだ。

よくわからない処理が行われているのだろうきっと。

これで動いたからよしとする。

PHPでandroid,iphoneからの画像の回転処理

AndroidやiPhoneでは画像を保存した時縦横のサイズではなくExifのOrientationで画像の向きを管理しているらしい。

なるほど、そのまま縮小しても向きがおかしいはずだ。

よってOrientationを考慮した動作が必要になる。

// コピー元画像の指定
$targetImage = $target_path;
// ファイル名から、画像インスタンスを生成
$image = imagecreatefromjpeg($targetImage);
// コピー元画像のファイルサイズを取得
list($image_w, $image_h) = getimagesize($targetImage);

// 出力する画像サイズの指定
//$width =640;
//$height = $width*$image_h/$image_w;


$min_width = 800; // 幅の最低サイズ
$min_height = 800; // 高さの最低サイズ


if($image_w == $image_h) {
   $width = $min_width;
   $height = $min_height;
} else if($image_w > $image_h) {//横長の場合
   $width = $min_width;
   $height = $image_h*($min_width/$image_w);
} else if($image_w < $image_h) {//縦長の場合
   $width = $image_w*($min_height/$image_h);
   $height = $min_height;
}


// サイズを指定して、背景用画像を生成
$canvas = imagecreatetruecolor($width, $height);

// 背景画像に、画像をコピーする
imagecopyresampled($canvas,  // 背景画像
      $image,   // コピー元画像
      0,        // 背景画像の x 座標
      0,        // 背景画像の y 座標
      0,        // コピー元の x 座標
      0,        // コピー元の y 座標
      $width,   // 背景画像の幅
      $height,  // 背景画像の高さ
      $image_w, // コピー元画像ファイルの幅
      $image_h  // コピー元画像ファイルの高さ
);



$exif_datas = exif_read_data($target_path);
//返り値として連想配列でExif情報が取得できます。

//var_dump($exif_datas);
if(isset($exif_datas["Orientation"])){
 if($exif_datas["Orientation"]==6){

 // 回転
 $canvas = imagerotate($canvas, 270, 0);

 }
 if($exif_datas["Orientation"]==8){

 // 回転
 $canvas = imagerotate($canvas, 90, 0);

 }
 if($exif_datas["Orientation"]==3){

 // 回転
 $canvas = imagerotate($canvas, 180, 0);

 }
 }
// 画像を出力する
imagejpeg($canvas,           // 背景画像
      "./shohou_image_m/".$new_dir."/" . basename( $_FILES['f1']['name'])."_0.jpg",    // 出力するファイル名(省略すると画面に表示する)
      100                // 画像精度(この例だと100%で作成)
);

// メモリを開放する
imagedestroy($canvas);

こんなところかなー