{ "info": { "author": "Michael Calvin McCoy", "author_email": "calvin.mccoy@protonmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Natural Language :: English", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Topic :: Security :: Cryptography" ], "description": "Kravatte Achouffe Cipher Suite in Python/NumPy\n==============================================\n\nAn implementation, in Python3, of the\n`Kravatte `__ pseudo-random function\nand associated modes based on the `Farfalle\nPRF `__ system. At its core,\nKravatte accepts a user defined secret key and a sequence of input bytes\nto generate pseudo-random output of arbitrary size. From this primitive, a \nnumber of authenticated encryption modes can be built.\n\nKravatte makes use of the\n`Keccak `__\npermutation, most notably used in NIST\u2019s `FIPS 202 SHA-3\nalgorithm `__.\nBecause the underlying structure of Keccak function works on a\nthree-dimensional state of 1600 bits, it maps well to a 5x5 matrix of\n64-bit unsigned integers. As such, the `NumPy `__\ncomputational library is a natural fit to quickly manipulate such a\nstructure and thus is a hard requirement.\n\nThis implementation reflects the updated, more secure Kravatte\n**Achouffe** released in late 2017. The older ``Kravatte 6644`` logic is\navailable within this repo as well.\n\nAlso supported are the `Kravatte-SANE and Kravatte-SANSE `__\nsession based modes. These modes replace the deprecated Kravatte-SAE and Kravatte-SIV modes and \nutilizes the ``Deck-SANE`` and ``Deck-SANSE`` modes described in the `Xoodoo Cookbook `__.\n\nInstallation\n------------\nKravatte can be easily installed from `pypi `__ via ``pip``:\n\n.. code:: bash\n\n $ pip install kravatte\n\nIf ``pip`` is unavailable, this repo can be cloned and setup can be done manually:\n\n.. code:: bash\n\n $ python setup.py install\n\n\nKravatte Object\n---------------\n\nThe basic ``Kravatte`` object operates on two Keccak-1600 state matrices;\nthe collector state and the key state. Instantiating a ``Kravatte`` object\ninitializes the key state with provided user key and sets the collector\nstate to zeros.\n\n.. code:: python\n\n In [1]: from kravatte import Kravatte\n In [2]: my_krav = Kravatte(b'1234567890')\n\nThe newly initialized ``Kravatte`` object is now ready to accept input\nstrings of bytes for absorption into the collector state via the\n``collect_message`` method. Repeated calls to ``collect_message`` are\nequivalent to ``B \u25e6 A`` sequences as described in the the Farfalle\nspec:\n\n.. code:: python\n\n In [3]: input_a = b'The quick brown fox jumps over the lazy dog'\n In [4]: my_krav.collect_message(input_a)\n In [5]: input_b = b'3533392d36302d35313235'\n In [6]: my_krav.collect_message(input_b)\n\nOnce absorbing message strings is complete, the ``Kravatte`` object can\nproduce an arbitrary number of pseudo-random output bytes via the\n``generate_digest`` method. Those bytes are then available in the\n``digest`` attribute:\n\n.. code:: python\n\n In [7]: output_bytes = 64\n In [8]: my_krav.generate_digest(output_bytes)\n In [9]: from binascii import hexlify\n In [10]: hexlify(my_krav.digest)\n Out[10]: b'8a0fc89899e058dedd368b60111bf4958f4f24216bbac76936471e6f7c3958b881c38c8e829ff07bf137701917b3e49ab392e93f3b2abfc714f90c0ca023124d'\n\nThe absorb/output sequence can be restarted with another call to\n``collect_message``. This clears the collector state and resets the key\nstate to its initialized value. Alternatively, the user may change to a\nnew secret key with the ``update_key`` method to reinitialize the key\nstate used at the start of message absorption.\n\nWhen a Kravatte object has reached the end of its usable lifetime, the ``scrub`` method\ncan be used to try and cleanup interim state and key data in resident memory. This method is executed by default\non the standalone functions ``mac``, ``siv_wrap``, ``siv_unwrap``, and is available in all Kravatte derived classes.\n*NOTE* This method only clears the sensitive attributes ``collector``, ``kra_key``, and ``roll_key`` and shouldn't be\nconsidered applicable when using the multi-process accelerated mode.\n\nMAC\n---\n\nThe most basic mode of ``Kravatte`` is an authenticated pseudo-random\nfunction (PRF). ``Kravatte`` can absorb an arbitrary sized user message and\nkey, and output an arbitrary collection of pseudo-random bytes that can\nact as a message authentication code. The ``mac`` does this in a single step:\n\n.. code:: python\n\n In [1] from kravatte import mac\n In [2] from binascii import hexlify\n In [3] message = b'Attack at Dawn!'\n In [4] key = b'something_secret'\n In [5] mac_size = 64\n In [6] g = mac(key, message, mac_size)\n In [7] hexlify(g)\n Out[7] b'24f61fc5fd38fef7f3d799ed72b24578c4479e1c035c70d8bc55ce23d74124255d5e8a0c5dd33aa36d5289f1e4e995a19be804d97bb338fa875e01e3c2d2dd51'\n\n\nKravatte-SANE\n-------------\n\n``Kravatte-SANE`` mode is a session based method of AEAD. Given a random\nnonce and secret key, this mode encrypts a sequence of plaintext\nmessages and/or metadata into appropriately sized ciphertexts and a validation\ntags. The sequence of plaintext/metadata is tracked as a history that\nbuilds a chain of authentication from message to message and requires\nall generated ciphertexts to be processed to fully decrypt and verify.\n\nA separate ``KravatteSANE`` class is provided that adds the history\ntracking for each encryption operation done via the ``wrap`` method.\n\nEncrypt\n~~~~~~~\n\n.. code:: python\n\n In [1]: from os import urandom\n In [2]: from binascii import hexlify\n In [3]: from time import monotonic\n In [4]: my_nonce=urandom(32)\n In [5]: hexlify(my_nonce)\n Out[5]: b'41c48803e34eefd9ac1d39d3412d3e32592173fbcdd1b60d85dc177ae7156733'\n In [6]: message1=b'Nice List:'\n In [7]: meta1=str(monotonic()).encode()\n In [8]: message2=b'Alice,Bob'\n In [9]: meta2=str(monotonic()).encode()\n In [10]: message3=b'Naughty List:'\n In [11]: meta3=str(monotonic()).encode()\n In [12]: message4=b'Chuck, Eve'\n In [13]: meta4=str(monotonic()).encode()\n In [14]: my_sane = KravatteSANE(my_nonce,my_key)\n In [15]: ctext_1, tag_1 = my_sane.wrap(message1, meta1)\n In [16]: hexlify(ctext_1)\n Out[16]: b'4b42fef9cb5a6ce69d78'\n In [17]: hexlify(tag_1)\n Out[17]: b'169e7eb0f63cebd70efb779ff45a67f0'\n In [18]: ctext_2, tag_2 = my_sane.wrap(message2, meta2)\n In [19]: ctext_3, tag_3 = my_sane.wrap(message3, meta3)\n In [20]: ctext_4, tag_4 = my_sane.wrap(message4, meta4)\n\nFor decryption and validation, the ``unwrap`` method accepts the\nciphertext, original metadata, and validation tag to not only decrypt\nthe plaintext, but return a boolean if the decrypted plaintext is valid\nwithin the chain of messages.\n\nDecrypt\n~~~~~~~\n\n.. code:: python\n\n In [21]: decrypt_sane = KravatteSANE(my_nonce,my_key)\n In [22]: ptext_1, tag_valid1 = decrypt_sane.unwrap(ctext_1, meta1, tag_1)\n In [23]: ptext_1\n Out[23]: b'Nice List:'\n In [24]: tag_valid1\n Out[24]: True\n In [25]: ptext_2, tag_valid2 = decrypt_sane.unwrap(ctext_2, meta2, tag_2)\n In [26]: tag_valid2\n Out[26]: True\n In [27]: ptext_2\n Out[27]: b'Alice,Bob'\n In [28]: ptext_3, tag_valid3 = decrypt_sane.unwrap(ctext_3, meta3, tag_3)\n In [29]: ptext_3\n Out[29]: b'Naughty List:'\n In [30]: tag_valid3\n Out[30]: True\n In [31]: ptext_4, tag_valid4 = decrypt_sane.unwrap(ctext_4, meta4, tag_4)\n In [32]: ptext_4\n Out[32]: b'Chuck, Eve'\n In [33]: tag_valid4\n Out[33]: True\n\n\nKravatte-SANSE\n--------------\n\n``Kravatte-SANSE`` mode is session based method of authenticated encryption with\nassociated metadata (AEAD) that allows for encrypting a provided\nplaintext with a secret shared key and an arbitrary metadata value.\nThis mode does not require a nonce as it operates with a \n`Synthetic Initialization Vector (SIV) `__\nEncryption generates an equal length ciphertext and fixed length tag\nthat can be used to validate the plaintext at decryption. Metadata\nvalues can be shared for different key/message combinations with\nunderstanding that the more a value is used, the greater the chance of a\ntag collision. This mode replaces ``Kravatte-SIV``\n\nA ``KravatteSANSE`` class is provided that adds the history\ntracking for each encryption operation done via the ``wrap`` method.\n\nEncrypt\n~~~~~~~\n\n.. code:: python\n\n In [1]: from binascii import hexlify\n In [2]: from kravatte import KravatteSANSE\n In [3]: my_message = b'And yet it moves'\n In [4]: my_key = b'name of childhood pet'\n In [5]: metadata_1 = b'1024x768'\n In [6]: another_message = b'The present is theirs; the future, for which I really worked, is mine.'\n In [7]: metadata_2 = b'7680x4320'\n In [8]: my_sanse = KravatteSANSE(my_key)\n In [9]: ctext_1, tag_1 = my_sanse.wrap(my_message, metadata_1)\n In [10]: hexlify(ctext_1)\n Out[10]: b'79e4773536a2ac4b4ec9e93583a817a5'\n In [11]: hexlify(tag_1)\n Out[11]: b'eaa50cb8a02e3238aa8dd5d1186ec0a87ebf6fe71b6fd89bea20b2001fef6810'\n In [12]: ctext_2, tag_2 = my_sanse.wrap(another_message, metadata_2)\n\nDecrypt\n~~~~~~~\n\n.. code:: python\n\n In [13]: decrypt_sanse = KravatteSANSE(my_key)\n In [14]: ptext_1, tag_valid_1 = decrypt_sanse.unwrap(ctext_1, metadata_1, tag_1)\n In [15]: ptext_1\n Out[15]: b'And yet it moves'\n In [16]: tag_valid_1\n Out[16]: True\n In [17]: ptext_2, tag_valid_2 = decrypt_sanse.unwrap(ctext_2, metadata_2, tag_2)\n In [18]: ptext_2\n Out[18]: b'The present is theirs; the future, for which I really worked, is mine.'\n In [19]: tag_valid_2\n Out[19]: True\n\n\nKravatteWBC\n-----------\n\nKravatte Wide Block Cipher mode is a symmetric block cipher mode where the user can specify\nthe size of the block, an arbitrary ``tweak`` value input, and arbitrary secret key. The ``KravatteWBC``\nobject, once initialized, can encrypt/decrypt messages of the given block size (or smaller). ``KravatteWBC``\nsplits messages into left and right components and uses a 4-stage Feistel sequence to encrypt/decrypt.\n\nEncrypt and Decrypt\n~~~~~~~~~~~~~~~~~~~\n\n.. code:: python\n\n In [1]: from kravatte import KravatteWBC\n In [2]: block_size = 64\n In [3]: my_tweak = b'tweak can be anything'\n In [4]: my_key = b'\\x00' * 24\n In [5]: my_wbc = KravatteWBC(block_size, my_tweak, my_key)\n In [6]: c_block = my_wbc.encrypt(b'This is some random 64-byte text string to use in this example!!')\n In [7]: from binascii import hexlify\n In [8]: hexlify(c_block)\n Out[8]: b'2368fae1271e5c784537df331586d5d4daeeb34a6fe4ebea03cc1df7f9c0d79fcc709a9ff2199514f431da685e27658dbf6c5afed11ce5c8172f7615c19db1b9'\n In [9]: my_wbc.decrypt(c_block)\n Out[9]: b'This is some random 64-byte text string to use in this example!!'\n\n\nKravatteWBC-AE\n--------------\n\n``KravatteWBC-AE`` is a variant of ``KravatteWBC`` that extends the desired block size by 16 bytes and \nembeds authentication data. The tweak is replaced with arbitrary associated metadata. When the \nblock is decrypted it is also validated as being encrypted with same secret key.\n\nEncrypt and Decrypt\n~~~~~~~~~~~~~~~~~~~\n\n.. code:: python\n\n In [1]: from datetime import datetime\n In [2]: from binascii import hexlify\n In [3]: my_key = b\"Doesn't look like anything to me\"\n In [4]: metadata = str(datetime.now()).encode()\n In [5]: message = b'These violent delights have violent ends'\n In [6]: len(message)\n Out[6]: 40\n In [7]: my_WBC_AE = KravatteWBC_AE(40, my_key)\n In [8]: ctext_ae = my_WBC_AE.wrap(message, metadata)\n In [9]: len(ctext_ae)\n Out[9]: 56\n In [10]: hexlify(ctext_ae)\n Out[10]: b'388623f7a7d3c044cda574063b4ff16edbdfc95cb449f335a1c5ad5ed37897aa2470f3575825a55df04cc1dab34b4feb03aa6d35f6190d62'\n In [11]: plaintext, validated = my_WBC_AE.unwrap(ctext_ae, metadata)\n In [12]: plaintext\n Out[12]: b'These violent delights have violent ends'\n In [13]: validated\n Out[13]: True\n\n\nKravatteOracle\n--------------\n\n``KravatteOracle`` is a simple pseudo-random number generator built from the ``Kravatte`` PRF primitive. Initialized\nwith an authentication key, the ``KravatteOracle`` object absorbs an arbitrarily sized seed value into the\ncollector state. From there, streams of random bytes can be generated on demand via the ``random`` method.\nThe generator can be re-seeded at any point with the ``seed_generator`` method.\n\nGenerate Random Numbers\n~~~~~~~~~~~~~~~~~~~~~~~\n\n.. code:: python\n\n In [1]: my_psrng = KravatteOracle(my_seed, my_key)\n In [2]: my_key = b'1234'\n In [3]: my_seed = b'watermelon'\n In [4]: my_psrng = KravatteOracle(my_seed, my_key)\n In [5]: random_bytes = my_psrng.random(24)\n In [6]: hexlify(random_bytes)\n Out[6]: b'14a42ab5756efe61eae73893570b6736b392d0031a87e36d'\n In [7]: random_bytes = my_psrng.random(42)\n In [8]: hexlify(random_bytes)\n Out[8]: b'77d6308e18d57fb124e75602ced2e863e7de34c69ea57bec47efae84e85d0075c3ebbf7e535ec0fb096f'\n\nRe-seed Generator\n~~~~~~~~~~~~~~~~~\n\n.. code:: python\n\n In [9]: my_psrng.seed_generator(b'apple')\n In [10]: random_bytes = my_psrng.random(18)\n In [11]: hexlify(random_bytes)\n Out[11]: b'3e108c3f627f561943893b6a3184e5b76472'\n\nKravatte-SIV (Deprecated)\n-------------------------\n\n``Kravatte-SIV`` mode is a method of authenticated encryption with\nassociated metadata (AEAD) that allows for encrypting a provided\nplaintext with a secret shared key and an arbitrary metadata value.\nEncryption generates an equal length ciphertext and fixed length tag\nthat can be used to validate the plaintext at decryption. Metadata\nvalues can be shared for different key/message combinations with\nunderstanding that the more a value is used, the greater the chance of a\ntag collision. **Deprecated in favor of Kravatte-SANSE**\n\nEncrypt\n~~~~~~~\n\n.. code:: python\n\n In [1] from kravatte import siv_wrap, siv_unwrap\n In [2] from binascii import hexlify\n In [3] from datetime import datetime\n In [4] message = b'Attack at Dawn!'\n In [5] key = b'something_secret'\n In [6] metadata = str(datetime.now()).encode()\n In [7] ciphertext, tag = siv_wrap(key, message, metadata)\n In [8] hexlify(ciphertext)\n Out[8] b'79f7bd89a7cb7af1892ea51c531f4b'\n In [9] hexlify(tag)\n Out[9] b'37c7e11f0c9c744e7c113590fdfba7737cb38b629ef6901df22d6994340e89eas'\n\nDecrypt\n~~~~~~~\n\n.. code:: python\n\n In [10] plaintext, tag_valid = siv_unwrap(key, ciphertext, tag, metadata)\n In [11] plaintext\n Out[11] b'Attack at Dawn!'\n In [12] tag_valid\n Out[12] True\n\nKravatte-SAE (Deprecated)\n-------------------------\n\n``Kravatte-SAE`` mode is a session based method of AEAD. Given a random\nnonce and secret key, this mode encrypts a sequence of plaintext\nmessages and/or metadata into equal size ciphertexts and a validation\ntag. The sequence of plaintext/metadata is tracked as a history that\nbuilds a chain of authentication from message to message and requires\nall generated ciphertexts to be processed to fully decrypt and verify.\n**Deprecated in favor of Kravatte-SANE**\n\nA separate ``KravatteSAE`` class is provided that adds the history\ntracking for each encryption operation done via the ``sae_wrap`` method.\n\nEncrypt\n~~~~~~~\n\n.. code:: python\n\n In [1]: from kravatte import KravatteSAE\n In [2]: from datetime import datetime\n In [3]: from binascii import hexlify\n In [4]: message_1 = b'Directions to my house:'\n In [5]: metadata_1 = str(datetime.now()).encode()\n In [6]: message_2 = b'Turn right on main street'\n In [7]: metadata_2 = str(datetime.now()).encode()\n In [8]: message_3 = b'Continue straight for 3500 miles'\n In [9]: metadata_3 = str(datetime.now()).encode()\n In [10]: message_4 = b'You have arrived at your destination'\n In [11]: metadata_4 = str(datetime.now()).encode()\n In [12]: nonce = b'a well chosen random number'\n In [13]: key = b'an even better random number'\n In [14]: KravSAE_wrapper = KravatteSAE(nonce, key)\n In [15]: ciphertext_1, tag_1 = KravSAE_wrapper.sae_wrap(message_1, metadata_1)\n In [16]: hexlify(ciphertext_1)\n Out[16]: b'7b8932a1c3673fcfe752631ef5b867843951514335de61'\n In [17]: hexlify(tag_1)\n Out[17]: b'3384885ca293925cc65a03fa10790420'\n In [18]: ciphertext_2, tag_2 = KravSAE_wrapper.sae_wrap(message_2, metadata_2)\n In [19]: hexlify(ciphertext_2)\n Out[19]: b'ab48882d4339c6def9d5d06f608db5318a87a417566c0b20bd'\n In [20]: hexlify(tag_2)\n Out[20]: b'347f5a152dcc9ccc3c19fa936067c3d2'\n In [21]: ciphertext_3, tag_3 = KravSAE_wrapper.sae_wrap(message_3, metadata_3)\n In [22]: hexlify(ciphertext_3)\n Out[22]: b'bc461f40db74705c10b1400b6a9967dd7164cbf774c196d5b649faf2bd792339'\n In [23]: hexlify(tag_3)\n Out[23]: b'6ba2faee4d2aa5654a054222a049d926'\n In [24]: ciphertext_4, tag_4 = KravSAE_wrapper.sae_wrap(message_4, metadata_4)\n In [25]: hexlify(ciphertext_4)\n Out[25]: b'1f451f51d9882f9f7674c37dace4036efd9efe39d6b58ccdf6b012ef988e4e1f2617479f'\n In [26]: hexlify(tag_4)\n Out[26]: b'5f3511f140b4ea36412c0e4b22d1c218'\n\nFor decryption and validation, the ``sae_unwrap`` method accepts the\nciphertext, original metadata, and validation tag to not only decrypt\nthe plaintext, but return a boolean if the decrypted plaintext is valid\nwithin the chain of messages.\n\nDecrypt\n~~~~~~~\n\n.. code:: python\n\n In [27]: KravSAE_unwrapper = KravatteSAE(nonce, key)\n In [28]: plaintext_1, check_tag_1 = KravSAE_unwrapper.sae_unwrap(ciphertext_1, metadata_1, tag_1)\n In [29]: plaintext_1\n Out[29]: b'Directions to my house:'\n In [30]: check_tag_1\n Out[30]: True\n In [31]: plaintext_2, check_tag_2 = KravSAE_unwrapper.sae_unwrap(ciphertext_2, metadata_2, tag_2)\n In [32]: plaintext_2\n Out[32]: b'Turn right on main street'\n In [33]: check_tag_2\n Out[33]: True\n In [34]: plaintext_3, check_tag_3 = KravSAE_unwrapper.sae_unwrap(ciphertext_3, metadata_3, tag_3)\n In [35]: plaintext_3\n Out[35]: b'Continue straight for 3500 miles'\n In [36]: check_tag_3\n Out[36]: True\n In [37]: plaintext_4, check_tag_4 = KravSAE_unwrapper.sae_unwrap(ciphertext_4, metadata_4, tag_4)\n In [38]: plaintext_4\n Out[38]: b'You have arrived at your destination'\n In [39]: check_tag_4\n Out[39]: True\n\n\nMulti-Process Performance Mode\n---------------------------------\nThe Farfalle PRF allows for significant parallelism in both the compression and expansion phases when\nconsuming or generating large numbers of blocks. We can exploit that fact for increased performance\nvia Python's `multiprocessing `__ module.\nThis allows us to spawn any number of identical worker subprocesses that can consume additional\nCPU core resources. Enabling the multi-process mode is done at object creation time for ``Kravatte``,\nor any of its operating modes, with the ``workers`` arguments:\n\n.. code:: python\n\n In [1]: new_kravatte = Kravatte(my_key, workers=8)\n In [2]: my_kra_mac = mac(my_key, my_message, my_output_size, workers=16)\n In [3]: my_wbc = KravatteWBC(block_size, my_tweak, my_key, workers=4)\n\nFor optimal performance, the number of workers should match the number of CPU cores reported by\n``os.cpu_count``. This is set automatically if ``workers`` is set to 0:\n\n.. code:: python\n\n # Equivalent objects\n In [4]: my_psrng = KravatteOracle(my_seed, my_key, workers=0)\n In [5]: my_psrng = KravatteOracle(my_seed, my_key, workers=os.cpu_count())\n\nMulti-process mode can be explicitly disabled by setting workers to ``None``:\n\n.. code:: python\n\n In [6]: my_psrng = KravatteOracle(my_seed, my_key, workers=None)\n\nThere is a non-trivial performance cost associated with generating new Python processes. For small,\ngenerally < 100KB, inputs and outputs, it can be faster to use the single process variant.\n\nFor asymmetrically sized workloads, such a generating a MAC on a multi-megabyte input and only\ngenerating a few dozen bytes of output, multiprocessing mode can be explicitly enabled or disabled with the\n``mp_input`` and ``mp_output`` arguments. These booleans are available for ``Kravatte`` and all derived classes/functions.\n\n.. code:: python\n\n # Enable Multiprocessing acceleration only for processing of input bytes\n In [7]: my_psrng = KravatteOracle(my_seed, my_key, workers=16, mp_input=True, mp_output=False)\n\n\nTesting\n-------\n\nA full test suite is available in the ``test/`` dir. Tests can be invoked with pytest:\n\n.. code:: bash\n\n $ cd path/to/cloned/kravatte/\n $ pytest -xvvv\n\nThe same tests are run against the standard codepath and the multiprocess code path utilizing all available\nCPU cores. Test vectors were generated using the\n`KeccakTools `__ C++ library available from the Keccak Team\n\nCaveats\n-------\n\n- Being a Python implementation, performance on large files or data\n sets may be inadequate (even with multi-processing enabled).\n- The inputs and outputs of this implementation are limited to byte\n (8-bit) divisible sizes\n- While security was top of mind during development, this\n implementation has not been fully audited for timing attacks, side\n channel attacks or other vulnerabilities. Other bugs not caught by\n the test cases may be present. Use in a production environment is not\n encouraged.\n\nIf any of above are of concern, please check out the official\n`KeccakTools `__ and `Keccak Code\nPackage `__\n\nChangelog\n---------\n\n1.2.0 (2018-12-02) \n~~~~~~~~~~~~~~~~~~\n\n- Add Kravatte-SANE Support [Calvin McCoy]\n- Add Kravatte-SANSE Support [Calvin McCoy]\n- Refactor tests into seperate classes [Calvin McCoy]\n\n1.1.0 (2018-09-08) \n~~~~~~~~~~~~~~~~~~\n\n- Add TravisCI Testing [Calvin McCoy]\n- Add memory scrub functionality. [Calvin McCoy]\n- Optimizations to Keccak, expand permutation, and compress permutations [Calvin McCoy]\n- Added ability to enable Multi-processing for just input or output [Calvin McCoy]\n- Fixed Typos and Added Some Extra Comments [Calvin McCoy]\n\n1.0.0 (2018-05-19)\n~~~~~~~~~~~~~~~~~~\n\n- Added Multi-processing mode [Calvin McCoy]\n- Cleanup for 1.0 release [Calvin McCoy]\n\n0.9.2 (2018-04-07)\n~~~~~~~~~~~~~~~~~~\n\n- Add KravatteOracle pseudo-random generator [Calvin McCoy]\n- Add type hinting [Calvin McCoy]\n- Fix Typos [Calvin McCoy]\n\n0.9.0 (2018-03-31)\n~~~~~~~~~~~~~~~~~~\n\n- General package cleanup and fix typos [Calvin McCoy]\n\n\n0.8.0 (2018-03-28)\n~~~~~~~~~~~~~~~~~~\n\n- Initial Commit [Calvin McCoy]\n\n", "description_content_type": "", "docs_url": null, "download_url": "https://github.com/inmcm/kravatte/archive/1.2.0.tar.gz", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/inmcm/kravatte", "keywords": "kravatte,farfalle,PRF,AEAD,MAC,crypto,encryption", "license": "MIT license", "maintainer": "", "maintainer_email": "", "name": "kravatte", "package_url": "https://pypi.org/project/kravatte/", "platform": "", "project_url": "https://pypi.org/project/kravatte/", "project_urls": { "Download": "https://github.com/inmcm/kravatte/archive/1.2.0.tar.gz", "Homepage": "https://github.com/inmcm/kravatte" }, "release_url": "https://pypi.org/project/kravatte/1.2.0/", "requires_dist": [ "numpy (>=1.12.0)" ], "requires_python": "", "summary": "Kravatte Encryption Authentication Tools", "version": "1.2.0" }, "last_serial": 4552920, "releases": { "0.9.1": [ { "comment_text": "", "digests": { "md5": "c766fccb67ecdffdf0078a2c7afa677b", "sha256": "b69dbade2fac258b52becdfbe38202e23e25f2bc839ab63291101051cdd06751" }, "downloads": -1, "filename": "kravatte-0.9.1-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "c766fccb67ecdffdf0078a2c7afa677b", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 18215, "upload_time": "2018-03-31T18:20:01", "url": "https://files.pythonhosted.org/packages/f4/14/08935204897b260be1c19cbc1d36795d94db2d1aea102538e89a354a952b/kravatte-0.9.1-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "a65d6918cad1acd4dc65ac38a19874d7", "sha256": "853a3ec45b6e675f6ce93ac57cf3609769f7b4025390f05414160b32be7bbb57" }, "downloads": -1, "filename": "kravatte-0.9.1.tar.gz", "has_sig": false, "md5_digest": "a65d6918cad1acd4dc65ac38a19874d7", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 17126, "upload_time": "2018-03-31T18:20:02", "url": "https://files.pythonhosted.org/packages/a7/9b/e6806a34e5d8ac8b520f6ce248e86207245f3474d65f849250686c19cb70/kravatte-0.9.1.tar.gz" } ], "0.9.2": [ { "comment_text": "", "digests": { "md5": "ae12e6525da767da274060a6df52a4d6", "sha256": "70e72d2f7218408683c81ba49e8bed9ab0be886c293b72d1d0a0f3132876fc55" }, "downloads": -1, "filename": "kravatte-0.9.2-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "ae12e6525da767da274060a6df52a4d6", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 19572, "upload_time": "2018-04-07T21:58:31", "url": "https://files.pythonhosted.org/packages/5a/71/f0192fde3a8c453e1b5c5eddc7e21d282cd1172733b4c877d4e8b91691cc/kravatte-0.9.2-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "958365350f6577d352c87f159441babc", "sha256": "5ef0bc9963a10b70fed43891c561e74710bf4605dd672096b965a5fbc2ff8e8b" }, "downloads": -1, "filename": "kravatte-0.9.2.tar.gz", "has_sig": false, "md5_digest": "958365350f6577d352c87f159441babc", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 18434, "upload_time": "2018-04-07T21:58:32", "url": "https://files.pythonhosted.org/packages/c0/2f/d550d30232c98cb576ba9af1626bb3b4b8a4f5cf3aea1de8beb4fcac2574/kravatte-0.9.2.tar.gz" } ], "1.0.0": [ { "comment_text": "", "digests": { "md5": "4c1242c4d5859cb742c268acd90d0093", "sha256": "a56808a1a12a3a2841f62c251f1afcc3de5d3d8abdd0f15e3a14d91ff6f8b102" }, "downloads": -1, "filename": "kravatte-1.0.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "4c1242c4d5859cb742c268acd90d0093", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 21737, "upload_time": "2018-05-19T20:04:53", "url": "https://files.pythonhosted.org/packages/f9/52/466b12267df201d5e9202183dfebd2b9037edd0f06ccdddea7e8349222bd/kravatte-1.0.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "e667a11a6352650605937346188255fc", "sha256": "a0e04531815312a57bf3482789e68709a7f71139232ab6f069c2f0cd86f4877f" }, "downloads": -1, "filename": "kravatte-1.0.0.tar.gz", "has_sig": false, "md5_digest": "e667a11a6352650605937346188255fc", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 20554, "upload_time": "2018-05-19T20:04:54", "url": "https://files.pythonhosted.org/packages/c7/35/d9eef2344df12197afd58ba4c4490d650cab3f80180b811c984b1738509a/kravatte-1.0.0.tar.gz" } ], "1.1.0": [ { "comment_text": "", "digests": { "md5": "f2dd390eaa6ef6e5e25014654e84c901", "sha256": "3c42a968a99b49d63d7e690a2b8f22fe15b60ce615095e903d1dabe5198fdd10" }, "downloads": -1, "filename": "kravatte-1.1.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "f2dd390eaa6ef6e5e25014654e84c901", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 15960, "upload_time": "2018-09-08T16:55:54", "url": "https://files.pythonhosted.org/packages/58/ad/201e10415c23ab92c03b8c88f00d4fa9727cb3590c552d4175426510943d/kravatte-1.1.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "fc7d6bad2d38454c5a92d63743e08679", "sha256": "f927db75757b5d6b08ca4df4bc443671c1f50c68decfbb8076f115f56bfee05b" }, "downloads": -1, "filename": "kravatte-1.1.0.tar.gz", "has_sig": false, "md5_digest": "fc7d6bad2d38454c5a92d63743e08679", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 22065, "upload_time": "2018-09-08T16:55:57", "url": "https://files.pythonhosted.org/packages/31/9d/6985793633f5ef164dc443bebb6253af6b26b89e407c32ccc08b92d60508/kravatte-1.1.0.tar.gz" } ], "1.2.0": [ { "comment_text": "", "digests": { "md5": "59deb22b6dcb37609e3f37a5a6cd6e5a", "sha256": "40feaeed0208fc2e4d04da7784b937037dbb3a2d0b68574b6657443e67520c81" }, "downloads": -1, "filename": "kravatte-1.2.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "59deb22b6dcb37609e3f37a5a6cd6e5a", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 18743, "upload_time": "2018-12-02T18:03:30", "url": "https://files.pythonhosted.org/packages/1b/45/93adce0095701e79a382b15c67ef6797f4837b4a61561e8f63e073d5dc50/kravatte-1.2.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "ae4713951e9f356a0ceaedafb7ee5b44", "sha256": "50d7aecc5782a9e0bad2d2601eb0b1f14916a10d089ab0565cb7602b937dcfe0" }, "downloads": -1, "filename": "kravatte-1.2.0.tar.gz", "has_sig": false, "md5_digest": "ae4713951e9f356a0ceaedafb7ee5b44", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 25841, "upload_time": "2018-12-02T18:03:32", "url": "https://files.pythonhosted.org/packages/af/35/826e0b65805ef776b576ab17064a145d809bc1ed5c5f3b0cec829c383b2f/kravatte-1.2.0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "59deb22b6dcb37609e3f37a5a6cd6e5a", "sha256": "40feaeed0208fc2e4d04da7784b937037dbb3a2d0b68574b6657443e67520c81" }, "downloads": -1, "filename": "kravatte-1.2.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "59deb22b6dcb37609e3f37a5a6cd6e5a", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 18743, "upload_time": "2018-12-02T18:03:30", "url": "https://files.pythonhosted.org/packages/1b/45/93adce0095701e79a382b15c67ef6797f4837b4a61561e8f63e073d5dc50/kravatte-1.2.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "ae4713951e9f356a0ceaedafb7ee5b44", "sha256": "50d7aecc5782a9e0bad2d2601eb0b1f14916a10d089ab0565cb7602b937dcfe0" }, "downloads": -1, "filename": "kravatte-1.2.0.tar.gz", "has_sig": false, "md5_digest": "ae4713951e9f356a0ceaedafb7ee5b44", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 25841, "upload_time": "2018-12-02T18:03:32", "url": "https://files.pythonhosted.org/packages/af/35/826e0b65805ef776b576ab17064a145d809bc1ed5c5f3b0cec829c383b2f/kravatte-1.2.0.tar.gz" } ] }