Appearance
Example of Using Crypt
The crypto module provides encryption capabilities, including a complete package of hashing, HMAC, encryption, decryption, signing, and verification functions.
Note: The examples of plaintext keys in this document are for convenience. During actual product code development, do not hardcode sensitive information such as keys, bank accounts, and email addresses.
Hash algorithm
The hash algorithm maps a binary value of any length to a binary value of a shorter fixed length. This small binary value is called a hash value. A hash is a unique and extremely compact numeric representation of a piece of data. If you hashed a piece of plaintext and changed even one letter of the paragraph, the subsequent hashes will produce a different value. It is computationally impossible to find two different inputs hashing the same value, so the hash value of the data can verify the integrity of the data. It is generally used for fast lookup and encryption algorithms.
Generally, the login password is encrypted using the hash algorithm. Typical hash algorithms include md5, sha1, sha256, and sha512.
ts
import * as crypto from 'crypto';
import * as buffer from 'buffer';
let hash = crypto.createHash(crypto.Hashs.SHA512);
console.log(hash.sum(buffer.from('1xxxxxxxxxxx1')).toString(buffer.Encoding.Base64));
HMAC algorithm
HMAC is a hash-based message authentication code (HMAC) that uses a key and a message as the input, and generates a message digest as the output. HMAC can effectively prevent attacks such as rainbow tables similar to MD5. For example, some common passwords stored in the database in MD5 may be cracked reversely.
To define the HMAC, a hash function for encryption is required. (indicated as H, which can be MD5 or SHA-1) And a key k. We use B to represent the number of bytes in a data block. (B=64 word length of the partitioned data block of the hash function mentioned above), L is used to represent the number of bytes in the output data of the hash function. In MD5, L is 16 and in SHA-1, L is 20. The length of the authentication key may be any positive integer value less than or equal to the length of the data block word. If the key length used in the application program is larger than B, the hash function H is used to act on it first, and then the L-length string output by H is used as the key actually used in HMAC. In general, the recommended minimum key K length is L bytes.
ts
import * as crypto from 'crypto';
import * as buffer from 'buffer';
let hmac = crypto.createHmac(crypto.Hashs.SHA256, buffer.from('2xxxxxxxxxxx2'));
console.log(hmac.sum(buffer.from('1xxxxxxxxxxx1')).toString(buffer.Encoding.Base64));
Encryption and Decryption Algorithms
For login passwords, decryption is not required. Irreversible algorithms are usually used, such as md5, sha-1 and so on. However, for data with security requirements, we need to encrypt storage and then decrypt the data. In this case, we need to use a reversible encryption algorithm. Key-based algorithms can be divided into symmetric encryption and asymmetric encryption.
The principle of the symmetric encryption algorithm is easy to understand. One party uses the KEK to encrypt the plaintext, and the other party uses the same KEY to decrypt the plaintext. An asymmetric encryption algorithm uses two pairs of keys that are completely different but exactly the same: public key and private key. When an asymmetric encryption algorithm is used to encrypt a file, the plaintext can be encrypted and decrypted only after a pair of matched public and private keys are used.
symmetric algorithm
ts
import * as crypto from 'crypto';
import * as buffer from 'buffer';
let key = buffer.from('paaswordpaasword');
let iv = buffer.from('paaswordpassword');
let palinText = buffer.from('huawei');
let cipher = crypto.createCipher(crypto.Algorithm.AES_CBC, key, {
iv: iv,
padding: crypto.Padding.PKCS7,
});
let chipherText = cipher.encrypt(palinText);
console.log(chipherText.toString(buffer.Encoding.Base64));
let decipher = crypto.createDecipher(crypto.Algorithm.AES_CBC, key, {
iv: iv,
padding: crypto.Padding.PKCS7,
});
let decrypted = decipher.decrypt(chipherText);
console.log(decrypted.toString(buffer.Encoding.Utf8));
Asymmetric algorithm
ts
import * as crypto from 'crypto';
import * as buffer from 'buffer';
let rsakey = crypto.generateKey(1024);
let data = buffer.from('huawei');
let cipherText = crypto.publicEncrypt(rsakey.publicKey, data);
console.log(cipherText.toString(buffer.Encoding.Base64));
let plainText = crypto.privateDecrypt(rsakey.privateKey, cipherText);
console.log(plainText.toString());
RSA segment encryption and decryption
ts
import * as crypto from 'crypto';
import * as buffer from 'buffer';
const privateKey = `-----BEGIN RSA PRIVATE KEY-----
...
-----END RSA PRIVATE KEY-----`;
const cipherText = `...`;
let cipherBytes = buffer.from(cipherText, buffer.Encoding.Base64);
let inputLen = cipherBytes.size();
let keyBuf = buffer.from(privateKey);
let offset = 0;
let plainText = "";
for (let i = 0; inputLen - offset > 0; offset += 128) {
let size = inputLen - offset >= 128 ? 128 : inputLen - offset;
let buf = cipherBytes.slice(offset, offset + size)
console.log("current buffer=", buf.toString(buffer.Encoding.Base64));
plainText += crypto.privateDecrypt(keyBuf, buf, crypto.RSAPadding.PKCS1).toString();
console.log(plainText);
}
console.log(plainText);
Signature and Verification
In addition to encrypting and decrypting data, we also need to determine whether the data is true and complete during transmission and whether it is tampered with. In this case, the signature and verification algorithms are required. The asymmetric encryption algorithm is used. The private key is used to sign the digital signature, and the public key is used to verify the authenticity of the data.
The following figure shows the process of creating and verifying a digital signature.
We use Singer and Verify objects to complete the signing and verification.
ts
import * as crypto from 'crypto';
import * as buffer from 'buffer';
let rsakey = crypto.generateKey(1024);
let data = buffer.from('huawei');
let sign = crypto.createSign(crypto.Hashs.SHA256);
let signed = sign.sign(rsakey.privateKey, data);
console.log('signed', signed.toString(buffer.Encoding.Base64));
let verify = crypto.createVerify(crypto.Hashs.SHA256);
console.log(verify.verify(rsakey.publicKey, signed, data));
Salt algorithm
As we know, if the password is directly hashed, the hacker can obtain the password by obtaining the password hash value and then query the hash value dictionary (for example, MD5 password cracking website) to obtain the password of a user. Salt: In cryptography, a specific character string is inserted into a fixed position of a password to make the hash result inconsistent with the hash result of the original password. This process is called salting.
The salted hash value can greatly reduce the password leakage risk caused by user data theft. Even if the original content corresponding to the hash value is found through the rainbow table, the inserted character string disturbs the actual password due to salting. so that the probability of obtaining the real password is greatly reduced.
The process of salting is usually to add specific characters to a specific position of a field to be hashed, disrupting the original character string, and changing the hash result. For example, if a user uses a password 123465 and the MD5 hashing result is as follows:
3d9188577cc9bfe9291ac66b5cc872b7
However, the short password hash result is easy to be cracked by the rainbow table due to the insufficient length of the user password. Therefore, the specific character string 123465abcdefghijklmnopqrstuvwxyz is added to the end of the user password.
As a result, the salted password has a longer length and the result of the hash changes: 27e20c64ccb8cce9ad68b8ccff6252cf
ts
//Salt algorithm
import * as crypto from 'crypto';
import * as buffer from 'buffer';
let md5 = crypto.createHash(crypto.Hashs.MD5);
let txt = buffer.from('1xxxxx5');
console.log(md5.sum(txt).toString(buffer.Encoding.Hex));
md5 = crypto.createHash(crypto.Hashs.MD5);
let salt = 'abcdefghijklmnopqrstuvwxyz';
console.log(md5.sum(buffer.from(txt + salt)).toString(buffer.Encoding.Hex));
Instead of salting yourself, we can use the crypto.pbkdf2 function, which calls the hmac algorithm by default, uses the hash function, and can set the number of iterations and the length of the ciphertext.
randomBytes
Generating a Secure Random String
ts
import * as crypto from 'crypto';
import * as buffer from 'buffer';
let rand = crypto.randomBytes(32);
console.log(rand.toString(buffer.Encoding.Base64));
pbkdf2
ts
import * as crypto from 'crypto';
import * as buffer from 'buffer';
let password = buffer.from('1xxxxxxxxxxx');
let salt = buffer.from('1xxxxxxxxxxx1');
let crypt = crypto.pbkdf2(password, salt, 1000, KEY_LEN, crypto.Hashs.SHA1);
console.log(crypt.toString(buffer.Encoding.Base64));