您现在的位置是:网站首页 > 加密与哈希文章详情
加密与哈希
陈川
【
Node.js
】
49541人已围观
7663字
加密与哈希的基本概念
加密和哈希是信息安全领域的两个核心概念,虽然它们都涉及数据转换,但目的和机制完全不同。加密是一种可逆过程,通过算法和密钥将明文转换为密文,只有持有正确密钥的人才能解密还原原始数据。哈希则是单向过程,将任意长度的输入通过哈希函数转换为固定长度的输出,理论上无法逆向推导原始输入。
// 加密示例
const crypto = require('crypto');
const algorithm = 'aes-256-cbc';
const key = crypto.randomBytes(32);
const iv = crypto.randomBytes(16);
function encrypt(text) {
let cipher = crypto.createCipheriv(algorithm, Buffer.from(key), iv);
let encrypted = cipher.update(text);
encrypted = Buffer.concat([encrypted, cipher.final()]);
return { iv: iv.toString('hex'), encryptedData: encrypted.toString('hex') };
}
// 哈希示例
function hash(text) {
return crypto.createHash('sha256').update(text).digest('hex');
}
Node.js中的加密模块
Node.js内置的crypto模块提供了完整的加密功能支持。该模块包含对称加密、非对称加密、哈希、HMAC、数字签名等实现。使用时需要先通过require引入:
const crypto = require('crypto');
crypto模块支持多种算法:
- 哈希算法:SHA-1、SHA-256、SHA-512等
- 加密算法:AES、DES、RC4等
- 非对称加密:RSA、DSA等
典型应用场景包括:
- 密码存储(使用哈希)
- 数据传输加密
- 数字签名验证
- 随机数生成
对称加密的实现
对称加密使用相同密钥进行加密和解密,AES是最常用的对称加密算法。Node.js中实现AES加密:
const crypto = require('crypto');
// AES-256-CBC加密
function aesEncrypt(text, key) {
const iv = crypto.randomBytes(16);
const cipher = crypto.createCipheriv('aes-256-cbc', Buffer.from(key), iv);
let encrypted = cipher.update(text);
encrypted = Buffer.concat([encrypted, cipher.final()]);
return iv.toString('hex') + ':' + encrypted.toString('hex');
}
// AES-256-CBC解密
function aesDecrypt(text, key) {
const parts = text.split(':');
const iv = Buffer.from(parts.shift(), 'hex');
const encryptedText = Buffer.from(parts.join(':'), 'hex');
const decipher = crypto.createDecipheriv('aes-256-cbc', Buffer.from(key), iv);
let decrypted = decipher.update(encryptedText);
decrypted = Buffer.concat([decrypted, decipher.final()]);
return decrypted.toString();
}
// 使用示例
const key = 'my32lengthsupersecretkeynooneknows1';
const encrypted = aesEncrypt('Hello World', key);
console.log(encrypted); // 输出加密结果
console.log(aesDecrypt(encrypted, key)); // 输出解密后的原文
非对称加密的应用
非对称加密使用公钥和私钥对,RSA是典型代表。Node.js中生成RSA密钥对:
const { generateKeyPair } = require('crypto');
generateKeyPair('rsa', {
modulusLength: 4096,
publicKeyEncoding: {
type: 'spki',
format: 'pem'
},
privateKeyEncoding: {
type: 'pkcs8',
format: 'pem',
cipher: 'aes-256-cbc',
passphrase: 'top secret'
}
}, (err, publicKey, privateKey) => {
if (err) throw err;
console.log(publicKey);
console.log(privateKey);
});
使用RSA加密解密:
const { publicEncrypt, privateDecrypt } = require('crypto');
const encryptedData = publicEncrypt(
publicKey,
Buffer.from('Secret message')
);
const decryptedData = privateDecrypt(
{
key: privateKey,
passphrase: 'top secret'
},
encryptedData
);
console.log(decryptedData.toString());
哈希函数的深入解析
哈希函数将任意长度数据映射为固定长度值,具有以下特性:
- 确定性:相同输入总是产生相同输出
- 快速计算:容易计算哈希值
- 抗碰撞性:难以找到两个不同输入产生相同哈希
- 单向性:无法从哈希值反推原始输入
Node.js中常用哈希算法:
const crypto = require('crypto');
// SHA-256哈希
const hash = crypto.createHash('sha256');
hash.update('some data to hash');
console.log(hash.digest('hex'));
// 更安全的scrypt哈希
crypto.scrypt('password', 'salt', 64, (err, derivedKey) => {
if (err) throw err;
console.log(derivedKey.toString('hex'));
});
密码哈希的最佳实践
存储用户密码时,直接使用普通哈希函数不够安全,应采用专门技术:
- 加盐(Salt):为每个密码生成随机盐值
- 迭代哈希:多次应用哈希函数增加计算成本
- 使用专门算法:如PBKDF2、bcrypt、scrypt
Node.js实现PBKDF2:
const crypto = require('crypto');
function hashPassword(password) {
const salt = crypto.randomBytes(16).toString('hex');
const hash = crypto.pbkdf2Sync(password, salt, 1000, 64, 'sha512').toString('hex');
return { salt, hash };
}
function verifyPassword(password, salt, storedHash) {
const hash = crypto.pbkdf2Sync(password, salt, 1000, 64, 'sha512').toString('hex');
return hash === storedHash;
}
// 使用示例
const { salt, hash } = hashPassword('userPassword123');
console.log(verifyPassword('userPassword123', salt, hash)); // true
console.log(verifyPassword('wrongPassword', salt, hash)); // false
HMAC与数字签名
HMAC(哈希消息认证码)结合哈希函数和密钥,用于验证消息完整性和真实性:
const crypto = require('crypto');
// 创建HMAC
const hmac = crypto.createHmac('sha256', 'a secret key');
hmac.update('some data to hash');
console.log(hmac.digest('hex'));
// 数字签名
const { sign, verify } = require('crypto');
const { privateKey, publicKey } = crypto.generateKeyPairSync('rsa', {
modulusLength: 2048,
});
const signature = sign('sha256', Buffer.from('some data'), {
key: privateKey,
padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
});
const isVerified = verify('sha256', Buffer.from('some data'), {
key: publicKey,
padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
}, signature);
console.log('Signature verified:', isVerified);
加密与哈希的性能考量
不同算法对性能影响显著,选择时需权衡安全性和性能:
- 对称加密:AES-GCM比CBC模式更快更安全
- 哈希函数:SHA-3比SHA-2更安全但更慢
- 密码哈希:bcrypt和scrypt设计为计算密集型
性能测试示例:
const crypto = require('crypto');
const bench = require('benchmark');
const suite = new bench.Suite();
suite
.add('SHA-256', function() {
crypto.createHash('sha256').update('test').digest('hex');
})
.add('SHA-512', function() {
crypto.createHash('sha512').update('test').digest('hex');
})
.on('cycle', function(event) {
console.log(String(event.target));
})
.run();
常见安全漏洞与防范
-
弱哈希:使用MD5、SHA1等已被破解的算法
- 解决方案:使用SHA-256、SHA-3等强哈希
-
不安全的密钥管理:硬编码密钥或使用弱密钥
- 解决方案:使用密钥管理系统,定期轮换密钥
-
加密误用:如ECB模式、不正确的IV使用
- 解决方案:使用GCM等认证加密模式
-
时序攻击:通过响应时间推断敏感信息
- 解决方案:使用恒定时间比较函数
// 安全的字符串比较
function safeCompare(a, b) {
const aBuf = Buffer.from(a);
const bBuf = Buffer.from(b);
if (aBuf.length !== bBuf.length) return false;
let result = 0;
for (let i = 0; i < aBuf.length; i++) {
result |= aBuf[i] ^ bBuf[i];
}
return result === 0;
}
实际应用案例分析
- JWT实现:结合哈希和签名
const crypto = require('crypto');
function base64UrlEncode(str) {
return Buffer.from(str).toString('base64')
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=/g, '');
}
function createJWT(payload, secret) {
const header = { alg: 'HS256', typ: 'JWT' };
const encodedHeader = base64UrlEncode(JSON.stringify(header));
const encodedPayload = base64UrlEncode(JSON.stringify(payload));
const signature = crypto
.createHmac('sha256', secret)
.update(`${encodedHeader}.${encodedPayload}`)
.digest('base64url');
return `${encodedHeader}.${encodedPayload}.${signature}`;
}
const token = createJWT({ userId: 123 }, 'secret');
console.log(token);
- 文件完整性校验
const fs = require('fs');
const crypto = require('crypto');
function getFileHash(filePath, algorithm = 'sha256') {
return new Promise((resolve, reject) => {
const hash = crypto.createHash(algorithm);
const stream = fs.createReadStream(filePath);
stream.on('data', data => hash.update(data));
stream.on('end', () => resolve(hash.digest('hex')));
stream.on('error', reject);
});
}
// 使用示例
getFileHash('package.json').then(hash => {
console.log('File hash:', hash);
});
现代加密发展趋势
- 后量子密码学:抵抗量子计算机攻击的算法
- 同态加密:在加密数据上直接进行计算
- 零知识证明:验证信息真实性而不泄露信息本身
- 多方安全计算:多个参与方协同计算而不泄露各自输入
Node.js中实验性支持:
// 使用Web Crypto API(Node.js 15+)
const { webcrypto } = require('crypto');
const { subtle } = webcrypto;
async function generateKeys() {
return await subtle.generateKey(
{
name: 'RSA-PSS',
modulusLength: 2048,
publicExponent: new Uint8Array([1, 0, 1]),
hash: 'SHA-256'
},
true,
['sign', 'verify']
);
}
generateKeys().then(keys => {
console.log(keys);
});