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

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

新規登録して質問してみよう
ただいま回答率
85.50%
Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

暗号化

ネットワークを通じてデジタルデータをやり取りする際に、第三者に解読されることのないよう、アルゴリズムを用いてデータを変換すること。

Q&A

解決済

1回答

2658閲覧

RubyのString#cryptと同じ暗号化文字列をnode.jsで出力するにはどうすれば良いですか?

hojo

総合スコア195

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

暗号化

ネットワークを通じてデジタルデータをやり取りする際に、第三者に解読されることのないよう、アルゴリズムを用いてデータを変換すること。

0グッド

0クリップ

投稿2017/01/02 21:12

編集2017/01/02 21:41

Ruby2.3.0p0で動作していた古いサービスがあります。

そのサービスのユーザデータは全てデータベース(MySQL)に保存されており、パスワードがRubyのString#cryptによって暗号化されて保存されていることがわかりました。

プロジェクトファイルのconfigには暗号化に必要なsalt文字列も記載されていたのでString#cryptで利用されている暗号化アルゴリズムとconfigに記載されているsaltを利用すれば異なる環境でも同じ暗号化文字列を出力することができると考えています。

現在、サービスの環境をrubyからnodeに切り替えている最中なのですが、古いサービスと新しいサービスとでパスワードの暗号化アルゴリズムが異なっています。

そのため、ユーザデータを新しい環境(node)に移しただけでは当然ログインすることができませんでした。

この問題を解決したいと考えています。

ちなみに、新しい環境(node)は、まだ開発段階なので現在は特に何も考えずSHA256を利用しています。

そこで皆様に以下の質問があります。

  1. node環境でRubyのString#cryptと同じアルゴリズムの暗号化関数を使うにはどうすれば良いですか?
  2. パスワードの暗号化に使うアルゴリズムはSHA256で問題ないですか?

ここからは作業の履歴になりますが、1に関しまして調査したところDESまたはcrypt(3)というアルゴリズムが使われているのかな?と推測しているのですが、暗号化についてあまり詳しくないために確証が持てていません。

わからないならとにかくやってみよう!と思い、とりあえずDESアルゴリズムが利用できる暗号化モジュールを探してみたところ以下が見つかりました。

node-crypt3
https://github.com/sendanor/node-crypt3

node-ffi
http://stackoverflow.com/questions/22401920/how-to-do-unix-crypt3-in-javascript
https://github.com/node-ffi/node-ffi

crypto
https://nodejs.org/api/crypto.html

あれこれ考えたのですが、最後に掲載させていただいたcryptoはnode標準の暗号化モジュールのため、ベターな選択だと思いましたので、まずはこれで試してうまくいかなければ他の方法を考えようと思いました。

cryptoについていろいろと調べているとcrypto.getCiphers()メソッドを実行することにより利用できるアルゴリズムの一覧を取得できることがわかりましたので実行してみました。すると以下のような結果が返ってきました。

[ 'aes-128-cbc', 'aes-128-cbc-hmac-sha1', 'aes-128-cbc-hmac-sha256', 'aes-128-ccm', 'aes-128-cfb', 'aes-128-cfb1', 'aes-128-cfb8', 'aes-128-ctr', 'aes-128-ecb', 'aes-128-gcm', 'aes-128-ofb', 'aes-128-xts', 'aes-192-cbc', 'aes-192-ccm', 'aes-192-cfb', 'aes-192-cfb1', 'aes-192-cfb8', 'aes-192-ctr', 'aes-192-ecb', 'aes-192-gcm', 'aes-192-ofb', 'aes-256-cbc', 'aes-256-cbc-hmac-sha1', 'aes-256-cbc-hmac-sha256', 'aes-256-ccm', 'aes-256-cfb', 'aes-256-cfb1', 'aes-256-cfb8', 'aes-256-ctr', 'aes-256-ecb', 'aes-256-gcm', 'aes-256-ofb', 'aes-256-xts', 'aes128', 'aes192', 'aes256', 'bf', 'bf-cbc', 'bf-cfb', 'bf-ecb', 'bf-ofb', 'blowfish', 'camellia-128-cbc', 'camellia-128-cfb', 'camellia-128-cfb1', 'camellia-128-cfb8', 'camellia-128-ecb', 'camellia-128-ofb', 'camellia-192-cbc', 'camellia-192-cfb', 'camellia-192-cfb1', 'camellia-192-cfb8', 'camellia-192-ecb', 'camellia-192-ofb', 'camellia-256-cbc', 'camellia-256-cfb', 'camellia-256-cfb1', 'camellia-256-cfb8', 'camellia-256-ecb', 'camellia-256-ofb', 'camellia128', 'camellia192', 'camellia256', 'cast', 'cast-cbc', 'cast5-cbc', 'cast5-cfb', 'cast5-ecb', 'cast5-ofb', 'des', 'des-cbc', 'des-cfb', 'des-cfb1', 'des-cfb8', 'des-ecb', 'des-ede', 'des-ede-cbc', 'des-ede-cfb', 'des-ede-ofb', 'des-ede3', 'des-ede3-cbc', 'des-ede3-cfb', 'des-ede3-cfb1', 'des-ede3-cfb8', 'des-ede3-ofb', 'des-ofb', 'des3', 'desx', 'desx-cbc', 'id-aes128-CCM', 'id-aes128-GCM', 'id-aes128-wrap', 'id-aes192-CCM', 'id-aes192-GCM', 'id-aes192-wrap', 'id-aes256-CCM', 'id-aes256-GCM', 'id-aes256-wrap', 'id-smime-alg-CMS3DESwrap', 'idea', ... 19 more items ]

どうやらDESアルゴリズムは種類があるようで、String#cryptがどのアルゴリズムを利用しているのかわかりません。

調べてもDESまたはcrypt(3)以上の情報が見つかりませんでしたので、とりあえず'des'を試してみようと思いました。

実行したコードは以下になります。

node

1var cipher = crypto.createCipher('des', 'salt here'); 2cipher.update('password here') 3// <Buffer 80 05 eb a7 29 9e 83 59>

結果がバッファ(バイナリ?)で出力されてしまったようなのですが、String#cryptの暗号化文字列はutf-8で出力されているようなのでutf-8で出力したいです。

調べてみるとこちらでは以下のようにupdate()メソッドをコールしていましたので同じように実行してみました。

cipher.update('password here', 'utf8', 'hex') // '390910129cef7a1c'

うまくいったか!?と期待したのですが、どうやらString#cryptとそれに利用されているsaltを使って出力した文字列とは異なるようでした。

そもそも、RubyのString#cryptが出力する文字列は'ha4NAXDFh4S3c'のような文字列であり、上記の出力結果はどうみても16進数の数値文字列になっているように見えます。

引数に'hex'を指定しているので当然だろうということで、引数を削ってみたのですがうまく出力できませんでした。

こういう時はドキュメントをしっかり読むことが大切だと思いましてここら辺を見てみると、どうやらencodingはutf8以外にasciilatin1を指定できるようで、また出力方法もhex以外にlatin1base64が指定できるようでした。

ここまで試したところで少し疲れてしまいまして、パターンが多すぎて混乱しています。そもそもものすごく簡単なことを遠回りに実装しているような気もしてきました。

一体、RubyのString#cryptと同じ暗号化文字列をnode.jsで出力するにはどうすれば良いのでしょうか。

以下の質問事項

  1. node環境でRubyのString#cryptと同じアルゴリズムの暗号化関数を使うにはどうすれば良いですか?
  2. パスワードの暗号化に使うアルゴリズムはSHA256で問題ないですか?

に加えて、何か気になることがございましたら指摘していただけると助かります。

宜しくお願いいたします。m(_ _)m

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

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

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

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

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

guest

回答1

0

ベストアンサー

  1. node環境でRubyのString#cryptと同じアルゴリズムの暗号化関数を使うにはどうすれば良いですか?

Ruby#cryptはシステムライブラリのcrypt(3)をそのまま利用している形です。これはUNIX/Linuxなどのpasswdに使うのと同じ形式です。node.jsにおいてcrypt(3)と互換性があるライブラリはnode-crypt3になりますので、こちらを使うのが一番早いと思います。ただし、crypt(3)が無い環境(例えばWindows)では使えず、使用できるアルゴリズムはcrypt(3)の実装依存になりますので、注意してください。OSやディストリビューションを変更している場合は確認が必要です。

  1. パスワードの暗号化に使うアルゴリズムはSHA256で問題ないですか?

すでに暗号化済みのデータが何であるかはその暗号化データのsalt部分を見るとわかります。"$"から始まってなければDES、"$1$"ならMD5、"$5$"ならSHA-256などと決まりがあります。ただ、それらに対応しているかどうかはcrypt(3)の実装次第ですので、言語よりもOSの環境によります。
新たにパスワードを暗号化するのであれば、bcryptの方がいいと最近は言われています。npmでいくつか配付されています。cryptと同じく、bcryptを使っている場合でも、bcrypt自体のバージョンがあっていれば、言語間で共通で使用することも可能です。(cryptとbcryptを混ぜても、salt部分で区別が付くため、保存するカラムを新たに作る必要はありません。ただし、データの長さはかなり長くなるため、DB上のカラムに設定されたサイズに注意が必要です)

いずれにしてもcryptoを直接使用することはあまりお勧めできません。この分野はセキュアな設計が求められるため、専門家では無い人のオレオレ設計では脆弱性が産まれる可能性を大きくしてしまいます。各ライブラリの使用を検討してください。

投稿2017/01/03 01:56

編集2017/01/03 01:57
raccy

総合スコア21733

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問