使用AES加密游戏资源文件

原创文章,转载请注明: 转载自All-iPad.net 本文链接地址: 使用AES加密游戏资源文件

在研究Angry Birds的过程中了解到其部分lua脚本文件被进行了加密,关于如何解密以及如何找到解密key的方法见前一篇博客。游戏资源文件加密是pc上的游戏必做的一件事,虽然无论何种加密方法都无法阻止别人的破解,但是加密至少能够提高应用被破解的门槛,说白了就是不能让随便一个人都能看到里面的一切。

Andgry Birds对lua文件的加密采用的是AES加密算法,使用CBC模式,另外原始文件内容还进行了7z压缩。为了能够解密,AES加密的key必然会保存在应用的某个地方,所以别人还是能够找到破解的方法,能够还原出原始的资源文件,具体用到的方法就是前一篇博客里说到的。

在学习如何解密的过程中找到了一篇不错的文章,介绍如何使用Python的PyCrypto模块来对文件进行AES加密,并且提供了python编写的加密解密源代码,在后面的评论中有人将其进行了改造,支持streamio模式的加密解密,也就是可以操作内存数据。

代码具有很高的实用价值,如果需要在自己的应用中添加一个加密模块,这是个不错的开始,虽然不一定会采用python来实现。

代码如下:

 

 

#!/usr/bin/env python
#
# Code adapted from: http://eli.thegreenplace.net/2010/06/25/aes-encryption-of-files-in-python-with-pycrypto/
#
#

import os, random, struct
from Crypto.Cipher import AES
from StringIO import StringIO
import hashlib
import base64

## def encrypt_file(key, in_filename, out_filename=None, chunksize=64*1024):
## ( This is an adaptation from using filenames in order that StringIO can be used to encrypt a string. )
## Note: If in_file / out_file is provided, open with +b!

def encrypt_file(key, in_file, out_file=None, chunksize=64*1024):
    """ Encrypts a file using AES (CBC mode) with the
        given key.

        key:
            The encryption key - a string that must be
            either 16, 24 or 32 bytes long. Longer keys
            are more secure.

        in_file:
            Input file

        out_file:
            If None, a StringIO will be returned.

        chunksize:
            Sets the size of the chunk which the function
            uses to read and encrypt the file. Larger chunk
            sizes can be faster for some files and machines.
            chunksize must be divisible by 16.
    """
    if not out_file:
        out_file = StringIO()

    iv = ''.join(chr(random.randint(0, 0xFF)) for i in range(16))
    encryptor = AES.new(key, AES.MODE_CBC, iv)

    in_file.seek(0,2)
    filesize=in_file.tell()
    in_file.seek(0)

    # filesize = os.path.getsize(in_file)

    infile=in_file

    outfile=out_file
    outfile.seek(0)

    outfile.write(struct.pack('<Q', filesize))
    outfile.write(iv)

    while True:

        chunk = infile.read(chunksize)
        if len(chunk) == 0:
            break
        elif len(chunk) % 16 != 0:
            chunk += ' ' * (16 - len(chunk) % 16)

        outfile.write(encryptor.encrypt(chunk))

    outfile.seek(0)
    return outfile

## def decrypt_file(key, in_filename, out_filename=None, chunksize=24*1024):
## ( This is an adaptation from using filenames in order that StringIO can be used to encrypt a string. )
## Note: If in_file / out_file is provided, open with +b!

def decrypt_file(key, in_file, out_file=None, chunksize=24*1024):
    """ Decrypts a file using AES (CBC mode) with the
        given key. Parameters are similar to encrypt_file.
    """
    if not out_file:
        out_file = StringIO()

    infile=in_file
    infile.seek(0)

    outfile=out_file
    outfile.seek(0)

    origsize = struct.unpack('<Q', infile.read(struct.calcsize('Q')))[0]
    iv = infile.read(16)
    decryptor = AES.new(key, AES.MODE_CBC, iv)

    while True:
        chunk = infile.read(chunksize)
        if len(chunk) == 0:
            break
        outfile.write(decryptor.decrypt(chunk))

    outfile.truncate(origsize)

    outfile.seek(0)
    return outfile

# Method suggested by Eli by turn mnemonic password into 32 byte key.
def getHashKey(aKey):
    return hashlib.sha256(aKey).digest()

# My ( J. Norment's ) Additions
def getInFile(aFileName=None):
    if not aFileName:
        return StringIO()
    else:
        return open(aFileName,'rb')

def getOutFile(aFileName=None):
    if not aFileName:
        return StringIO()
    else:
        return open(aFileName,'wb')

def getB64encoded(aString):
    return base64.b64encode(aString)

def getB64decoded(aString):
    return base64.b64decode(aString)

原创文章,转载请注明: 转载自All-iPad.net

本文链接地址: 使用AES加密游戏资源文件

你可能感兴趣的:(使用AES加密游戏资源文件)