使用AES加密游戏资源文件
在研究Angry Birds的过程中了解到其部分lua脚本文件被进行了加密,关于如何解密以及如何找到解密key的方法见前一篇博客。游戏资源文件加密是pc上的游戏必做的一件事,虽然无论何种加密方法都无法阻止别人的破解,但是加密至少能够提高应用被破解的门槛,说白了就是不能让随便一个人都能看到里面的一切。
Andgry Birds对lua文件的加密采用的是AES加密算法,使用CBC模式,另外原始文件内容还进行了7z压缩。为了能够解密,AES加密的key必然会保存在应用的某个地方,所以别人还是能够找到破解的方法,能够还原出原始的资源文件,具体用到的方法就是前一篇博客里说到的。
在学习如何解密的过程中找到了一篇不错的文章,介绍如何使用Python的PyCrypto模块来对文件进行AES加密,并且提供了python编写的加密解密源代码,在后面的评论中有人将其进行了改造,支持streamio模式的加密解密,也就是可以操作内存数据。
代码具有很高的实用价值,如果需要在自己的应用中添加一个加密模块,这是个不错的开始,虽然不一定会采用python来实现。
代码如下:
001 #!/usr/bin/env python
002 #
003 # Code adapted from: http://eli.thegreenplace.net/2010/06/25/aes-encryption-of-files-in-python-with-pycrypto/
004 #
005 #
006
007 import os, random, struct
008 from Crypto.Cipher import AES
009 from StringIO import StringIO
010 import hashlib
011 import base64
012
013 ## def encrypt_file(key, in_filename, out_filename=None, chunksize=64*1024):
014 ## ( This is an adaptation from using filenames in order that StringIO can be used to encrypt a string. )
015 ## Note: If in_file / out_file is provided, open with +b!
016
017 def encrypt_file(key, in_file, out_file=None, chunksize=64*1024):
018 """ Encrypts a file using AES (CBC mode) with the
019 given key.
020
021 key:
022 The encryption key - a string that must be
023 either 16, 24 or 32 bytes long. Longer keys
024 are more secure.
025
026 in_file:
027 Input file
028
029 out_file:
030 If None, a StringIO will be returned.
031
032 chunksize:
033 Sets the size of the chunk which the function
034 uses to read and encrypt the file. Larger chunk
035 sizes can be faster for some files and machines.
036 chunksize must be divisible by 16.
037 """
038 if not out_file:
039 out_file = StringIO()
040
041 iv = ''.join(chr(random.randint(0, 0xFF)) for i in range(16))
042 encryptor = AES.new(key, AES.MODE_CBC, iv)
043
044 in_file.seek(0,2)
045 filesize=in_file.tell()
046 in_file.seek(0)
047
048 # filesize = os.path.getsize(in_file)
049
050 infile=in_file
051
052 outfile=out_file
053 outfile.seek(0)
054
055 outfile.write(struct.pack('<Q', filesize))
056 outfile.write(iv)
057
058 while True:
059
060 chunk = infile.read(chunksize)
061 if len(chunk) == 0:
062 break
063 elif len(chunk) % 16 != 0:
064 chunk += ' ' * (16 - len(chunk) % 16)
065
066 outfile.write(encryptor.encrypt(chunk))
067
068 outfile.seek(0)
069 return outfile
070
071 ## def decrypt_file(key, in_filename, out_filename=None, chunksize=24*1024):
072 ## ( This is an adaptation from using filenames in order that StringIO can be used to encrypt a string. )
073 ## Note: If in_file / out_file is provided, open with +b!
074
075 def decrypt_file(key, in_file, out_file=None, chunksize=24*1024):
076 """ Decrypts a file using AES (CBC mode) with the
077 given key. Parameters are similar to encrypt_file.
078 """
079 if not out_file:
080 out_file = StringIO()
081
082 infile=in_file
083 infile.seek(0)
084
085 outfile=out_file
086 outfile.seek(0)
087
088 origsize = struct.unpack('<Q', infile.read(struct.calcsize('Q')))[0]
089 iv = infile.read(16)
090 decryptor = AES.new(key, AES.MODE_CBC, iv)
091
092 while True:
093 chunk = infile.read(chunksize)
094 if len(chunk) == 0:
095 break
096 outfile.write(decryptor.decrypt(chunk))
097
098 outfile.truncate(origsize)
099
100 outfile.seek(0)
101 return outfile
102
103 # Method suggested by Eli by turn mnemonic password into 32 byte key.
104 def getHashKey(aKey):
105 return hashlib.sha256(aKey).digest()
106
107 # My ( J. Norment's ) Additions
108 def getInFile(aFileName=None):
109 if not aFileName:
110 return StringIO()
111 else:
112 return open(aFileName,'rb')
113
114 def getOutFile(aFileName=None):
115 if not aFileName:
116 return StringIO()
117 else:
118 return open(aFileName,'wb')
119
120 def getB64encoded(aString):
121 return base64.b64encode(aString)
122&nb
补充:综合编程 , 安全编程 ,