【问题标题】:Non-ASCII character '\x97' in file, but no encoding declared文件中的非 ASCII 字符“\x97”,但未声明编码
【发布时间】:2018-07-12 09:04:25
【问题描述】:

我正在尝试在Linux 中编码Python 脚本的内容。我刚开始使用一个名为 test.py 的简单脚本 -

# !/app/logs/Python/bin/python3
# -*- coding: ascii -*-
print ("hi")

获得脚本后,我执行vim -x test.py 并输入两次加密密钥。然后正常保存文件,然后使用python test.py执行脚本

我尝试了链接here 中提供的几乎所有示例,但最终还是出现以下错误 -

SyntaxError: Non-ASCII character '\x97' in file test.py on line 1, but no encoding declared; see http://www.python.org/peps/pep-0263.html for details

我使用print sys.getdefaultencoding()检查了默认编码,它是acsii。

我在这里缺少什么。请澄清。我知道这个问题是重复的,但没有一个解决方案有帮助。

【问题讨论】:

  • 除非我遗漏了一些你已经加密文件的东西,所以 python 将无法运行它。抱怨是因为您试图(有效地)向 python 解释器提供垃圾。当您cat test.py 时,它应该显示该文件不再具有 python 可用内容
  • 当然是通过解密。
  • 您可以通过解密脚本使其可执行。如果你想对“人”隐藏来源,你需要定义边界;那么我们也许可以提出一些建议的方法。例如您是否希望他们也能够运行脚本?然而,这实际上并不在本网站的范围内。像information security SE 这样的网站可能更适合解决这类问题。
  • @sdevgd 你误解了评论。如果您想要隐藏信息的高级方法,请在 sec.se 上发布。对于如何处理代码中的错误,这是正确的地方。
  • @sdevgd 你拿了一个文本文件,加密它,然后试图让解释器运行它。那永远行不通。如果您的目标是向运行它的人隐藏脚本语言的内容,那么 that 需要成为您的问题(以及您的研究来源)。

标签: python linux unicode


【解决方案1】:

Python 知道如何执行明文 Python 源代码。如果对源文件进行加密,则不再包含有效的 Python 源,无法直接执行。

这里有两种可能的方法。首先是仅混淆您的来源。您应该知道,混淆不是安全的,用户可以通过一些工作恢复一些 Python 源(不一定是原始源,因为 cmets 和 doc 字符串可能已被剥离,变量名可能已被更改)。您可以阅读 How do I protect Python code? 和 google 以了解 python obfuscate 以找到一些混淆 Python 源代码的可能方法及其权衡。

混淆源的好消息是任何人都可以使用而无需任何密码。

第二种方法是加密源。如果您使用一个不错的工具,您可以假设在不知道密钥的情况下无法读取或执行文件。从这个意义上说,vimcrypto 的声誉并不是最高的。以最简单的方式(例如您的示例vim -x),您必须解密文件才能执行它。不幸的是,好的加密模块没有在标准的 Python 安装中提供,必须从 pypi 下载。众所周知的加密模块包括pycryptocryptography

然后您可以加密大部分代码,然后在运行时请求密钥、解密并执行它。仍然是一项严肃的工作,但可行。

或者,您可以用另一种语言 (C/C++) 构建一个解密器,用于解密文件的其余部分并将其输入 python 解释器,但从功能上讲,这只是上述方法的一种变体。


根据您的评论,我假设您想在运行时加密源代码并解密(使用密码)。原则是:

  • 构建一个 Python 脚本,该脚本将采用另一个任意 Python 脚本,使用安全加密模块对其进行编码,并在其前面添加一些解密代码。
  • 在运行时,前置代码会询问密码,解密加密的代码执行它

构建器可以是(此代码使用 cryptography 模块):

import cryptography.fernet
import cryptography.hazmat.primitives.kdf.pbkdf2
import cryptography.hazmat.primitives.hashes
import cryptography.hazmat.backends
import base64
import os
import sys

# the encryption function
def encrypt_source(infile, outfile, passwd):
    with open(infile, 'rb') as fdin:     # read original file
        plain_data = fdin.read()
    salt, key = gen_key(passwd)          # derive a key from the password
    f = cryptography.fernet.Fernet(key)
    crypted_data = f.encrypt(plain_data) # encrypt the original code
    with open(outfile, "w") as fdout:    # prepend a decoding block
        fdout.write("""#! /usr/bin/env python

import cryptography.fernet
import cryptography.hazmat.primitives.kdf.pbkdf2
import cryptography.hazmat.primitives.hashes
import cryptography.hazmat.backends
import base64
import os

def gen_key(passwd, salt):             # key derivation
    kdf = cryptography.hazmat.primitives.kdf.pbkdf2.PBKDF2HMAC(
        algorithm = cryptography.hazmat.primitives.hashes.SHA256(),
        length = 32,
        salt = salt,
        iterations = 100000,
        backend = cryptography.hazmat.backends.default_backend()
    )
    return base64.urlsafe_b64encode(kdf.derive(passwd))

passwd = input("Password:")            # ask for the password
salt = base64.decodebytes({})
key = gen_key(passwd.encode(), salt)   # derive the key from the password and the original salt

crypted_source = base64.decodebytes(   # decode (base64) the crypted source
b'''{}'''
)
f = cryptography.fernet.Fernet(key)
plain_source = f.decrypt(crypted_source) # decrypt it
exec(plain_source)                     # and exec it
""".format(base64.encodebytes(salt),
           base64.encodebytes(crypted_data).decode()))

# derive a key from a password and a random salt
def gen_key(passwd, salt=None):        
    if salt is None: salt = os.urandom(16)
    kdf = cryptography.hazmat.primitives.kdf.pbkdf2.PBKDF2HMAC(
        algorithm = cryptography.hazmat.primitives.hashes.SHA256(),
        length = 32,
        salt = salt,
        iterations = 100000,
        backend = cryptography.hazmat.backends.default_backend()
    )
    return salt, base64.urlsafe_b64encode(kdf.derive(passwd))

if __name__ == '__main__':
    if len(sys.argv) != 3:
        print("Usage {} infile outfile".format(sys.argv[0]))
        sys.exit(1)
    passwd = input("Password:").encode()             # ask for a password
    encrypt_source(sys.argv[1], sys.argv[2], passwd) # and generates an encrypted Python script

【讨论】:

  • 谢谢。看起来有关在运行时解密文件的解决方案应该对我有所帮助。当我加密它时,我能够设置一个密钥,但是当我尝试运行它时,它并没有要求密钥。您能帮我了解如何在运行时启用它吗?
猜你喜欢
  • 2019-06-20
  • 1970-01-01
  • 1970-01-01
  • 2015-12-05
  • 2012-07-22
  • 1970-01-01
相关资源
最近更新 更多