原文合集地址如下,有需要的朋友可以关注
@[TOC]
对称加密
对称加密是一种加密算法,也称为私钥加密。在对称加密中,使用同一个密钥(也称为私钥或密钥)对数据进行加密和解密。加密和解密过程都使用相同的密钥,因此称为对称加密。
对称加密的过程如下:
加密:将明文(原始数据)和密钥作为输入,经过特定的加密算法,生成密文(加密后的数据)。
解密:将密文和相同的密钥作为输入,经过特定的解密算法,还原出明文。
对称加密算法具有以下特点:
快速:相比非对称加密算法,对称加密算法的加密和解密速度更快,适用于大量数据的加解密操作。
简单:对称加密算法的实现相对简单,只需要使用相同的密钥进行加解密操作。
安全性限制:由于加密和解密使用相同的密钥,密钥的管理和传输是对称加密的一个重要挑战。如果密钥被泄露,那么整个加密系统就会受到威胁。
适用场景:对称加密通常用于对数据进行加密,以保护数据的机密性。然而,在需要数据的安全性和完整性验证时,通常需要使用额外的手段,如数字签名和消息认证码。
常见的对称加密算法包括DES(Data Encryption Standard)、AES(Advanced Encryption Standard)和3DES(Triple Data Encryption Standard)等。
AES
AES(Advanced Encryption Standard)是一种对称加密算法,用于保护敏感数据的安全性。它是目前广泛使用的加密算法之一,具有高安全性和较快的加密/解密速度。AES支持128位、192位和256位密钥长度。
AES的加密和解密过程涉及以下步骤:
密钥扩展(Key Expansion):根据输入的密钥生成多个轮密钥。
初始轮(Initial Round):将输入数据和第一个轮密钥进行异或运算。
主要轮(Main Rounds):重复执行一系列步骤,包括字节替换、行移位、列混淆和轮密钥加。
最终轮(Final Round):执行最后一轮操作,不包含列混淆。
输出:得到加密后的数据。
在JavaScript中,可以使用crypto库来实现AES加密。注意,crypto库是Node.js的内置模块,不适用于浏览器环境。
下面是使用Node.js的crypto库实现AES加密的示例代码:
const crypto = require('crypto');
// 加密函数
function encrypt(text, key) {
const cipher = crypto.createCipher('aes-256-cbc', key);
let encrypted = cipher.update(text, 'utf8', 'hex');
encrypted += cipher.final('hex');
return encrypted;
}
// 解密函数
function decrypt(encrypted, key) {
const decipher = crypto.createDecipher('aes-256-cbc', key);
let decrypted = decipher.update(encrypted, 'hex', 'utf8');
decrypted += decipher.final('utf8');
return decrypted;
}
// 测试
const originalText = 'Hello, this is a secret message.';
const encryptionKey = 'my-secret-key';
const encryptedText = encrypt(originalText, encryptionKey);
console.log('Encrypted:', encryptedText);
const decryptedText = decrypt(encryptedText, encryptionKey);
console.log('Decrypted:', decryptedText);
上述代码中,使用AES-256-CBC加密模式和一个密钥来对数据进行加密和解密。
非对称加密
非对称加密是一种加密算法,也称为公钥加密。在非对称加密中,使用一对密钥,分别为公钥和私钥,来进行加密和解密操作。公钥可以公开给其他人使用,而私钥必须保密,只有密钥的所有者可以访问。
非对称加密的过程如下:
加密:使用公钥对数据进行加密,生成密文(加密后的数据)。
解密:只有使用与加密时相对应的私钥,才能对密文进行解密,还原出原始的明文数据。
由于公钥可以公开给其他人使用,而私钥只有密钥的所有者持有,因此非对称加密提供了更好的密钥管理和分发机制。非对称加密算法广泛应用于数字签名、身份认证、密钥交换等场景。
非对称加密算法具有以下特点:
安全性:非对称加密算法提供了较高的安全性,即使公钥泄露也不会导致密文被解密。
密钥分发:由于公钥可以公开,因此密钥的分发和交换更加便捷和安全。
效率:与对称加密相比,非对称加密的加密和解密速度较慢,适用于处理较小的数据块。
数字签名:非对称加密可以用于生成和验证数字签名,确保数据的完整性和来源可信性。
常见的非对称加密算法包括RSA(Rivest-Shamir-Adleman)、DSA(Digital Signature Algorithm)、ECC(Elliptic Curve Cryptography)等。
RSA
RSA(Rivest-Shamir-Adleman)是一种非对称加密算法,其加密和解密过程使用不同的密钥,即公钥和私钥。RSA加密算法的原理如下:
密钥生成:
- 随机选择两个大素数p和q。
- 计算n = p * q。
- 计算欧拉函数φ(n) = (p-1) * (q-1)。
- 随机选择一个整数e,1 < e < φ(n),且e与φ(n)互质。
- 计算d,使得 (d * e) % φ(n) = 1。
- 公钥为(n, e),私钥为(n, d)。
加密过程:
- 将明文消息转换为整数m,且 0 < m < n。
- 计算密文c = (m^e) % n。
解密过程:
- 使用私钥中的d来计算明文消息m = (c^d) % n。
在JavaScript中,可以使用crypto库的crypto.publicEncrypt
和crypto.privateDecrypt
方法来实现RSA加密和解密。注意,crypto库是Node.js的内置模块,不适用于浏览器环境。
以下是使用Node.js的crypto库实现RSA加密的示例代码:
const crypto = require('crypto');
// 生成RSA密钥对
const {
publicKey, privateKey } = crypto.generateKeyPairSync('rsa', {
modulusLength: 2048, // RSA密钥长度
publicKeyEncoding: {
type: 'spki',
format: 'pem'
},
privateKeyEncoding: {
type: 'pkcs8',
format: 'pem',
cipher: 'aes-256-cbc', // 私钥加密算法
passphrase: 'my-secret-passphrase' // 私钥加密密码
}
});
// 明文消息
const plaintext = 'Hello, this is a secret message.';
// 使用公钥加密
const encrypted = crypto.publicEncrypt(publicKey, Buffer.from(plaintext, 'utf8'));
console.log('Encrypted:', encrypted.toString('base64'));
// 使用私钥解密
const decrypted = crypto.privateDecrypt(
{
key: privateKey,
passphrase: 'my-secret-passphrase'
},
encrypted
);
console.log('Decrypted:', decrypted.toString('utf8'));
在上述代码中,使用2048位的RSA密钥对来进行加密和解密。注意,在生成RSA密钥对时,私钥被加密,并使用passphrase
指定私钥的加密密码。在解密时,需要提供私钥和相应的密码。
由于RSA算法涉及大数运算,密钥的生成和加密解密过程相对较慢。因此,在实际应用中,通常将RSA用于对小块数据(如对称密钥)进行加密,而不是直接对大数据进行加密。
DSA
DSA(Digital Signature Algorithm)是一种非对称加密算法,用于数字签名和验证数字签名的有效性。与RSA类似,DSA也使用公钥和私钥来实现数字签名和验证。
DSA加密算法的原理如下:
密钥生成:
- 随机选择一个大素数p和一个较小的整数q,满足p-1能被q整除。
- 选择一个整数g,1 < g < p,使得g^q % p = 1。
- 随机选择一个整数x,1 < x < q,作为私钥。
- 计算y = g^x % p,作为公钥。
- 公钥为(p, q, g, y),私钥为x。
数字签名:
- 假设要对消息m进行签名。
- 随机选择一个整数k,1 < k < q。
- 计算r = (g^k % p) % q。
- 计算s = (k^(-1) (SHA1(m) + x r)) % q,其中SHA1(m)表示对消息m进行哈希运算。
- 数字签名为(r, s)。
验证数字签名:
- 假设收到消息m和数字签名(r, s)以及公钥(p, q, g, y)。
- 计算w = s^(-1) % q。
- 计算u1 = (SHA1(m) * w) % q。
- 计算u2 = (r * w) % q。
- 计算v = ((g^u1 * y^u2) % p) % q。
- 如果v等于r,则数字签名有效,否则无效。
在JavaScript中,可以使用Node.js的crypto库的crypto.createSign
和crypto.createVerify
方法来实现DSA数字签名和验证。注意,crypto库是Node.js的内置模块,不适用于浏览器环境。
以下是使用Node.js的crypto库实现DSA数字签名和验证的示例代码:
const crypto = require('crypto');
// 明文消息
const message = 'Hello, this is a message to sign with DSA.';
// 生成DSA密钥对
const {
privateKey, publicKey } = crypto.generateKeyPairSync('dsa', {
modulusLength: 1024, // DSA密钥长度
});
// 创建签名对象
const sign = crypto.createSign('DSA');
// 使用私钥对消息进行签名
sign.update(message);
const signature = sign.sign(privateKey, 'hex');
console.log('Signature:', signature);
// 创建验证对象
const verify = crypto.createVerify('DSA');
// 使用公钥验证签名的有效性
verify.update(message);
const isSignatureValid = verify.verify(publicKey, signature, 'hex');
console.log('Signature Valid:', isSignatureValid);
在上述代码中,使用1024位的DSA密钥对来对消息进行签名和验证。注意,对于更高的安全要求,建议使用更大的密钥长度。与RSA类似,DSA的密钥生成和签名验证过程也相对较慢,因此在实际应用中需要根据需求和性能进行权衡。
哈希函数
哈希函数是一种将任意长度的数据映射为固定长度哈希值(散列值)的函数。哈希函数将输入数据(也称为消息或明文)转换为固定长度的哈希值,通常用一个固定长度的字符串(如十六进制表示)来表示哈希值。哈希函数的输出通常称为哈希码、散列码或摘要。
哈希函数具有以下特点:
固定输出长度:哈希函数产生的哈希值长度固定,无论输入数据的长度是多少,都会生成固定长度的哈希值。
单向不可逆:哈希函数是单向不可逆的,即从哈希值无法还原出原始输入数据。这意味着无法从哈希值计算出原始数据,保护了数据的安全性。
雪崩效应:即使输入数据的微小变化,也会导致生成的哈希值有很大的差异,保证了数据的完整性。
碰撞概率:哈希函数的输入空间可能远大于输出空间,因此存在两个不同的输入数据生成相同的哈希值的可能,这被称为碰撞。好的哈希函数应该尽量避免碰撞,即使碰撞概率很小。
哈希函数在计算机科学和密码学中有广泛的应用,例如:
- 数据完整性验证:用于确保数据在传输或存储过程中没有被篡改。
- 数据加密:用于密码学中生成数字指纹,进行数字签名,验证消息等。
- 散列表:用于散列算法,将数据映射到散列表的索引位置。
常见的哈希函数包括MD5、SHA-1、SHA-256、SHA-512等。
SHA-256
SHA-256(Secure Hash Algorithm 256-bit)是一种密码学哈希函数,用于将任意长度的消息转换为256位的固定长度哈希值。SHA-256是SHA-2系列中的一种,具有较高的安全性,被广泛用于数字签名、数据完整性验证等应用。
SHA-256的原理如下:
初始化:初始化一组常数,作为哈希算法中使用的初始变量。
填充消息:对输入消息进行填充,使得消息长度满足一定的要求。填充包括添加一个1和若干个0来保证消息长度达到特定长度。
处理消息分组:将填充后的消息分成多个512位的分组,并对每个分组进行处理。
处理分组:对每个分组进行64轮的运算。每轮运算涉及四个操作:置换、逻辑运算、加法和置换。
计算结果:对最后一个分组的输出进行连接,得到256位的哈希值。
在JavaScript中,可以使用Node.js的crypto库来实现SHA-256哈希函数。注意,crypto库是Node.js的内置模块,不适用于浏览器环境。
以下是使用Node.js的crypto库实现SHA-256哈希函数的示例代码:
const crypto = require('crypto');
function sha256(input) {
return crypto.createHash('sha256').update(input).digest('hex');
}
// 测试
const message = 'Hello, this is a message to hash with SHA-256.';
const hashValue = sha256(message);
console.log('SHA-256 Hash:', hashValue);
在上述代码中,定义了一个sha256
函数来计算输入消息的SHA-256哈希值。通过调用crypto.createHash('sha256')
创建SHA-256哈希对象,然后使用update
方法传入要计算的消息,最后使用digest('hex')
方法获取十六进制表示的256位哈希值。
注意,SHA-256是单向不可逆的哈希函数,意味着无法从哈希值还原出原始消息。哈希函数的主要应用是验证数据的完整性,而不是加密。因此,SHA-256哈希值的安全性取决于其抗碰撞(collision resistance)和抗第二像性(second preimage resistance)的能力。
MD5
MD5(Message Digest Algorithm 5)是一种单向不可逆的哈希函数,用于将任意长度的消息转换为128位的固定长度哈希值。MD5的加密原理主要包括以下步骤:
填充消息:将输入的消息按照一定的规则进行填充,使得消息长度满足特定要求。填充的目的是将消息长度扩展为512位的倍数,以便后续处理。
初始化缓冲区:MD5使用四个32位的缓冲区(A、B、C和D)来存储中间结果。这些缓冲区是在加密过程中不断更新的。
处理消息分组:将填充后的消息分成多个512位的分组,并对每个分组进行处理。
处理分组:对每个512位的分组进行64轮的循环运算。每轮运算包括四个步骤:置换、逻辑运算、加法和置换。
输出结果:对最后一个分组进行处理后,得到128位的MD5哈希值,即最终结果。
MD5的核心运算主要涉及位操作、逻辑运算和加法运算,通过多次迭代和混淆来确保生成的哈希值具有较好的雪崩效应和碰撞抵抗能力。
MD5加密(或称哈希)是单向不可逆的,意味着无法从MD5哈希值还原出原始消息。MD5的主要应用是用于验证数据的完整性和校验,而不是用于加密敏感数据。
由于MD5算法的安全性存在缺陷,它容易受到碰撞攻击(collision attack),即两个不同的输入可能产生相同的MD5哈希值,从而降低了数据完整性验证的可靠性。因此,在安全性要求较高的场景中,建议使用更强大的哈希算法如SHA-256来代替MD5。
在JavaScript中,可以使用Node.js的crypto库来实现MD5哈希函数。请注意,crypto库是Node.js的内置模块,不适用于浏览器环境。
以下是使用Node.js的crypto库实现MD5哈希函数的示例代码:
const crypto = require('crypto');
function md5(input) {
return crypto.createHash('md5').update(input).digest('hex');
}
// 测试
const message = 'Hello, this is a message to hash with MD5.';
const hashValue = md5(message);
console.log('MD5 Hash:', hashValue);