node_05基本モジュール

7861 ワード

crypto
cryptoモジュールの目的は、汎用的な暗号化およびハッシュアルゴリズムを提供することである.これらの機能を純粋なJavaScriptコードで実現することは不可能ではありませんが、速度が非常に遅くなります.NodejsはC/C++でこれらのアルゴリズムを実装した後,cyptoというモジュールを介してJavaScriptインタフェースに露出し,使いやすく,実行速度も速い.
MD 5とSHA 1
MD 5は、任意のデータに「署名」を与えるためによく使用されるハッシュアルゴリズムである.この署名は通常16進数の文字列で表されます.
    const crypto = require('crypto');

    const hash = crypto.createHash('md5');

    //        update():
    hash.update('Hello, world!');
    hash.update('Hello, nodejs!');
    //        

    console.log(hash.digest('hex')); // 7e1977739c748beac0c0fd14fd26a544

update()メソッドのデフォルト文字列はUTF-8に符号化され、Bufferに転送されます.
SHA 1を計算するには、「md 5」を「sha 1」に変更するだけで、SHA 1の結果1 f 32 b 9 c 9932 c 02227819 a 4151 feed 43 e 131 aca 40が得られる.
より安全なsha 256およびsha 512を使用することもできる.
Hmac
Hmacアルゴリズムは、MD 5やSHA 1などのハッシュアルゴリズムを利用することができるハッシュアルゴリズムでもある.違いは、Hmacには鍵が必要です.
    const crypto = require('crypto');

    const hmac = crypto.createHmac('sha256', 'secret-key');

    hmac.update('Hello, world!');
    hmac.update('Hello, nodejs!');

    console.log(hmac.digest('hex')); // 80f7e22570...

鍵が変化すれば,同じ入力データにも異なる署名が得られるため,Hmacは乱数で「増強」されたハッシュアルゴリズムと理解できる.
AES
AESは一般的な対称暗号化アルゴリズムであり,復号化には同じ鍵が用いられる.cryptoモジュールはAESのサポートを提供していますが、自分で関数をカプセル化し、使いやすいようにする必要があります.
    const crypto = require('crypto');

    function aesEncrypt(data, key) {
        const cipher = crypto.createCipher('aes192', key);
        var crypted = cipher.update(data, 'utf8', 'hex');
        crypted += cipher.final('hex');
        return crypted;
    }

    function aesDecrypt(encrypted, key) {
        const decipher = crypto.createDecipher('aes192', key);
        var decrypted = decipher.update(encrypted, 'hex', 'utf8');
        decrypted += decipher.final('utf8');
        return decrypted;
    }

    var data = 'Hello, this is a secret message!';
    var key = 'Password!';
    var encrypted = aesEncrypt(data, key);
    var decrypted = aesDecrypt(encrypted, key);

    console.log('Plain text: ' + data);
    console.log('Encrypted text: ' + encrypted);
    console.log('Decrypted text: ' + decrypted);

実行結果は次のとおりです.
Plain text: Hello, this is a secret message!
Encrypted text: 8a944d97bdabc157a5b7a40cb180e7...
Decrypted text: Hello, this is a secret message!

AESにはaes 192,aes−128−ecb,aes−256−cbcなど多くの異なるアルゴリズムがあることに注目した.AESは鍵の他にIVも指定できます(Initial Vector)では、システムによってIVが異なる限り、同じ鍵で同じデータを暗号化して得られる暗号化結果も異なる.暗号化結果には通常hexとbase 64の2つの表現方法があり、これらの機能Nodejsはすべてサポートされているが、アプリケーションでは復号化の双方がNodejs、他方がJava、PHPなどの他の言語を使用する場合、注意が必要であるテスト.正しく復号できない場合は、双方が同じAESアルゴリズムに従っているか、文字列鍵とIVが同じか、暗号化されたデータがhexまたはbase 64形式に統一されているかを確認します.
Diffie-Hellman
DHアルゴリズムは鍵交換プロトコルであり、双方が鍵を漏らさずに鍵を交渉することができる.DHアルゴリズムは数学の原理に基づいています.例えば、明ちゃんと紅ちゃんは鍵を協議したいと思っています.
小明はまず1つの素数と1つの基数を選んで、例えば、素数p=23、基数g=5(基数は任意に選択することができます)、更に1つの秘密の整数a=6を選んで、A=g^a mod p=8を計算して、それから大声で小紅に教えます:p=23、g=5、A=8;
紅ちゃんは明ちゃんからp,g,Aを受け取った後、秘密の整数b=15を選んで、それからB=g^b mod p=19を計算して、そして大声で明ちゃんに教えます:B=19;
明ちゃんは自分でs=B^a mod p=2を計算し、紅ちゃんも自分でs=A^b mod p=2を計算したので、最終的に協議した鍵sは2です.
この過程で、鍵2は明ちゃんが紅ちゃんに言ったのではなく、紅ちゃんが明ちゃんに言ったのではなく、双方が協議して計算したのです.サードパーティはp=23,g=5,A=8,B=19しか知ることができず,双方が選択した秘密整数a=6とb=15を知らないため鍵2を算出することができない.
cryptoモジュールによるDHアルゴリズムの実装は以下の通りである.
    const crypto = require('crypto');

    // xiaoming's keys:
    var ming = crypto.createDiffieHellman(512);
    var ming_keys = ming.generateKeys();

    var prime = ming.getPrime();
    var generator = ming.getGenerator();

    console.log('Prime: ' + prime.toString('hex'));
    console.log('Generator: ' + generator.toString('hex'));

    // xiaohong's keys:
    var hong = crypto.createDiffieHellman(prime, generator);
    var hong_keys = hong.generateKeys();

    // exchange and generate secret:
    var ming_secret = ming.computeSecret(hong_keys);
    var hong_secret = hong.computeSecret(ming_keys);

    // print secret:
    console.log('Secret of Xiao Ming: ' + ming_secret.toString('hex'));
    console.log('Secret of Xiao Hong: ' + hong_secret.toString('hex'));

実行後、次の出力が得られます.
    Prime: 80f65a4455ecfc93b472be8a67fbe5edd2836de38885ae779db15a1e86449cd84138df156d5cb2dcdab680da8822431e5642d22614a55390bd665313a62b540b
    Generator: 02
    Secret of Xiao Ming: 5518afe72bde63dad7493804ae2e556f2e2df4aef34a761f089fd3c996e8d753fbc822d3e75a59530a4e28a55733f90f2f1d18f2eff3ef005a6ed3e643ba0853
    Secret of Xiao Hong: 5518afe72bde63dad7493804ae2e556f2e2df4aef34a761f089fd3c996e8d753fbc822d3e75a59530a4e28a55733f90f2f1d18f2eff3ef005a6ed3e643ba0853

RSA
RSAアルゴリズムは、1つの秘密鍵と1つの公開鍵からなる鍵対、秘密鍵暗号化、公開鍵復号、または公開鍵暗号化、秘密鍵復号である非対称暗号化アルゴリズムである.ここで、公開鍵は公開することができ、秘密鍵は秘密にしなければならない.
RSAアルゴリズムは1977年にRon Rivest、Adi Shamir、Leonard Adlemanが共同で提案したので、彼ら3人の姓の頭文字で命名された.
明ちゃんが赤ちゃんにメッセージを送るときは、明ちゃん自身の秘密鍵で暗号化することができ、赤ちゃんは明ちゃんの公開鍵で復号化することができ、赤ちゃんの公開鍵で暗号化することができ、赤ちゃんは彼女自身の秘密鍵で復号化することができ、これは非対称暗号化である.対称暗号化と比較して,非対称暗号化は個人ごとに自分の秘密鍵を持ちながら自分の公開鍵を公開するだけであり,AESのように2人で同じ鍵を共有する必要はない.
ノードを使用してRSA暗号化を行う前に、秘密鍵と公開鍵を用意します.
まず、コマンドラインで次のコマンドを実行して、RSAキーペアを生成します.
openssl genrsa -aes256 -out rsa-key.pem 2048

ヒント入力パスワードによると、このパスワードはRSA鍵を暗号化するためのものであり、暗号化方式はAES 256と指定され、生成されたRSAの鍵長は2048ビットである.実行に成功すると、暗号化rsa-keyが得られました.pemファイル.
2つ目は上のrsa-keyを通ります.pem暗号化ファイルでは、元の秘密鍵をエクスポートできます.コマンドは次のとおりです.
openssl rsa -in rsa-key.pem -outform PEM -out rsa-prv.pem

最初のステップのパスワードを入力し、秘密を理解した秘密鍵を取得します.
同様に、元の公開鍵を次のコマンドでエクスポートします.
openssl rsa -in rsa-key.pem -outform PEM -pubout -out rsa-pub.pem

これにより、元の秘密鍵ファイルrsa-prvを用意します.pemと元の公開鍵ファイルrsa-pub.pem,符号化フォーマットはいずれもPEMである.
以下、cryptoモジュールが提供する方法を用いて、非対称復号化を実現することができる.
まず、秘密鍵で暗号化し、公開鍵で復号します.
    const
        fs = require('fs'),
        crypto = require('crypto');

    //      key:
    function loadKey(file) {
        // key     PEM      :
        return fs.readFileSync(file, 'utf8');
    }

    let
        prvKey = loadKey('./rsa-prv.pem'),
        pubKey = loadKey('./rsa-pub.pem'),
        message = 'Hello, world!';

    //       :
    let enc_by_prv = crypto.privateEncrypt(prvKey, Buffer.from(message, 'utf8'));
    console.log('encrypted by private key: ' + enc_by_prv.toString('hex'));


    let dec_by_pub = crypto.publicDecrypt(pubKey, enc_by_prv);
    console.log('decrypted by public key: ' + dec_by_pub.toString('utf8'));

実行すると、元のメッセージと同じ復号されたメッセージが得られます.
次に、公開鍵暗号化、秘密鍵復号を使用します.
//       :
let enc_by_pub = crypto.publicEncrypt(pubKey, Buffer.from(message, 'utf8'));
console.log('encrypted by public key: ' + enc_by_pub.toString('hex'));

//       :
let dec_by_prv = crypto.privateDecrypt(prvKey, enc_by_pub);
console.log('decrypted by private key: ' + dec_by_prv.toString('utf8'));

復号化されたメッセージは、元のメッセージと同じです.
メッセージ文字列の長さを1 Mなどに長くすると、RSA暗号化を実行すると、RSA暗号化の元の情報がKeyよりも小さくなければならないため、data too large for key sizeのようなエラーが発生します.では、RSAで長いメッセージを暗号化するにはどうすればいいですか?実際、RSAはビッグデータを暗号化するのに適していないが、まずランダムなAESパスワードを生成し、元の情報をAESで暗号化し、その後、AESパスワードをRSAで暗号化する.このように、実際にRSAを使用する場合、相手に伝達された暗号文は2つの部分に分けられ、一部はAES暗号化された暗号文であり、もう一部はRSA暗号化されたAESパスワードである.相手はRSAで先にAESパスワードを解読し、AESで暗号文を解読すれば、明文を得ることができる.
証明書
cryptoモジュールはデジタル証明書も処理できます.デジタル証明書は、通常、SSL接続、すなわちWebのhttp接続に使用されます.一般的にhttps接続は、サーバ側の一方向認証のみを処理する必要があります.例えば、特別なニーズがない場合(例えば、自分がRootとして顧客に認証証明書を発行するなど)、逆プロキシサーバ、例えばNginxなどのWebサーバで証明書を処理することをお勧めします.