与pycrypto混淆间歇性失败

时间:2012-08-31 18:51:17

标签: pycrypto

我一直在玩python的加密库,我构建了一个简单的线程服务器来加密和解密。我遇到的问题是大约有三分之一的解密错误地回来了。这是代码:

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);
}

1 个答案:

答案 0 :(得分:1)

在您的解密例程中,您使用:

 unhexed.split('|')

找到IV和密文之间的边界。但是,IV是由发送者随机生成的。有时,它的16个字节中的一个将是124,即边界字符“|”。

当发生这种情况时(大约6%的情况),解密例程将使用

初始化密码
  • 长度介于1到15个字节之间的IV,这会导致异常或
  • 长度为0的IV,导致解密不正确,因为在PyCrypto版本<2.6中,默认情况下将使用全零16字节IV

在解密例程中你应该改为:

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

或者你可以摆脱'|'分离器。