1

私は python の crypto ライブラリで遊んでいて、暗号化と復号化を行う単純なスレッド サーバーを構築しました。私が抱えている問題は、3 回の復号のうち約 1 回が正しく返されないことです。コードは次のとおりです。

class ThreadedTCPRequestHandler(SocketServer.BaseRequestHandler):

    def handle(self):
        global KEY
        request_text = ''
        while request_text.rfind("\n") == -1:
            sock_data='';
            recv_size=8192
            sock_data=self.request.recv(recv_size)
            if sock_data == '':
                print "hangup"
                break
            request_text = request_text + sock_data

        args = json.loads(request_text)
        print request_text
        print "\n"
        if args['command'] == 'encrypt':
            iv = Random.new().read(AES.block_size)
            cipher = AES.new(KEY, AES.MODE_CFB, iv)
            crypted_message = iv + b'|' + cipher.encrypt(unquote_plus(args['message']))
            response = {'encrypted_message': binascii.hexlify(crypted_message)}

        if args['command'] == 'decrypt':
            unhexed = binascii.unhexlify(args['message'])
            components = unhexed.split('|')
            iv = components[0]
            cipher = AES.new(KEY, AES.MODE_CFB, iv)
            decrypted_message = cipher.decrypt(components[1])
            response = {'decrypted_message': decrypted_message}

        self.request.sendall(json.dumps(response) + "\n")

多くの場合、Python から次のエラーが発生します。

    Traceback (most recent call last):
  File "/usr/local/lib/python2.7/SocketServer.py", line 582, in process_request_thread
    self.finish_request(request, client_address)
  File "/usr/local/lib/python2.7/SocketServer.py", line 323, in finish_request
    self.RequestHandlerClass(request, client_address, self)
  File "/usr/local/lib/python2.7/SocketServer.py", line 639, in __init__
    self.handle()
  File "cryptoserver.py", line 40, in handle
    cipher = AES.new(KEY, AES.MODE_CFB, iv)
  File "build/bdist.macosx-10.4-x86_64/egg/Crypto/Cipher/AES.py", line 95, in new
    return AESCipher(key, *args, **kwargs)
  File "build/bdist.macosx-10.4-x86_64/egg/Crypto/Cipher/AES.py", line 59, in __init__
    blockalgo.BlockAlgo.__init__(self, _AES, key, *args, **kwargs)
  File "build/bdist.macosx-10.4-x86_64/egg/Crypto/Cipher/blockalgo.py", line 141, in __init__
    self._cipher = factory.new(key, *args, **kwargs)
ValueError: IV must be 16 bytes long
----------------------------------------

同じように、エラーは発生しませんが、復号化は正しく機能しません。このphpを使用してテストしています:

<?php
include_once("config.php");

function encrypt($text) {
    $package = array("command" => "encrypt",
                    "message" => base64_encode($text));
    $package_json = json_encode($package);
    $serverSays = transmit($package_json);
    $serverSaysArray = json_decode($serverSays);
    return $serverSaysArray->encrypted_message;
}

function decrypt($text) {
    $package = array("command" => "decrypt",
                    "message" => $text);

    $package_json = json_encode($package);
    $serverSays = transmit($package_json);
    $serverSaysArray = json_decode($serverSays);
    return base64_decode($serverSaysArray->decrypted_message);
}

function transmit($package) {
    global $CRYPTO_PORT;
    global $CRYPTO_HOST;

    $serverLink = fsockopen($CRYPTO_HOST, $CRYPTO_PORT);
    if ($serverLink === FALSE) {
        error_log("Could not connect to encryption server");
        return FALSE;
    }
    fwrite($serverLink, $package . "\n");

    $response = '';
    while (!feof($serverLink)) {
        $response .= fgets($serverLink, 128);
    }
    fclose($serverLink);
    return $response;
}

while (TRUE) {
    $enc = encrypt('totsadaddywoopxxx');
    print "$enc\n";
    $dec = decrypt($enc);
    print "$dec\n";
    $enc = encrypt('totsadaddywoopxxx');
    print "$enc\n";
    $dec = decrypt($enc);
    print "$dec\n";
    $enc = encrypt('totsadaddywoopxxx');
    print "$enc\n";
    $dec = decrypt($enc);
    print "$dec\n";
    #print decrypt('1c6dee677126551fa4b3f0732986dc3b7c985c64c07075e3651213d7a69435bcd87083e729e8de860c');
    #print "\n";
    #print decrypt('550cbec7498371dc01bcd6b88fc623b47cb2efd1881da6e07ee992229308305992bbc7ccc374f00c91d56d10a68d6110e2');
    print "===========================\n";

    sleep(1);
}
4

1 に答える 1

1

復号化ルーチンでは、次を使用します。

 unhexed.split('|')

IV と暗号文の境界を見つけます。ただし、IV は送信者によってランダムに生成されます。その 16 バイトの 1 つが 124、つまり境界文字 '|' になる場合があります。

これが発生すると (約 6% のケースで)、復号化ルーチンは暗号を次のいずれかで初期化します。

  • 長さが 1 ~ 15 バイトの IV (例外が発生する)、または
  • 長さ 0 の IV。PyCrypto バージョン <2.6 では、すべてゼロの 16 バイト IV がデフォルトで使用されるため、誤った復号化につながります。

復号化ルーチンでは、代わりに次のものが必要です。

components = [ unhexed[:AES.block_size], unhexed[AES.block_size+1:] ]

または、「|」を取り除くこともできます 全体的にセパレーター。

于 2012-08-31T19:43:39.520 に答える