介绍

和前面DES加密学习一样,只学习用法及实现以供爬虫逆向所用,不深入原理

AES加密算法是用来取代DES的,同样有一个密钥,用来加密或解密,同时支持以下:

  • mode
    • CBC
    • CFB
    • CTR
    • CTRGladman
    • ECB(唯一无iv向量模式)
    • OFB
  • padding
    • ZeroPadding
    • NoPadding
    • AnsiX923
    • Iso10126
    • Iso97971
    • Pkcs7
      (以上列表不完全列出)

AES加密密钥长度为AES128、AES192、AES256,即128位、192位、256位,某些库会在长度不够时自动填充

JS实现

同样使用Crypto-Js库实现,代码与前DES基本一致:

let crypto = require('crypto-js')

function aesEncrypt(aesMsg,aesKey,aesIv){
    let key = crypto.enc.Utf8.parse(aesKey),
        iv = crypto.enc.Utf8.parse(aesIv),
        msg = crypto.enc.Utf8.parse(aesMsg),
        encrypted = crypto.AES.encrypt(msg,key,{
            iv:iv,
            mode:crypto.mode.CBC,
            padding:crypto.pad.Pkcs7
        })
    return encrypted.toString()
}

console.log(aesEncrypt('HELLO WORLD','0123456789abcdef','0123456789abcdef'))

运行结果:

u9CkJDGEw0frLa/SQ51GOg==

解密与之差不多,但要注意小细节

function aesDecrypt(aesMsg,aesKey,aesIv){
    let key = crypto.enc.Utf8.parse(aesKey),
        iv = crypto.enc.Utf8.parse(aesIv),
        encrypted = crypto.AES.decrypt(aesMsg,key,{
            iv:iv,
            mode:crypto.mode.CBC,
            padding:crypto.pad.Pkcs7
        })
    return encrypted.toString(crypto.enc.Utf8)
}
console.log(aesDecrypt('u9CkJDGEw0frLa/SQ51GOg==','0123456789abcdef','0123456789abcdef'))

运行结果:

HELLO WORLD

实战-优师云

优师云-登录

data
请求表单password加密

可以走发起程序或者XHR断点,这里选择XHR断点
找寻到这里比较直观的调用,但是password已是密文
调用

继续寻找
FIND IT

这里/Android|webOS|iPhone|iPod|iPad|BlackBerry|MicroMessenger/i.test(navigator.userAgent)false,那么可以视代码如下:

 return false || (a = Object(_["g"])({
    data: e,
    key: "password.yunjy.y",
    param: ["password"]
}))

猜测这块就是加密函数,可以直接复制进控制台调用以下看看:

现在来研究这个函数,跳转至源码:

var u = function(t) {
    var e = t.data
      , n = t.type
      , a = t.param
      , r = t.key
      , o = JSON.parse(JSON.stringify(e));
    return "Base64" === n ? a.forEach((function(t) {
        o[t] = btoa(o[t])
    }
    )) : a.forEach((function(t) {
        var e = o[t];
        r = i.a.enc.Latin1.parse(r);
        var n = r
          , a = i.a.AES.encrypt(e, r, {
            iv: n,
            mode: i.a.mode.CBC,
            padding: i.a.pad.ZeroPadding
        });
        o[t] = a.toString()
    }
    )),
    o
}

注意以下被传入的参数:

{
    "data": {
        "username": "15312341234",
        "password": "asda1348315135153",
        "redomStr": ""
    },
    "key": "password.yunjy.y",
    "param": [
        "password"
    ]
}

这里出现了i.a.AES.encrypt(),老办法,先在在控制台输出看看i.a,果然是包含了很多加密方法,直接用crypto-js平替,最终本地代码为:

let crypto = require('crypto-js')


function getData(t) {
    var e = t.data
      , n = t.type
      , a = t.param
      , r = t.key
      , o = JSON.parse(JSON.stringify(e));
    return "Base64" === n ? a.forEach((function(t) {
        o[t] = btoa(o[t])
    }
    )) : a.forEach((function(t) {
        var e = o[t];
        r = crypto.enc.Latin1.parse(r);
        var n = r
          , a = crypto.AES.encrypt(e, r, {
            iv: n,
            mode: crypto.mode.CBC,
            padding: crypto.pad.ZeroPadding
        });
        o[t] = a.toString()
    }
    )),
    o
}

var t = {
    "data": {
        "username": "15312341234",
        "password": "asda1348315135153",
        "redomStr": ""
    },
    "key": "password.yunjy.y",
    "param": [
        "password"
    ]
}

console.log(getData(t))

运行结果:

{
  username: '15312341234',
  password: '2JcH1czr87e1kCAbqlXtyw2b8OGpkw44Sfhhfhbz3Nw=',
  redomStr: ''
}

与表单重结果一致,逆向完毕

最后优化下代码:

let crypto = require('crypto-js')


function __getData(t) {
    var e = t.data
      , n = t.type
      , a = t.param
      , r = t.key
      , o = JSON.parse(JSON.stringify(e));
    return "Base64" === n ? a.forEach((function(t) {
        o[t] = btoa(o[t])
    }
    )) : a.forEach((function(t) {
        var e = o[t];
        r = crypto.enc.Latin1.parse(r);
        var n = r
          , a = crypto.AES.encrypt(e, r, {
            iv: n,
            mode: crypto.mode.CBC,
            padding: crypto.pad.ZeroPadding
        });
        o[t] = a.toString()
    }
    )),
    o
}

function getData(account,pswd,redomStr){
    return __getData({
        "data": {
        "username": account,
        "password": pswd,
        "redomStr": redomStr
        },
        "key": "password.yunjy.y",
        "param": [
            "password"
        ]
    })
}