Return to Snippet

Revision: 57031
at July 22, 2012 15:05 by weilawei


Updated Code
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

#   This code is public domain.
#
#   usage: generate_agent plaincode.py [observation...] > agent.py
#
#   This is an implementation of a clueless agent generator which creates self-decrypting clueless
#   agents as described in "Environmental Key Generation towards Clueless Agents" by  J. Riordan
#   and B. Schneier.
#
#   It requires Python 3.2 and PyCrypto of a recent build (tested with 2.4 and higher).
#   To use, pass a python file (or other file) to be encrypted, followed by a series of
#   "observations" on the command line. These observations are hashed to yield the encryption key.
#   A signature is generated by hashing the key, and this signature will be expected to be present
#   in the target environment. Pipe the resulting agent to a file or see the agent code directly
#   on stdout.  Additionally, there is an is_debug flag that can be specified (see the source) or
#   tweaked in the resulting agent, to be more verbose.
#
#   To attempt decryption/execution of a clueless agent, simply run the generated python script
#   (agent) and pass a set of observations on the command line. If the hash of the hash of the
#   observations match the signature, the hash of the observations will be used as the decryption
#   key. If the signature does not match, the agent will exit with no output.
#
#   The code previously directly exec()'d the resulting code, however, it simply outputs to stdout
#   now. The resulting code would otherwise execute directly in-line, at that location in the
#   program, which has many undesirable consequences. Piping it to a file and executing, piping
#   it to a memory-backed temporary file and executing it, or placing the resulting code directly
#   in memory afterward and then executing it, are all ways to run the code contained within. This
#   makes it fundamentally little different from encrypting a file directly, except that the key
#   is environmentally generated, perhaps by a daemon that feeds environmental observations on the
#   command line to the agent.
#
#   Note, that you can encrypt more than Python scripts, and agents can be made to contain themselves.
#
#   $ ./agent_generator.py plaincode.py 0 > cipheragent.py
#   $ ./agent_generator.py cipheragent.py some more observations > double_agent.py
#   $ ./double_agent.py wrong observations
#   --nothing here--
#   $ ./double_agent.py some more observations > cipheragent_2.py
#   --cipheragent_2.py now holds the same content as cipheragent.py--
#   $ ./cipheragent.py 0 > plaincode_2.py
#   --plaincode_2.py now holds the same content as plaincode.py--
#   $ ./plaincode_2.py
#   --should yield the same as--
#   $ ./plaincode.py

import functools
import base64

from Crypto.Hash import RIPEMD
from Crypto.Cipher import ARC4

agent_template = """#!/usr/bin/env python
# -*- coding: utf-8 -*-

#   usage:  python agent.py [observation...] > plaincode.py

is_debug = %s

import functools
import base64

from Crypto.Hash import RIPEMD
from Crypto.Cipher import ARC4

def execute_agent(observations, signature, ciphercode):
    key             = RIPEMD.new()
    signature_check = RIPEMD.new()

    key.update(functools.reduce(lambda a, b: a + b, observations))
    key_digest = key.hexdigest()
    signature_check.update(key_digest)
    signature_check_digest = bytes(signature_check.hexdigest(), encoding='utf-8')

    if is_debug:
        print("expecting: %%s" %% (signature,))
        print("sig check: %%s" %% (signature_check_digest,))

    if (signature_check_digest == signature):
        decrypter = ARC4.new(key_digest)
        plaincode = decrypter.decrypt(base64.b64decode(ciphercode))

        if is_debug:
            print("key digest: %%s" %% (key_digest,))
            print("decrypted: %%s" %% (plaincode,))

        print(plaincode)

if __name__ == "__main__":
    import sys
    observations    = sys.argv[1:]
    signature       = b'%s'
    ciphercode      = %s
    execute_agent(observations, signature, ciphercode)
"""

def ciphercode_from_string(plaincode, observations):
    key       = RIPEMD.new()
    signature = RIPEMD.new()

    key.update(functools.reduce(lambda a, b: a + b, observations))
    key_digest  = key.hexdigest()
    encrypter   = ARC4.new(key_digest)
    ciphercode  = base64.b64encode(encrypter.encrypt(plaincode))
    signature.update(key_digest)

    return (signature.hexdigest(), ciphercode)

def generate_agent(plaincode, observations, is_debug=False):
    return agent_template % tuple([is_debug] + list(ciphercode_from_string(plaincode, observations)))

if __name__ == "__main__":
    import sys

    with open(sys.argv[1], 'rb') as plaincode:
        print(generate_agent(plaincode.read(), sys.argv[2:], is_debug=False))

Revision: 57030
at July 20, 2012 03:11 by weilawei


Updated Code
#!/usr/bin/env python
# -*- coding: utf-8 -*-

#   This code is public domain.
#
#   usage: generate_agent plaincode.py [observation...] > agent.py
#
#   This is an implementation of a clueless agent generator which creates self-decrypting clueless
#   agents as described in "Environmental Key Generation towards Clueless Agents" by  J. Riordan
#   and B. Schneier.
#
#   It requires Python and PyCrypto of a recent build (tested with 2.3 and higher).
#   To use, pass a python file (or other file) to be encrypted, followed by a series of
#   "observations" on the command line. These observations are hashed yo yield the encryption key.
#   A signature is generated by hashing the key, and this signature will be expected to be present
#   in the target environment. Pipe the resulting agent to a file or see the agent code directly
#   on stdout.  Additionally, there is an is_debug flag that can be specified (see the source) or
#   tweaked in the resulting agent, to be more verbose.
#
#   To attempt decryption/execution of a clueless agent, simply run the generated python script
#   (agent) and pass a set of observations on the command line. If the hash of the hash of the
#   observations match the signature, the hash of the observations will be used as the decryption
#   key. If the signature does not match, the agent will exit with no output.
#
#   The code previously directly exec()'d the resulting code, however, it simply outputs to stdout
#   now. The resulting code would otherwise execute directly in-line, at that location in the
#   program, which has many undesirable consequences. Piping it to a file and executing, piping
#   it to a memory-backed temporary file and executing it, or placing the resulting code directly
#   in memory afterward and then executing it, are all ways to run the code contained within. This
#   makes it fundamentally little different from encrypting a file directly, except that the key
#   is environmentally generated, perhaps by a daemon that feeds environmental observations on the
#   command line to the agent.
#
#   Note, that you can encrypt more than Python scripts, and agents can be made to contain themselves.
#
#   $ ./agent_generator.py plaincode.py 0 > cipheragent.py
#   $ ./agent_generator.py cipheragent.py some more observations > double_agent.py
#   $ ./double_agent.py wrong observations
#   --nothing here--
#   $ ./double_agent.py some more observations > cipheragent_2.py
#   --cipheragent_2.py now holds the same content as cipheragent.py--
#   $ ./cipheragent.py 0 > plaincode_2.py
#   --plaincode_2.py now holds the same content as plaincode.py--
#   $ ./plaincode_2.py
#   --should yield the same as--
#   $ ./plaincode.py

import functools
import base64

from Crypto.Hash import RIPEMD
from Crypto.Cipher import ARC4

agent_template = """#!/usr/bin/env python
# -*- coding: utf-8 -*-

#   usage:  python agent.py [observation...] > plaincode.py

is_debug = %s

import functools
import base64

from Crypto.Hash import RIPEMD
from Crypto.Cipher import ARC4

def execute_agent(observations, signature, ciphercode):
    key             = RIPEMD.new()
    signature_check = RIPEMD.new()

    key.update(functools.reduce(lambda a, b: a + b, observations))
    key_digest = key.hexdigest()
    signature_check.update(key_digest)
    signature_check_digest = bytes(signature_check.hexdigest(), encoding='utf-8')

    if is_debug:
        print("expecting: %%s" %% (signature,))
        print("sig check: %%s" %% (signature_check_digest,))

    if (signature_check_digest == signature):
        decrypter = ARC4.new(key_digest)
        plaincode = decrypter.decrypt(base64.b64decode(ciphercode))

        if is_debug:
            print("key digest: %%s" %% (key_digest,))
            print("decrypted: %%s" %% (plaincode,))

        print(plaincode)

if __name__ == "__main__":
    import sys
    observations    = sys.argv[1:]
    signature       = b'%s'
    ciphercode      = %s
    execute_agent(observations, signature, ciphercode)
"""

def ciphercode_from_string(plaincode, observations):
    key       = RIPEMD.new()
    signature = RIPEMD.new()

    key.update(functools.reduce(lambda a, b: a + b, observations))
    key_digest  = key.hexdigest()
    encrypter   = ARC4.new(key_digest)
    ciphercode  = base64.b64encode(encrypter.encrypt(plaincode))
    signature.update(key_digest)

    return (signature.hexdigest(), ciphercode)

def generate_agent(plaincode, observations, is_debug=False):
    return agent_template % tuple([is_debug] + list(ciphercode_from_string(plaincode, observations)))

if __name__ == "__main__":
    import sys

    with open(sys.argv[1], 'r') as plaincode:
        print(generate_agent(plaincode.read(), sys.argv[2:], is_debug=True))

Revision: 57029
at May 7, 2012 00:01 by weilawei


Initial Code
#!/usr/bin/env python
# -*- coding: utf-8 -*-

#   usage: generate_agent plaincode.py [observation...] > agent.py

import functools
import base64

from Crypto.Hash import RIPEMD
from Crypto.Cipher import ARC4

agent_template = """#!/usr/bin/env python
# -*- coding: utf-8 -*-

#   usage:  python agent.py [observation...] > plaincode.py

is_debug = %s

import functools
import base64

from Crypto.Hash import RIPEMD
from Crypto.Cipher import ARC4

def execute_agent(observations, signature, ciphercode):
    key             = RIPEMD.new()
    signature_check = RIPEMD.new()

    key.update(functools.reduce(lambda a, b: a + b, observations))
    key_digest = key.hexdigest()
    signature_check.update(key_digest)
    
    if is_debug:
        print("expecting: %%s" %% (signature,))
        print("sig check: %%s" %% (signature_check.hexdigest(),))

    if (signature_check.hexdigest() == signature):
        decrypter = ARC4.new(key_digest)
        plaincode = decrypter.decrypt(base64.b64decode(ciphercode))
        
        if is_debug:
            print("key digest: %%s" %% (key_digest,))
            print("decrypted: %%s" %% (plaincode,))
        
        print(plaincode)

if __name__ == "__main__":
    import sys
    observations    = sys.argv[1:]
    signature       = b'%s'
    ciphercode      = b'%s'
    execute_agent(observations, signature, ciphercode)
"""

def ciphercode_from_string(plaincode, observations):
    key       = RIPEMD.new()
    signature = RIPEMD.new()
    
    key.update(functools.reduce(lambda a, b: a + b, observations))
    key_digest  = key.hexdigest()    
    encrypter   = ARC4.new(key_digest)
    ciphercode  = base64.b64encode(encrypter.encrypt(plaincode))
    signature.update(key_digest)    

    return (signature.hexdigest(), ciphercode)
  
def generate_agent(plaincode, observations, is_debug=False):
    return agent_template % tuple([is_debug] + list(ciphercode_from_string(plaincode, observations)))

if __name__ == "__main__":
    import sys

    with open(sys.argv[1], 'r') as plaincode:
        print(generate_agent(plaincode.read(), sys.argv[2:]))

Initial URL


Initial Description
This is an implementation of a clueless agent generator which creates self-decrypting clueless agents as described in "Environmental Key Generation towards Clueless Agents" by  J. Riordan and B. Schneier.

It requires Python 3.2 and PyCrypto of a recent build (tested with 2.4 and higher).

To use, pass a python file (or other file) to be encrypted, followed by a series of "observations" on the command line. These observations are hashed to yield the encryption key. A signature is generated by hashing the key, and this signature will be expected to be present in the target environment. Pipe the resulting agent to a file or see the agent code directly on stdout.  Additionally, there is an is_debug flag that can be specified (see the source) or tweaked in the resulting agent, to be more verbose.

To attempt decryption/execution of a clueless agent, simply run the generated python script (agent) and pass a set of observations on the command line. If the hash of the hash of the observations match the signature, the hash of the observations will be used as the decryption key. If the signature does not match, the agent will exit with no output.

The code previously directly exec()'d the resulting code, however, it simply outputs to stdout now. The resulting code would otherwise execute directly in-line, at that location in the program, which has many undesirable consequences. Piping it to a file and executing, piping it to a memory-backed temporary file and executing it, or placing the resulting code directly in memory afterward and then executing it, are all ways to run the code contained within. This makes it fundamentally little different from encrypting a file directly, except that the key is environmentally generated, perhaps by a daemon that feeds environmental observations on the command line to the agent.

Note, you can encrypt more than Python scripts, and agents can be made to contain themselves.

$ ./agent_generator.py plaincode.py 0 > cipheragent.py

$ ./agent_generator.py cipheragent.py some more observations > double_agent.py

$ ./double_agent.py wrong observations

--nothing here--

$ ./double_agent.py some more observations > cipheragent_2.py

--cipheragent_2.py now holds the same content as cipheragent.py--

$ ./cipheragent.py 0 > plaincode_2.py

--plaincode_2.py now holds the same content as plaincode.py--

$ ./plaincode_2.py

--should yield the same as--

$ ./plaincode.py

Initial Title
A Clueless Agent Generator for Python 3.2

Initial Tags


Initial Language
Python