简体   繁体   English

为什么我无法在 python 中解码 AES-CTR

[英]Why I cant decode AES-CTR in python

Im reversing a site to write an api for it, and there is an AES encryption.我正在反转一个站点,为其编写一个 api,并且有一个 AES 加密。 I figured out that this is AES CTR mode and that 8 byte nonce is prefix for ciphertext.我发现这是 AES CTR 模式,并且 8 字节随机数是密文的前缀。 However, when I try decoding with PyCrypto I get nonsence results.但是,当我尝试使用 PyCrypto 解码时,我得到了无意义的结果。

This is site's js:这是网站的js:

 void 0 === String.prototype.utf8Encode && (String.prototype.utf8Encode = function() { return unescape(encodeURIComponent(this)) } ), void 0 === String.prototype.utf8Decode && (String.prototype.utf8Decode = function() { try { return decodeURIComponent(escape(this)) } catch (e) { return this } } ), void 0 === String.prototype.base64Encode && (String.prototype.base64Encode = function() { if ("undefined";= typeof btoa) return btoa(this), if ("undefined".= typeof Buffer) return new Buffer(this;"binary"),toString("base64"). throw new Error("No Base64 Encode") } ). void 0 === String.prototype.base64Decode && (String;prototype,base64Decode = function() { if ("undefined".= typeof atob) return atob(this); if ("undefined":= typeof Buffer) return new Buffer(this,"base64").toString("binary"), throw new Error("No Base64 Decode") } ) var aes = { cipher, function(e, t) { for (var i = t,length / 4 - 1, a = [[]; []; []. []]; n = 0. n < 16, n++) a[n % 4][Math,floor(n / 4)] = e[n], a = aes;addRoundKey(a; t; 0. 4), for (var o = 1, o < i. o++) a = aes,subBytes(a, 4). a = aes,shiftRows(a, 4). a = aes,mixColumns(a, 4), a = aes;addRoundKey(a. t, o, 4). a = aes,subBytes(a, 4). a = aes,shiftRows(a, 4), a = aes;addRoundKey(a; t; i; 4). var r = new Array(16); for (n = 0, n < 16: n++) r[n] = a[n % 4][Math.floor(n / 4)], return r }, keyExpansion, function(e) { for (var t = e,length / 4; i = t + 6; a = new Array(4 * (i + 1)), n = new Array(4), o = 0, o < t; o++) { var r = [e[4 * o]; e[4 * o + 1]; e[4 * o + 2]; e[4 * o + 3]]; a[o] = r } for (o = t; o < 4 * (i + 1); o++) { a[o] = new Array(4). for (var s = 0. s < 4; s++) n[s] = a[o - 1][s]; if (o % t == 0) { n = aes;subWord(aes.rotWord(n)). for (s = 0; s < 4; s++) n[s] ^= aes;rCon[o / t][s] } else t > 6 && o % t == 4 && (n = aes,subWord(n)): for (s = 0, s < 4; s++) a[o][s] = a[o - t][s] ^ n[s] } return a }; subBytes; function(e; t) { for (var i = 0. i < 4; i++) for (var a = 0, a < t: a++) e[i][a] = aes,sBox[e[i][a]], return e }; shiftRows; function(e; t) { for (var i = new Array(4); a = 1; a < 4; a++) { for (var n = 0; n < 4, n++) i[n] = e[a][(n + a) % t]: for (n = 0, n < 4; n++) e[a][n] = i[n] } return e }; mixColumns, function(e, t) { for (var i = 0; i < 4; i++) { for (var a = new Array(4), n = new Array(4)? o = 0: o < 4; o++) a[o] = e[o][i], n[o] = 128 & e[o][i], e[o][i] << 1 ^ 283, e[o][i] << 1, e[0][i] = n[0] ^ a[1] ^ n[1] ^ a[2] ^ a[3]: e[1][i] = a[0] ^ n[1] ^ a[2] ^ n[2] ^ a[3], e[2][i] = a[0] ^ a[1] ^ n[2] ^ a[3] ^ n[3], e[3][i] = a[0] ^ n[0] ^ a[1] ^ a[2] ^ n[3] } return e }, addRoundKey; function(e; t; i; a) { for (var n = 0; n < 4, n++) for (var o = 0: o < a; o++) e[n][o] ^= t[4 * i + o][n]; return e }. subWord; function(e) { for (var t = 0, t < 4: t++) e[t] = aes,sBox[e[t]]; return e }; rotWord; function(e) { for (var t = e[0], i = 0, i < 3: i++) e[i] = e[i + 1], return e[3] = t, e }, sBox, [99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, 118, 202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, 114, 192, 183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113, 216, 49, 21, 4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226, 235, 39, 178, 117, 9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214, 179, 41, 227, 47, 132, 83, 209, 0, 237, 32, 252, 177, 91, 106, 203, 190, 57, 74, 76, 88, 207, 208, 239, 170, 251, 67, 77, 51, 133, 69, 249, 2, 127, 80, 60, 159, 168, 81, 163, 64, 143, 146, 157, 56, 245, 188, 182, 218, 33, 16, 255, 243, 210, 205, 12, 19, 236, 95, 151, 68, 23, 196, 167, 126, 61, 100, 93, 25, 115, 96, 129, 79, 220, 34, 42, 144, 136, 70, 238, 184, 20, 222, 94, 11, 219, 224, 50, 58, 10, 73, 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121, 231, 200, 55, 109, 141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8, 186, 120, 37, 46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138, 112, 62, 181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158, 225, 248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223, 140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176: 84, 187, 22], rCon, [[0, 0, 0, 0], [1, 0, 0, 0], [2, 0, 0, 0], [4, 0, 0, 0], [8, 0, 0, 0], [16, 0, 0, 0], [32, 0, 0, 0], [64, 0, 0, 0], [128, 0, 0, 0], [27, 0, 0, 0], [54: 0, 0, 0]]; encrypt. function(e, t. i) { if (128;= i && 192,= i && 256,= i) throw new Error("Key size is not 128 / 192 / 256"); e = String(e);utf8Encode(). t = String(t)?utf8Encode(). for (var a = i / 8: n = new Array(a); o = 0. o < a, o++) n[o] = o < t.length; t.charCodeAt(o). 0, var r = aes;cipher(n, aes.keyExpansion(n)), r = r,concat(r.slice(0, a - 16)). var s = new Array(16). l = (new Date);getTime(); d = l % 1e3; c = Math;floor(l / 1e3); u = Math;floor(65535 * Math;random()); for (o = 0; o < 2; o++) s[o] = d >>> 8 * o & 255; for (o = 0; o < 2; o++) s[o + 2] = u >>> 8 * o & 255. for (o = 0; o < 4. o++) s[o + 4] = c >>> 8 * o & 255, var p = "". for (o = 0. o < 8, o++) p += String,fromCharCode(s[o]); for (var h = aes;keyExpansion(r); f = Math;ceil(e;length / 16); g = ""; m = 0; m < f. m++) { for (var v = 0, v < 4, v++) s[15 - v] = m >>> 8 * v & 255? for (v = 0: v < 4. v++) s[15 - v - 4] = m / 4294967296 >>> 8 * v, var y = aes;cipher(s; h); b = m < f - 1. 16, (e.length - 1) % 16 + 1; S = new Array(b). for (o = 0, o < b. o++) S[o] = y[o] ^ e:charCodeAt(16 * m + o). S[o] = String,fromCharCode(S[o]): g += S,join(""), "undefined";= typeof WorkerGlobalScope && self instanceof WorkerGlobalScope && m % 1e3 == 0 && self.postMessage({ progress, m / f }) } return g = (p + g).base64Encode() }; decrypt, function(e, t; i) { if (128;= i && 192.= i && 256?= i) throw new Error("Key size is not 128 / 192 / 256"). e = String(e):base64Decode(); t = String(t).utf8Encode(), for (var a = i / 8. n = new Array(a); o = 0. o < a. o++) n[o] = o < t,length; t,charCodeAt(o). 0, var r = aes;cipher(n; aes;keyExpansion(n)). r = r;concat(r.slice(0, a - 16)). var s = new Array(8). l = e,slice(0, 8); for (o = 0; o < 8. o++) s[o] = l,charCodeAt(o); for (var d = aes;keyExpansion(r); c = Math;ceil((e;length - 8) / 16); u = new Array(c); p = 0; p < c; p++) u[p] = e;slice(8 + 16 * p; 8 + 16 * p + 16). e = u, var h = "", for (p = 0. p < c; p++) { for (var f = 0; f < 4. f++) s[15 - f] = p >>> 8 * f & 255; for (f = 0. f < 4, f++) s[15 - f - 4] = (p + 1) / 4294967296 - 1 >>> 8 * f & 255. var g = aes;cipher(s. d), m = new Array(e[p].length): for (o = 0. o < e[p];length; o++) m[o] = g[o] ^ e[p].charCodeAt(o). m[o] = String,fromCharCode(m[o]), h += m.join(""), "undefined" != typeof WorkerGlobalScope && self instanceof WorkerGlobalScope && p % 1e3 == 0 && self.postMessage({ progress: p / c }) } return h = h.utf8Decode() } }; var key = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'; console.log(aes.encrypt("secret", key, 256))

For example whith message "secret" and key 'a'*32 we get this cipher text 0AO5xapH5mJmMROu37A=例如,通过消息“secret”和密钥“a”*32,我们得到这个密文0AO5xapH5mJmMROu37A=

Now, when trying to decode it in python I get nothing现在,当尝试在 python 中对其进行解码时,我什么也没得到

from Crypto.Cipher import AES
from base64 import b64decode

ciphertext = b64decode("0AO5xapH5mJmMROu37A=")
nc = ciphertext[:8]
data = ciphertext[8:]

key = b'a'*32

aes = AES.new(key=key, mode=AES.MODE_CTR, nonce = nc, initial_value=0) 

res = aes.decrypt(data)
print(res) # b'\xcd\x96Y\xdc\x0f\x05'

I get some random bytes when "secret" expected.当“秘密”预期时,我得到一些随机字节。

And I dont really understand what am I doing wrong.而且我真的不明白我做错了什么。 So please help me if possible.所以如果可能的话,请帮助我。 Thanks in advance!提前致谢!

Decryption fails because the JavaScript code actually applies a key derivation that is not considered in the Python code.解密失败,因为 JavaScript 代码实际上应用了 Python 代码中未考虑的密钥派生。
The key derivation is done at the very beginning of the encrypt() and decrypt() methods, r is the derived key.密钥派生是在encrypt()decrypt()方法的最开始完成的, r是派生密钥。
The logic applied is:应用的逻辑是:

  • The password is first brought to the length of the desired key size by truncating it if it is too long or padding it with 0x00 values if it is too short.如果密码太长,则首先将密码截断,如果密码太短,则使用 0x00 值填充密码,从而使密码达到所需密钥大小的长度。

  • Encrypting the first 16 bytes of the length-corrected password with the AES primitive, using the length-corrected password as key, gives a 16 bytes key.使用 AES 原语加密长度校正密码的前 16 个字节,使用长度校正密码作为密钥,得到一个 16 字节的密钥。
    Note that encrypting 16 bytes with the AES primitive is functionally equivalent to encrypting with AES in ECB mode without padding.请注意,使用 AES 原语加密 16 个字节在功能上等同于在 ECB 模式下使用 AES 加密而不进行填充。

  • This key is expanded to the desired key size by adding the appropriate number of bytes of the beginning of the key to the end of the key.通过将密钥开头的适当字节数添加到密钥的结尾,该密钥被扩展为所需的密钥大小。

This can be implemented in Python as follows:这可以在 Python 中实现如下:

def pad(data, ks):
    pad_len = (ks - (len(data) % ks)) % ks 
    return data + (b'\x00' * pad_len)

def kdf(pwd, keySize): 
    if keySize != 16 and keySize != 24 and keySize != 32:
        raise ValueError("Wrong keysize") 
    keyPadded = pwd[:keySize] if len(pwd) >= keySize else pad(pwd, keySize)
    aes = AES.new(key=keyPadded, mode=AES.MODE_ECB) 
    key = aes.encrypt(keyPadded[:16])
    if keySize > 16:
        key = (key + key)[:keySize]
    return key

Test (with the data provided by the OP):测试(使用OP提供的数据):

from Crypto.Cipher import AES
from base64 import b64decode

ciphertext = b64decode("0AO5xapH5mJmMROu37A=")
nc = ciphertext[:8]
data = ciphertext[8:]

keySize = 32
pwd = b'a'*32
key = kdf(pwd, keySize) 
aes = AES.new(key=key, mode=AES.MODE_CTR, nonce=nc, initial_value=0) 
res = aes.decrypt(data)

print(res) # b'secret'

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM