この記事では、Nodejs の暗号化モジュールのセキュリティ知識について詳しく説明します。必要な方は、参考として私をフォローしてください。
インターネット時代において、ネットワーク上のデータ量は毎日驚くべき速度で増加しています。同時に、ネットワークセキュリティに関するさまざまな問題も次々と浮上しています。今日、情報セキュリティの重要性がますます顕著になっているため、開発者はセキュリティについての理解を強化し、技術的手段を通じてサービスのセキュリティを強化する必要があります。
crypto モジュールは、nodejs のコアモジュールの 1 つで、ダイジェスト操作、暗号化、電子署名などのセキュリティ関連の機能を提供します。多くの初心者は、長い API リストをどのように始めればよいのかわからないため、セキュリティ分野の多くの知識が必要になります。
この記事では、API の背後にある理論的知識の説明に重点を置き、主に次の内容が含まれます:
ダイジェスト (ハッシュ)、ダイジェストベースのメッセージ検証コード (HMAC)
対称暗号化、非対称暗号化、電子署名
ブロック暗号化モード
ダイジェスト (ハッシュ)
ダイジェスト (ダイジェスト): 可変長のメッセージを入力として受け取り、ハッシュ関数を実行して固定長の出力を生成します。この出力はダイジェストと呼ばれます。通常、メッセージが完全で改ざんされていないことを確認するために使用されます。
ダイジェスト操作は元に戻すことができません。言い換えれば、入力が固定されると、固定された出力が生成されます。しかし、出力が既知であれば、入力を推定することはできません。
疑似コードは以下の通りです。
digest = Hash(message)
一般的なダイジェストアルゴリズムと対応する出力桁は次のとおりです:
MD5: 128 ビット
SHA-1: 160 ビット
SHA256: 256 ビット
SHA512: 512 ビット
nodejs の例:
var crypto = require('crypto'); var md5 = crypto.createHash('md5'); var message = 'hello'; var digest = md5.update(message, 'utf8').digest('hex'); console.log(digest); // 输出如下:注意这里是16进制 // 5d41402abc4b2a76b9719d911017c592
注: さまざまな記事やドキュメントでは、abstract、hash、および hash という単語が同じ意味で使用されることが多く、多くの初心者が混乱しているように見えます。実際、ほとんどの場合、これらはすべて同じ意味です。上記の抽象の定義を思い出してください。
MAC、HMAC
MAC (メッセージ認証コード): データの整合性を保証するためのメッセージ認証コード。操作の結果は、メッセージ自体と秘密キーによって異なります。
MAC は、HMAC など、さまざまな方法で実装できます。
HMAC (Hash-based Message Authentication Code): 秘密鍵を持つハッシュ関数として大まかに理解できます。
nodejs の例は次のとおりです:
const crypto = require('crypto'); // 参数一:摘要函数 // 参数二:秘钥 let hmac = crypto.createHmac('md5', '123456'); let ret = hmac.update('hello').digest('hex'); console.log(ret); // 9c699d7af73a49247a239cb0dd2f8139
対称暗号化、非対称暗号化
暗号化/復号化: 平文が与えられると、特定のアルゴリズムを通じて暗号化された暗号文が生成されます。このプロセスは暗号化と呼ばれます。その逆が復号化です。
encryptedText = encrypt( plainText ) plainText = decrypt( encryptedText )
秘密鍵: 暗号化/復号化アルゴリズムのセキュリティをさらに強化するために、暗号化/復号化プロセスに秘密鍵が導入されます。秘密鍵は暗号化・復号化アルゴリズムのパラメータとみなすことができ、暗号文が既知である場合、復号化に使用される秘密鍵が分からなければ暗号文を復号化することはできない。
encryptedText = encrypt(plainText, encryptKey) plainText = decrypt(encryptedText, decryptKey)
暗号化と復号化に使用される秘密鍵が同じかどうかにより、暗号化アルゴリズムは対称暗号化と非対称暗号化に分けられます。
1. 対称暗号化
暗号化と復号化に使用される秘密鍵は同じです。つまり、encryptKey === decryptKey です。
一般的な対称暗号化アルゴリズム: DES、3DES、AES、Blowfish、RC5、IDEA。
疑似コードを追加して復号化します:
encryptedText = encrypt(plainText, key); // 加密 plainText = decrypt(encryptedText, key); // 解密
2. 非対称暗号化
公開キー暗号化とも呼ばれます。暗号化と復号化に使用される秘密鍵は異なります (encryptKey !== decryptKey)。
暗号化キーは公開されており、公開キーと呼ばれます。復号化キーは秘密に保たれ、秘密キーと呼ばれます。
一般的な非対称暗号化アルゴリズム: RSA、DSA、ElGamal。
疑似コードの追加と復号:
encryptedText = encrypt(plainText, publicKey); // 加密 plainText = decrypt(encryptedText, priviteKey); // 解密
3. 比較と応用
秘密鍵の違いに加えて、計算速度にも違いがあります。一般的に言えば:
対称暗号化は非対称暗号化よりも高速です。
非対称暗号化は通常、短いテキストの暗号化に使用され、対称暗号化は通常、長いテキストの暗号化に使用されます。
HTTPS プロトコルなど、この 2 つは組み合わせて使用でき、ハンドシェイク フェーズ中に RSA 交換を通じて対称キーを生成できます。後続の通信フェーズでは、対称暗号化アルゴリズムを使用してデータを暗号化でき、ハンドシェイク フェーズ中に秘密キーが生成されます。
注: 対称鍵交換は必ずしも RSA を通じて行う必要はありませんが、DH などを通じて行うこともできますが、ここでは拡張しません。
デジタル署名
デジタル署名の用途は署名からおおよそ推測できます。主な機能は次のとおりです:
情報が特定の主題からのものであることを確認します。
情報が完全で、改ざんされていないことを確認してください。
上記の目的を達成するには、次の 2 つのプロセスが必要です:
送信者: 署名を生成します。
受信者: 署名を確認します。
1. 送信者は署名
を生成し、元のメッセージのダイジェストを計算します。
秘密キーを使用してダイジェストに署名し、電子署名を取得します。
元の情報と電子署名を受信者に送信します。
添付ファイル: 署名擬似コード
digest = hash(message); // 计算摘要 digitalSignature = sign(digest, priviteKey); // 计算数字签名
2. 受信者は署名を検証します
公開鍵を通じて電子署名のロックを解除し、ダイジェストD1を取得します。 (解決できない場合は情報源本体の検証に失敗します)
元の情報のダイジェストD2を計算します。
D1 と D2 を比較します。D1 が D2 と等しい場合、元の情報が完全で改ざんされていないことを意味します。
添付: 署名検証疑似コード
digest1 = verify(digitalSignature, publicKey); // 获取摘要 digest2 = hash(message); // 计算原始信息的摘要 digest1 === digest2 // 验证是否相等
3. 非対称暗号化の比較
由于RSA算法的特殊性,加密/解密、签名/验证 看上去特别像,很多同学都很容易混淆。先记住下面结论,后面有时间再详细介绍。
加密/解密:公钥加密,私钥解密。
签名/验证:私钥签名,公钥验证。
分组加密模式、填充、初始化向量
常见的对称加密算法,如AES、DES都采用了分组加密模式。这其中,有三个关键的概念需要掌握:模式、填充、初始化向量。
搞清楚这三点,才会知道crypto模块对称加密API的参数代表什么含义,出了错知道如何去排查。
1、分组加密模式
所谓的分组加密,就是将(较长的)明文拆分成固定长度的块,然后对拆分的块按照特定的模式进行加密。
常见的分组加密模式有:ECB(不安全)、CBC(最常用)、CFB、OFB、CTR等。
以最简单的ECB为例,先将消息拆分成等分的模块,然后利用秘钥进行加密。
后面假设每个块的长度为128位
2、初始化向量:IV
为了增强算法的安全性,部分分组加密模式(CFB、OFB、CTR)中引入了初始化向量(IV),使得加密的结果随机化。也就是说,对于同一段明文,IV不同,加密的结果不同。
以CBC为例,每一个数据块,都与前一个加密块进行亦或运算后,再进行加密。对于第一个数据块,则是与IV进行亦或。
IV的大小跟数据块的大小有关(128位),跟秘钥的长度无关。
3、填充:padding
分组加密模式需要对长度固定的块进行加密。分组拆分完后,最后一个数据块长度可能小于128位,此时需要进行填充以满足长度要求。
填充方式有多重。常见的填充方式有PKCS7。
假设分组长度为k字节,最后一个分组长度为k-last,可以看到:
不管明文长度是多少,加密之前都会会对明文进行填充 (不然解密函数无法区分最后一个分组是否被填充了,因为存在最后一个分组长度刚好等于k的情况)
如果最后一个分组长度等于k-last === k,那么填充内容为一个完整的分组 k k k ... k (k个字节)
如果最后一个分组长度小于k-last < k,那么填充内容为 k-last mod k
01 -- if lth mod k = k-1 02 02 -- if lth mod k = k-2 . . . k k ... k k -- if lth mod k = 0
概括来说
分组加密:先将明文切分成固定长度的块(128位),再进行加密。
分组加密的几种模式:ECB(不安全)、CBC(最常用)、CFB、OFB、CTR。
填充(padding):部分加密模式,当最后一个块的长度小于128位时,需要通过特定的方式进行填充。(ECB、CBC需要填充,CFB、OFB、CTR不需要填充)
初始化向量(IV):部分加密模式(CFB、OFB、CTR)会将 明文块 与 前一个密文块进行亦或操作。对于第一个明文块,不存在前一个密文块,因此需要提供初始化向量IV(把IV当做第一个明文块 之前的 密文块)。此外,IV也可以让加密结果随机化。
上面是我整理给大家的,希望今后会对大家有帮助。
相关文章:
以上がNodejs の暗号モジュールのセキュリティに関する知識 (詳細なチュートリアル)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。