質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

OpenSSL

OpenSSLはSSL/TLSのプロトコルと一般的な暗号のライブラリを導入するオープンソースのソフトウェアのツールキットです。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

3回答

6209閲覧

PHPで暗号化,JS(Node.js)で復号ができない

hirosnow

総合スコア16

Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

OpenSSL

OpenSSLはSSL/TLSのプロトコルと一般的な暗号のライブラリを導入するオープンソースのソフトウェアのツールキットです。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

4クリップ

投稿2019/05/08 07:39

編集2019/05/08 09:41

初めまして。
復号で嵌っているので、お助けいただけますと嬉しいです。

前提・実現したいこと

使用言語:PHP(7.2.13),JS(Node.js(10.14.1))
実現したいこと:PHPで暗号化した文をJS側で復号したい

発生している問題・エラーメッセージ

修正前
(node:11944) UnhandledPromiseRejectionWarning: Error: error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt
修正後
(node:18364) UnhandledPromiseRejectionWarning: Error: error:0606506D:digital envelope routines:EVP_DecryptFinal_ex:wrong final block length

該当のソースコード

平文:テスト太郎

修正前

PHP

1 base64_encode(openssl_encrypt($planeText, 'aes-256-ecb', 'testtes'));

Node

1 const crypto = require("crypto"); 2 3 const planeText = 'cEtkTUxJMngwK0VJMWNHa0NWRE1Xdz09';//平文をPHPで暗号化した文字列 4 const buffer = new Buffer(planeText, 'base64'); 5 const ascii = buffer.toString('ascii'); 6 console.log('ascii: '+ ascii); 7 8 const passowrd = 'testtes'; 9 const alg = 'aes-256-ecb' 10 const encoding = 'base64' 11 12 const decipher = crypto.createDecipher(alg, passowrd); 13 let dec = decipher.update(ascii, encoding, 'utf8'); 14 dec += decipher.final('utf8'); 15 16 console.log('decrypted: ' + dec);
修正後

PHP

1 openssl_encrypt($planeText, 'aes-256-ecb', 'testtes', 1);

Node

1 const crypto = require("crypto"); 2 3 const planeText = 'A4A74C2C8DB1D3E108D5C1A40950CC5B';//平文をPHPで暗号化した文字列 4 const buffer = new Buffer(planeText, 'base64'); 5 const ascii = buffer.toString('ascii'); 6 console.log('ascii: '+ ascii); 7 8 const passowrd = 'testtes'; 9 const alg = 'aes-256-ecb' 10 const encoding = 'binary' 11 12 const decipher = crypto.createDecipher(alg, passowrd); 13 let dec = decipher.update(ascii, encoding, 'utf8'); 14 dec += decipher.final('utf8'); 15 16 console.log('decrypted: ' + dec);

試したこと

https://qiita.com/hm0429/items/2acee723170b32b91304
https://qiita.com/mokemokechicken/items/7dfb4d2a9800426ead9d
https://qiita.com/tomi_linka/items/e39e767f77eaca4e82f5
その他もろもろ見ましたが、うまくいきませんでした。
そもそもPHP側で暗号化した場合とJS側で暗号化した際に文字列が言語ごとで異なる理由がわかりません。
(復号方法が違うからなんでしょうが・・・)

また、PHPで暗号化する際に'base64'せずに'binary'にすることができましたが、修正後でもエラーが出ており上手く動きません。

補足情報(FW/ツールのバージョンなど)

暗号化する際に『aes-256-ecb』を使用するのはよくないことは承知しております。
ですが、今回は上記を利用したいと考えております。

何卒宜しくお願い致します。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

m.ts10806

2019/05/08 07:46

Node環境手元になく検証できないのでこちらでコメントしますが、Base64って言語によって仕様がまちまちで実装もそれぞれ細かいところを見ると違うようです。それは原因に思います。 https://izariuo440.hatenadiary.org/entry/20110127/1296138201 ※それに厳密にいうとあくまで「エンコード(別の形式への変換)」であって暗号化ではないと思います・・
hirosnow

2019/05/08 07:58

ご回答いただきましてありがとうございます。 PHPのopenssl_encryptに関して、上に書いた方法だと自動的にBase64に変換されてしまうと思うのですが、binary型で出力する方法はご存知でしょうか。
m.ts10806

2019/05/08 08:00

※私のコメントは回答ではなく「質問への追記・修正依頼」のコメントです。 >PHPのopenssl_encryptに関して、上に書いた方法だと自動的にBase64に変換されてしまうと思うのですが、binary型で出力する方法はご存知でしょうか。 要件になりますので質問本文に追記してください。 タイトルや質問内容も変わってきませんか?調整してみてください。
hirosnow

2019/05/08 08:04

失礼いたしました。 本文とタイトル変更・追記したいと思います。 お手数おかけいたしました。
guest

回答3

0

ベストアンサー

PHPでは次の変換が行われています。
平文 => 暗号化されたバイナリ => base64テキスト

node側でその逆の変換がちょっと変ですね。
変数の名前も変なので、その処理でどの状態になるのか多分十分理解できていないのだと思います。

逆の処理としては、
base64テキスト => base64デコードしたBuffer(=暗号化されたバイナリ) => 平文

なんですが、平文への復号時に下のようになっています。

let dec = decipher.update(ascii, encoding, 'utf8');

ここでencodingがbase64なので、base64デコードを二重に行う形になってそうな気がします。
encoding='binary'にしたり、指定しないと(デフォルトの状態だと)どうなりますか?

投稿2019/05/08 08:17

otolab

総合スコア765

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hirosnow

2019/05/08 08:53

ご回答いただきありがとうございます。 node.jsの'encoding'を'binary'に変更、指定なし、にしたところどちらも ################################################## (node:13408) UnhandledPromiseRejectionWarning: Error: error:0606506D:digital envelope routines:EVP_DecryptFinal_ex:wrong final block length ################################################## とエラーが表示されました。 また、試しに'テスト太郎'をnode.jsで暗号化したのですが、'E9SdJxUl2WBSbFV7jnZYvg=='と暗号化されPHPと違う文字列になり混乱しております。 (文字列が同じになるはずでは?と考えておりました。)
otolab

2019/05/08 12:34

Nodeでencrypto(+base64 encode)した文字列を、もとのplain textに複合することはできますか? 違う文字列になることは確かに奇妙ですが、paddingとかsaltとか考えられる可能性はあるので、そこまで致命的な違いだとは思いません。 とりあえず、エラーの内容が変化したことは一つの僥倖ではあって、それをググってみるのも一つの手ですね。 ちなみに、この辺を読むと、decipher.update()はencrypto+base64のエンコードをまとめて処理できるようなので、Bufferを通さずに直接渡してみるのはどうでしょう。 https://github.com/PeculiarVentures/node-webcrypto-ossl/issues/112#issuecomment-418991594
hirosnow

2019/05/08 12:56

ご回答いただきましてありがとうございます。 >>Nodeでencrypto(+base64 encode)した文字列を、もとのplain textに複合することはできますか? Nodeで暗号化した文字列を元の文字列に複合できるか?という認識で合っていますでしょうか。 それであれば問題なくできました。 ご指摘いただいた通り、paddingやsaltなどの関係があるか確認をしたいと思います。 教えて頂いたサイトとエラーが変化したことについては改めて明日確認してみたいと思います。 他のサイトに書かれているのは'aes-256-cbc'で暗号化しているものが多いので、そちらも確認します。 ご丁寧に回答いただき、ありがとうございました。
guest

0

自己解決しました。
結局、PHPで暗号化→Nodeで復号はできませんでしたので、MySQL上で暗号化&復号することにしました。

MySQL暗号化&復号https://qiita.com/mhagita/items/899483f08347fddd9567
TypeORMhttps://typeorm.io/#/select-query-builder/getting-raw-results
を参考にしました。

PHPでMySQLにINSERTする際、AES形式で暗号化した文字列を格納
Nodeで取り出す際にTypeORMを使用して、SELECT文を操作することで復号した文字列を取り出せました。

推測ではありますが、PHPのopensslのバージョンとNodeのopensslのバージョンがあっていなかったか、
そもそも言語間で互換性がなかったかということで整理をしています。
(CBCでは復号化できているサイトが多いので、後者は違うかな?)

投稿2019/05/09 07:12

編集2019/05/09 07:23
hirosnow

総合スコア16

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

直接の回答ではないのですが、このスクリプトの目的は何でしょうか? 単なるJavaScrptの練習などであればよいのですが、もしも実用を目指しているのであれば、そもそもの考え方に問題があります。
というのは、ブラウザが受け取る HTMLとJavaScriptが盗聴された場合、暗号化データと鍵がセットで盗まれてしまうので、盗聴者は容易に復号できるからです。とくにプログラムの解読などがっつりやらなくても、デバッガ上で適当なところにブレークポイントを置いて、復号されたタイミングでデータを取得すればよいでしょう。

上記を承知の上で、練習としてやっているならよいのですが、念の為お知らせします。

投稿2019/05/08 10:48

ockeghem

総合スコア11701

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

otolab

2019/05/08 12:31

decryptはNode.jsを想定しているようなので、サーバサイドでの処理になるはずです。たぶん問題ないかと。
ockeghem

2019/05/08 12:35

確かにそうですね。失礼しました
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問