09-数据加密-crypto

322 阅读7分钟

数据加密-crypto

hash 例子

// hash.digest(encoding)  用于创建创建哈希时传递的数据的摘要
// 计算摘要,encoding可以是hex latin1 或者 base64 如果声明了encoding, 那么返回字符串,否则返回buffer实例,注意:调用 hash.digest() 后 hash对象就作废了,再次调用会出错
// hash.update(data, encoding)  用于用给定的数据更新哈希
// encoding可以是utf-8 ascii latin1 如果data是字符串,且没有指定encoding,则默认utf-8,注意,hash.update()方法可以调用多次
const content = fs.readFileSync("./aa.txt", { encoding: "utf-8" });
const hash = crypto.createHash("sha256");

let output;
hash.update(content);
output = hash.digest("hex");
// 15e2b0d3c33891ebb0f1ef609ec419420c20e320ce94c65fbc8c3312448eb225
console.log(output);

例子也可以这样

const input = fs.createReadStream("./aa.txt", { encoding: "utf-8" });
const hash = crypto.createHash("sha256");
hash.setEncoding("hex");
input.pipe(hash).pipe(process.stdout);
// 15e2b0d3c33891ebb0f1ef609ec419420c20e320ce94c65fbc8c3312448eb225

hash.digest() 后,再次调用 digest() 或者 update()

const content = fs.readFileSync("./aa.txt", { encoding: "utf-8" });
const hash = crypto.createHash("sha256");
let output;
hash.update(content);
hash.digest("hex");

// hash.update(content)// 报错 Digest already called
// hash.digest('hex')// 报错 Digest already called

HMAC 例子 例子 1

// HMAC的全称是, Hash-based Message Authentication Code 也即是hash的加盐运算,
const secret = "secret";
const hmac = crypto.createHmac("sha256", secret);
const input = fs.readFileSync("./aa.txt", { encoding: "utf-8" });
hmac.update(input);

console.log(hmac.digest("hex"));
// e9f1f91535398c73105b095ee2be45fa6a26fd4ee56f17b1410ce2145850df42

HMAC 例子 例子 2

const secret = "secret";
const hmac = crypto.createHmac("sha256", secret);
const input = fs.createReadStream("./aa.txt", { encoding: "utf-8" });
hmac.setEncoding("hex");
input.pipe(hmac).pipe(process.stdout);
// e9f1f91535398c73105b095ee2be45fa6a26fd4ee56f17b1410ce2145850df42

加密/解密

// 加密和解密主要用到了下面的两组方法
加密;
crypto.createCipher(algorithm, password);
crypto.createCipheriv(algorithm, key, iv);
解密;
crypto.createDecipher(algorithm, password);
crypto.createDecipheriv(algorithm, key, iv);

加密 crypto.createCipher(algorithm, password)

// 两个参数分别是,加密算法,密码
// algorithm 加密算法,比如aes192,具体有哪些可选的算法,依赖于本地openssl的版本,可以通过openssl list-cipher-algorithm 命令查看本地支持哪些算法
// password 用来生成秘钥key 初始化向量IV
// 备注:这里nodejs屏蔽了AES的使用和实现细节,关于key iv 可以自行查看

const secret = "secret";
const cipher = crypto.createCipher("aes192", secret);
const content = "hello";
let cryptedContent;
cipher.update(content);
cryptedContent = cipher.final("hex");
console.log(cryptedContent);
// 71d30ec9bc926b5dbbd5150bf9d3e5fb

解密 crypto.createDecipher(algorithm, password)

// 可以看做是 crypto.createCipher(algorithm,password)的逆向操作,
const secret = "secret";
const cipher = crypto.createCipher("aes192", secret);
const content = "hello";
let cryptedContent;
cipher.update(content);
cryptedContent = cipher.final("hex");
console.log(cryptedContent); // 71d30ec9bc926b5dbbd5150bf9d3e5fb

const decipher = crypto.createDecipher("aes192", secret);
let decryptedContent;
decipher.update(cryptedContent, "hex");
decryptedContent = decipher.final("utf8");
console.log(decryptedContent); // hello

加密 crypto.createCipheriv(algorithm, key, iv)

解密 crypto.createDecipheriv(algorithm, key, iv)

// 相对于 crypto.createCipher() 来说, 需要提供key和iv,而 crypto.createCipher() 是根据用户提供的password来计算出来的
// key iv 可以是buffer,也可以是utf8编码的字符串,需要重点关注长度
// key 根据选择的算法相关,比如 aes128 aes192 aes256 长度分别是 128 129 256位(16 24 32字节)
// iv  都是128位(16字节)

const key = crypto.randomBytes(192 / 8);
const iv = crypto.randomBytes(128 / 8);
const algorithm = "aes192";
function encrypt(text) {
  const cipher = crypto.createCipheriv(algorithm, key, iv);
  cipher.update(text);
  return cipher.final("hex");
}
function decrypt(encrypted) {
  const decipher = crypto.createDecipheriv(algorithm, key, iv);
  decipher.update(encrypted, "hex");
  return decipher.final("utf8");
}

const content = "hello";
const crypted = encrypt(content);
console.log(crypted); // 99d4db7f60fde555aa4c4c1f0f54626d

const decrypted = decrypt(crypted);
console.log(decrypted); // hello

数组签名/签名校验

假设:
1.服务端的原始信息为M,摘要算法未Hash,Hash(M)得出的摘要是H
2.公钥是Pub,私钥是Piv,非对称加密算法为Encrypt,非对称解密算法为Decrypt
3.Encrypt(H)得到的结果是S
4.客户端拿到的信息为M1,利用Hash(M1)得出的结果是H1

数字签名的产生,检验步骤分别如下
1.数字签名的陈生步骤:利用摘要算法Hash算出M的摘要,即Hash(M) == HTMLAllCollection,利用非对称加密算法对摘要进行加密Encrypt(H,Piv)得到数字签名S
2.数字签名的检验步骤,利用解密算法D对数字签名进行解密,即Decrypt(S) == H,计算M1的摘要 Hash(M1) == H1,如果两者相同,则通过检验.

  const privateKey = fs.readFileSync('./private-key.pem')// 私钥
  const publicKey = fs.readFileSync('./public-key.pem') // 公钥
  const algorithm = "RSA-SHA256"//加密算法 摘要算法
// 数字签名
  function sign(text) {
    const sign = crypto.createSign(algorithm)
    sign.update(text)
    return sign.sign(privateKey, 'hex')
  }
// 校验签名
  function verify(oriContent, signature) {
    const verifer = crypto.createVerify(algorithm)
    verifer.update(oriContent)
    return verifer.verify(publicKey, signature, 'hex')
  }

// 对内容进行签名
  const content = 'hello world'
  const signature = sign(content)
  console.log(signature); // 31ad2c71b0a5940ba0cf3587d4a7e4e3b2eaf8045d8bf6128cfd6be6fbe65a8d6e9abfa271e78b169c322ab78dae7686115f6ef5287a4472dab4ac95199e1f299e3c7435a584d429c55380288f02d51fa46b5a41b90e8398adc684b46c98eadce259ab062c9b06dc05bce02db1db782b5af0cc0a1b833bf5bde98a75a3f57ffc

// 检验签名,如果通过,返回true
  const verifed = verify(content, signature)
  console.log(verifed); // true

diffieHellman

// diffieHellman Diffie-Hellman key exchange 做些为D-H,是一种安全协议,让通信双方在预先没有对象信息的情况下,通过不安全通信信道,创建一个秘钥,这个密钥可以在后续的通信中,作为对称加密的密钥加密传递信息

const alice = crypto.createDiffieHellman(2048); // 创建了一个 DiffieHellman key 交换对象
const aliceKey = alice.generateKeys();
// crypto.createDiffieHellman 参数: 字符串、数字或缓冲区值
const bob = crypto.createDiffieHellman(alice.getPrime(), alice.getGenerator());
const bobKey = bob.generateKeys();

const aliceSecret = alice.computeSecret(bobKey);
const bobSecret = bob.computeSecret(aliceKey);

assert.equal(aliceSecret.toString("hex"), bobSecret.toString("hex"));

ECDH Elliptic Curve Diffie-Hellman 椭圆曲线

const alice = crypto.createECDH("secp521r1");
const aliceKey = alice.generateKeys();

const bob = crypto.createECDH("secp521r1");
const bobKey = bob.generateKeys();

const aliceSecret = alice.computeSecret(bobKey);
const bobSecret = alice.computeSecret(aliceKey);

assert(aliceSecret, bobSecret);

crypto.createECDH(curveName)

// 用于通过由curveName字符串定义的预定义付钱来创建椭圆曲线(ECDH)key交互对象,此外还可以使用 crypto.getCurves()方法来返回可用曲线名称的列表
// 参数: 单个参数 curveName
// 返回 ECDHkey 对象

ecdh.computeSecret(otherPublicKey, inputEncoding, outputEncoding)

// 用于使用对方的公钥创建共享秘密,可以使用各自的参数指定输入公钥和输出key的编码
// 参数 otherPublickey 他是另一方的公钥,根据他生成共享秘密
// 参数 inputEncoding 这是一个字符串值,用于指定对方公钥的编码,如果未指定参数,则为Buffer TypedArray 或 DataView
// 参数 outputEncoding 这是一个字符串值,用于指定生成共享机密的编码
// 返回 以指定的编码返回椭圆曲线 DiffieHellman 共享 key 。当没有提供编码时,它作为一个缓冲区返回,否则返回一个字符串。

ecdn.generateKeys(encoding, format)

// 用于生成椭圆曲线 Diffie-Hellman (ECDH) 对象的私钥和公钥值。它只返回给定格式和编码的公钥。
// 参数 encoding 这是一个字符串值,用于指定返回值的编码
// 参数 format 是一个字符串,用于指定key的格式,值可以是 compressed 或者 uncompromised
// 返回 以指定的编码返回椭圆曲线 DiffieHellman 公钥。当没有提供编码时,它作为一个缓冲区返回,否则返回一个字符串。

关键点

// md5: 固定长度(128bit),不可逆(重要),不同数据的散列值可能相同(重要),高度离散型(原文细微的变化,会导致离散值差异很大)
// sha1 固定长度160bit,广泛使用(若TLS,目前安全性受密码学者的质疑)
// SHA-256/SHA-384/SHA-512  后面标识摘要长度
// 用途: 数字签名,文件完整性校验
// 关系: sha1基于MD5, MD5基于MD4
// md5(1991)->SHA1
// sha家族:由美国国家安全局(NSA)设计,并有美国国家标准和技术研究院发布,是美国的政府标准

相关术语

// SPKAC:Signed Public Key and Challenge
// MD5:Message-Digest Algorithm 5,信息-摘要算法。
// SHA:Secure Hash Algorithm,安全散列算法。
// HMAC:Hash-based Message Authentication Code,密钥相关的哈希运算消息认证码。
// SPKAC:
// 对称加密:比如AES、DES
// 非对称加密:比如RSA、DSA
// AES:Advanced Encryption Standard(高级加密标准),密钥长度可以是128、192和256位。
// DES:Data Encryption Standard,数据加密标准,对称密钥加密算法(现在认为不安全)。https://en.wikipedia.org/wiki/Data_Encryption_Standard
// DiffieHellman:Diffie–Hellman key exchange,缩写为D-H,是一种安全协议,让通信双方在预先没有对方信息的情况下,通过不安全通信信道,创建一个密钥。这个密钥可以在后续的通信中,作为对称加密的密钥加密传递的信息。(备注,使是用协议的发明者命名)