# Copyright (c) 2013 Stefano Palazzo <stefano.palazzo@gmail.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import unittest
import os

from pcr.aes import AES


class AESTest(unittest.TestCase):

    def test_key_schedule(self):
        a = AES()
        self.assertEqual(a.rijndael_key_schedule(b"\1" * 16), bytearray(
            b"\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01"
            b"\x01|}}}}||||}}}}|||nmm\x82\x13\x11\x11\xfeoll\x83\x12\x10"
            b"\x10\xff\xa0\xa7{K\xb3\xb6j\xb5\xdc\xda\x066\xce\xca\x16\xc9"
            b"\xdc\xe0\xa6\xc0oV\xccu\xb3\x8c\xcaC}F\xdc\x8a\x96f\xd8?\xf90"
            b"\x14JJ\xbc\xde\t7\xfa\x02\x83\x9b\x114\xa5b! \xef(\x9d\xfe\xe6"
            b"\x1fg\xfce^\xa1ye<\x80Y\x8a\x14\x1d\xa7l\x0bz[\t\x04\x98xN8\x18"
            b"!\xc4,\x05\x86\xa8\'\x7f\xdd\xa1\xcdYJ\x82\xf5AkF\xd9D\xed\xee"
            b"\xfe;0O\x19]\xce9\xec\x1c\xa5\x7f5XH\x91\xcbcx\xde"))
        self.assertEqual(a.rijndael_key_schedule(b"\1" * 24), bytearray(
            b"\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01"
            b"\x01\x01\x01\x01\x01\x01\x01\x01\x01|}}}}||||}}}}||||}}}}|||n"
            b"mm\x82\x13\x11\x11\xfeoll\x83\x12\x10\x10\xffnmm\x82\x13\x11"
            b"\x11\xfe\xe8\xef\xd6\xff\xfb\xfe\xc7\x01\x94\x92\xab\x82\x86"
            b"\x82\xbb}\xe8\xef\xd6\xff\xfb\xfe\xc7\x01[)\xaa\xf0\xa0\xd7m"
            b"\xf14E\xc6s\xb2\xc7}\x0eZ(\xab\xf1\xa1\xd6l\xf0\xbdy&\xc2"
            b"\x1d\xaeK3)\xeb\x8d@\x9b,\xf0N\xc1\x04[\xbf`\xd27O(\xe3\xa2\x12"
            b"5M\xe9!\x1c\xa6da\x87\x8a\x94/F\x8e\xcf\x90&\\\xf8\xdf\"\xa2<"
            b"\xe5\x17\xef\xd5\xc4\x0bI\xb1\xa5\x8c\xc3%\x8a\xcaM\xea\x1a\xec"
            b"\x11\x12\xc5 k\x9a+7\x84O\xef<\xcd\xfeJ\xb0\x0e\xdb\xc0"))
        self.assertEqual(a.rijndael_key_schedule(b"\1" * 32), bytearray(
            b"\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01"
            b"\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01"
            b"\x01\x01|}}}}||||}}}}|||\xfe\x11\x11\x11\xff\x10\x10\x10\xfe"
            b"\x11\x11\x11\xff\x10\x10\x10\xb4\xb7\xb7k\xc9\xcb\xcb\x17\xb5"
            b"\xb6\xb6j\xc8\xca\xca\x16\x16eeV\xe9uuF\x17ddW\xe8ttG\"%\x17"
            b"\xf0\xeb\xee\xdc\xe7^Xj\x8d\x96\x92\xa0\x9b\x86*\x85Bo_\xf0"
            b"\x04x;\x94S\x90O\xe0\x14\xae\xc4\xed\x90E*1w\x1br[\xfa\x8d"
            b"\xe0\xfba\xdb\xcb\x8a\xad\xb4\x94z\xa9\xcc\xaf\xee\xfa\\\xe0"
            b"\x0e\xee_o\xc5\xda\x1aE\xf4\xad\x017\xafW\x8c\xd7T6\xbf\xc5"
            b"\xaa\xa8\x0bQ\xd0\x01\xc7\xfe>\xfb\x9b\x1e0\x15\rk\x9c\xce"
            b"\x17.hc\x16\x19\xc74\x9a\xce\x93\x02\x07Nv\xdf\x0c\x1f\xa6"
            b"\xde\xcb\xe1\x98%P\xff\xa80[\xa9\x98\x9dL\x87\xf0\xfeZ\x9e7"
            b"\xca\xc0P\xa4\xc8"))

    def test_shift_rows(self):
        a = AES()
        self.assertEqual(a.shift_rows(bytearray(range(1, 17))), bytearray(
            [1, 2, 3, 4, 6, 7, 8, 5, 11, 12, 9, 10, 16, 13, 14, 15]))

    def test_mix_columns(self):
        a = AES()
        self.assertEqual(a.mix_columns(bytearray(range(1, 17))), bytearray(
            [9, 10, 11, 12, 29, 30, 31, 16, 1, 2, 3, 36, 21, 22, 23, 40]))

    def test_decrypt(self):
        a = AES()
        for n in [16, 24, 32]:
            for i in range(30):
                d, k = os.urandom(16), os.urandom(n)
                self.assertEqual(a.decrypt(a.encrypt(d, k), k), d)
        d, k = os.urandom(16), os.urandom(33)
        with self.assertRaises(ValueError):
            a.encrypt(d, k)
        with self.assertRaises(ValueError):
            a.decrypt(d, k)

    def test_rijndael_key_schedule(self):
        a = AES()
        with self.assertRaises(ValueError):
            a.rijndael_key_schedule(os.urandom(33))

    def test_encryption(self):
        a = AES()
        self.assertEqual(
            a.encrypt(b"d" * 16, b"k" * 32),
            b'\xa7i\xfdW\x98T@{v\xdd\x05Ye\x87I\xb7')
        self.assertEqual(a.encrypt(
            b'\xea\x0c\x073\xca\xac\xc2\xe3w\xd0$c]\xadz$',
            b'V\x87\xecg,}"\x91*\xf3\xb7\x04\x9a\x96\xcaj'), (
            b'+\xe9:Y\xbaS\x13\x07oB\x16\x11V\xff&\x05'))
        self.assertEqual(a.encrypt(
            b'\xfc;\x15\xcc%K\xe1R6\xde\x1de\xae\xa7\x90L',
            b'Q\x01Y\x8e\x16\x17\x1a\x88g\xa4\xb7\xce39\xa6\xb9'), (
            b'?\xce\xe0j1\x8b\xb0\xca\xdf\xcc}\xbc\xd95\x92#'))
        self.assertEqual(a.encrypt(
            b'7\xbeF\x8e\\]0\x95\xdb\x14\xdcQ\x0c\x9fH\x88',
            b'lfvV\x1a\xba\xb6\xb6S\xc2z\xbc\x7fts\x9a'), (
            b'\xea\x92\nY\xb7\xf9\xd9\\\x07\xfd\xb4\x05\x1b8C\xed'))
        self.assertEqual(a.encrypt(
            b'\xa1j\xb1)\x12\xe4\xa4\xdaW \x97Gy\x93.\xc2',
            b'\xe8\xe6\x0c\xc0\xc4\x84\xfeR;/\x04\xe1\xfb\x90\xed\xb8'), (
            b'UZ*$L/\xa67\x91W\xc3\xea\x83\xb8m"'))
        self.assertEqual(a.encrypt(
            b'\xe8F~%\xf3>\x02\xc3*\x1a\x83!0\x99\x81\x1a',
            b':\xe0\xad\xf3:\x04H\xfa\x02\n\xb5\x13\xca\x93\xe35'), (
            b'\xa1{\xf2T;\xbe3\x9a\xe9G\x95\x81\xe7L\xd6m'))
        self.assertEqual(a.encrypt(
            b'\x1d\x81r\xafPK\xba\xcf\xfa:h\xecR\xd8\xad\xc4',
            b'\x12w\xacE\x17^\xd0\x8c\xba\xe7\x91\xbe7\xbe,+'), (
            b'W\xfd\xe8uyf\xc2\xbdX~\x95Ar\x92\xbbt'))
        self.assertEqual(a.encrypt(
            b'9\xa3(-I\x1b(uBn\xa9\xf1\x9c\xd6v9',
            b'[\xd4\x89\xe6{\xa2`\xd63\x94n\tb$\x935'), (
            b'\x1amk\x83\xc6\x9d\xe9\xcd\x96\xceu\xc1\x7f\xf7\xa9\x9d'))
        self.assertEqual(a.encrypt(
            b'1\x18:Ul\xc9bk\xec\x17\x9b\x13\xb5\xef\x1cf',
            b'\xa1c\x0bgD\xf1\xde,;h\xack\x96\x98\x19\x12'), (
            b'\xa9w~\x80]\xed\xb5\xcdo\xce#\xfa?\x85\xb5W'))
        self.assertEqual(a.encrypt(
            b'W[\xb8#\xa3\xc1\xa2\xcc\xd0\xfd\xb4\xe7\xad!\xbd\x1c',
            b'KVn\xa6\xbf.\x8fGM\x15\x04R\xb1:\x17:'), (
            b'\xb7m\xc9</f\xc0vcRF\x96\x19D\x07\xf3'))
        self.assertEqual(a.encrypt(
            b'Zj\x02N1\xc2n\xf8\x9e\x80\x1c\x04_"Q\xef',
            b'O\x1dO1Gh\xc9\xf2\x1a\x06\xef\x82|\x14\xe44'), (
            b'Q\xeaXq\x0eY\x98\x06\x1f\xe5\xa6\xf2\x1d(1<'))
        self.assertEqual(a.encrypt(
            b'f\xed^\xe2\xf5\xfc\x1f\xd9\xb2"#\xe8\x9c\xd7P\x9b',
            b'\xe0LN$w[G\xa9\xe7B\xfd\xae\xfa8\xdb\xfa'), (
            b'\xab\x90\xdd\x99\x06&37t\r\xd8\x05\xb8\xe4\xf2T'))
        self.assertEqual(a.encrypt(
            b'\x8b\x82\xe2\xf0X\x8aX\xc7\x98In\xbc\xb4\xac+o',
            b'\x9f<V\xadZ\x1b(\xa9\xb4q\xbd\xac\xa0Y\xe8\xd5'), (
            b'\x12\x11Ne=\xca\xe90/w\x1b\xac\x07\xd2\xb8\xd7'))
        self.assertEqual(a.encrypt(
            b'\xc6PA\xe5\x05\xc2\x846\xf4d$[{\x8f!i',
            b'\xbc\xb7X\xc4\x92)\xb1F\x8aV\x1f\xb5\xe0\xf2;\x80'), (
            b'`q|3\xd0)\xcd\xb79\xad\xd1\xdb\xd0NBM'))
        self.assertEqual(a.encrypt(
            b'\nO\x16\xa2t\x10\nx?\xbb\x15\x89\x15\x16\xf7\xea',
            b'\xdd\xa1Q~\xed\x92\x07\xab\xb1J\xf3\xefs\xa0\xdd\xe6'), (
            b'~9O`\x86\xebn\xbb\xb0BM\x86H\xccNy'))
        self.assertEqual(a.encrypt(
            b'\xbd\xe5k\x8c\r\x01`\xad)Q\x01\xc6\x11\xa2bE',
            b'p\x11\x88\xf7Yx\xfcw\xf9D\xb9$\xfc\x90\xabJ'), (
            b'\xe0\x13k x\x05\x85b\x83\xa0\xf0@`f\xc8\xcc'))
        self.assertEqual(a.encrypt(
            b'\x19x=\x1a\xdc\x02\xdc\xc6\xf2s\xf5h\xd2\xc4\xffP',
            b'\xb4/\r\xb3\x0cE\xea\n\xb7nMK\xe6kn\xab'), (
            b':\x12\xcd\x1d\xb8\xd8O=\xef\x85\xb0\x83\xec7\xacs'))
        self.assertEqual(a.encrypt(
            b'\x96\xb4\xd2\x8b\x0e;{Vinh|S\x08d\x17',
            b'k/\xec:\x16h\xf1\xbfr\xba\xf0\x8b\x19\xba\xb5\xe5'), (
            b'U\xf7\x06\xdb\xd7\xe9,\xb1f\xd2\x98\'\xc7\xcb"\x1f'))
        self.assertEqual(a.encrypt(
            b'\xcf\xa7\xd21\xb8\x8aS\xa8\xaa)\x08\xb7+\x18\x9c\xf9',
            b'Lm5\x92\x18d\xf6\x8e\xb2Q\xd3s\x10\xfa\x07\xeb'), (
            b'\xe9.\xad\x83\xb2Lu\x9a\x03F\xf9\xc5\\\xd5\x08\xe0'))
        self.assertEqual(a.encrypt(
            b'\xdb\xdf\xc7_\x0e\xd5\xdb>\x92\xed\xe3\xc0U]\xe1O',
            b',\x98\xd9Y\x91\xf3/H\xb7st:\xe8\xf7h\xa8'), (
            b'\x1b\x00$\xda""\xc2\x9c\xb4\xef\x1c\xc7\x80\xa5@\xfc'))
        self.assertEqual(a.encrypt(
            b'\xe7\xd4.\xdf\xe2y\xcf)\xceH\x8f\x08\xc8\xf5l\xe9',
            b"\x04\x90\xcb\x8d\xa4\x92\xe3x$}\x04iU'\xa2\xe6"), (
            b'\xc8\x7f!\x1c%9\x03\xd1\xf1\x9f\x05o\xe3\x99ng'))
        self.assertEqual(a.encrypt(
            b'D6j\xd9\xf9\xb1_{g\xfe\xe1\x95|=\x95\xbb',
            b'1\xb2\xb1\xb0\x82\xa8\xad\xecM\xc5Z\x90'
            b'\x88\x94\xad3\xa32\x07@p6w\xe4'), (
            b'\xc1)A\xb7\xb5s\xdf6\xa23\xe2\xd4\xd8f\x1eN'))
        self.assertEqual(a.encrypt(
            b'\xbc\xe3\xbc`\x95\x00c\x1f\xf0\xa4\xc2wDO\xa4\x9f',
            b'\x06\xcf\xf1V\xeb\xf9\xd2\xc5\x03\xb3Dt'
            b'\x9e#\xf6n\xefq\xf4\xe1\x84\x8f\x7f\xb5'), (
            b'\x02N\x97\xfd\xca~\x11 5B\xe3\xfe\x08@X\xc4'))
        self.assertEqual(a.encrypt(
            b'\x9d\x1a\xf4;\xab\xe7\xf0\xad\xe3\x9e\x940)\x80\x1f\xca',
            b"'\x18\x85-\x89kcbU\xbf\x0e\xedLK\xd5\x9a}L)"
            b"\xd9\x9e\x1c\xe2Y"), (
            b'\t\xdd\x19>\xf6`\x07\x94\xb1\x9b\x9em\x9a\xb9\x16\xe7'))
        self.assertEqual(a.encrypt(
            b'S\x9e\x0bF\xd1\xc853*\xbb\\iPT\xae\xaa',
            b'\t\xaaF\x08e\xc7\xf1\xd3;\xa1\x92M\xe7Z=\x04e'
            b'\x08\x10\xf1\x90\x07@\xbf'), (
            b"H\xe7b\xf5S6.\x89V\xfa`\xaf\xef''\x95"))
        self.assertEqual(a.encrypt(
            b'f\xfb\xc4d\x14-\x9ex\x8b\xab@M\xe3\xce\xc6\x04',
            b'\xb4y\xfe\xef*TG@M\xe8N\xb5\x08\xbf\x19\xc8\xda'
            b'\x19\x86\x1a\x08\x98\xab\xd1'), (
            b'~\xe1\xce3o\xf2X\xa0\xcc\xa5\xb26J\xad\x7fD'))
        self.assertEqual(a.encrypt(
            b'\xe5\xd1\xa7M\xb6\xbb\xf6A\xa6\t\x81\xd5\xe70\xe0\x16',
            b'I\x04\xeb7x\xcb5\xa0g\xa3\xa0\x1dC\x89R-'
            b'\x95x\x8bq\x1a\x1c\x9c\xf9'), (
            b';H@\xd1M\xe6b\x19\x99g?R\xf3t\x07\xf8'))
        self.assertEqual(a.encrypt(
            b'\n\xf9\xcc\xee?D\x9ab\xddo|n\x1d\x82?\xcb',
            b'\r\x7fm\xcd\x19\x18,\xb1\xc4\xa0'
            b'\xac\xed\xb0\xce\x89\x18\x19\xdakw\xf4BY\xfe'), (
            b"\xa5\x81\x14\xafl\n\x91s\x94\xf9'\xf0\x0b\xe4\xd49"))
        self.assertEqual(a.encrypt(
            b'\xa6\nC\x17\xed)\xfcA?\x97\xe0L\xda\x19\xfe\xaa',
            b"\xfe\x10*\xc7\x9a\xfd\x984Y\x19\x7fD"
            b"\xf2 \xc7U'\xde\xf01F\x1f)a"), (
            b"\xaa+\xd3k&\x00\xd9\xa1DEk\xfck\xb9lw"))
        self.assertEqual(a.encrypt(
            b'x\xff@\xed\x92(>\x85\x85\xa4b|\xfa\r\xf3\xc9',
            b'\xdaq\xd0\x80\x9dz\xabb\x18\nW\x03Dg%\x0cn\xb7\xf3R|\xef$Y'), (
            b'\xed\x1a\xe0\x8d\xd8\x15y<?\x87\xf1\xaa\xcf\x14\x98\x14'))
        self.assertEqual(a.encrypt(
            b'\xa4\x90BI\xba\xd0B\xb0"\x03\xa5\xa9\xa1*\xf1K',
            b'D\x04\xfeO\x05\x07Q!+\x10\xe0\xc4'
            b'\xec!\x90%\xc88\xe0\x1c\xb3w\xe3\xc5'), (
            b'QY\xed\x8f8\x84\xba\xbdkx_B\xfa%@A'))
        self.assertEqual(a.encrypt(
            b'j\xd4Y4\xf81\x95\x89\xe7u"[\xc1\x0e\x7f\xe7',
            b'!P\xfc\xff\x9f\xad\x98\x80\xccEE$s;>M|z\xbe\x03?\xe7Lf'), (
            b'\xb9^\xc8\xf9\xac\xfd\x8eP\xdd\r\xa4\xb1\x9e\xd8\xfc\xf2'))
        self.assertEqual(a.encrypt(
            b'\xfd+\x05\x177%#\xe6\xce\xe4Ke\x0c\x90\xfb\xec',
            b'\x85\x8b\xe6\xb5\x82\x02\x8f\xc6u-\xbbo'
            b'\x7fa\xdc\xce(N\x0f{\xce\xc1\x81z'), (
            b'\x06$\xeb\xeekzP\xbe\xd9\xfe\x84\xf4&&\x16\xa3'))
        self.assertEqual(a.encrypt(
            b'\xdcR\x14\xf2\x14\xf5\xb1\xd5=\x9cd,\x15\xaf+\xcb',
            b'\xf0n\xbe\xa9L\x83=U)\xa9|\xe2\xeea\x16D'
            b'\xceX\x9dy\xfa\x80\x91\x9e'), (
            b')\xeb\xf6\xab\xee\x04J;\xe17\x97\x86\x183\x86\xc9'))
        self.assertEqual(a.encrypt(
            b'\x00\x07\xcf&\xddjsO\xf7(\xd3\xe4"\x14~\xd9',
            b'\xc9\xee\x8c\xfd\xd8\xb5\xc5\xb69>\xf7'
            b'\xd1\xcdj\xf1\x80\xd1,\xdbl \x1b\xa4]'), (
            b'\x98\x97.\x91\xf1D\x0e2q\xb4r\xcb\xf5A\x04)'))
        self.assertEqual(a.encrypt(
            b'\xbc\x12\x99(\xfb\xa4\x0e\xb4\xa8a\x12Q6h\xbb+',
            b'\x89\xae=m\x80A\x1d\x08\x17\x87=Aw\x98'
            b'\x86/\xf3e\xd3\xcb\xca\xeb=\xf8'), (
            b'\xed\xb2\xd7\xdaH\x8el\xcc\xa4\x0e\xaf\xc0\xf7Q\xea\xa0'))
        self.assertEqual(a.encrypt(
            b'\x89#4\xe8\xb3\n\x9d,\xa9n\xd62n\xe5\xce\xcb',
            b'\x13\x8bo\x19KI\xde\xfd~\xf0\xff\x05o'
            b'\xe0*\x97\x13Nc\x82\xd1v\xfbX'), (
            b'\x15\xa3/@\x9e\xa6\xa8\xe1"\xc1\x18\x87-MR>'))
        self.assertEqual(a.encrypt(
            b'\xec++f\xc8\x01\xb7m\\\xeb~\xf3\x96\xdd\x95\\',
            b'\xd7[\xf9\xbe\xbe\x94\x12\x91\x00\x83'
            b'\xc2\xca"s!\xec\xc6.\xf8\xe4\x1a\x93\xbc\xcc'), (
            b'\x84\xe0\xdb\xc5\xb8\t\x078\xff\xf1\xbf\xe8N\xd5\x84\x18'))
        self.assertEqual(a.encrypt(
            b'K\xcfOM\x9b\xfb8g$tQ\x06\xf7\xf7\xd3\xb2',
            b'\x07\xef\xfe\xf3\xb7\xa7\xe8\x84\xabf\xba\x83'
            b'\xac\x1d\x03\x87\xe9F\xb9\xadK\xa4\x04F'), (
            b'a\x83\x85\xd8J\xe4\x82\x9c[p\xe2\x84t\xef\xbd6'))
        self.assertEqual(a.encrypt(
            b'\xa7\x13\x80?\xba\n^J\xb5\xb0\xdc\xf9\xc28c\xe6',
            b'\x85I\xc3@\xe1\x99\x8b\x91?\xaf\xa6|J\xf9w'
            b'\x83\xfd\xe5\x9bp\xb1\xb7s\xab'), (
            b':\xba\x93\xdd\xc4\x0f|\xfc\xe7\xebm[ \xd8e\xb5'))
        self.assertEqual(a.encrypt(
            b'\x1e\xef\x18h\xa4M\xdd-\xf7:y\x16\xd6\xd5!_',
            b'\x85\xd0\x0c\xcfJ\x11\x91\xe6\x92<Ic\x91'
            b'\xc3G\xf2E\x1b\xce\x84\xd2\xf6\x15\xdf'), (
            b"\x1f'H\x1f\x9b2\xbc\xa2\xdejz/\x9b-^\xb6"))
        self.assertEqual(a.encrypt(
            b'\xb4\x06\x85\xd8\xa3\xce\x07\xe9\x85\xe9\xae\xdf\xdf\xf4$k',
            b'"}\xdb\xac\x8b^&o\x9b\xc8\x15)\xf0~\xcbJ'
            b'\x93E\xadmNt\xa2,C\xd1\xe2\xfd:\xf7\x7fe'), (
            b'f\xfax\x99\x06A\x00\xcc\x88\xf2\x88\x19U\xddwW'))
        self.assertEqual(a.encrypt(
            b',J\xa0\x043V\x97\xcb\xf1qJ\xfd0\x9bAC',
            b'\xb7\xc56\xa8,\x8b\xc3\x81)/O\x10\x89\x85'
            b'\x15\xff\xbe\xdcc\xbf=!\xee\xe5b\xa5\x14\x8ep\xe75\xee'), (
            b'lQU\xd8)M\xb8a\x01R\xda\x1e\xad&\x9fA'))
        self.assertEqual(a.encrypt(
            b'\x0c\xf1s\x0f\x0f\x10\xbb\x8c\xdanA\xbc5\x90\x01+',
            b'\x1a\xe9\x12-L\xa5<v[\xbb"V\x80\x9c\xa6\xed'
            b'\xac\xfbS0n\xad\x9d\xea\x9b\x95\xf5\xea#\xfaW\x03'), (
            b'\x98\xab\x83ha!\x97\xe2\xf8\x98~[\xf9\x91<\xff'))
        self.assertEqual(a.encrypt(
            b'\x15KhU\xfcF8X\x8a_b\xeb\xc9\x8f\x16M',
            b'\x98Z\xa4(\x9e\xb4\xf0\xe2\x1d60j\xb3;\x8c\x89'
            b'\x11\xff\x0c\xb2Vcz\x1dWc\xf2g\x1c\x19\xb7\x9e'), (
            b'\xbb\xacT\xe9_\\\x1a\x86\xee1\x84\xa4\xf3\xd5\xbcE'))
        self.assertEqual(a.encrypt(
            b'\x0f\xca\xdc\xea\x16p\x97\xc8/\x19*\xbb;\xe2y\xe2',
            b'F\xd4>\x95}\x87\xd4k[s9\xbb1v\xd7\xc8\t\xcf\xcc\x93'
            b'\xde\xe6&\xd5#|\xb8$F\xf5\x9b\x1a'), (
            b'\xc3AO\xfdt\xd5\xb1\x8d\x19\xf5\xe2S\x1b\xd6\xfb?'))
        self.assertEqual(a.encrypt(
            b'f(\x94\x9b\x9d\xc7;E\xd7^\xed\x99\x08\xcb\x12\xb6',
            b'\x8e\x15 O\xb3\xe3\x8d\x08\x9e\xcf}\xbb'
            b'\x89I\xaf\x94\xb9^\xe6,\x10\xe8\x08\xaa\xa9\x9aa{\xa5\x03&$'), (
            b'\xee\x1dHc\xdcoqm\x9f\xc7%\xca&\xec\xd3x'))
        self.assertEqual(a.encrypt(
            b'$)\xfc]\x88|\xca\xf3c_A.\xfd\x12L\xaa',
            b'\xbb\\\xcaT\x1a\xc7;\xba\x9f\xd6\x1e\x97\xae'
            b'\xe7}\xc9\xa5\xbfR\xbc\x10\xf9\x02\x15]X\x9bgjq\x96b'), (
            b'`m\xb3\xcae~.\xfa,\xfd\xf8\xf0?y\x80\x8e'))
        self.assertEqual(a.encrypt(
            b'\x99q\x90\x96\x12l\t\xdc\xee\xaf\x97~\xcb\x9e\xc5\x1f',
            b'\xb6\xb1\xe5\ni\xb2+s\x11\x9e\x0e\xe6\xdb\xb3'
            b'\x93\x04\xa4\x80\x8a\xe2\xaa\x84,\x8b.\xab\x03sQ\xa6\x9d('), (
            b"\x1a\xc7^KI\xc7)\xf4c'6uP0gF"))
        self.assertEqual(a.encrypt(
            b'\xaa\x13\xeb\x92\x96\x96\x17\x93\x0c\xd0G3\xdc\xe7b)',
            b'$\x92K\xa6\xa6o\x1c\xfbg\xf6b\xd3\xe1\x8c\xa31'
            b'\xc5|\xcf\xfc&\xb8/\xde\x02y\xbb\xb7\x94~h\xa3'), (
            b'\xfa\xa2\xa2\x83\x05r\x8d;\xfb2\x94c\xd5Q\x12\xe8'))
        self.assertEqual(a.encrypt(
            b'\xda<\xea\xd2\x1b\xc5\x00\xf5_\xe7\xce\x1c \x00\xd2\xd5',
            b'\x10\xb6{4\xefH\xaf\x84\xb41V\xf8\x91\xb3\x962'
            b'\xbb\xfffrS\x9f\xa7\xec\x91Iv\xef\x1b;\x1c\x19'), (
            b'\xcaw\xf0\xa0LA\xa5\xd1\x95\xc5S\x15Dy\xd2y'))
        self.assertEqual(a.encrypt(
            b'.g4\xe3\x98\x9f\xd8\xc0\x8eX\xd4\x7f\xf7\xe0\x98\xf7',
            b"\x14C;\x88\x12\x88z6%N\x83E\xaa\xf8\x00L\xbe"
            b"\xe1^\xbf>\t\xbc'\xe6\xaf\xe1c\xf9\tA\x97"), (
            b'fV\xe6\x85g\x98\xbe.*\xa9\xc0-\xd3\xa6\xdb\xe4'))
        self.assertEqual(a.encrypt(
            b'*\xbc\xdc\xf6\xe0\t\x02 R\xac/!\x94\x82\xff\xa0',
            b'/s\xaa~\x13\x1a\xd9<\x16\x84\xba\xd5\xbf\xf5`i'
            b'\xae[\x84$S\xe0\xcd\xf2\\\xf0\xf4\x0c\xd1\xe3\xd4\x99'), (
            b's\x83\xa1}r\x92\xc2\xd0\x02\xfe\xda\xc6L=\r\xad'))
        self.assertEqual(a.encrypt(
            b'\xf7\xf48\x15\xfc\xe2\xa5c!H\xa6R{4\x83\xce',
            b'\xbcuxw*\xc8}"w\x9f"\x1d(y\xf0(\x92\xc7\x7f{J'
            b'\tx~kZ<\r\xe3\x14\r\x03'), (
            b'\x03N\xfa\x89\xdc\xba\xf82\xbf\x124\x9a\xf2\xbcT|'))
        self.assertEqual(a.encrypt(
            b'\xaf\x86O\xa6v\xacsi4tw\xd8\xcb\xc5[w',
            b'e\xaa\xe4=\xbb\xe3\x9b\xd4h\xa4\xf6\xf2M$\xe9'
            b'\x8e^\x02\x8b\xc7\xb8\xa9J\xe2\x82\rL@%M\xfe\xae'), (
            b'\x96 \xf4\xa1\xf0\xc4tJ\xe1\xab\xbf\xa6$n\xe0\x18'))
        self.assertEqual(a.encrypt(
            b'UA\x9c\x88NL\xae\xbc\xdf\x91\xeeN\x808\xb9&',
            b'\xfa\xb3\xc2\x8a$\xe5\xbcd\xc3\x1e\xe0\x06Z'
            b'\xa5?*\x8d\x00\xfa\x9con\xd8\xe4\xe2\x87\xd8cQ\x95}\x86'), (
            b'\xb3\xb0)f\x05y\xef\xbd\xfb\x08\x864\xe6\xeey\xfa'))
        self.assertEqual(a.encrypt(
            b'\xad\x93"\xa58\ra\xfc\x12\xfcKp\x97\xd8u\xe1',
            b'\xaa\x9d\xa1\xab#!\xb5P\x88oa8\x7f\x9c\x07%\xb7'
            b'\xef~\xf0\xa1ZA\xe7vA2L\x82\t\xabk'), (
            b'\xcf\x89\xa5R\xd8\xdfy\xab\xd9*\xd6-1\xbf\x8f/'))
        self.assertEqual(a.encrypt(
            b'\x7f\xa5\xfa\x8a\x98\'p\x15x\xe58\x1cT\xd7D"',
            b's\xa5\x98\xfc\x12#\xb9.q\nim\xdb8\xfdc[\xe3>'
            b'\xc8g\x89\xaa;rg)5\x1f\xb9\xde\x19'), (
            b'p\x1b\x16\xe4\xaa\xb94\xd9\xe2cdo\xd4&\xa6\xb8'))
        self.assertEqual(a.encrypt(
            b'43\x9d\xdf\x96\x0f\x04\xa9\xc2\xa0j\xf4(\x0c\xcb\xb0',
            b'2\x8b\'\xf975\x15\xc5\xb7\x81\xbb/!>\x9b\xf3'
            b'\xddfDX\xac\xf3\x1e\x19"\x14\x13\xfd`\xf8x\xad'), (
            b'\x16u\xf5Ak\xd6\xa8\xa3X\x19ihA\xa6R\x90'))
        self.assertEqual(a.encrypt(
            b'\x18*\rKI\xbc\x99-Ad\xf3\xf9\xa9\x15\n\x91',
            b'\xdc\x04\x0b\x05\xd7\x96\xdc\xb6u\x95\xda\xef'
            b'\x02\xc9\xbd.{\x0e\x87\xdeTJ\xd9\x0fG\xf7x\x16\xefM\xf2C'), (
            b'\x8d\xef\xfd\x1f\x8f\x83\xb9i\xafU\xad\xdb\xedJrJ'))
        self.assertEqual(a.encrypt(
            b'\xd4\xf6vE\xcd9\xd8\xdeX2\xd4%\xa3z\x0c\xb0',
            b'C\xae\x9c\xbf\x16c\xfe-\xb4\xff\xcc9\x06\x0e'
            b'\x1e\x81I\xa1\xca\x89ON);\x9bM\xbc\xfb!U\x07S'), (
            b'E\x80\xd5\xbc\xe1\xdf\x0e\xce\xa3\x9b\xa9z]T5\x97'))
