Introduction
Cryptography is one of the most basic technologies for internet applications, primarily ensuring data security. Security is multidimensional; through irreversible hash algorithms, we can ensure the safety of login passwords; through asymmetric encryption algorithms, we can ensure the security of data storage; through digital signatures, we can verify whether data has been tampered with during transmission.
When developing internet applications, data security is an issue that cannot be ignored. Otherwise, it may lead to incidents such as the leakage of plaintext passwords for 1 million users on CSDN, or the leakage of personal information of 1 million users on Ctrip.
The Crypto library in Node.js provides various encryption algorithms, making it very convenient for us to use cryptographic techniques to solve problems in application development.
Table of Contents
Introduction to Crypto Hash Algorithms Hmac Algorithms Encryption and Decryption Algorithms Signature and Verification Algorithms Salt Algorithms Program Code
1. Introduction to Crypto
The Crypto library is packaged and released with the Node.js core, primarily providing functions for encryption, decryption, signing, and verification. Crypto utilizes the OpenSSL library to implement its cryptographic technologies, encapsulating a series of hash methods from OpenSSL, including hmac, cipher, decipher, signing, and verification methods.
Crypto official documentation: http://nodejs.org/api/crypto.html
2. Hash Algorithms
A hash algorithm maps an arbitrary length of binary value to a shorter fixed-length binary value, which is called a hash value. The hash value is a unique and extremely compact numerical representation of a piece of data. If a plaintext is hashed and even a single letter in that paragraph is changed, the subsequent hash will produce a different value. It is computationally impossible to find two different inputs that hash to the same value, so the hash value of data can verify the integrity of the data. Hash algorithms are generally used for quick lookups and encryption algorithms.
Typically, we use hash algorithms to encrypt login passwords. Typical hash algorithms include ‘md5’, ‘sha’, ‘sha1’, ‘sha256’, ‘sha512’, ‘RSA-SHA’. Let’s conduct a test of the algorithm.
System Environment
-
Win7 64bit
-
Node.js:v0.10.31
-
Npm:1.4.23
Create Project
~ cd D:\workspace\javascript ~ D:\workspace\javascript>mkdir nodejs-crypto && cd nodejs-crypto
Create a new file hash.js to print the supported hash algorithms.
~ vi hash.js var crypto = require('crypto'); // Load crypto library console.log(crypto.getHashes()); // Print supported hash algorithms
Run the program
~ node hash.js[ 'DSA', 'DSA-SHA', 'DSA-SHA1', 'DSA-SHA1-old', 'RSA-MD4', 'RSA-MD5', 'RSA-MDC2', 'RSA-RIPEMD160', 'RSA-SHA', 'RSA-SHA1', 'RSA-SHA1-2', 'RSA-SHA224', 'RSA-SHA256', 'RSA-SHA384', 'RSA-SHA512', 'dsaEncryption', 'dsaWithSHA', 'dsaWithSHA1', 'dss1', 'ecdsa-with-SHA1', 'md4', 'md4WithRSAEncryption', 'md5', 'md5WithRSAEncryption', 'mdc2', 'mdc2WithRSA', 'ripemd', 'ripemd160', 'ripemd160WithRSA', 'rmd160', 'sha', 'sha1', 'sha1WithRSAEncryption', 'sha224', 'sha224WithRSAEncryption', 'sha256', 'sha256WithRSAEncryption', 'sha384', 'sha384WithRSAEncryption', 'sha512', 'sha512WithRSAEncryption', 'shaWithRSAEncryption', 'ssl2-md5', 'ssl3-md5', 'ssl3-sha1', 'whirlpool' ]
We see that there are quite a few supported Hash algorithms. How to choose the suitable one, I cannot clarify. Based on my understanding of algorithms, I would choose based on encryption computation time and encoding length. Below, let’s simply compare several common algorithms.
Edit hash.js file
~ vi hash.js /////////////////////////// // Hash Algorithms /////////////////////////// var crypto = require('crypto') ,fs = require('fs'); function hashAlgorithm(algorithm){ var s1 = new Date(); var filename = "package.json"; var txt = fs.ReadStream(filename); var shasum = crypto.createHash(algorithm); txt.on('data', function(d) { shasum.update(d); }); txt.on('end', function() { var d = shasum.digest('hex'); var s2 = new Date(); console.log(algorithm+','+(s2-s1) +'ms,'+ d); }); } function doHash(hashs){ hashs.forEach(function(name){ hashAlgorithm(name); }) } //var algs = crypto.getHashes(); var algs = [ 'md5','sha','sha1','sha256','sha512','RSA-SHA','RSA-SHA1','RSA-SHA256','RSA-SHA512']; doHash(algs);
Run the program
~ node hash.js md5,6ms,85cd416f811574bd4bdb61b241266670 sha,18ms,b1fc6647fa4fdb4b1b394f8dc7856ac140e2fbdb sha1,20ms,0777e65066dca985569fa892fa88e21b45dc656d sha256,21ms,5e4aea76f93ee87f422fcbd9458edad0e33ddf256d5d93bcc47977e33cb1654c sha512,23ms,94249ec2f83b006354774dd8f8ec81125ea9e1e00f94393d8b20bbd7678e63db53fab6af125e139f9257fd7dbb6c69474e443d059903a9cb2dded03a94c8143 RSA-SHA,24ms,b1fc6647fa4fdb4b1b394f8dc7856ac140e2fbdb RSA-SHA1,25ms,0777e65066dca985569fa892fa88e21b45dc656d RSA-SHA256,26ms,5e4aea76f93ee87f422fcbd9458edad0e33ddf256d5d93bcc47977e33cb1654c RSA-SHA512,26ms,94249ec2f83b006354774dd8f8ec81125ea9e1e00f94393d8b20bbd7678e63db53fab6af125e139f9257fd7dbb6c69474e4433d059903a9cb2dded03a94c8143
The output is comma-separated, showing the algorithm name, time, and ciphertext. The most common md5 has the shortest ciphertext length and the least computation time; sha and sha1 are quite close; sha512 has the longest ciphertext and the longest computation time.
Since md5 has a large number of dictionary libraries, for websites with general security levels, use sha1; if the security level is very high and the CPU configuration is also very powerful, consider using sha512.
3. Hmac Algorithms
HMAC is a key-related hash operation message authentication code (Hash-based Message Authentication Code). HMAC uses a hash algorithm with a key and a message as input to generate a message digest as output. HMAC can effectively prevent attacks similar to rainbow tables, such as storing common passwords directly in MD5 in databases, which may be cracked in reverse.
Defining HMAC requires a hashing function for encryption (represented as H, which can be MD5 or SHA-1) and a key K. We use B to represent the byte size of the data block (the block length of the hashing function mentioned above is B=64), and L to represent the output data byte size of the hashing function (L=16 for MD5, L=20 for SHA-1). The length of the authentication key can be any positive integer less than or equal to the data block length. If the key length used in the application is larger than B, it is first hashed using the hashing function H, and then the L-length string output from H is used as the actual key in HMAC. Generally, the recommended minimum key K length is L bytes.
Since HMAC uses a hashing function, we will also test the several algorithms mentioned above. Create a new file hmac.js.
~ vi hmac.js /////////////////////////// // Hmac Algorithms /////////////////////////// var crypto = require('crypto') ,fs = require('fs'); function hmacAlgorithm(algorithm,key){ var s1 = new Date(); var filename = "package.json"; var txt = fs.ReadStream(filename); var shasum = crypto.createHmac(algorithm,key); txt.on('data', function(d) { shasum.update(d); }); txt.on('end', function() { var d = shasum.digest('hex'); var s2 = new Date(); console.log(algorithm+','+(s2-s1) +'ms,'+ d); }); } function doHmac(hashs,key){ console.log("\nKey : %s", key); console.log("============================"); hashs.forEach(function(name){ hmacAlgorithm(name,key); }) } //var algs = crypto.getHashes(); var algs = [ 'md5','sha','sha1','sha256','sha512','RSA-SHA','RSA-SHA1','RSA-SHA256','RSA-SHA512']; // Short KEY test setTimeout(function(){ doHmac(algs,"abc"); },1) // Long KEY test setTimeout(function(){ var key = "jifdkd;adkfaj^&fjdifefdafda,ijjifdkd;adkfaj^&fjdifefdafdaljifdkd;adkfaj^&fjdifefdafda"; doHmac(algs,key); },2*1000)
Run the program
~ node hmac.js Key : abc ============================ md5,6ms,bf106a077abcfa0fffe6ec0da039545b sha,6ms,a43a00981346ac64bb7b6fb0641b72a101fb04a5 sha1,6ms,aead69a72da77d0615a854dda1086d885807574a sha256,7ms,98ac955cb2205ba01a6337951d0ed3fd9b68753544cf81275eced365da57fc5d sha512,8ms,054f37e34b55a19e64a7f88fb60b1122dc0a30e9864ca28d01d61115b13c74de292ab66e85bf007e1a463a52d7c30fdff174618ef954401bc9c2c3318e762c8f RSA-SHA,10ms,a43a00981346ac64bb7b6fb0641b72a101fb04a5 RSA-SHA1,11ms,aead69a72da77d0615a854dda1086d885807574a RSA-SHA256,12ms,98ac955cb2205ba01a6337951d0ed3fd9b68753544cf81275eced365da57fc5d RSA-SHA512,13ms,054f37e34b55a19e64a7f88fb60b1122dc0a30e9864ca28d01d61115b13c74de292ab66e85bf007e1a463a52d7c30fdff174618ef954401bc9c2c3318e762c8f
Short key test
Key : jifdkd;adkfaj^&fjdifefdafda,ijjifdkd;adkfaj^&fjdifefdafdaljifdkd;adkfaj^&fjdifefdafda ============================ md5,5ms,164a8fee6e37bb3e40a9d5dff5c2fd66 sha,5ms,ba06f536856553c3756aa36254a63ef35e225d38 sha1,7ms,f3a89b0a5ee8a55c2bb6a861748d43e9d44dc489 sha256,7ms,f2df911f40e74b2b9bb3d53a7ca4b78d438d511e015d4b50431eaea65339380d sha512,8ms,5b4b57386b1fcc4f1945c47788bf38c013e1cde356fc15e1f946e6bf6738b5dc52ecf17b3ddc80b2ff21f985a1a707df9357fe305e9aa143da073d2cafd794dc RSA-SHA,11ms,ba06f536856553c3756aa36254a63ef35e225d38 RSA-SHA1,12ms,f3a89b0a5ee8a55c2bb6a861748d43e9d44dc489 RSA-SHA256,14ms,f2df911f40e74b2b9bb3d53a7ca4b78d438d511e015d4b50431eaea65339380d RSA-SHA512,16ms,5b4b57386b1fcc4f1945c47788bf38c013e1cde356fc15e1f946e6bf6738b5dc52ecf17b3ddc80b2ff21f985a1a707df9357fe305e9aa143da073d2cafd794dc
By comparing short and long keys, we can see that the longer key has some impact on the encoding length. Since HMAC has a second parameter key, it provides better security than simply hashing login passwords.
For the design of website login passwords, we can store them in two fields, using the password field for the ciphertext and the passkey field for the key, encapsulating the algorithm directly in the program.
{ username: 'xxxx' password: 'aead69a72da77d0615a854dda1086d885807574a', passkey:'abc' }
Even if the database is attacked, the hacker only obtains the ciphertext and key, and the plaintext password is not leaked. Moreover, without knowing the encryption algorithm, it is also very difficult to conduct an attack through rainbow tables.
4. Encryption and Decryption Algorithms
For login passwords, there is no need to consider decryption; irreversible algorithms like md5 and sha-1 are typically used. However, for data with security requirements, we need to store it securely and then decrypt it when needed, which requires reversible encryption algorithms. This type of key-based algorithm can be divided into symmetric and asymmetric encryption.
The principle of symmetric encryption algorithms is easy to understand; one party encrypts the plaintext with a KEK, and the other party decrypts it with the same key to obtain the plaintext. Asymmetric encryption algorithms use two completely different but perfectly matching keys: a public key and a private key. When encrypting a file using asymmetric encryption algorithms, only the matching pair of public and private keys can complete the encryption and decryption process for the plaintext. The Crypto package also provides extensive algorithm support for this type of operation. Create a new file cipher.js to print the supported algorithms.
~ vi cipher.js var crypto = require('crypto'); console.log(crypto.getCiphers());
Run the program ~ node cipher.js
[ 'CAST-cbc', 'aes-128-cbc', 'aes-128-cbc-hmac-sha1', '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-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-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', '3des', '3des-cbc', '3des-cfb', '3des-ecb', '3des-ofb', 'id-aes128-GCM', 'id-aes192-GCM', 'id-aes256-GCM', 'idea', 'idea-cbc', 'idea-cfb', 'idea-ecb', 'idea-ofb', 'rc2', 'rc2-40-cbc', 'rc2-64-cbc', 'rc2-cbc', 'rc2-cfb', 'rc2-ecb', 'rc2-ofb', 'rc4', 'rc4-40', 'rc4-hmac-md5', 'seed', 'seed-cbc', 'seed-cfb', 'seed-ecb', 'seed-ofb' ]
Again, with so many algorithms, it’s hard to know how to choose. I will still use the computation time for encryption and decryption as a reference and select several common algorithms for testing.
/////////////////////////// // Encryption and Decryption Algorithms /////////////////////////// var crypto = require('crypto') ,fs = require('fs'); // Encryption function cipher(algorithm, key, buf ,cb){ var encrypted = ""; var cip = crypto.createCipher(algorithm, key); encrypted += cip.update(buf, 'binary', 'hex'); encrypted += cip.final('hex'); cb(encrypted); } // Decryption function decipher(algorithm, key, encrypted,cb){ var decrypted = ""; var decipher = crypto.createDecipher(algorithm, key); decrypted += decipher.update(encrypted, 'hex', 'binary'); decrypted += decipher.final('binary'); cb(decrypted); } function cipherDecipherFile(filename,algorithm, key){ fs.readFile(filename, "utf-8",function (err, data) { if (err) throw err; var s1 = new Date(); cipher(algorithm, key,data,function(encrypted){ var s2 = new Date(); console.log('cipher:'+algorithm+','+(s2-s1) +'ms'); decipher(algorithm, key,encrypted,function(txt){ var s3 = new Date(); console.log('decipher:'+algorithm+','+(s3-s2) +'ms'); // console.log(txt); }); }); }); } //console.log(crypto.getCiphers()); var algs = ['blowfish','aes-256-cbc','cast','des','des3','idea','rc2','rc4','seed']; var key = "abc"; var filename = "book.pdf";//"package.json"; algs.forEach(function(name){ cipherDecipherFile(filename,name,key);
Run the program ~ node cipher.js
cipher:blowfish,46ms decipher:blowfish,95ms cipher:des,67ms decipher:des,104ms cipher:idea,54ms decipher:idea,88ms cipher:rc4,16ms decipher:rc4,44ms cipher:des3,158ms decipher:des3,193ms cipher:aes-256-cbc,19ms decipher:aes-256-cbc,47ms cipher:cast,46ms decipher:cast,82ms cipher:seed,64ms decipher:seed,98ms cipher:rc2,104ms decipher:rc2,99ms
The output consists of three columns: the first column shows cipher (encryption) and decipher (decryption); the second column shows the algorithm name; the third column shows the computation time.
Among the selected algorithms, rc4 and aes-256-cbc perform well, with relatively short encryption and decryption times, and an encryption time to decryption time ratio of 1:3; other algorithms generally take longer overall, with some having an encryption time to decryption time ratio of 1:1. Therefore, how to choose an algorithm also depends on business needs. If the number of decryption operations is much greater than the number of encryption operations and is performed on the server, we should find algorithms with an encryption time to decryption time ratio greater than 1:1; if encryption is done on the server and decryption on the client, then the aes-256-cbc algorithm’s computation time ratio is very suitable.
5. Signature and Verification Algorithms
In addition to encrypting and decrypting data, we also need to determine whether the data transmitted is authentic and complete, and whether it has been tampered with. This requires signature and verification algorithms that utilize asymmetric encryption algorithms to create a digital signature using a private key and verify the authenticity of the data using a public key.
The process of creating and verifying a digital signature is shown in the diagram below.
Next, we will use a program to visualize the operations in the diagram. Since the certificate is self-generated and not intended for public disclosure, and has not been certified by a CA, the following process will not include the steps of public key forgery and CA certification.
First, we need to generate a private key server.pem and a public key cert.pem using the openSSL command.
# Generate private key
~ D:\workspace\javascript\nodejs-crypto>openssl genrsa -out server.pem 1024
Generating RSA private key, 1024 bit long modulus
..................++++++
..................++++++
e is 65537 (0x10001)
# Generate public key
~ D:\workspace\javascript\nodejs-crypto>openssl req -key server.pem -new -x509 -out cert.pem
You are about to be asked to enter information that will be incorporated into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:
State or Province Name (full name) [Some-State]:
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (eg, YOUR name) []:
Email Address []:
Next, we will use the generated private key to create a mathematical signature, and then verify the data using the public key to see if it has been tampered with. Create a new file signer.js.
~ vi signer.js
///////////////////////////
// Signature Verification Algorithms
// openssl genrsa -out server.pem 1024
// openssl req -key server.pem -new -x509 -out cert.pem
///////////////////////////
var crypto = require('crypto')
,fs = require('fs');
function signer(algorithm,key,data){
var sign = crypto.createSign(algorithm);
sign.update(data);
sig = sign.sign(key, 'hex');
return sig;
}
function verify(algorithm,pub,sig,data){
var verify = crypto.createVerify(algorithm);
verify.update(data);
return verify.verify(pubkey, sig, 'hex')
}
var algorithm = 'RSA-SHA256';
var data = "abcdef"; // Data to be transmitted
var privatePem = fs.readFileSync('server.pem');
var key = privatePem.toString();
var sig = signer(algorithm,key,data); // Digital signature
var publicPem = fs.readFileSync('cert.pem');
var pubkey = publicPem.toString();
console.log(verify(algorithm,pubkey,sig,data)); // Verify data, using public key and digital signature => original data
console.log(verify(algorithm,pubkey,sig,data+"2")); // Verify data, using public key and digital signature => not original data
Run the program
~ node signer.js true false
The output consists of two lines; the first line shows the verification result as true, indicating that the data has not been tampered with during transmission; the second line shows the verification result as false, indicating that the data has been tampered with and is not the original data. Of course, how to ensure the matching of the private key and public key requires third-party CA certification, which is not covered in this article.
6. Salt Algorithms
We know that if we directly hash a password, a hacker can obtain the hash value of that password and then look it up in a hash value dictionary (for example, MD5 password cracking websites) to discover a user’s password.
Salt, in cryptography, refers to inserting a specific string at any fixed position in the password, making the hashed result differ from the hash result of the original password. This process is called “salting.” The salted hash value can greatly reduce the risk of password leakage due to user data theft. Even if someone finds the hashed value corresponding to the original content through a rainbow table, the inserted string confuses the actual password, significantly reducing the probability of obtaining the real password.
The implementation of salting typically involves adding specific characters at certain positions of the field to be hashed, disrupting the original string, causing the generated hash result to vary. For example, if a user uses the password:
123465
After MD5 hashing, the result can be:
3d9188577cc9bfe9291ac66b5cc872b7
However, since the user’s password length is insufficient, the short password’s hash result can be easily cracked by a rainbow table. Therefore, adding a specific string at the end of the user’s password:
123465abcdefghijklmnopqrstuvwxyz
Thus, the salted password length is longer, and the hash result changes:
27e20c64ccb8cce9ad68b8ccff6252cf
Create a new file salt.js to implement the above program.
~ vi salt.js ////////////////////////////// // Salt Algorithms ////////////////////////////// var crypto = require('crypto'); var md5 = crypto.createHash('md5'); var txt = "123465"; md5.update(txt); console.log(md5.digest('hex')); md5 = crypto.createHash('md5'); var salt = "abcdefghijklmnopqrstuvwxyz"; md5.update(txt+salt); console.log(md5.digest('hex'));
We can use the crypto.pbkdf2() function without manually salting, which will call the HMAC algorithm by default, using the sha1 hash function, and allows setting the number of iterations and the length of the ciphertext. The specific usage code is as follows.
~ vi salt.js var crypto = require('crypto'); var txt = "123465"; var salt = "abcdefghijklmnopqrstuvwxyz"; // Generate ciphertext, default HMAC function is sha1 algorithm crypto.pbkdf2(txt, salt, 4096, 256, function (err,hash) { if (err) { throw err; } console.log(hash.toString('hex')); })
Run the program to generate a 256-bit ciphertext.
~ node salt.js 29c7de002d942ebcbf3afe05f3eb0ff620f0515fe6b8f19176736273cd70805afdfcc828a6f227152dfa4d0c4f96da184fbd060d4d4c86a5deb8d704699c3e8653acdb0e5bc3e584e0890a44206bb2926f0289fc8e0abe49fd1876461fcc50f06dc7991c4b93cc4e80076529c73b2f2c56f16b5b319368edf017f3d3583a33aa44fd30f89801f0d8877eb8262925f5fdc40a5c57f1b275e5674784dca635c75bc58b6c22264e0f29e363eb25dedf1a242429084e3e17d344b59cab3b9723db03ee4838b632786d1a9eb968f2523404286e5d0a41a1707577650cc3cc2f1ab65714a4cb31f068e4aefa259c6be68174e0a475d5610168305a4935a14bb221a516
If the salt is always a fixed value, it will also be insecure. We can also use the random randomBytes() function along with the pbkdf2() function to ensure that each time a different salt is generated, creating ciphertext of a higher security level.
~ vi salt.js // Generate salt using pseudo-random code crypto.randomBytes(128, function (err, salt) { if (err) { throw err;} salt = salt.toString('hex'); console.log(salt); // Generate salt crypto.pbkdf2(txt, salt, 4096, 256, function (err,hash) { if (err) { throw err; } hash = hash.toString('hex'); console.log(hash);// Generate ciphertext }) })
Run the program
~ node salt.js # Randomly generated salt 78e59de99f16697e3eb684dcfa8efa086db0940c7cd47d33f9311e3bfcf9d58bf30915f54b3f72793b5c8568d32f1f15c55cc87affd043d96f1ed1f56c25a8054b3d83a306636f3b9e3bc9e48c3303aff54da006f92e370023165857fce0a1d1ff0b89178ae8c1416747275daba25652ea864d52a80427658ea69dbe500a7261 # Ciphertext generated by salt 48943eb51ea702b436f95bf1dacc7f64bc41cf7cfa4cb40d101d5550c28caafc58ca720934352238430634f21fd5a6a4ef63fe5828c2665362e9902adc0305f93d2523fbd28521ad00947a74ff8229f63ad5796f2e12677cbed6af02b9973ee0187a69ad67e86790471d95f18d6d2c43ef904f7d17a5d8264f8236f227363a016ae2c14559c17236d540e06c5fd443af740721897f76bdbd9711c8499d7a34cae2e917f900fc364f72f9afaf301845c6e0b5c37def949b4af62336a39dbd1e829405d6189536092c7769a5d7e427b8e97419988da4e1bad49c69f25ac4e96f74a0ce3eab9e1433277568105b1dcc0cf9e1f9c91a7ed391c5825eefcd71ef5ca1
We store the salt and ciphertext together to ensure the security of user passwords.
7. Program Code
The program code for this article can be directly downloaded from GitHub at the source code of this article’s project. Download address: https://github.com/bsspirit/nodejs-crypto
You can also directly use the GitHub command line to download:
~ git clone [email protected]:bsspirit/nodejs-crypto.git # Download GitHub project ~ cd nodejs-crypto # Enter the downloaded directory
Recommended Reading:
Top 15 – Material Design Frameworks and Libraries (Translation)
Beyond Programming: 8 Ways to Expand
Useful Tips for Chrome Developer Tools (Translation)
Make Your Website Support HTTP/2