0%

浅析网络应用中常用的加密手段

目的

一般情况下,对数据做加密处理确保两点即可:1.有效性 2.完整性

基本概念

  • 初始向量(initialize vector)
  • PKCS

AES-128-CBC简单声明

  • AES-128-CBC是一种常用的分组对称加密算法,即用同一组key进行明文和密文的转换,以128bits为一组,也就是16Bytes,意思就是明文中的16Bytes为一组对应加密后的16Byte的密文
  • 若明文最后不足16Bytes,需要进行填充,通常采用PKCS#7进行填充。比如最后缺3Bytes,则填充6个0x03;若缺11Bytes,则填充22个0x0b
  • 若明文刚好为16Bytes,则最后要再加32个0x10作为一个分组。
  • key,IV长度均为16Bytes
  • CBC工作模式是:给定一个初始向量iv对第一分组进行加密,生成16Bytes密文作为下一分组的偏移向量递归进行加密,直到所有明文均已转换成密文为止

RSA简单声明

  • 对极大整数做因数分解的难度决定了RSA算法的可靠性。
  • CA一般采用2048bits长度密钥
  • 其运算速度大约为相同安全级别的对称算法的1/1000左右
  • RSA密钥长度随保密级别提高,增加更快(2的指数倍)

常用的加密手段

  1. 首先,peer1生成key以及iv,将明文用AES-128-CBC算法加密并用base64序列化密文,随后对key用私钥RSA算法加密,也就是数字签名,随后通过网络将密文、签名后的key以及iv传输至peer2
  2. peer2拿到密文先用base64反序列化,然后通过公钥(可以通过CA也可通过peer获取)用RSA算法解密拿到key,接着用AES-128-CBC反解得到明文。

demo

  • 生成私钥

    openssl genrsa -out rsa_private_key.pem 1024

  • 转成pkcs8格式私钥

    openssl pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM -nocrypt >> rsa_private_key_pkcs8.pem

  • 生成公钥

    openssl rsa -in rsa_private_key_pkcs8.pem -pubout -out rsa_public_key.pem

  • node(8.0LTS)

    const crypto = require(‘crypto’)
    const fs = require(‘fs’)
    // aesKey
    const aesKey = ‘abcdefghijklmnop’
    // iv
    const iv = ‘0000000000000000’
    // privateKey
    const privateKey = fs.readFileSync(‘rsa_private_key_pkcs8.pem’).toString()
    // publicKey
    const publicKey = fs.readFileSync(‘rsa_public_key.pem’).toString()
    // 创建加密类实例
    const cipheriv = crypto.createCipheriv(‘aes-128-cbc’, aesKey, iv)
    // 结果数据结构
    let res = {
    encryptedData: ‘’,
    publicKey,
    encryptedKey: ‘’,
    iv
    }

    // aes加密过程
    let promiseHandler = null
    let cryptoPromise = new Promise((resolve, reject) => {
    promiseHandler = resolve
    })
    cipheriv.on(‘readable’, () => {
    const data = cipheriv.read()
    if (data) res.encryptedData += data.toString(‘hex’)
    })

    cipheriv.on(‘end’, () => {
    res.encryptedData = res.encryptedData
    console.log(aes加密后的密文为:${res.encryptedData})
    promiseHandler()
    })

    cipheriv.write(‘狼牙月,伊人憔悴。忍字诀,几番轮回。’)
    cipheriv.end()

    // 验证公私钥对是否匹配
    const sign = crypto.createSign(‘SHA256’)

    sign.write(aesKey)
    sign.end()
    let signed = sign.sign(privateKey, ‘base64’)
    const verify = crypto.createVerify(‘SHA256’)

    verify.write(aesKey)
    verify.end()

    console.log(aesKey签名结果为:${signed})
    console.log(公私钥是否匹配:${verify.verify(res.publicKey, signed, 'base64')})

    // 数字签名
    res.encryptedKey = crypto.privateEncrypt(privateKey, Buffer.from(aesKey, ‘utf8’)).toString(‘base64’)
    console.log(私钥加密为:${res.encryptedKey})
    // 公钥解密
    let decryptedKey = crypto.publicDecrypt(res.publicKey, Buffer.from(res.encryptedKey, ‘base64’))
    console.log(公钥解密为:${decryptedKey})

    // 利用key和iv去解密res.encryptedData
    let deCipheriv = crypto.createDecipheriv(‘aes-128-cbc’, decryptedKey, res.iv)
    let decrypted = ‘’
    deCipheriv.on(‘readable’, () => {
    const data = deCipheriv.read()
    if (data) decrypted += data.toString(‘utf8’)
    })
    deCipheriv.on(‘end’, () => {
    console.log(aes解密后的明文为:${decrypted})
    })

    cryptoPromise.then(() => {
    deCipheriv.write(res.encryptedData, ‘hex’)
    deCipheriv.end()
    })