2016-08-17 8 views
-1

私のクライアントコードはここにあります。暗号化されたデータをクライアントに送信する方法は?

import socket, pickle,time 

from encryption import * 

def Main(): 

    host = '127.0.0.1' 
    port = 5006 
    s = socket.socket() 
    s.connect((host, port)) 
    m= encryption() 
    pri_key,pub_key,n=m.generating_keys(1) 
    filename = input("Filename? -> ") 

    if filename != 'q': 
     data=[filename,pub_key,n] 
     msg=pickle.dumps(data) 
     s.send(msg) 
     data = s.recv(1024) 
     data=data.decode('utf-8') 
     if data == '1': 
      size = s.recv(1024) 
      size = int(size.decode('utf-8')) 
      filesize = size 
      message = input("File exists, " + str(filesize) +"Bytes, download? (Y/N)? -> ") 
      if message == 'Y': 
       s.send(b'1') 
       count=0 
       f = open('new_'+filename, 'wb') 
       data = s.recv(1024) 
       data=int.from_bytes(data,byteorder="little") 
       msg=m.decrypt(data,pri_key,n) 
       totalRecv = len(msg) 
       f.write(msg) 
       #count=0 
       while totalRecv<filesize: 
        #time.sleep(.300) 
        decipher = s.recv(1024) 
        decipher=int.from_bytes(decipher,byteorder="little") 
        print(decipher) 
        if(decipher==0): 
         break 
        msg=m.decrypt(decipher,pri_key,n) 
        totalRecv += len(msg) 
        f.write(msg) 
        print ("{0:.2f}".format((totalRecv/float(filesize))*100)+ "% Done") 
       print ("Download Complete!") 
       f.close() 
     else: 
      print ("File Does Not Exist!") 
    s.close() 
if __name__ == '__main__': 

    Main() 

ここは私のサーバーコードです。

import socket,threading,os,pickle 

from encryption import * 

def RetrFile(name, sock): 

    m=encryption() 
    filename = sock.recv(1024) 
    dat=pickle.loads(filename) 
    if os.path.isfile(dat[0]): 
     s='1' 
     s=s.encode('utf-8') 
     sock.send(s) 
     k=str(os.path.getsize(dat[0])) 
     k=k.encode('utf-8') 
     sock.send(k) 
     count=8 
     userResponse = sock.recv(1024) 
     if userResponse[:2] == (b'1'): 
      with open(dat[0],'rb') as f: 
       bytesToSend = f.read(1024) 
       #print(type(bytesToSend)) 
       #print('1') 
       #print(bytesToSend) 
       msg= m.encrypt(bytesToSend,dat[1],dat[2]) 
       #print(msg) 
       #print(1) 
       k=msg.bit_length() 
       if(k%8>=1): 
        k=k+1 
       msg=msg.to_bytes(k,byteorder="little") 
       #print (msg) 
       #msg=msg.encode('utf-8') 
       #print(msg) 
       sock.send(msg) 
       s='' 
       s=s.encode('utf-8') 
       while bytesToSend != s: 

        bytesToSend = f.read(1024) 
        msg= m.encrypt(bytesToSend,dat[1],dat[2]) 
        k=msg.bit_length() 
        if(k%8>=1): 
         k=k//8+1 
        msg=msg.to_bytes(k,byteorder="little") 
        sock.send(msg) 
       #count=count.to_bytes(1,byteorder="little") 
       #sock.send(count)  
    else: 
     sock.send(b'ERR') 

    sock.close() 

def Main(): 

    host = '127.0.0.1' 
    port = 5006 


    s = socket.socket() 
    s.bind((host,port)) 

    s.listen(5) 
    print ("Server Started.") 
    while True: 
     c, addr = s.accept() 
     print ("client connedted ip:<" + str(addr) + ">") 
     t = threading.Thread(target=RetrFile, args=("RetrThread", c)) 
     t.start()   
    s.close() 
if __name__ == '__main__': 

    Main() 

私の問題は、クライアント側のdecipher.recv(1024)がメッセージを受信して​​いないことです。私は何をすべきか。サーバー側では

+5

あなたは、これが**最小**再現性の一例であることを確認していますか?トレースバックもデバッグもあなたの側では必要ありません。これは、完全なコードダンプとそれに続く「何をしますか?」というものです。私たちがあなたを助けるために、あなたの質問にもっと力を入れるべきです。 –

+0

私のコードは実行されていますが、結果はサーバーによって送信されますrecvの部分で同じではありません。これはdecipher = s.recv()が正しいデータを取得していないことを意味します。私もpickleを使用して、 、私は入力エラーを使い果たしました。したがって、クライアントにデータを送信する方法があれば、教えてください。 –

+2

'encryption'クラスへのリンクを提供します。コードは暗号化なしで動作しますか?ところで、「m」は本当にいい名前です、私にとっては短くて意味のないようです。命名は本当に重要であり、コードの文書のかなりの部分です。 – zaph

答えて

0

にコードを変更:

while bytesToSend != s: 
    bytesToSend = f.read(1024) 
    length = len(bytesTosend) 
    leng = length.to_bytes(4, 'little') 
    sock.sendall(leng) 
    msg = m.encrypt(bytesToSend, dat[1], dat[2]) 
    k = msg.bit_length() 
    if k % 8 >= 1 : 
     k = k // 8 + 1 
    else: 
     k = k // 8 
    msg = msg.to_bytes(k, byteorder='little') 
    sock.sendall(msg) 

とクライアント側で:

while True: 
    length = s.recv(4) 
    length = int.from_bytes(length, byteorder='little') 
    decipher = s.recv(leng) 
    decipher = int.from_bytes(decipher, byteorder='little') 
    if not decipher: 
     break 
    msg = m.decrypt(decipher, pri_key, n) 
    f.write(msg) 
f.close() 
0

あなたで参照encryptionモジュールを見ることなく、あなたのコードを確認することはかなり困難ですコード。このような機能がないと、問題がどこにあるかを調べるテストが不可能になります。したがって、次のプログラムが、別の暗号化モジュールの実装とともに提供されます。


サーバーはコマンドラインから実行し、実行時にポート番号とパスワードを入力する必要があります。使用される認証または許可の唯一の形式は、クライアントの適切な理解です。クライアントは、サーバーが理解するために同じパスワードを使用する必要があります。

#! /usr/bin/env python3 
import argparse 
import pathlib 
import pickle 
import pickletools 
import random 
import socket 
import socketserver 
import zlib 


import encryption 
BYTES_USED = bytes(range(1 << 8)) 
CHAIN_SIZE = 1 << 8 


def main(): 
    """Start a file server and serve clients forever.""" 
    parser = argparse.ArgumentParser(description='Execute a file server demo.') 
    parser.add_argument('port', type=int, help='location where server listens') 
    parser.add_argument('password', type=str, help='key to use on secure line') 
    arguments = parser.parse_args() 
    server_address = socket.gethostbyname(socket.gethostname()), arguments.port 
    server = CustomServer(server_address, CustomHandler, arguments.password) 
    server.serve_forever() 


class CustomServer(socketserver.ThreadingTCPServer): 

    """Provide server support for the management of encrypted data.""" 

    def __init__(self, server_address, request_handler_class, password): 
     """Initialize the server and keep a set of security credentials.""" 
     super().__init__(server_address, request_handler_class, True) 
     self.key = encryption.Key.new_client_random(
      BYTES_USED, 
      CHAIN_SIZE, 
      random.Random(password) 
     ) 
     self.primer = encryption.Primer.new_client_random(
      self.key, 
      random.Random(password) 
     ) 


class CustomHandler(socketserver.StreamRequestHandler): 

    """Allow forwarding of data to all connected clients.""" 

    def __init__(self, request, client_address, server): 
     """Initialize the handler with security translators.""" 
     self.decoder = encryption.Decrypter(server.key, server.primer) 
     self.encoder = encryption.Encrypter(server.key, server.primer) 
     super().__init__(request, client_address, server) 

    def handle(self): 
     """Run the code to handle clients while dealing with errors.""" 
     try: 
      self.process_file_request() 
     except (ConnectionResetError, EOFError): 
      pass 

    def process_file_request(self): 
     """Deal with clients that wish to download a file.""" 
     segment = self.load() 
     path = pathlib.Path(segment) 
     if path.is_file(): 
      size = path.stat().st_size 
      self.dump(size) 
      accepted = self.load() 
      if accepted: 
       with path.open('rb') as file: 
        while True: 
         buffer = file.read(1 << 15) 
         self.dump(buffer) 
         if not buffer: 
          break 
     else: 
      error = 'The given path does not specify a file.' 
      self.dump(error) 

    def load(self): 
     """Read the client's connection with blocking.""" 
     data = self.decoder.load_16bit_frame(self.rfile) 
     bytes_object = zlib.decompress(data) 
     return pickle.loads(bytes_object) 

    def dump(self, obj): 
     """Send an object securely over to the client if possible.""" 
     pickle_string = pickle.dumps(obj, pickle.HIGHEST_PROTOCOL) 
     bytes_object = pickletools.optimize(pickle_string) 
     data = zlib.compress(bytes_object, zlib.Z_BEST_COMPRESSION) 
     self.encoder.dump_16bit_frame(data, self.wfile) 


if __name__ == '__main__': 
    main() 

Serverは、クライアントは、コマンドラインから実行すると、ホスト名、ポート番号、およびサーバー用のパスワードを必要としなければなりません。通信はパスワードで暗号化されており、異なる場合は正しく復号化できません。 2つのプログラムにはエラーチェックがほとんどありませんのでご注意ください。 encryptionモジュールへのアクセスが提供されなかったので

クライアント

#! /usr/bin/env python3 
import argparse 
import pathlib 
import pickle 
import pickletools 
import random 
import socket 
import zlib 


import encryption 
BYTES_USED = bytes(range(1 << 8)) 
CHAIN_SIZE = 1 << 8 


# These are possible answers accepted for yes/no style questions. 
POSITIVE = tuple(map(str.casefold, ('yes', 'true', '1'))) 
NEGATIVE = tuple(map(str.casefold, ('no', 'false', '0'))) 


def main(): 
    """Connect a file client to a server and process incoming commands.""" 
    parser = argparse.ArgumentParser(description='Execute a file client demo.') 
    parser.add_argument('host', type=str, help='name of server on the network') 
    parser.add_argument('port', type=int, help='location where server listens') 
    parser.add_argument('password', type=str, help='key to use on secure line') 
    arguments = parser.parse_args() 
    connection = socket.create_connection((arguments.host, arguments.port)) 
    try: 
     talk_to_server(*make_dump_and_load(connection, arguments.password)) 
    finally: 
     connection.shutdown(socket.SHUT_RDWR) 
     connection.close() 


def make_dump_and_load(connection, password): 
    """Create objects to help with the encrypted communications.""" 
    reader = connection.makefile('rb', -1) 
    writer = connection.makefile('wb', 0) 
    chaos = random.Random(password) 
    key = encryption.Key.new_client_random(BYTES_USED, CHAIN_SIZE, chaos) 
    chaos = random.Random(password) 
    primer = encryption.Primer.new_client_random(key, chaos) 
    decoder = encryption.Decrypter(key, primer) 
    encoder = encryption.Encrypter(key, primer) 

    def dump(obj): 
     """Write an object to the writer file in an encoded form.""" 
     pickle_string = pickle.dumps(obj, pickle.HIGHEST_PROTOCOL) 
     bytes_object = pickletools.optimize(pickle_string) 
     data = zlib.compress(bytes_object, zlib.Z_BEST_COMPRESSION) 
     encoder.dump_16bit_frame(data, writer) 

    def load(): 
     """Read an object from the reader file and decode the results.""" 
     data = decoder.load_16bit_frame(reader) 
     bytes_object = zlib.decompress(data) 
     return pickle.loads(bytes_object) 

    return dump, load 


def talk_to_server(dump, load): 
    """Converse with the serve while trying to get a file.""" 
    segment = input('Filename: ') 
    dump(segment) 
    size = load() 
    if isinstance(size, int): 
     print('File exists and takes', size, 'bytes to download.') 
     response = get_response('Continue? ') 
     dump(response) 
     if response: 
      location = input('Where should the new file be created? ') 
      with pathlib.Path(location).open('wb') as file: 
       written = 0 
       while True: 
        buffer = load() 
        if not buffer: 
         break 
        written += file.write(buffer) 
        print('Progress: {:.1%}'.format(written/size)) 
      print('Download complete!') 
    else: 
     print(size) 


def get_response(query): 
    """Ask the user yes/no style questions and return the results.""" 
    while True: 
     answer = input(query).casefold() 
     if answer: 
      if any(option.startswith(answer) for option in POSITIVE): 
       return True 
      if any(option.startswith(answer) for option in NEGATIVE): 
       return False 
     print('Please provide a positive or negative answer.') 


if __name__ == '__main__': 
    main() 

、代替の実装は、以下に含まれています。容量または目的にかかわらず、その適合性が保証されていません。ソフトウェアが現在構成されているのでやや遅いかもしれませんが、難読化が必要な場合はうまくいきます。

暗号

"""Provide an implementation of Markov Encryption for simplified use. 

This module exposes primitives useful for executing Markov Encryption 
processes. ME was inspired by a combination of Markov chains with the 
puzzles of Sudoku. This implementation has undergone numerous changes 
and optimizations since its original design. Please see documentation.""" 

############################################################################### 

# Import several functions needed later in the code. 

from collections import deque 
from math import ceil 
from random import Random, SystemRandom 
from struct import calcsize, pack, unpack 
from inspect import currentframe 

__author__ = 'Stephen "Zero" Chappell <[email protected]>' 
__date__ = '18 August 2016' 
__version__ = 2, 0, 8 

############################################################################### 

# Create some tools to use in the classes down below. 

_CHAOS = SystemRandom() 


def slots(names=''): 
    """Set the __slots__ variable in the calling context with private names. 

    This function allows a convenient syntax when specifying the slots 
    used in a class. Simply call it in a class definition context with 
    the needed names. Locals are modified with private slot names.""" 
    currentframe().f_back.f_locals['__slots__'] = \ 
     tuple('__' + name for name in names.replace(',', ' ').split()) 

############################################################################### 

# Implement a Key primitive data type for Markov Encryption. 


class Key: 

    """Key(data) -> Key instance 

    This class represents a Markov Encryption Key primitive. It allows for 
    easy key creation, checks for proper data construction, and helps with 
    encoding and decoding indexes based on cached internal tables.""" 

    slots('data dimensions base size encoder axes order decoder') 

    @classmethod 
    def new(cls, bytes_used, chain_size): 
     """Return a Key instance created from bytes_used and chain_size. 

     Creating a new key is easy with this method. Call this class method 
     with the bytes you want the key to recognize along with the size of 
     the chains you want the encryption/decryption processes to use.""" 
     selection, blocks = list(set(bytes_used)), [] 
     for _ in range(chain_size): 
      _CHAOS.shuffle(selection) 
      blocks.append(bytes(selection)) 
     return cls(tuple(blocks)) 

    @classmethod 
    def new_deterministic(cls, bytes_used, chain_size): 
     """Automatically create a key with the information provided.""" 
     selection, blocks, chaos = list(set(bytes_used)), [], Random() 
     chaos.seed(chain_size.to_bytes(ceil(
      chain_size.bit_length()/8), 'big') + bytes(range(256))) 
     for _ in range(chain_size): 
      chaos.shuffle(selection) 
      blocks.append(bytes(selection)) 
     return cls(tuple(blocks)) 

    @classmethod 
    def new_client_random(cls, bytes_used, chain_size, chaos): 
     """Create a key using chaos as the key's source of randomness.""" 
     selection, blocks = list(set(bytes_used)), [] 
     for _ in range(chain_size): 
      chaos.shuffle(selection) 
      blocks.append(bytes(selection)) 
     return cls(tuple(blocks)) 

    def __init__(self, data): 
     """Initialize the Key instance's variables after testing the data. 

     Keys are created with tuples of carefully constructed bytes arrays. 
     This method tests the given data before going on to build internal 
     tables for efficient encoding and decoding methods later on.""" 
     self.__test_data(data) 
     self.__make_vars(data) 

    @staticmethod 
    def __test_data(data): 
     """Test the data for correctness in its construction. 

     The data must be a tuple of at least two byte arrays. Each byte 
     array must have at least two bytes, all of which must be unique. 
     Furthermore, all arrays should share the exact same byte set.""" 
     if not isinstance(data, tuple): 
      raise TypeError('Data must be a tuple object!') 
     if len(data) < 2: 
      raise ValueError('Data must contain at least two items!') 
     item = data[0] 
     if not isinstance(item, bytes): 
      raise TypeError('Data items must be bytes objects!') 
     length = len(item) 
     if length < 2: 
      raise ValueError('Data items must contain at least two bytes!') 
     unique = set(item) 
     if len(unique) != length: 
      raise ValueError('Data items must contain unique byte sets!') 
     for item in data[1:]: 
      if not isinstance(item, bytes): 
       raise TypeError('Data items must be bytes objects!') 
      next_length = len(item) 
      if next_length != length: 
       raise ValueError('All data items must have the same size!') 
      next_unique = set(item) 
      if len(next_unique) != next_length: 
       raise ValueError('Data items must contain unique byte sets!') 
      if next_unique^unique: 
       raise ValueError('All data items must use the same byte set!') 

    def __make_vars(self, data): 
     """Build various internal tables for optimized calculations. 

     Encoding and decoding rely on complex relationships with the given 
     data. This method caches several of these key relationships for use 
     when the encryption and decryption processes are being executed.""" 
     self.__data = data 
     self.__dimensions = len(data) 
     base, *mutations = data 
     self.__base = base = tuple(base) 
     self.__size = size = len(base) 
     offset = -sum(base.index(block[0]) for block in mutations[:-1]) % size 
     self.__encoder = base[offset:] + base[:offset] 
     self.__axes = tuple(reversed([tuple(base.index(byte) for byte in block) 
             for block in mutations])) 
     self.__order = key = tuple(sorted(base)) 
     grid = [] 
     for rotation in range(size): 
      block, row = base[rotation:] + base[:rotation], [None] * size 
      for byte, value in zip(block, key): 
       row[key.index(byte)] = value 
      grid.append(tuple(row)) 
     self.__decoder = tuple(grid[offset:] + grid[:offset]) 

    def test_primer(self, primer): 
     """Raise an error if the primer is not compatible with this key. 

     Key and primers have a certain relationship that must be maintained 
     in order for them to work together. Since the primer understands 
     the requirements, it is asked to check this key for compatibility.""" 
     primer.test_key(self) 

    def encode(self, index): 
     """Encode index based on internal tables and return byte code. 

     An index probes into the various axes of the multidimensional, 
     virtual grid that a key represents. The index is evaluated, and 
     the value at its coordinates is returned by running this method.""" 
     assert len(index) == self.__dimensions, \ 
      'Index size is not compatible with key dimensions!' 
     *probes, current = index 
     return self.__encoder[(sum(
      table[probe] for table, probe in zip(self.__axes, probes) 
     ) + current) % self.__size] 

    def decode(self, index): 
     """Decode index based on internal tables and return byte code. 

     Decoding does the exact same thing as encoding, but it indexes 
     into a virtual grid that represents the inverse of the encoding 
     grid. Tables are used to make the process fast and efficient.""" 
     assert len(index) == self.__dimensions, \ 
      'Index size is not compatible with key dimensions!' 
     *probes, current = index 
     return self.__decoder[sum(
      table[probe] for table, probe in zip(self.__axes, probes) 
     ) % self.__size][current] 

    @property 
    def data(self): 
     """Data that the instance was initialized with. 

     This is the tuple of byte arrays used to create this key and can 
     be used to create an exact copy of this key at some later time.""" 
     return self.__data 

    @property 
    def dimensions(self): 
     """Dimensions that the internal, virtual grid contains. 

     The virtual grid has a number of axes that can be referenced when 
     indexing into it, and this number is the count of its dimensions.""" 
     return self.__dimensions 

    @property 
    def base(self): 
     """Base value that the internal grid is built from. 

     The Sudoku nature of the grid comes from rotating this value by 
     offsets, keeping values unique along any axis while traveling.""" 
     return self.__base 

    @property 
    def order(self): 
     """Order of base after its values have been sorted. 

     A sorted base is important when constructing inverse rows and when 
     encoding raw bytes for use in updating an encode/decode index.""" 
     return self.__order 

############################################################################### 

# Implement a Primer primitive data type for Markov Encryption. 


class Primer: 

    """Primer(data) -> Primer instance 

    This class represents a Markov Encryption Primer primitive. It is very 
    important for starting both the encryption and decryption processes. A 
    method is provided for their easy creation with a related key.""" 

    slots('data') 

    @classmethod 
    def new(cls, key): 
     """Return a Primer instance from a parent Key. 

     Primers must be compatible with the keys they are used with. This 
     method takes a key and constructs a cryptographically sound primer 
     that is ready to use in the beginning stages of encryption.""" 
     base = key.base 
     return cls(bytes(_CHAOS.choice(base) 
         for _ in range(key.dimensions - 1))) 

    @classmethod 
    def new_deterministic(cls, key): 
     """Automatically create a primer with the information provided.""" 
     base, chain_size, chaos = key.base, key.dimensions, Random() 
     chaos.seed(chain_size.to_bytes(ceil(
      chain_size.bit_length()/8), 'big') + bytes(range(256))) 
     return cls(bytes(chaos.choice(base) for _ in range(chain_size - 1))) 

    @classmethod 
    def new_client_random(cls, key, chaos): 
     """Create a primer using chaos as the primer's source of randomness.""" 
     base = key.base 
     return cls(
      bytes(chaos.choice(base) for _ in range(key.dimensions - 1)) 
     ) 

    def __init__(self, data): 
     """Initialize the Primer instance after testing validity of data. 

     Though not as complicated in its requirements as keys, primers do 
     need some simple structure in the data they are given. A checking 
     method is run before saving the data to the instance's attribute.""" 
     self.__test_data(data) 
     self.__data = data 

    @staticmethod 
    def __test_data(data): 
     """Test the data for correctness and test the data. 

     In order for the primer to be compatible with the nature of the 
     Markov Encryption processes, the data must be an array of bytes; 
     and to act as a primer, it must contain at least some information.""" 
     if not isinstance(data, bytes): 
      raise TypeError('Data must be a bytes object!') 
     if not data: 
      raise ValueError('Data must contain at least one byte!') 

    def test_key(self, key): 
     """Raise an error if the key is not compatible with this primer. 

     Primers provide needed data to start encryption and decryption. For 
     it be compatible with a key, it must contain one byte less than the 
     key's dimensions and must be a subset of the base in the key.""" 
     if len(self.__data) != key.dimensions - 1: 
      raise ValueError('Key size must be one more than the primer size!') 
     if not set(self.__data).issubset(key.base): 
      raise ValueError('Key data must be a superset of primer data!') 

    @property 
    def data(self): 
     """Data that the instance was initialized with. 

     This is the byte array used to create this primer and can be used 
     if desired to create an copy of this primer at some later time.""" 
     return self.__data 

############################################################################### 

# Create an abstract processing class for use in encryption and decryption. 


class _Processor: 

    """_Processor(key, primer) -> NotImplementedError exception 

    This class acts as a base for the encryption and decryption processes. 
    The given key is saved, and several tables are created along with an 
    index. Since it is abstract, calling the class will raise an exception.""" 

    slots('key into index from') 

    def __init__(self, key, primer): 
     """Initialize the _Processor instance if it is from a child class. 

     After passing several tests for creating a valid processing object, 
     the key is saved, and the primer is used to start an index. Tables 
     are also formed for converting byte values between systems.""" 
     if type(self) is _Processor: 
      raise NotImplementedError('This is an abstract class!') 
     key.test_primer(primer) 
     self.__key = key 
     self.__into = table = dict(map(reversed, enumerate(key.order))) 
     self.__index = deque(map(table.__getitem__, primer.data), 
          key.dimensions) 
     self.__from = dict(map(reversed, table.items())) 

    def process(self, data): 
     """Process the data and return its transformed state. 

     A cache for the data transformation is created and an internal 
     method is run to quickly encode or decode the given bytes. The 
     cache is finally converted to immutable bytes when returned.""" 
     cache = bytearray() 
     self._run(data, cache.append, self.__key, self.__into, self.__index) 
     return bytes(cache) 

    @staticmethod 
    def _run(data, cache_append, key, table, index): 
     """Run the processing algorithm in an overloaded method. 

     Since this is only an abstract base class for encoding/decoding, 
     this method will raise an exception when run. Inheriting classes 
     should implement whatever is appropriate for the intended function.""" 
     raise NotImplementedError('This is an abstract method!') 

    @property 
    def primer(self): 
     """Primer representing the state of the internal index. 

     The index can be retrieved as a primer, useful for initializing 
     another processor in the same starting state as the current one.""" 
     index = self.__index 
     index.append(None) 
     index.pop() 
     return Primer(bytes(map(self.__from.__getitem__, index))) 

############################################################################### 

# Inherit from _Processor and implement the ME encoding algorithm. 


class Encrypter(_Processor): 

    """Encrypter(key, primer) -> Encrypter instance 

    This class represents a state-aware encryption engine that can be fed 
    data and will return a stream of coherent cipher-text. An index is 
    maintained, and a state-continuation primer can be retrieved at will.""" 

    slots() 

    @staticmethod 
    def _run(data, cache_append, key, table, index): 
     """Encrypt the data with the given arguments. 

     To run the encryption process as fast as possible, methods are 
     cached as names. As the algorithm operates, only recognized bytes 
     are encoded while running through the selective processing loop.""" 
     encode, index_append = key.encode, index.append 
     for byte in data: 
      if byte in table: 
       index_append(table[byte]) 
       cache_append(encode(index)) 
      else: 
       cache_append(byte) 

    def dump_16bit_frame(self, data, file): 
     """Write the data to the file using a guaranteed frame size.""" 
     size = len(data) 
     if not 1 <= size <= 1 << 16: 
      raise ValueError('data has an unsupported length') 
     packed = self.process(pack('<H{}s'.format(size), size - 1, data)) 
     if file.write(packed) != len(packed): 
      raise IOError('frame was not properly written to file') 

############################################################################### 

# Inherit from _Processor and implement the ME decoding algorithm. 


class Decrypter(_Processor): 

    """Decrypter(key, primer) -> Decrypter instance 

    This class represents a state-aware decryption engine that can be fed 
    data and will return a stream of coherent plain-text. An index is 
    maintained, and a state-continuation primer can be retrieved at will.""" 

    slots() 

    SIZE = '<H' 
    DATA = '{}s' 

    @staticmethod 
    def _run(data, cache_append, key, table, index): 
     """Decrypt the data with the given arguments. 

     To run the decryption process as fast as possible, methods are 
     cached as names. As the algorithm operates, only recognized bytes 
     are decoded while running through the selective processing loop.""" 
     decode, index_append = key.decode, index.append 
     for byte in data: 
      if byte in table: 
       index_append(table[byte]) 
       value = decode(index) 
       cache_append(value) 
       index[-1] = table[value] 
      else: 
       cache_append(byte) 

    def load_16bit_frame(self, file): 
     """Read some data from the file using a guaranteed frame size.""" 
     size = unpack(self.SIZE, self.process(self.read_all(
      file, 
      calcsize(self.SIZE) 
     )))[0] + 1 
     return unpack(self.DATA.format(size), self.process(self.read_all(
      file, 
      size 
     )))[0] 

    @staticmethod 
    def read_all(file, size): 
     """Get all the data that has been requested from the file.""" 
     if not 1 <= size <= 1 << 16: 
      raise ValueError('size has an unsupported value') 
     buffer = bytearray() 
     while size > 0: 
      data = file.read(size) 
      if not data: 
       raise EOFError('file has unexpectedly reached the end') 
      buffer.extend(data) 
      size -= len(data) 
     if size < 0: 
      raise IOError('more data was read than was required') 
     return bytes(buffer) 
+0

@BikashGuptaそれは見て素晴らしいです! ["誰かが私の質問に答えるとどうすればいいですか?"](http://stackoverflow.com/help/someone-answers)ヘルプセンターは、 StackOverflowコミュニティ。 –

関連する問題