Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

【加密】crypto/argon2

  • crypto不需要安装

    • 是随Nodejs内核一起打包发布的
  • argon2安装

    npm i -S argon2
    
    • 不需要封装到api_crypto.js中,而是直接使用
      import * as argon2 from "argon2";
      
      const encrypt_password = await argon2.hash(password);
      
      await argon2.verify(user.password, password)
      
  • 引入

    import crypto from "crypto";
    import config from "config";
    import fs from "fs";
    
  • md5

    export const string2md5 = (s) => {
        if (!s || s.length === 0) return null;
        let md5 = createHash('md5');
        return md5.update(s).digest('hex');
    };
    
  • sha1

    export const string2sha1 = (s) => {
        if (!s || s.length === 0) return null;
        let sha1 = createHash('sha1');
        return sha1.update(s).digest('hex');
    };
    
  • pbkdf2

    export const pbkdf2Encrypt = async (password) => {
        return new Promise((resolve)=>{
            pbkdf2(password, config.pbkdf2_salt, 4096, 512, 'sha256', (err, key) => {
                if (err) throw err;
                resolve(key.toString('hex'));
            });
        });
    }
    
    • 这个是异步函数
  • AES 对称加密

    • 作用
      • 对一些重要的隐私信息,用密钥+iv写成加密串
      • iv:加密串存入数据库
      • 就算数据库泄漏,没有服务器的密钥,也无法解密
    • 封装加密函数
      const AES_ALGORITHM = 'aes-256-gcm';
      const IV_LENGTH = 16;
      
      export const AESEncrypt = (text) => {
          if (!text || text.length === 0) return null;
          let iv = randomBytes(IV_LENGTH);
          let cipher = createCipheriv(AES_ALGORITHM, config.aes_key, iv); 
          let encrypted = cipher.update(text);
          encrypted = Buffer.concat([encrypted, cipher.final()]);
          return iv.toString('hex') + ":" + encrypted.toString('hex');
      };
      
    • 封装解密函数
      export const AESDecrypt = (text) => {
          if (!text || text.length === 0) return null;
          let textParts = text.split(':');
          let iv = Buffer.from(textParts.shift(), 'hex');
          let encryptedText = Buffer.from(textParts.join(':'), 'hex');
          let decipher = createDecipheriv(AES_ALGORITHM, config.aes_key, iv); 
          let decrypted = decipher.update(encryptedText);
          //TO_FIX: 下面这一行的 decipher.final() 会报错,注释掉就没事,但不知道不调用会有什么副作用...
          //decrypted = Buffer.concat([decrypted, decipher.final('utf8')]);
          return decrypted.toString();
      };
      
    • 需要在config中配置aes_key
  • RSA 非对称加密

    • 作用1: 公钥加密,私钥解密

      • 把公钥放出去,有人用公钥加密了内容传到服务器
      • 只有拥有对应私钥,才能解密出真正的信息
    • 作用2:私钥签名,公钥验证

      • 用私钥来加密内容,分发给别人
      • 别人手上有你的公钥,只有对应私钥签发的内容,才能被公钥解密
    • 根目录下新建cert目录

      mkdir cert
      
      cd cert
      
    • 执行

      openssl
      
      • 会出现OpenSSL
    • 生成私钥

      genrsa -out common_rsa_private_key.pem 1024
      
    • 根据私钥生成公钥

      rsa -in common_rsa_private_key.pem -pubout -out common_rsa_public_key.pem
      
    • 封装加密函数(作用1)

      export const RSAEncrypt = (s, public_key_path) => {
          if (!s || s.length === 0) return null;
          let publicKey = fs.readFileSync(public_key_path, 'ascii').toString();
          let encryptResult = publicEncrypt({key: publicKey, padding: constants.RSA_PKCS1_PADDING}, Buffer.from(s,'utf8'))
          return encryptResult.toString('base64');
      };
      
    • 封装解密函数(作用1)

      export const RSADecrypt = (s, private_key_path) => {
          if (!s || s.length === 0) return null;
          let privateKey = fs.readFileSync(private_key_path, 'ascii').toString();
          let decryptResult = privateDecrypt({key: privateKey, padding: constants.RSA_PKCS1_PADDING}, Buffer.from(s,'base64'))
          return decryptResult.toString('utf8');
      };
      
    • 封装签名函数(作用2)

      • 要用到privateEncrypt
    • 封装验签函数(作用2)

      • 要用到publicDecrypt
    • 测试代码

      const text = "test content for rsa encrypt"
      let encrypted = RSAEncrypt(text, __dirname + config.cert_common.public_key_path);
      console.log(encrypted);
      let dectypted = RSADecrypt(encrypted, __dirname + config.cert_common.private_key_path);
      console.log(dectypted)
      
      • 需要用到
        import path from "path";
        const __dirname = path.resolve();
        
        • 获取根目录