JS 开发密码学速览

  • 胡键
  • 更新于 2022-05-01 12:50
  • 阅读 3711

面向 JS 开发者的密码学要点速览。

原文链接

加密 API 选用原则

  • 优先语言标准库。
  • 优先知名且经过审计的库。
  • 选用第三方库时,先摸清背景。

基础

  • 编码:使用 Buffer 完成各类编码格式转换。
  • 随机数
    • 各类加密技术的基础。
    • 真随机数获取极其困难,常用加密专用伪随机数。
    • 不要使用 Math.random !!
    • 使用 crypto 模块中的 random 函数,如 crypto.randomBytes
  • Hash
    • 单向。
    • 输出为定长字符串。
    • 相同输入,输出相同。
    • 不同输入,输出不同。
    • 典型应用
      • 数据完整性验证
      • 口令哈希
      • 派生密钥
  • 密钥
    • 派生密钥:由主密钥生成的密钥。
    • 密钥封装:加密并导出密钥。
    • 解封密钥:解密并导入密钥。
  • 认证加密:加密且防篡改
  • 对称加密
    • 加解密使用相同密钥
    • 速度快
    • 可操作大数据块
    • 密钥交换是难题
  • 非对称加密
    • 公钥 + 私钥
      • 加密:公钥加密,私钥解密
      • 签名:私钥加密,公钥解密
    • 速度慢
    • 不适合大数据块
    • 典型应用
      • 密钥交换
      • 数字证书
      • 数字签名
  • 混合加密
    • 以上两种组合
      • 非对称加密交换密钥
      • 对称加密操作数据

Hash

  • 不推荐的算法
    • MD5
    • SHA-1
    • PBKDF2
    • bcrypt
  • 消息摘要:SHA-256 及其它同族
    • crypto.createHash('sha256')
    • 对于大数据采用流模式
    • 不要用于敏感数据,如口令。
  • 消息认证码(HMAC)
    • 结合哈希和密钥(密钥需双方事先协商)
    • crypto.createHmac('sha256', 'secret')
  • 口令哈希和 KDF(Key Derivation Function)
    • 特点:
      • 自带 salt
      • 有意用慢算法抵消硬件升级带来的计算速度提升
    • argon2(优先)
    • scrypt
      • crypto.scrypt

对称加密

  • 不推荐的算法
    • DES
    • AES-ECB
  • AES
    • 典型模式:
      • AES-CBC,不需要认证时
        • crypto.createCipheriv('aes-256-cbc', ...)
        • crypto.createDecipheriv('aes-256-cbc', ...)
      • AES-GCM,需要认证时
        • crypto.createCipheriv('aes-256-gcm', ...)
        • crypto.createDecipheriv('aes-256-gcm', ...)
    • 对于大数据采用流模式
  • ChaCha20-Poly1305
    • ChaCha20 加密 + Poly1305 哈希
    • 等同于 AES-GCM
    • 适用于无 AES 硬件加速支持的环境
    • crypto.createCipheriv('chacha20-poly1305', ...)
    • crypto.createDecipheriv('chacha20-poly1305', ...)

非对称加密

  • ASN.1 数据结构
  • 键编码格式:PEM 格式
    • 公钥:SPKI
      • // 导入
        crypto.createPrivateKey(fs.readFileSync("public.pem"));
        
    • 私钥:
      • PKCS #1(旧,RSA only)
      • PKCS #8(新,面向多种算法)
      • //导入
        crypto.createPrivateKey(fs.readFileSync("private.pem"));
        
    • 导出:crypto.KeyObject.export(option)
  • RSA
    • key
      • crypto.generateKeyPair('rsa', ...)
    • 加解密
      • padding:加密前给明文加入随机数据以提高 RSA 的抗攻击能力。
        • 如无理由,总是使用。
        • crypto.constants.RSA_PKCS1_OAEP_PADDING(推荐)
        • crypto.constants.RSA_PKCS1_PADDING(不推荐)
      • crypto.publicEncrypt(
          {
            key: publicKey,
            padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
            oaepHash: "sha256",
          },
          plaintext
        );
        
      • crypto.privateDecrypt(
          {
            key: privateKey,
            padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
            oaepHash: "sha256",
          },
          message
        );
        
    • 数字签名
      • padding:
        • crypto.constants.RSA_PKCS1_PADDING(缺省)
        • crypto.constants.RSA_PKCS1_PSS_PADDING(新版本,推荐)
      • crypto.sign("sha256", message, {
          key: privateKey,
          padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
        });
        
      • crypto.verify(
          "sha256",
          message,
          {
            key: publicKey,
            padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
          },
          signature
        );
        
  • 椭圆曲线
    • 与 RSA 同等的安全性
    • 密钥更短、更快、消耗资源更少
    • 常用曲线
      • P-256:secp256r1 / prime256v1,NIST 标准
      • Curve25519
        • 密钥交换时,X25519
        • 数字签名时,Ed25519
      • secp256k1,比特币采用
    • 典型应用
      • 密钥交换(ECDH)
      • 数字签名
    • key
      • crypto.generateKeyPair('ec', ...)
    • ECDH
      • 不同于 RSA(一方用另一方的公钥加密密钥之后,发给对方解密即可)。
      • DH 协议
        • Alice 和 Bob 各生成一个密钥对
        • 两者交换对方的公钥
        • 结合自身的私钥生成公共密钥,即:
          • shareSecret(A 公钥, B 私钥) = shareSecret(B 公钥, A 私钥)
      • crypto.diffieHellman({对方公钥,自己私钥})
      • 公共密钥的一个参考实现:
        • crypto.diffieHellman 得到 shareSecret
        • 生成随机 salt
        • sha256(shareSecret, salt) 为公共密钥,注:salt 记得随密文传给对方。
    • 数字签名
      • ECDSA(使用 prime256v1)
        • crypto.sign('sha256', message, privateKey)
        • crypto.verify('sha256', message, publicKey, signature)
      • EdDSA(使用 Ed25519),因其已经内置数字签名算法,故无需外部配置 hash 函数。
        • crypto.sign(null, message, privateKey)
        • crypto.verify(null, message, publicKey, signature)

Web Crypto

  • 应用于浏览器环境
  • 编码
    • ArrayBuffer
    • atobbtoa
    • TextEncoder
  • 随机数:
    • Window.crypto.getRandomValues
    • Window.crypto.randomUUID
  • 密钥
    • window.crypto.subtle.generateKey(algorithm, extractable, usages)
    • window.crypto.subtle.importKey(format, data, algorithm, extractable, usages)
    • window.crypto.subtle.exportKey(format, key)
    • window.crypto.subtle.wrapKey
    • window.crypto.subtle.unwrapKey
    • window.crypto.subtle.deriveKey
  • 哈希
  • 加解密(同时适用于对称和非对称)
    • crypto.subtle.encrypt(algorithm, key, data)
    • crypto.subtle.decrypt(algorithm, key, data)
  • 数字签名
    • window.crypto.subtle.sign
    • window.crypto.subtle.verify

参考

点赞 1
收藏 2
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

1 条评论

请先 登录 后评论
胡键
胡键
CSM / 架构师 / 创业者,先后就职于中兴和 SAP,现专注于工业物联网、机器学习和区块链。同时,作为机器学习和区块链技术活动的组织者和分享者活跃于本地社区。