淺析網路應用中常用的加密手段

清風0o0發表於2018-04-18

目的

一般情況下,對資料做加密處理確保兩點即可: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()
})
複製程式碼

相關文章