ValueError: слишком большая последовательность;не может быть больше 32 - PullRequest
0 голосов
/ 23 января 2019

Я написал этот код:

from Crypto.Cipher import AES
import numpy as np
import cv2, base64

BLOCK_SIZE = 16
PADDING = '{'

pad = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * PADDING

EncodeAES = lambda c, s: base64.b64encode(c.encrypt(pad(s)))
DecodeAES = lambda c, e: c.decrypt(base64.b64decode(e)).rstrip(PADDING)

secret = "youwanttoknowmysecretdontyouhaha"
cipher = AES.new(secret)

video = cv2.VideoCapture(0)
a = 0

while True:
    a = a + 1

    check, frame = video.read()

    encrypted = EncodeAES(cipher, str(frame))

    img = DecodeAES(cipher, encrypted)

    cv2.imshow("Capturing", np.ndarray(img))
    key = cv2.waitKey(1)

    if key == ord('q'):
        break

Но это не работает так, как должно.

Я хочу, чтобы он воспроизводил мою живую камеру, но выдает следующую ошибку:

Traceback (последний вызов был последним): файл "tester.py", строка 28, в cv2.imshow ("Захват", np.ndarray (img)) ValueError: слишком большая последовательность; не может быть больше 32

Мне бы очень хотелось узнать, что я делаю неправильно, и не дать мне только решение, но объяснить, пожалуйста, я все еще учусь

EDIT

Я использую Python 2.7

EDIT

Следующий код работает, но я использую его в программе, где хост отправляет зашифрованные на другой компьютер. В этом случае вы не можете использовать frame.dtype.

from Crypto.Cipher import AES
import numpy as np
import cv2, base64

BLOCK_SIZE = 16
PADDING = '{'

pad = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * PADDING

EncodeAES = lambda c, s: base64.b64encode(c.encrypt(pad(s)))
DecodeAES = lambda c, e: c.decrypt(base64.b64decode(e)).rstrip(PADDING)

secret = "youwanttoknowmysecretdontyouhaha"
cipher = AES.new(secret)

video = cv2.VideoCapture(0)
a = 0

while True:
    a = a + 1

    check, frame = video.read()

    encrypted = EncodeAES(cipher, frame.tobytes())

    decrypted = DecodeAES(cipher, encrypted)

    img = np.frombuffer(decrypted, dtype=frame.dtype).reshape(frame.shape)

    cv2.imshow("Capturing", img)
    key = cv2.waitKey(1)

    if key == ord("q"):
        break

video.release()

Однако я могу отправить frame.dtype на другой компьютер.

Когда я отправляю зашифрованную форму frame.dtype и frame_shape на компьютер, дешифрую и использую ее там, я получаю следующую ошибку

img = np.frombuffer(decod_ed, dtype=img_dtype).reshape(img_shape)
TypeError: data type "ûÿùùÖÿùÖÿùÖÿÖÖÿÖÖÿÜÜÖøøÜ£ÜÖ£ÜÖÜÜÖÜÜÖÿÜÜÿÜÜÿÜøÖø£øøøøøøØ£ÿØ£ÿØ£ÿƒ×ÜØ×Ü׃ø؃ÖøØùØØùØØùƒ£ÿ×øùƒ£ÿƒ£ÿƒø܃øÜíØ£íØ£íØ£ó×Øó×Øó×Øóƒøóƒøúá£óƒøáƒøáƒø׃ø׃ø£ƒø£ƒø£ƒø£ƒøƒ×ÜáƒøúíøúíøÑáøÑáøñ×øу£ñØ×Ñ׃ñáƒñáƒóíØíá£áó£ƒíø×áÜ×áÜøƒÖ£áÜ£ƒø£ƒøƒØ£ƒØ£á×Øá×ØØØ£ØØ£××؃ƒ×ƒƒ×××Ø׃ø׃ø£ƒø£ƒø£×Ø£×Ø£×Ø£×ØØá£Øá£ØíøØíøáó£áó£×ó£Øíø܃øù£ÿôÜÿôÜÿÿÜÜÿÜÜøøøØØØíƒ×óáƒíƒ×íƒ×óáƒóáƒñúƒñúƒªÑíñúƒñúƒñúƒúó×úó×úó×úó×óó£óó£úñøúñøúúØññ×óñ×óñ×óúƒóúƒóóíóóíóúƒñÑíóªááñ××ñ××ñ××úƒáÑí׺á׺á£ñƒ£ñƒáúƒáúƒññúóóíúíáúíáííáññúññúññúñÑíñÑíóúƒñÑíñÑíñÑíóÑíóÑíóúƒóúƒñÑíñÑíñÑíóúƒáúƒóÑíóÑíáúƒƒó×áúƒóÑíóÑíóÑíáúƒáúƒƒó׃ó××íØØíøØíøØóÖØóÖØíø£áÜáá܃ƒÖíƒÖƒØùØ×òƒáùØáùÜØöÜØöÜØöÖ×òÿØöù£ôù£ôûÜöûÜööÜööÜöÆøöÆøööÜööÜöûÜööÿÆûùôûùôÿûòûöôÆöôöûòöûòöûòöûòÆöôÉòæÉòæÉûÉÉûÉÅòÅÅòÅæòÅÉöÄÉöÄÉöÄÉöÄÅôìÉÆîÅæïææïÉÉèÉÅåÉÅåîÅåèìäçîâåïéêîüêîüçï~çï~àïÇàïÇë|å|" not understood

1 Ответ

0 голосов
/ 23 января 2019

Я предполагаю, что frame это [SciPy]: numpy.ndarray . Есть 2 проблемы. Ниже приведен пример:

code.py

#!/usr/bin/env python3

import sys
from Crypto.Cipher import AES
import numpy as np
import cv2
import base64


BLOCK_SIZE = 16
PADDING = b"{"

pad = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * PADDING

EncodeAES = lambda c, s: base64.b64encode(c.encrypt(pad(s)))
DecodeAES = lambda c, e: c.decrypt(base64.b64decode(e)).rstrip(PADDING)

CIPHER_MODE = AES.MODE_CBC
SECRET = b"youwanttoknowmysecretdontyouhaha"


def main():

    img0 = cv2.imread("c:/valmand.png")
    encrypt_cipher = AES.new(SECRET, CIPHER_MODE)  # Python 2: AES.new(SECRET)
    print("Original image data - Type: {:}, Size: {:d}, Attrs: {:}".format(type(img0), img0.size, img0.shape))
    img_stream_wrong = str(img0).encode()
    print("\nWrong img0 stream length: {:}".format(len(img_stream_wrong)))
    print("\nWrong img0 stream: {:}".format(img_stream_wrong))
    img_stream = img0.tobytes()
    print("\nCorrect img0 stream length: {:}".format(len(img_stream)))
    encrypted = EncodeAES(encrypt_cipher, img_stream)
    print("\nEncrypted length: {:d}".format(len(encrypted)))
    decrypt_cipher = AES.new(SECRET, CIPHER_MODE)  # Python 2: AES.new(SECRET)
    decrypted = DecodeAES(decrypt_cipher, encrypted)
    print("\nDecrypted length: {:d}".format(len(decrypted)))
    img1 = np.frombuffer(decrypted, dtype=img0.dtype).reshape(img0.shape)
    print("\nFinal image data - Type: {:}, Size: {:d}, Attrs: {:}".format(type(img1), img1.size, img1.shape))
    #cv2.imshow("Capturing", img1)


if __name__ == "__main__":
    print("Python {:s} on {:s}\n".format(sys.version, sys.platform))
    main()

Примечания

  • Я упростил пример, чтобы загрузить только изображение
  • Поскольку на Python 2 не установлены все необходимые пакеты, я использовал Python 3 . Вот почему были внесены некоторые изменения, не связанные с вопросом:
    • Переключение с строки на байтов
    • AES изменения:
      • AES.new подпись изменена ( [PyCryptodome]: AES )
      • Тот же шифр нельзя использовать для дешифрования после того, как он был использован для шифрования, поэтому создайте другой с теми же свойствами (возможно, есть какой-то более чистый способ сделать это, но я не тратил на него слишком много времени)
  • Ошибки :

    • Как видно, применение str к ndarray дает удобное для пользователя представление этого ndarray , а не его содержимого, поэтому оно будет синтаксически правильно, но семантически неправильно
      • Чтобы исправить это, массив должен быть правильно сериализован, используя тобайт метод
    • И наоборот, при попытке десериализации конструктор ndarray вызывается в байтовом потоке (который молча преобразуется в кортеж из int s - что ожидает конструктор - имеет ту же длину, что и поток)

      • Проблема здесь в том, что конструктор не принимает последовательности, большие чем 32 :

        >>> np.ndarray([0] * 32)
        array([], shape=(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
              dtype=float64)
        >>> np.ndarray([0] * 33)
        Traceback (most recent call last):
          File "<stdin>", line 1, in <module>
        ValueError: sequence too large; cannot be greater than 32
        
      • Чтобы исправить это, следует использовать [SciPy]: numpy.frombuffer . Чтобы новый ndarray был равен исходному, требуется еще 2 вещи (данные из оригинала):

        • Должен быть указан dtype (по умолчанию float и нам нужно uint8 )
        • Необходимо изменить

выход

e:\Work\Dev\StackOverflow\q054326620>"e:\Work\Dev\VEnvs\py_064_03.06.08_test0\Scripts\python.exe" code.py
Python 3.6.8 (tags/v3.6.8:3c6b436a57, Dec 24 2018, 00:16:47) [MSC v.1916 64 bit (AMD64)] on win32

Original image data - Type: <class 'numpy.ndarray'>, Size: 1493331, Attrs: (799, 623, 3)

Wrong img0 stream length: 629

Wrong img0 stream: b'[[[255 255 255]\n  [255 255 255]\n  [255 255 255]\n  ...\n  [255 255 255]\n  [255 255 255]\n  [255 255 255]]\n\n [[255 255 255]\n  [255 255 255]\n  [255 255 255]\n  ...\n  [255 255 255]\n  [255 255 255]\n  [255 255 255]]\n\n [[255 255 255]\n  [255 255 255]\n  [255 255 255]\n  ...\n  [255 255 255]\n  [255 255 255]\n  [255 255 255]]\n\n ...\n\n [[255 255 255]\n  [255 255 255]\n  [255 255 255]\n  ...\n  [255 255 255]\n  [255 255 255]\n  [255 255 255]]\n\n [[255 255 255]\n  [255 255 255]\n  [255 255 255]\n  ...\n  [255 255 255]\n  [255 255 255]\n  [255 255 255]]\n\n [[255 255 255]\n  [255 255 255]\n  [255 255 255]\n  ...\n  [255 255 255]\n  [255 255 255]\n  [255 255 255]]]'

Correct img0 stream length: 1493331

Encrypted length: 1991128

Decrypted length: 1493331

Final image data - Type: <class 'numpy.ndarray'>, Size: 1493331, Attrs: (799, 623, 3)

@ EDIT0

Видимо, есть некоторые проблемы с совместимостью. Я разработал ответ, используя Python 3 и pycrpytodome 3.7.2 . Я обновил до последней ( 3.7.3 ), я также установил его на Python 2 , и приведенный выше код работает. Вот что я получаю в консоли:

>>> from Crypto.Cipher import AES
>>> AES
<module 'Crypto.Cipher.AES' from 'e:\Work\Dev\VEnvs\py_064_02.07.15_test0\lib\site-packages\Crypto\Cipher\AES.pyc'>
>>> AES.new("")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: new() takes at least 2 arguments (1 given)
>>> import Crypto
>>> Crypto.__version__
'3.7.3'

Итак, у вас, вероятно, ужасно старая pycryptodome версия. В любом случае, я вслепую отправляю изменения, требуемые вашим кодом, чтобы включить исправления (, в то время как цикл только ):

# The rest of your code (exactly as in the question)

while True:
    a = a + 1

    check, frame = video.read()

    original_meta = frame.dtype.name, frame.shape

    encrypted_meta = EncodeAES(cipher, bytes(original_meta))
    encrypted_data = EncodeAES(cipher, frame.tobytes())

    # Here is the separation

    decrypted_meta = DecodeAES(cipher, encrypted_meta)
    decrypted_data = DecodeAES(cipher, encrypted_data)

    meta = ast.literal_eval(decrypted_meta)

    img = np.frombuffer(decrypted_data, dtype=np.dtype(meta[0])).reshape(meta[1])

    cv2.imshow("Capturing", img)
    key = cv2.waitKey(1)

    if key == ord("q"):
        break
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...