Package: aiootp
aiootp - Asynchronous pseudo one-time pad based crypto and anonymity library.aiootpis an asynchronous library providing access to cryptographic
primatives and abstractions, transparently encrypted / decrypted file
I/O and databases, as well as powerful, pythonic utilities that
simplify data processing & cryptographic procedures in python code.
This library’s online, salt reuse / misuse resistant, tweakable AEAD cipher, calledChunky2048, is an implementation of thepseudo one-time pad. The
aim is to create a simple, standard, efficient implementation that’s
indistinguishable from the unbreakable one-time pad cipher; to give
users and applications access to user-friendly cryptographic tools; and,
to increase the overall security, privacy, and anonymity on the web, and
in the digital world. Users will findaiootpto be easy to write,
easy to read, and fun.Important Disclaimeraiootpis experimental software that works with Python 3.7+.
It’s a work in progress. The programming API could change with
future updates, and it isn’t bug free.aiootpprovides powerful
security tools and misc utilities that’re designed to be
developer-friendly and privacy preserving.
As a security tool,aiootpneeds to be tested and reviewed
extensively by the programming and cryptography communities to
ensure its implementations are sound. We provide no guarantees.
This software hasn’t yet been audited by third-party security
professionals.Quick Install$sudoapt-getinstallpython3-setuptoolspython3-pip$pip3install--user--upgradepiptypingaiootpRun Tests$cd~/aiootp/tests$coveragerun--sourceaiootp-mpytest-vvtest_aiootp.pyTable Of ContentsTransparently Encrypted DatabasesIdeal InitializationUser ProfilesTagsMetatagsBasic ManagementMirrorsPublic Cryptographic FunctionsEncrypt / DecryptHMACsChunky2048 CipherHigh-level FunctionsHigh-level GeneratorsPasscryptHashing & Verifying PassphrasesPasscrypt Algorithm OverviewX25519 & Ed25519X25519Ed25519ComprendeSynchronous GeneratorsAsynchronous GeneratorsModule OverviewFAQChangelogKnown IssuesTransparently Encrypted Databases…………..Table Of ContentsThe package’sAsyncDatabase&Databaseclasses are very powerful data persistence utilities. They automatically handle encryption & decryption of user data & metadata, providing a pythonic interface for storing & retrieving any bytes or JSON serializable objects. They’re designed to seamlessly bring encrypted bytes at rest to users as dynamic objects in use.Ideal Initialization………………………Table Of ContentsMake a new user key with a fast, cryptographically secure pseudo-random number generator. Then this strong 64-byte key can be used to create a database object.fromaiootpimportacsprng,AsyncDatabasekey=awaitacsprng()db=awaitAsyncDatabase(key)User Profiles…………………………….Table Of ContentsWith User Profiles, passphrases may be used instead to open a database. Often, passwords & passphrases contain very little entropy. So, they aren’t recommended for that reason. However, profiles provide a succinct way to use passphrases more safely. They do this by deriving strong keys from low entropy user input using the memory/cpu hard passcrypt algorithm, & a secret salt which is automatically generated & stored on the user’s filesystem.# Automatically convert any available user credentials into# cryptographic tokens which help to safely open databases ->db=awaitAsyncDatabase.agenerate_profile(b"server-url.com",# Here an unlimited number of bytes-type# arguments can be passed as additionalb"address@email.net",# optional credentials.username=b"username",passphrase=b"passphrase",salt=b"optional salt keyword argument",# Optional passcrypt configuration:mb=256,# The memory cost in Mibibytes (MiB)cpu=2,# The computational complexity & number of iterationscores=8,# How many parallel processes passcrypt will utilize)Tags…………………………………….Table Of ContentsData within databases are primarily organized by Tags. Tags are simply string labels, and the data stored under them can be any bytes or JSON serializable objects.asyncwithdb:# Using bracketed assignment adds tags to the cachedb["tag"]={"data":"can be any JSON serializable object"}db["hobby"]=b"fash smasher"db["bitcoin"]="0bb6eee10d2f8f45f8a"db["lawyer"]={"#":"555-555-1000","$":13000.50}db["safehouses"]=["Dublin Forgery","NY Insurrection"]# Changes in the cache are saved to disk when the context closes.# View an instance's tags ->db.tags>>>{'tag','hobby','bitcoin','lawyer','safehouses'}# View the filenames that locate the data for each tag ->db.filenames>>>{'0z0l10btu_yd-n4quc8tsj9baqu8xmrxz87ix','197ulmqmxg15lebm26zaahpqnabwr8sprojuh','248piaop3j9tmcvqach60qk146mt5xu6kjc-u','2enwc3crove2cnrx7ks963d8_se25k6cdn6q9','5dm-60yspq8yhah4ywxcp52kztq_9toj0owm2'}# There are various ways of working with tags ->awaitdb.aset_tag("new_tag",["data","goes","here"])# stored only in cacheawaitdb.aquery_tag("new_tag")# reads from disk if not in the cache>>>['data','goes','here']tag_path=db.path/awaitdb.afilename("new_tag")"new_tag"indb>>>Truetag_path.is_file()# the tag is saved in the cache, not to disk yet>>>Falseawaitdb.asave_tag("new_tag")tag_path.is_file()# now it's saved to disk>>>True# This removes the tag from cache, & any of its unsaved changes ->awaitdb.arollback_tag("new_tag")# Or, the user can take the tag out of the database & the filesystem ->awaitdb.apop_tag("new_tag")>>>['data','goes','here']"new_tag"indb>>>Falsetag_path.is_file()>>>FalseAccess to data is open to the user, so care must be taken not to let external API calls touch the database without accounting for how that can go wrong.Metatags…………………………………Table Of ContentsMetatags are used to organize data by string names & domain separate cryptographic material. They are fully-fledged databases all on their own, with their own distinct key material too. They’re accessible from the parent through an attribute that’s added to the parent instance with the same name as the metatag. When the parent is saved, or deleted, then their descendants are also.# Create a metatag database ->molly=awaitdb.ametatag("molly")# They can contain their own sets of tags (and metatags) ->molly["hobbies"]=["skipping","punching"]molly["hobbies"].append("reading")# The returned metatag & the reference in the parent are the same ->assertmolly["hobbies"]isdb.molly["hobbies"]assertisinstance(molly,AsyncDatabase)# All of an instance's metatags are viewable ->db.metatags>>>{'molly'}# Delete a metatag from an instance ->awaitdb.adelete_metatag("molly")db.metatags>>>set()assertnothasattr(db,"molly")Basic Management………………………….Table Of ContentsThere’s a few settings & public methods on databases for users to manage their instances & data. This includes general utilities for saving & deleting databases to & from the filesystem, as well as fine-grained controls for how data is handled.# The path attribute is set within the instance's __init__# using a keyword-only argument. It's the directory where the# instance will store all of its files.db.path>>>PosixPath('site-packages/aiootp/aiootp/databases')# Write database changes to disk with transparent encryption ->awaitdb.asave_database()# Entering the instance's context also saves data to disk ->asyncwithdb:print("Saving to disk...")# Delete a database from the filesystem ->awaitdb.adelete_database()As databases grow in the number of tags, metatags & the size of data within, it becomes desireable to load data from them as needed, instead of all at once into the cache during initialization. This is why thepreloadboolean keyword-only argument is set toFalseby default.# Let's create some test values to show the impact preloading has ->asyncwith(awaitAsyncDatabase(key,preload=True))asdb:db["favorite_foods"]=["justice","community"]awaitdb.ametatag("exercise_routines")db.exercise_routines["gardening"]={"days":["moday","wednesday"]}db.exercise_routines["swimming"]={"days":["thursday","saturday"]}# Again, preloading into the cache is toggled off by default ->uncached_db=awaitAsyncDatabase(key)# To retrieve elements, ``aquery_tag`` isn't necessary when# preloading is used, since the tag is already in the cache ->asyncwithuncached_db:db["favorite_foods"]>>>["justice","community"]uncached_db["favorite_foods"]>>>Nonevalue=awaituncached_db.aquery_tag("favorite_foods",cache=True)assertvalue==["justice","community"]assertuncached_db["favorite_foods"]==["justice","community"]# Metatags will be loaded, but their tags won't be ->asserttype(uncached_db.exercise_routines)==AsyncDatabaseuncached_db.exercise_routines["gardening"]>>>Noneawaituncached_db.exercise_routines.aquery_tag("gardening",cache=True)>>>{"days":["moday","wednesday"]}uncached_db.exercise_routines["gardening"]>>>{"days":["moday","wednesday"]}# But, tags can also be queried without caching their values,value=awaituncached_db.exercise_routines.aquery_tag("swimming")value>>>{"days":["thursday","saturday"]}uncached_db.exercise_routines["swimming"]>>>None# However, changes to mutable values won't be transmitted to the# database if they aren't retrieved from the cache ->value["days"].append("sunday")value>>>{"days":["thursday","saturday","sunday"]}awaituncached_db.exercise_routines.aquery_tag("swimming")>>>{"days":["thursday","saturday"]}Mirrors………………………………….Table Of ContentsDatabase mirrors allow users to make copies of all files within a database under new encryption keys. This is useful if users simply want to make backups, or if they’d like to update / change their database keys.# A unique login key / credentials are needed to create a new# database ->new_key=awaitacsprng()new_db=awaitAsyncDatabase(new_key)# Mirroring an existing database is done like this ->awaitnew_db.amirror_database(db)assert(awaitnew_db.aquery_tag("favorite_foods")isawaitdb.aquery_tag("favorite_foods"))# If the user is just updating their database keys, then the old# database should be deleted ->awaitdb.adelete_database()# Now, the new database can be saved to disk & given an appropriate# name ->asyncwithnew_dbasdb:passPublic Cryptographic Functions……………..Table Of ContentsAlthough databases handle encryption & decryption automatically, users may want to utilize their databases’ keys to do custom cryptographic procedures manually. There are a few public functions available to users if they should want such functionality.Encrypt / Decrypt…………………………Table Of Contents# Either JSON serializable or bytes-type data can be encrypted ->json_plaintext={"some":"JSON data can go here..."}bytes_plaintext=b"some bytes plaintext goes here..."token_plaintext=b"some token data goes here..."json_ciphertext=awaitdb.ajson_encrypt(json_plaintext)bytes_ciphertext=awaitdb.abytes_encrypt(bytes_plaintext)token_ciphertext=awaitdb.amake_token(token_plaintext)# Those values can just as easily be decrypted ->assertjson_plaintext==awaitdb.ajson_decrypt(json_ciphertext)assertbytes_plaintext==awaitdb.abytes_decrypt(bytes_ciphertext)asserttoken_plaintext==awaitdb.aread_token(token_ciphertext)# Filenames may be added to classify ciphertexts. They also alter the# key material used during encryption in such a way, that without the# correct filename, the data cannot be decrypted ->filename="grocery-list"groceries=["carrots","taytoes","rice","beans"]ciphertext=awaitdb.ajson_encrypt(groceries,filename=filename)assertgroceries==awaitdb.ajson_decrypt(ciphertext,filename=filename)awaitdb.ajson_decrypt(ciphertext,filename="wrong filename")>>>"InvalidSHMAC: Invalid StreamHMAC hash for the given ciphertext."# Time-based expiration of ciphertexts is also available for all# encrypted data this package produces ->fromaiootp.asynchsimportasleepawaitasleep(6)awaitdb.ajson_decrypt(json_ciphertext,ttl=1)>>>"TimestampExpired: Timestamp expired by <5> seconds."awaitdb.abytes_decrypt(bytes_ciphertext,ttl=1)>>>"TimestampExpired: Timestamp expired by <5> seconds."awaitdb.aread_token(token_ciphertext,ttl=1)>>>"TimestampExpired: Timestamp expired by <5> seconds."# The number of seconds that are exceeded may be helpful to know. In# which case, this is how to retrieve that integer value ->try:awaitdb.abytes_decrypt(bytes_ciphertext,ttl=1)exceptdb.TimestampExpiredaserror:asserterror.expired_by==5HMACs……………………………………Table Of ContentsBesides encryption & decryption, databases can also be used to manually verify the authenticity of bytes-type data with HMACs.# Creating an HMAC of some data with a database is done this way ->data=b"validate this data!"hmac=awaitdb.amake_hmac(data)awaitdb.atest_hmac(hmac,data)# Runs without incident# Data that is not the same will be caught ->altered_data=b"valiZate this data!"awaitdb.atest_hmac(hmac,altered_data)>>>"InvalidHMAC: Invalid HMAC hash for the given data."# Any number of bytes-type arguments can be run thorugh the function,# the collection of items is canonically encoded automagically ->arbitrary_data=(b"uid_\x0f\x12",b"session_id_\xa1")hmac=awaitdb.amake_hmac(*arbitrary_data)awaitdb.atest_hmac(hmac,*arbitrary_data)# Runs without incident# Additional qualifying information can be specified with the ``aad``# keyword argument ->fromtimeimporttimetimestamp=int(time()).to_bytes(8,"big")hmac=awaitdb.amake_hmac(*arbitrary_data,aad=timestamp)awaitdb.atest_hmac(hmac,*arbitrary_data)>>>"InvalidHMAC: Invalid HMAC hash for the given data."awaitdb.atest_hmac(hmac,*arbitrary_data,aad=timestamp)# Runs fine# This is most helpful for domain separation of the HMAC outputs.# Each distinct setting & purpose of the HMAC should be specified# & NEVER MIXED ->uuid=awaitdb.amake_hmac(user_name,aad=b"uuid")hmac=awaitdb.amake_hmac(user_data,aad=b"data-authentication")#Chunky2048 Cipher…………………………Table Of ContentsTheChunky2048cipher is built from generators & SHA3-based key-derivation functions. It’s designed to be easy to use, difficult to misuse & future-proof with large security margins.High-level Functions……………………..Table Of ContentsThese premade recipes allow for the easiest usage of the cipher.importaiootpcipher=aiootp.Chunky2048(key)# Symmetric encryption of JSON data ->json_data={"account":33817,"names":["queen b"],"id":None}encrypted_json_data=cipher.json_encrypt(json_data,aad=b"demo")decrypted_json_data=cipher.json_decrypt(encrypted_json_data,aad=b"demo",ttl=120)assertdecrypted_json_data==json_data# Symmetric encryption of binary data ->binary_data=b"some plaintext data..."encrypted_binary_data=cipher.bytes_encrypt(binary_data,aad=b"demo")decrypted_binary_data=cipher.bytes_decrypt(encrypted_binary_data,aad=b"demo",ttl=30)assertdecrypted_binary_data==binary_data# encrypted URL-safe Base64 encoded tokens ->token_data=b"some plaintext token data..."encrypted_token_data=cipher.make_token(token_data,aad=b"demo")decrypted_token_data=cipher.read_token(encrypted_token_data,aad=b"demo",ttl=3600)assertdecrypted_token_data==token_dataHigh-level Generators……………………..Table Of ContentsWith these generators, the online nature of the Chunky2048 cipher can be utilized. This means that any arbitrary amount of data can be processed in streams of controllable, buffered chunks. These streaming interfaces automatically handle message padding & depadding, ciphertext validation & detection of out-of-order message blocks.Encryption:fromaiootpimportAsyncCipherStream# Let's imagine we are serving some data over a network ->receiver=SomeRemoteConnection(session).connect()# This will manage encrypting a stream of data ->stream=awaitAsyncCipherStream(key,aad=session.transcript)# We'll have to send the salt & iv in some way ->receiver.transmit(salt=stream.salt,iv=stream.iv)# Now we can buffer the plaintext we are going to encrypt ->forplaintextinreceiver.upload.buffer(4*stream.PACKETSIZE):awaitstream.abuffer(plaintext)# The stream will now produce encrypted blocks of ciphertext# as well as the block ID which authenticates each block ->asyncforblock_id,ciphertextinstream:# The receiver needs both the block ID & ciphertext ->receiver.send_packet(block_id+ciphertext)# Once done with buffering-in the plaintext, the ``afinalize``# method is called so the remaining encrypted data will be# flushed out of the buffer to the user ->asyncforblock_id,ciphertextinstream.afinalize():receiver.send_packet(block_id+ciphertext)# Here we can give an optional check of further authenticity,# also cryptographically asserts the stream is finished ->receiver.transmit(shmac=awaitstream.shmac.afinalize())Decryption / Authentication:fromaiootpimportAsyncDecipherStream# Here let's imagine we'll be downloading some data ->source=SomeRemoteConnection(session).connect()# The key, salt, aad & iv must be the same for both parties ->stream=awaitAsyncDecipherStream(key,salt=source.salt,aad=session.transcript,iv=source.iv)# The downloaded ciphertext will now be buffered & the stream# object will produce the plaintext ->forciphertextinsource.download.buffer(4*stream.PACKETSIZE):# Here stream.shmac.InvalidBlockID is raised if an invalid or# out-of-order block is detected within the last 4 packets ->awaitstream.abuffer(ciphertext)# If authentication succeeds, the plaintext is produced ->asyncforplaintextinstream:yieldplaintext# After all the ciphertext is downloaded, ``afinalize`` is called# to finish processing the stream & flush out the plaintext ->asyncforplaintextinstream.afinalize():yieldplaintext# An optional check for further authenticity which also# cryptographically asserts the stream is finished ->awaitstream.shmac.afinalize()awaitstream.shmac.atest_shmac(source.shmac)#Passcrypt…………………………Table Of ContentsThePasscryptalgorithm is a data independent memory & computationally hard password-based key derivation function. It’s built from a single primitive, the SHAKE-128 extendable output function from the SHA-3 family. Its resource costs are measured by three parameters:mb, which represents an integer number of Mibibytes (MiB);cpu, which is a linear integer measure of computational complexity & the number of iterations of the algorithm over the memory cache; andcores, which is an integer which directly assigns the number of separate processes that will be pooled to complete the algorithm. The number of bytes of the output tag are decided by the integertag_sizeparameter. And, the number of bytes of the automatically generatedsaltare decided by the integersalt_sizeparameter.Hashing & Verifying Passphrases……………………..Table Of ContentsBy far, the dominating measure of difficulty forPasscryptis determined by thembMibibyte memory cost. It’s recommended that increases to desired difficulty are first translated into highermbvalues, where resource limitations of the machines executing the algorithm permit. If more difficulty is desired than can be obtained by increasingmb, then increases to thecpuparameter should be used. The higher this parameter is the less likely an adversary is to benefit from expending less than the intended memory cost, & increases the execution time & complexity of the algorithm. The final option that should be considered, if still more difficulty is desired, is to lower thecoresparallelization parameter, which will just cause each execution to take longer to complete.fromaiootpimportPasscrypt,hash_bytes# The class accepts an optional (but recommended) static "pepper"# which is applied as additional randomness to all hashes computed# by the class. It's a secret random bytes value of any size that is# expected to be stored somewhere inaccessible by the database which# contains the hashed passphrases ->withopen(SECRET_PEPPER_PATH,"rb")aspepper_file:Passcrypt.PEPPER=pepper_file.read()# when preparing to hash passphrases, it's a good idea to use any &# all of the static data / credentials available which are specific# to the context of the registration ->APPLICATION=b"my-application-name"PRODUCT=b"the-product-being-accessed-by-this-registration"STATIC_CONTEXT=[APPLICATION,PRODUCT,PUBLIC_CERTIFICATE]# If the same difficulty settings are going to be used for every# hash, then a ``Passcrypt`` instance can be initialized to# automatically pass those static settings ->pcrypt=Passcrypt(mb=1024,cpu=2,cores=8)# 1 GiB, 8 cores# Now that the static credentials / settings are ready to go, we# can start hashing any user information that arrives ->username=form["username"].encode()passphrase=form["passphrase"].encode()email_address=form["email_address"].encode()# The ``hash_bytes`` function can then be used to automatically# encode then hash the multi-input data so as to prevent the chance# of canonicalization (&/or length extension) attacks ->aad=hash_bytes(*STATIC_CONTEXT,username,email_address)hashed_passphrase=pcrypt.hash_passphrase(passphrase,aad=aad)asserttype(hashed_passphrase)isbytesassertlen(hashed_passphrase)==38# Later, a hashed passphrase can be used to authenticate a user ->untrusted_username=form["username"].encode()untrusted_passphrase=form["passphrase"].encode()untrusted_email_address=form["email_address"].encode()aad=hash_bytes(*STATIC_CONTEXT,untrusted_username,untrusted_email_address)try:pcrypt.verify(hashed_passphrase,untrusted_passphrase,aad=aad,ttl=3600)exceptpcrypt.InvalidPassphraseasauth_fail:# If the passphrase does not hash to the same value as the# stored hash, then this exception is raised & can be handled# by the application ->app.post_mortem(error=auth_fail)exceptpcrypt.TimestampExpiredasregistration_expired:# If the timestamp on the stored hash was created more than# ``ttl`` seconds before the current time, then this exception# is raised. This is helpful for automating registrations which# expire after a certain amount of time, which in this case was# 1 hour ->app.post_mortem(error=registration_expired)else:# If no exception was raised, then the user has been authenticated# by their passphrase, username, email address & the context of# the registration ->app.login_user(username,email_address)#Passcrypt Algorithm Overview……………………..Table Of ContentsBy being secret-independent,Passcryptis resistant to side-channel attacks. This implementation is also written in pure python. Significant attention was paid to design the algorithm so as to suffer minimally from the performance inefficiencies of python, since doing so would help to equalize the cost of computation between regular users & dedicated attackers with custom hardware / software. Below is a diagram that depicts how an example execution works:#___________________# of rows ___________________|||initialmemorycache||row# of columns == 2 * max([1, cpu // 2])    |||# of rows == ⌈1024*1024*mb/168*columns⌉   |vvvcolumn|---'-----------------------------------------'---|theinitialcachecolumn|---'-----------------------------------------'---|ofsize~`mb`iscolumn|---'-----------------------------------------'---|builtveryquicklycolumn|---'-----------------------------------------'---|usingSHAKE-128.column|---'-----------------------------------------'---|each(row,column)column|---'-----------------------------------------'---|coordinateholdscolumn|---'-----------------------------------------'---|oneelementofcolumn|---'-----------------------------------------'---|168-bytes.^|reflectionrow<-||--------------------'-------'--------------------|eachrowis|--------------------'-------'--------------------|hashedthenhas|--------------------'-------'--------------------|anew168-byte|--------------------'-------'--------------------|digestoverwrite|--------------------'-------'--------------------|thecurrentpointer|--------------------'-------'--------------------|inanalternating|--------------------Xxxxxxxx'xxxxxxxxxxxxxxxxxxxx| sequence, first at|oooooooooooooooooooo'oooooooO--------------------| the index, then at|->itsreflection.index|--'-------------------------------------------'--|thiscontinues|--'-------------------------------------------'--|untiltheentire|--'-------------------------------------------Xxx| cache has been|ooO-------------------------------------------'--| overwritten.|xx'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'xx|asingle`shake_128`|oo'ooooooooooooooooooooooooooooooooooooooooooo'oo|object(H)isused|xx'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'xx|todoallofthe|oo'ooooooooooooooooooooooooooooooooooooooooooo'oo|hashing.|-><-|indexreflection|xxxxxxxxxxx'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| finally, the whole|ooooooooooo'ooooooooooooooooooooooooooooooooooooo| cache is quickly|xxxxxxxxxxx'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| hashed `cpu` + 2|ooooooooooo'ooooooooooooooooooooooooooooooooooooo| number of times.|Fxxxxxxxxxx'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| after each pass an|foooooooooo'ooooooooooooooooooooooooooooooooooooo| 84-byte digest is|fxxxxxxxxxx'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| inserted into the|foooooooooo'ooooooooooooooooooooooooooooooooooooo| cache, ruling out|->hashingstatecycles.|hashcpu+2# of times               Then a `tag_size`-vbytetagisoutput.H(cache)tag=H.digest(tag_size)#X25519 & Ed25519………………………….Table Of ContentsAsymmetric curve 25519 tools are available from these high-level interfaces over thecryptographypackage.X25519…………………………………..Table Of ContentsElliptic curve 25519 diffie-hellman exchange protocols.fromaiootpimportX25519,DomainKDF,GUID,Domains# Basic Elliptic Curve Diffie-Hellman ->guid=GUID().new()my_ecdhe_key=X25519().generate()yieldguid,my_ecdhe_key.public_bytes# send this to Bobraw_shared_secret=my_ecdhe_key.exchange(bobs_public_key)shared_kdf=DomainKDF(# Use this to create secret shared keysDomains.ECDHE,guid,bobs_public_key,my_ecdhe_key.public_bytes,key=raw_shared_secret,)# Triple ECDH Key Exchange client initialization ->withecdhe_key.dh3_client()asexchange:response=internet.post(exchange())exchange(response)clients_kdf=exchange.result()# Triple ECDH Key Exchange for a receiving peer ->identity_key,ephemeral_key=client_public_keys=internet.receive()server=ecdhe_key.dh3_server(identity_key,ephemeral_key)withserverasexchange:internet.post(exchange.exhaust())servers_kdf=exchange.result()# Success! Now both the client & server peers share an identical# ``DomainKDF`` hashing object to create shared keys ->assert(clients_kdf.sha3_512(context=b"test")==servers_kdf.sha3_512(context=b"test"))Ed25519………………………………….Table Of ContentsEdwards curve 25519 signing & verification.fromaiootpimportEd25519# In a land, long ago ->alices_key=Ed25519().generate()internet.send(alices_key.public_bytes)# Alice wants to sign a document so that Bob can prove she wrote it.# So, Alice sends the public key bytes of the key she wants to# associate with her identity, the document & the signature ->document=b"DesignDocument.cad"signed_document=alices_key.sign(document)message={"document":document,"signature":signed_document,"public_key":alices_key.public_bytes,}internet.send(message)# In a land far away ->alices_message=internet.receive()# Bob sees the message from Alice! Bob already knows Alice's public# key & she has reason believe it is genuinely Alice's. So, she'll# import Alice's known public key to verify the signed document ->assertalices_message["public_key"]==alices_public_keyalice_verifier=Ed25519().import_public_key(alices_public_key)alice_verifier.verify(alices_message["signature"],alices_message["document"])internet.send(b"Beautiful work, Alice! Thanks ^u^")The verification didn’t throw an exception! So, Bob knows the file was signed by Alice.Comprende………………………………..Table Of ContentsThis magic with generators is made simple with thecomprehensiondecorator. It wraps them inComprendeobjects with access to myriad data processing pipeline utilities right out of the box.Synchronous Generators…………………….Table Of Contentsfromaiootp.gentoolsimportcomprehension@comprehension()defgen(x:int,y:int):z=yieldx+yreturnx*y*z# Drive the generator forward with a context manager ->withgen(x=1,y=2)asexample:z=5# Calling the object will send ``None`` into the coroutine by default ->sum_of_x_y=example()assertsum_of_x_y==3# Passing ``z`` will send it into the coroutine, cause it to reach the# return statement & exit the context manager ->example(z)# The result returned from the generator is now available ->product_of_x_y_z=example.result()assertproduct_of_x_y_z==10# Here's another example ->@comprehension()defone_byte_numbers():fornumberinrange(256):yieldnumber# Chained ``Comprende`` generators are excellent inline data processors ->base64_data=one_byte_numbers().int_to_bytes(1).to_base64().list()# This converted each number to bytes then base64 encoded them into a list.# We can wrap other iterables to add functionality to them ->@comprehension()defunpack(iterable):foriteminiterable:yielditem# This example just hashes each output then yields themfordigestinunpack(base64_data).sha3_256():print(digest)Asynchronous Generators……………………Table Of ContentsAsyncComprendecoroutines have almost exactly the same interface as synchronous ones.fromaiootp.asynchsimportasleepfromaiootp.gentoolsimportComprende,comprehension@comprehension()asyncdefgen(x:int,y:int):# Because having a return statement in an async generator is a# SyntaxError, the return value is expected to be passed into# Comprende.ReturnValue, and then raised to propagate upstream.# It's then available from the instance's ``aresult`` method ->z=yieldx+yraiseComprende.ReturnValue(x*y*z)# Drive the generator forward.asyncwithgen(x=1,y=2)asexample:z=5# Awaiting the ``__call__`` method will send ``None`` into the# coroutine by default ->sum_of_x_y=awaitexample()assertsum_of_x_y==3# Passing ``z`` will send it into the coroutine, cause it to reach the# raise statement which will exit the context manager gracefully ->awaitexample(z)# The result returned from the generator is now available ->product_of_x_y_z=awaitexample.aresult()assertproduct_of_x_y_z==10# Let's see some other ways async generators mirror synchronous ones ->@comprehension()asyncdefone_byte_numbers():# It's probably a good idea to pass control to the event loop at# least once or twice, even if async sleeping after each iteration# may be excessive when no real work is being demanded by range(256).# This consideration is more or less significant depending on the# expectations placed on this generator by the calling code.awaitasleep()fornumberinrange(256):yieldnumberawaitasleep()# This is asynchronous data processing ->base64_data=awaitone_byte_numbers().aint_to_bytes(1).ato_base64().alist()# This converted each number to bytes then base64 encoded them into a list.# We can wrap other iterables to add asynchronous functionality to them ->@comprehension()asyncdefunpack(iterable):foriteminiterable:yielditem# Want only the first twenty results? ->asyncfordigestinunpack(base64_data).asha3_256()[:20]:# Then you can slice the generator.print(digest)# Users can slice generators to receive more complex output rules, like:# Getting every second result starting from the 4th result to the 50th ->asyncforresultinunpack(base64_data)[3:50:2]:print(result)# Although, negative slice numbers are not supported.Comprendegenerators have loads of tooling for users to explore. Play around with it and take a look at the other chainable generator methods inaiootp.Comprende.lazy_generators.Module Overview…………………………..Table Of ContentsHere’s a quick overview of this package’s modules:importaiootp# Commonly used constants, datasets & functionality across all modules ->aiootp.commons# The basic utilities & abstractions of the package's architecture ->aiootp.generics# A collection of the package's generator utilities ->aiootp.gentools# This module is responsible for providing entropy to the package ->aiootp.randoms# The high & low level abstractions used to implement the Chunky2048 cipher ->aiootp.ciphers# The higher-level abstractions used to create / manage key material ->aiootp.keygens# Global async / concurrency functionalities & abstractions ->aiootp.asynchs#FAQ……………………………………..Table Of ContentsQ: What is the one-time pad?A: It’s a cipher which provides an information theoretic guarantee of confidentiality. It’s typically thought to be too cumbersome a cipher for generalized application because it conveys strict, and well, cumbersome, requirements onto its users. The need for its keys to be at least as large as all the messages it’s ever used to encrypt is one such requirement. Our goal is to design a cipher which immitates the one-time pad through clever algorithms, in such a way as to minimize its inconveniences & still provide some form of information theoretic confidentiality guarantees or, at a minimum, be able to make non-trivial statements about its security against even computationally unbounded adversaries. In this effort, we’ve built what we hope to be a candidate cipher, which we’ve calledChunky2048.Q: How fast is this ``Chunky2048`` cipher?A: Well, because it relies onhashlib.shake_128hashing to build key material streams, it’s rather efficient. It can process about 24 MB/s on a ~1.5 GHz core for both encrypting & decrypting. This is still slow relative to other stream ciphers, but this package is written in pure Python & without hardware optimizations. Using SHA3 ASICs, specific chipset instructions, or a lower-level language implementation, could make this algorithm competitively fast.Q: What size keys does the ``Chunky2048`` cipher use?A: It’s been designed to work with any size of key >= 64 bytes.Q: What’s up with the ``AsyncDatabase`` / ``Database``?A: The idea is to create an intuitive, pythonic interface to a transparently encrypted and decrypted persistence tool that also cryptographically obscures metadata. It’s designed to persist raw bytes or JSON serializable data, which gives it native support for some of the most important basic python datatypes. It’s still a work in progress, albeit a very nifty one.Q: Why are the modules transformed into ``Namespace`` objects?A: We overwrite our modules in this package to have a more fine-grained control over what part of the package’s internal state is exposed to users & applications. The goal is make it more difficult for users to inadvertently jeopardize their security tools, & minimize the attack surface available to adversaries. TheNamespaceclass also makes it easier to coordinate and decide the library’s UI/UX across the package.Changelog………………………………..Table Of ContentsChanges for version 0.22.1Major ChangesThe top-levelDomainKDFclass’ hashing methods can now accept an arbitrary amount of additional data arguments which do not change the internal state of its objects.Switch the order of the internal raw guids with thenode_numberin theGUIDclass. This is intended to induce the most variability possible in output guids by interpreting the variable raw guids as more significant bits.Minor ChangesThe defaultcpucost forPasscryptwas lowered from 2 to 1.Ensured raw guid byte values used byGUIDclass are interpreted as big-endian integers.The top-level(a)csprngfunctions now don’t bother to convert a falsey, non-bytes, user-suppliedentropyargument tobytes. Instead they just use a value from an internal entropy pool as additional entropy for that invocation of the function.Code clean-ups.Documentation fixes.Added tests forDomainKDF,GUID&SyntheticIV, & improved clarity of some existing tests.Packaging changes to create coherent wheel files.Explicitly declare use of big-endian encoding throughout the package.Conduct a more comprehensive addition of the package’s types to theTypingclass.Changes for version 0.22.0(Major Rewrite: Backwards Incompatible)Security Advisory:The top-level(a)csprngfunctions were found to be unsafe in concurrent code, leading to the possibilty of producing identical outputs from distinct calls if run in quick succession from concurrently running threads & coroutines. The classification of this vulnerability is severe because: 1) users should be able to expect the output of a 64-byte cryptographically secure pseudo-random number generator to always produce unique outputs; and, 2) much of the package utilizes them to produce cryptographic material. This vulnerability does not effect users of the library which are not running it in multiple concurrent threads or coroutines. The vulnerability has been patched & all users arehighly encouragedto upgrade to v0.22.0+.Major ChangesSupport for python 3.6 was dropped. The package now supports python versions 3.7+.Chunky2048: A new version of the cipher has been developed which
implements algorithms & interfaces that offer improvements in multiple
regards: smaller size overhead of ciphertexts, faster execution time
for large messages & large keys, more robust salt reuse/misue resistance,
fewer aspects harming deniability & better domain separation.
Many of the changes are described here:The(a)bytes_keysgenerators were updated to useshake_128-based KDF objects instead ofsha3_512, yielding 256-bytes on each iteration instead of 128, now requiring only a single iteration to produce a keystream key for each block, instead of two. This choice was made during the process of analyzing the use of the user’s encryptionkeyto seed theseed_kdfon each iteration. We wanted to stop doing that essentially, because it slowed down the cipher too much when used with large keys. And because it seems like a bad idea to use the same key repeatedly while also not incorporating the uniqueness or entropy from the message’ssalt,sivoraad.But still, we somehow wanted to come up with an idea which could efficiently & continually extract entropy from the userkeyif it did happen to be large. An answer came in the form of expanding on an earlier implemented idea which used the key multiple times to create unique seeds during initialization. In this case, however, instead of creating unique seeds with the singleseed_kdf, each of the three KDFs & the MAC object used by the cipher will be given the wholekeyonce at initialization, with proper domain separation, & including the messagesalt&aad(Thesivcan’t be used because its creation happens after initialization during encryption). This gives each of their (SHA3) 200-byte internal states independent access to the full entropy of thekey.Then, the problem was that, by usingsha3_512internally, a maximum of 64-bytes of entropy could be communicated between KDFs at each round (and only 32-bytes from theStreamHMAC(shmac) object’ssha3_256MAC). But the blocksize of each round is 256-bytes. So, the idea became to attempt tocommunicatemore entropy between the KDFs & MAC each round than there exists possible messages in the message space of each round. It seems plausible, that by only assuming the independence of each of the KDFs / MAC & that they can indeedefficiently pass entropyto one another, that for large keys we could argue the relevant key space is that of the 800-byte internal state of the cipher at each round (which happens to be more than three times the size of the message space of each round). This is to say, we conjecture, that byefficiently communicating more entropyfromindependent sourcesthan there existspossible messages, & in fact incorporating the entropy ofeach message blockinto the cipher’s state at the start ofeach round, that the entropy of the internal keyspace is continually being refreshed in a way which is negligibly distinguishable from using a fresh random key each round the length of the blocksize. This seems like at least a feasible way to begin the argument that it is possible to meaningfully relate the information theoretic security of the one-time pad to a pseudo one-time pad in a measurable way.Efficiently Pass Entropy: By this we mean, the rate of bits extracted from one state object, to the rate of bits of actual entropy absorbed by a receiveing state object, up to its XORable state size, being different by only a negligible amount. Here, we can conservatively assume the limit of this efficiency is the XORable state size, since we know that in the ideal setting, XORingnuniform random bits with an unknown message of <=nbits is perfectly hiding, which implies perfectly efficient conveyance of entropy. By usingshake_128as each of the cipher’s state objects, & its larger rate of 168-bytes, more than twice the number of bytes can be passed to & extracted from each, per round & per call to their internalfpermutation, as compared withsha3_512.If they can efficiently pass entropy, then any secret state exposed by theleft_kdforright_kdfin the creation of ciphertext, can then be efficiently displaced by the introduction of new entropy from the other state objects. This follows from the theory that a finite sized pool of entropy which is already maximally filled with entropy, cannot incorporate more entropy without fundamentally erasing internal information. From this we arrived at the new design forChunky2048. In this new design, theshmacfeeds 168-bytes to theseed_kdf, theseed_kdfcreates 336-bytes to feed 168-bytes each to theleft_kdf&right_kdf, theleft_kdf&right_kdfeach produce 128-byte keys which XOR the 256-byte plaintext, then this ciphertext feeds theshmac& the cycle repeats.More work needs to be done to formalize these definitions & analyze their properties. We would be grateful for any help from those with expertise in formal proofs of security in tearing apart this design as we move closer to the first stable release of the package.TheSyntheticIVclass’ algorithm has been updated as a result of analyzing how we could improve the salt reuse / misuse resistance of the cipher without attesting to plaintext contents in the form of ansivattached to ciphertexts. This plaintext attestation worked counter to our goal of wanting to be able to say something non-trivial about the key-deniability of the cipher. It was noticed that the plaintext padding already incorporated an 8-byte timestamp (now reduced to 4-bytes) & 16-bytes of ephemeral randomness as part of the prepended inner-header, & that these values were not at all used to seed the cipher’s state during decryption. Instead a keyed-hash was calculated over the first block of plaintext during encryption to create the 24-bytesiv. But, this is actuallyless effectiveat producing salt reuse / misuse resistance than using the timestamp & ephemeral randomness directly in seeding theseed_kdf, because the timestamp is a unique & global counter that does not suffer from collisions. This understanding came while also trying to find a good use for the initialprimer_keygenerated by the keystream generator when sending in the first obligatoryNonevalue. In the previous version it was used to initialize theshmac, but now that theshmacwould be initialized directly with the userkey, it was searching for a use. So the idea was to pair them.The new 256-byteprimer_keywould be XORed with the 256-byte first block of plaintext to mask the inner-header. The unmasked inner-header & 148-bytes of theshmac’s digest will seed the keystream, & the freshly seeded keystream output would be truncated to XOR the part of the masked plaintext which doesn’t include the inner-header. There’s no need now to attach thesivto the ciphertext. Instead, during decryption, the decipher algorithm has access to the inner-header, because it has access to theprimer_key& the masked inner-header. The actual plaintext contents of the first block are only accessible after unmasking the inner-header & seeding the keystream. This combination alone of protection from a timestamp & 16-bytes of randomness should give a salt reuse / misuse resistance of at least~2 ^ 64 messagesper second!However, even with this new scheme, it would still be problematic to repeat a combination ofkey,salt&aad, since it would leak the XORs of timestamp information. With all of this in mind, the new formulation would include a 16-bytesalt& a newly introduced 16-byteiv, both of which are attached to ciphertexts. This is a header size reduction of 16-bytes, since priorsalt&sivsizes were 24-bytes each. The difference between thesalt&ivis that thesaltis available for the user to choose, but theivisalwaysgenerated randomly. Since theivisn’t dependent on message data the way that thesivwas, it too can now be incorporated into all of the state objects during initialization. Theivensures that even if akey,salt&aadtuple repeats, the timestamp is still protected. Below is a diagram of the procedure:#_____________________________________|||AlgorithmDiagram:Encryption||_____________________________________|------------------------------------------------------------------#|inner-header|firstblockofplaintext|#|timestamp|siv-key||#|4-bytes|16-bytes|236-bytes|#------------------------------------------------------------------#|----------------------entirefirstblock------------------------|#|#|#first256-bytekeystreamkey----⊕#|#|#V#maskedplaintextblock#------------------------------------------------------------------#|maskedinner-header|firstblockofmaskedplaintext|#------------------------------------------------------------------#|-----the236-bytemaskedplaintext-----|#|#|#siv=inner-header+shmac.digest(148)|#keystream(siv)[10:246]-----------------------⊕#|#|#V#------------------------------------------------------------------#|maskedinner-header|firstblockofciphertext|#------------------------------------------------------------------#_____________________________________|||AlgorithmDiagram:Decryption||_____________________________________|------------------------------------------------------------------#|maskedinner-header|firstblockofciphertext|#------------------------------------------------------------------#|----------------------entirefirstblock------------------------|#|#|#first256-bytekeystreamkey----⊕#|#|#V#unmaskedciphertextblock#------------------------------------------------------------------#|inner-header|firstblockofunmaskedciphertext|#------------------------------------------------------------------#|---the236-byteunmaskedciphertext----|#|#|#siv=inner-header+shmac.digest(148)|#keystream(siv)[10:246]-----------------------⊕#|#|#V#------------------------------------------------------------------#|inner-header|firstblockofplaintext|#|timestamp|siv-key||#|4-bytes|16-bytes|236-bytes|#------------------------------------------------------------------##ThePaddingclass has seen some changes. Firstly, the 8-byte timestamp in the inner-header was reduced to 4-bytes. Furthermore, to get the full 136 years out of the 4-byte timestamps, the epoch used to calculate them was changed to unix timestamp1672531200(Sun, 01 Jan 2023 00:00:00 UTC). This is the new default0date for the package’s timestamps. This saves some space & aims to provided fewer bits of confirmable attestation & correlation in proof games which simulate attacks on the key-deniability of the cipher. To explain: the plaintext padding includes random padding. That padding is intended to leave an adversary which attempts to brute force a ciphertext’s encryptionkey, even with unbounded computational resources, in a state where it cannot decide with better accuracy than random chance between the exponentially large number of keys which create the sameshmactag (the variablekeyspaceis much larger than the 32-byte tag) with their accompanying exponentially large number ofplausibleplaintexts (anyreasonableplaintext with any variable length random padding between 16 & 272 bytes), & the actual userkey& plaintext.We also got rid of the use of apadding_keyto indicate the end of a plaintext message. It used to be sliced off theprimer_key, but theprimer_keyhas a new use now. Also, thepadding_keywas another form of plaintext / key attestation harming deniability that we wanted to get rid of. Instead, a simpler method is now employed: The final byte of the final block of padded plaintext is a number which tells the decryptor exactly how many bytes of random padding were added to the plaintext to fill the block. This saves a lot of space, is simpler, minimizes unnecessary key attestation, & eliminates the need for thePaddingclass to know anything about user secrets in order to do the padding, which is an improvment all around.New(Async)CipherStream&(Async)DecipherStreamclasses were introduced which allow users to utilize the online nature of theChunky2048cipher, ciphering & deciphering data in bufferable chunks, without needing to know about or instantiate all of the low-level classes. They automatically handle the required plaintext padding, ciphertext authentication, & detection of out-of-order message blocks. This greatly simplifies the safe usage ofChunky2048in online mode, provides robustness, & gets rid of the need for users to worry about the dangers of release of unverified plaintexts.ThePasscryptalgorithm was redesigned to be data-independent, more efficiently acheive its security goals, & allow for more compact hashes which include its difficulty settings metadata. Thekbparameter was changed tomb, & now measures Mibibytes (MiB). A newcoresparallelization parameter was added, which indicates the number of parallel processes to use to complete the procedure. And thecpuparameter now measures the number of iterations over the memory cache that are done, as well as the computational complexity of the algorithm.Passcryptnow usesshake_128instead ofsha3_512internally. This also allows for users to specify atag_sizenumber of bytes to produce as an output tag. Asalt_sizeparameter can now also be supplied to the(a)hash_passphrasemethods. The(a)hash_passphrasemethods now produce raw-bytes outputs & the(a)hash_passphrase_raw&(a)verify_rawmethods were removed.(a)verifymethods now also acceptrange-type objects asmb_allowed,cpu_allowed, &cores_allowedkeyword argument inputs. These range objects can be used to specify the exact amount of resources which the user allows for difficulty settings, which can mitigate adversarial (or unintentional) DOS attacks on machines doing hash verification.Type annotations were added to most of the library, including return types, which were completely neglected in prior versions. They are still not functioning with mypy, & are serving right now as documentation & auto-complete helpers.Many unnecesssary, low-level or badly designed features, functions & classes were either deleted or pulled into private namespaces, along with major reorganization & cleanup of the codebase. The tangled mess of internal module imports was also cleaned up. The goal is to provide access to only the highest level, simplest, & safest by default interfaces which can actually help users in their data processing & cryptographic tasks. These changes aim to improve maintainability, readability, correctness & safety.New top-level(a)hash_bytesfunctions were added to the package, which accept an unlimited number bytes-type inputs as positional arguments & automatically canonically encode all inputs before being hashed (which aims to prevent canonicalization attacks & length-extension attacks). Akeykeyword-only argument can also be supplied to optionally produce keyed hashes.A new top-levelGUIDclass was added. It creates objects which produce variable length, obfuscated, pseudo-random bytes-type globally unique identifiers based on a user-defined integernode_number, a user-defined uniform bytessalt, a nanosecondtimestamp, randomentropybytes & a 1-bytecounter. The benefits of its novel design explained:1)the namespace separation of user-defined salts (like name-based uuids);2)guaranteed output uniqueness for all instances using the samesalt&node_numberwhich occur on a different nanosecond (like time-based uuids, but with higher precision);3)guaranteed output uniqueness between all instances which use the samesaltbut a differentnode_number, even if produced on the same nanosecond;4)guaranteed output uniqueness for any unique instance using the samesalt&node_numberif it produces 256 or fewer outputs every nanosecond;5)probabilistic output uniqueness for any unique instance using the samesalt&node_numberif it produces >256 outputs per-nanosecond, exponentially proportional to the number of randomentropybytes (which in turn are proportional to the output size of the GUIDs);6)output invertability, meaning outputs can be unmasked & sorted according totimestamp,node_number&counter;7)random-appearing outputs, with the marginal amount of privacy which can be afforded by obfuscated affine-group operations. Admittedly, point7)stillleaves much room for improvement, as the privacy of the design could instead be ensured by strong hardness assumptions given by other types of invertible permutations or group operations. The goal was to create something efficient (below 3µs per guid), which met the above criterion, & that produced output bit sequences which passed basic randomness tests. We’d be excited to accept pull requests which use strong invertable permutations or group operations that are also about as efficient, & that forn-byte declared output sizes, outputs do not repeat for fewer than ~256 **nsequential input values.The top-levelDomainKDFclass now also creates KDF objects which automatically canonically encode all inputs.TheX25519protocols now returnDomainKDFresults instead of plainsha3_512objects.The(Base)Comprendeclasses were greatly simplified, & the caching &messagesfeatures were removed.The top-level(a)mnemonicfunctions now return lists of bytes-type words, instead of str-type, & can now be used to quickly generate lists of randomly selected words without providing a (now optional) passphrase.The(Async)Databaseclasses’(a)generate_profilemethods no longer require tokens to first be created by the user. That is now handled internally, & the external API accepts raw bytes inputs for credentials from the user.ThePackageSigner&PackageVerifiernow usesha384for digests instead ofsha512. The verifier now by default recomputes & verifies the digests of files from the filesystem using thepathkeyword argument to the constructor as the root directory for the relative filepaths declared in the “checksums” entry of the signature summary.Minor ChangesA newClockclass was added to thegenerics.pymodule which provides a very intuitive API for handling time & timestamp functionalities for various time units.The test suite was reorganized, cleaned up & extended significantly, & now also utilizespytest-asyncioto run async tests. This led to many found & fixed bugs in code that was not being tested. There’s still a substantial amount of tests that need to be written. We would greatly appreciate contributions which extend our test coverage.Many improvements to the correctness, completeness & aesthetic beauty of the code documentation with the addition of visual aides, diagrams & usage examples.A top-levelreport_security_issuefunction was added, which provides a terminal application for users to automatically encrypt security reports to us using our new X25519 public key.We lost access to our signing keys in encrypted drives which were damaged in flooding. So we decided to shred them & start fresh. Our new Ed25519 signing key is “70d1740f2a439da98243c43a4d7ef1cf993b87a75f3bb0851ae79de675af5b3b”. Contact us via email or twitter if you’d like to confirm that the key you are seeing is really ours.Changes for version 0.21.1Minor ChangesFix usage of the wrong package signing key.Changes for version 0.21.0Major ChangesNon-backwards compatible changes:Altered theChunky2048cipher’s key derivation to continuously extract
entropy from users’ main encryption key. The design goal of the cipher
is to be as close as possible to a one-time pad, but because we use
key derivations to mix together all the relevant values used by the
cipher, there’s a limited amount of entropy that can be extracted
from the main key no matter how large it is. The changes feed the
main key into the internal seed KDF multiple times when creating the
cipher’s initial seeds, & once on every iteration of the(a)bytes_keysgenerators.Merged two internal KDFs used by the cipher into the one seed KDF. This
also now means that using the(a)update_keymethods of theStreamHMACclass updates the KDF used to ratchet the encryption keystream.Usesha3_512instead ofsha3_256for theStreamHMACfinal HMAC
& slice the first bytes designated by the package’scommons.pymodule.
This allows the HMAC length to be specified & changed easily. It’shighly discouragedto use anything less than 32-bytes.Minor ChangesInternal refactorings.Updates to tests.Changes for version 0.20.7Major ChangesChanged the way thePadding.(a)end_paddingmethods calculate the
required padding length. The change causes the methods to now assume
that the plaintext has already been prepended with the start padding.The varioustest_*&verify_*functions/methods throughout the
package have been changed to returnNoneon successful validation
instead ofTrue, which more closely matches the convention for
exception-raising validators.The defaultblock_idlength was changed from 16-bytes to 24-bytes.Minor ChangesMake the(a)end_paddingmethods of thePaddingclass assume the
supplied data has already been prepended with the start padding. This
better integrates with streams of plaintext (online usage).Small internal refactorings.Documentation fixes.Changes for version 0.20.6Major ChangesThe(Async)Databaseclasses now support storing rawbytestype
tag entries! This is a huge boon to time/space efficiency when needing
to store large binary files, since they don’t need to be converted to
& from base64. This feature was made possible with only very minor
changes to the classes, & they’re fully backwards-compatible! Older
versions will not be able handle rawbytesentries, but old JSON
serializable entries work the same way they did.Minor ChangesDocfixes.Small refactorings.Add new tests & make existing tests complete faster.Support empty strings to be passed to the(Async)Databaseconstructors’directorykwarg, signifying the current directory. NowNoneis
the only falsey value which triggers the constructors to use the default
database directory.Fixed a bug in theAsyncDatabaseclass’aset_tagmethod, which
would throw an attribute error when passed thecache=Falseflag.Add Windows support to the CI tests.Changes for version 0.20.5Minor ChangesInclude the missing changelog entries forv0.20.4.Changes for version 0.20.4Major ChangesAddpython3.10support by copying theasync_lrupackage’s main module
from their more up-to-date github repository instead of from PyPI.Minor ChangesSmall refactorings & code cleanups.Documentation updates.Type-hinting updates.Cleanups to the package’s module API.Improve CI & extend topython3.10.Changes for version 0.20.3Minor ChangesSmall refactorings.Documentation updates.Type-hinting updates.Additional tests.Changes for version 0.20.2Major ChangesChanged thePaddingclass’(a)check_timestampmethods to(a)test_timestamp, to better match the naming convention in the
rest of the package.Removed the(a)sum_sha3__(256/512)chainable generator methods from
theComprendeclass.Removed theos.urandombased functions in therandoms.pymodule.Minor ChangesFixes & improvements to out of date documentation.Small fixes to type-hints.Small refactorings.Add(a)generate_keyfunctions to the package &(Async)Keysclasses.Fix some exception messages.Changes for version 0.20.1Minor ChangesSmall fixes & improvements to documentation.Small fixes & improvements to tests.Small fixes to type-hints.Small re-organization of source file contents.Small bug fixes.Changes for version 0.20.0 (Backwards incompatible updates)Major ChangesThe(a)json_(en/de)crypt&(a)bytes_(en/de)cryptfunctions &
methods now only expect to work withbytestype ciphertext. And,
the low-level cipher generators expect iterables of bytes where they
used to expect iterables of integers.Thepidkeyword-only argument throughout the package was changed
toaadto more clearly communicate its purpose as authenticated
additional data.Thekey,salt&aadvalues throughout the package are now
expected to bebytestype values.Thekeymust now be at least 32-bytes for use within theChunky2048cipher & its interfaces.Thesalt, for use in theChunky2048cipher & its interfaces,
was decreased from needing to be 32-bytes to 24-bytes.Thesiv, for use in theChunky2048cipher & its interfaces, was
increased from needing to be 16-bytes to 24-bytes.The newKeyAADBundleclass was created as the primary interface
for consumingkey,salt,aad&sivvalues. This class’
objects are the only ones that are used to pass around these values
in low-levelChunky2048cipher functionalities. The higher-level
cipher functions are the only public interfaces that still receive
thesekey,salt, &aadvalues.TheKeyAADBundlenow manages the new initial key derivation of theChunky2048cipher. This new algorithm is much more efficient,
utilizing the output of the keystream’s first priming call instead of
throwing it away, removing the need for several other previously used
hashing calls.Thebytes_keys&abytes_keyskeystream generator algorithms
were improved & made more efficient. They also now only receivebytestype coroutine values orNone.TheStreamHMACalgorithms were improved & made more efficient.TheChunky2048class now creates instance’s that initialize, & who’s
methods are callable, much more efficiently by reducing its previously
dynamic structure. Its now reasonable to use these instances in code
that has strict performance requirements.TheKeys&AsyncKeysclasses were trimmed of all instance
behaviour. They are now strictly namespaces which contain static or
class methods.All instance’s of the wordpasswordthroughout the package have been
replaced with the wordpassphrase. ThePasscryptclass now only
acceptsbytestypepassphrase&saltvalues. The returned
hashes are also now alwaysbytes.ThePadding&BytesIOclasses’ functionalities were made more
efficient & cleaned up their implementations.NewPackageSigner&PackageVerifierclasses were added to thekeygens.pymodule to provide an intuituve API for users to sign their
own packages. This package now also uses these classes to sign itself.The newgentools.pymodule was created to organize the generator
utilities that were previously scattered throughout the package’s
top-level namespaces.The new_exceptions.pymodule was created to help organize the
exceptions raised throughout the package, improving readability
& maintainability.The new_typing.pymodule was added to assist in the long process
of adding functional type-hinting throughout the package. For now,
the type hints that have been added primarily function as documentation.A newSlotsbase class was added to thecommons.pymodule to
simplify the creation of more memory efficient & performant container
classes. The new_containers.pymodule was made for such classes
for use throughout the package. And, most classes throughout the
package were given__slots__attributes.A newOpenNamespaceclass was added, which is a subclass ofNamespace,
with the only difference being that instances do not omit attributes
from their repr’s.The new(a)bytes_are_equalfunctions, which are pointers tohmac.compare_digestfrom the standard library, have replaced the(a)time_safe_equalityfunctions.The(a)sha_256(_hmac)&(a)sha_512(_hmac)functions have had
their names changed to(a)sha3__256(_hmac)&(a)sha3__512(_hmac).
This was done to communicate that they are actually SHA3 functions,
but the double underscore is to keep them differentiable from the
standard library’shashlibobjects. They can now also returnbytesinstead of hex strings if theirhexkeyword argument is truthy.The base functionality of theComprendeclass was refactored out into aBaseComprendeclass. The chainable data processor generator methods
remain in theComprendeclass. Their endpoint methods (such as(a)list&(a)join) have also been changed so they don’t cache results by default.ThePasscryptclass’kb&hardnesscan now be set to values
independently from one another. The algorithm runs on the new(a)bytes_keyscoroutines, & a slightly more effective cache building
procedure.The databases classes now don’t preload their values by default. And,
various methods which work with tags & metatags have been given acachekeyword-only argument to toggle on/off the control of using
the cache for each operation.New method additions/changes to the database classes:(a)rollback_tag,(a)clear_cache, & afilenamesproperty
were added.(a)hmacwas changed to(a)make_hmac, & now returnsbyteshashes.(a)savewas changed to(a)save_database.(a)querywas changed to(a)query_tag.(a)setwas changed to(a)set_tag.(a)popwas changed to(a)pop_tag.Thetags,metatags&filenamesproperties now return sets
instead of lists.TheRopakeclass has been removed from the package pending changes to
the protocol & its implementation.The(a)generate_saltfunction now returnsbytestype values,
& takes asizekeyword-only argument, with no default, that determines
the number of bytes returned between [8, 64].The(a)random_512&(a)random_256public functions can now cause
their underlying random number generators to fill their entropy pools
when either theroundsorrefreshkeyword arguments are specified.The following variables were removed from the package:(a)keys,(a)passcrypt,(a)seeder,(a)time_safe_equality,Datastream,bits,(a)seedrange,(a)build_tree,(a)customize_parameters,convert_class_method_to_member,convert_static_method_to_member,(a)xor,(a)padding_key,(a)prime_table,(a)unique_range_gen,(a)non_0_digits,(a)bytes_digits,(a)digits,(a)permute,(a)shuffle,(a)unshuffle,(a)create_namespace,
((a)depad_plaintext,(a)pad_plaintext& their generator forms.
Only the non-generator forms remain in thePaddingclass), (The(a)passcrypt,(a)uuids,(a)into_namespacemethods from the
database classes), (The(a)csprbgfunctions were removed & instead
the(a)csprngfunctions producebytestype values.)Thorough & deep refactorings of modules, classes & methods. Many methods
& functions were made private, cleaning up the APIs of the package,
focusing on bringing the highest-level functionalities to top level
namespaces accessible to users. Some purely private functionalities
were entirely moved to private namespaces not readily accessible to
users.Most of the constants which determine the functionalities throughout
the package were refactored out intocommons.py. This allows
for easy changes to protocols & data formats.Minor ChangesMany documentation improvements, fixes, trimmings & updates.Added aWeakEntropyclass to therandoms.pymodule.Changes for version 0.19.4Major ChangesCreated a privateEntropyDaemonclass to run a thread in the
background which feeds into & extracts entropy from some of the
package’s entropy pools. Also moved the separate private_cacheentropy pools from the parameters to the random number generators.
They’re now a single private_poolshared global that’s
asynchronously & continuously updated by the background daemon thread.Switched therandomportion of function names in therandoms.pymodule to readuniqueinstead. This was done to the functions which
are actually pseudo-random. This should give users a better idea of
which functions do what. The exception is that therandom_sleep&arandom_sleepfunctions have kept their names even though they
sleep a pseudo-randomly variable amount of time. Their names may
cause more confusion if they were either(a)unique_sleepor(a)urandom_sleep. Because they don’t useos.urandom& what
is aunique_sleep? When / if a better name is found these
function names will be updated as well.Minor ChangesVarious docstring / documentation fixes & refactorings.Changes for version 0.19.3Major ChangesRemovedascii_encipher,ascii_decipher,aascii_encipher&aascii_deciphergenerators from theChunky2048&Comprendeclasses, & the package. It was unnecessary, didn’t fit well with the
intended use of thePaddingclass, & users would be much better
served by converting their ascii to bytes to use thebytes_generators instead.Removed themap_encipher,map_decipher,amap_encipher&amap_deciphergenerators from theChunky2048&Comprendeclasses, & the package. They were not being used internally to the
package anymore, & their functionality, security & efficiency could
not be guaranteed to track well with the changes in the rest of the
library.Added domain specificity to theX25519protocols’ key derivations.Renamed the database classes’(a)encrypt&(a)decryptmethods
to(a)json_encrypt&(a)json_decryptfor clarity & consistency
with the rest of the package. Their signatures, as well as those in(a)bytes_encrypt&(a)bytes_decrypt, were also altered to
receive plaintext & ciphertext as their only positional arguments.
Thefilenameargument is now a keyword-only argument with a defaultNonevalue. This allows databases to be used more succinctly for
manual encryption & decryption by making the filename tweak optional.Therunskeyword argument for the functions inrandoms.pywas
renamed torounds. It seems more clear that it is controlling the
number of rounds are internally run within the(a)random_number_generatorfunctions when deriving new entropy.Minor ChangesFixes to docstrings & tutorials. Rewrite & reorganization of thePREADME.rst&README.rst. More updates to the readme’s are still
on the way.Slight fix to the Passcrypt docstring’s algorithm diagram.Moved the default passcrypt settings to variables in thePasscryptclass.Added the ability to send passcrypt settings into themnemonic&amnemoniccoroutines, which call the algorithm internally but
previously could only use the default settings.Some code cleanups & refactorings.Changes for version 0.19.2Minor ChangesMade the output lengths of thePaddingclass’ generator functions
uniform. When the footer padding on a stream of plaintext needs to
exceed the 256-byte blocksize (i.e. when the last unpadded plaintext
block’s lengthLis232 < L < 256), then another full block of
padding is produced. The generators now yield 256-byte blocks
consistently (except during depadding when the last block of plaintext
may be smaller than the blocksize), instead of sometimes producing a
final padded block which is 512 bytes.Changes for version 0.19.1Minor ChangesFixed a bug where database classes were evaluating as falsey when they
didn’t have any tags saved in them. They should be considered truthy
if they’re instantiated & ready to store data, even if they’re
currently empty & not saved to disk. This was reflected in their__bool__methods. The bug caused empty metatags not to be loaded
when an instance loads, even whenpreloadis toggledTrue.Removed the coroutine-receiving logic from thePaddingclass’Comprendegenerators. Since they buffer data, the received values
aren’t ever going to coincide with the correct iteration & will be
susceptible to bugsFixed a bug in thePaddingclass’Comprendegenerators which
cut iteration short because not enough data was available from the
underlying generators upfront. Now, if used correctly to pad/depad
chunks of plaintext 256 bytes at a time, then they work as expected.Theupdate,aupdate,update_key&aupdate_keymethods
in both theStreamHMAC&DomainKDFclasses now returnselfto allow inline updates.Addedacsprng&csprngfunction pointers to theChunky2048class.Updates to docstrings which didn’t get updated with info on the newsynthetic IVfeature.Some other docstring fixes.Some small code cleanups & refactorings.Changes for version 0.19.0Major ChangesSecurity Upgrade: The package’s cipher was changed to an online,
authenticated scheme with salt reuse / misuse resistance. This was
acheived through a few backwards incompatible techniques:A synthetic IV (SIV) is calculated from the keyed-hash of the first
256-byte block of plaintext. The SIV is then used to seed the
keystream generator, & is used to update the validator object. This
ensures that if the first block is unique, then the whole ciphertext
will be unique.A 16-byte ephemeral & random SIV-key is also prepended to the
first block of plaintext during message padding. Since this value
is also hashed to derive the SIV, this key gives a strong
guarantee that a given message will produce a globally unique
ciphertext.An 8-byte timestamp is prepended to the first block of plaintext
during padding. Timestamps are inherently sequential, they can be
verified by a user within some bounds, & can also be used to
mitigate replay attacks. Since it’s hashed to make the SIV, then
it helps make the entire ciphertext unique.After being updated with each block of ciphertext, the validator’s
current state is again fed into the keystream generator as a new
rotating seed. This mitigation is limited to ensuring only that
every following block of ciphertext to a block which is unique
will also be unique. More specifically this means that:ifallother mitigations fail to be unique, or are missing, then
the first block which is uniquewill appear the same, except
for the bits which have changed,but, all following blocks will
be randomized.This limitation could be avoided with a linear
expansion in the ciphertext size by generating an SIV for each
block of plaintext. This linear expansion is prohibitive as a
default setting, but the block level secrecy, even when all other
mitigations fail, is enticing. This option may be added in the
future as a type of padding mode on the plaintext.The SIV-key is by far the most important mitigation, as it isn’t
feasibly forgeable by an adversary, & therefore also protects against
attacks using encryption oracles. These changes can be found in theSyntheticIVclass, the (en/de)cipher & xor generators, & theStreamHMACclass in theciphers.pymodule. The padding
changes can also be found in the newPaddingclass in thegenerics.pymodule. The SIV is attached in the clear with ciphertexts & was
designed to function with minimal user interaction. It needs only to
be passed into theStreamHMACclass during decryption – during
encryption it’s automatically generated & stored in theStreamHMACvalidator object’ssivproperty attribute.Security Patch: The internalsha3_512kdf’s to theakeys,keys,abytes_keys&bytes_keyskeystream generators are now updated
with 72 bytes of (64 key material + 8 padding), instead of just 64
bytes of key material. 72 bytes is thebitrateof thesha3_512object. This change causes the internal state of the object to be permuted
for each iteration update & before releasing a chunk of key material.
Frequency analysis of ciphertext bytes didn’t smooth out to the
cumulative distribution expected for all large ciphertexts prior to
this change. But after the change the distribution does normalize as
expected. This indicates that the key material streams were biased
away from random in a small but measurable way. Although, no
particular byte values seem to have been preferred by this bias, this
is a huge shortcoming with unknown potential impact on the strength
of the package’s cipher. This update is strongly recommended & is
backwards incompatible.This update gives a name to the package’s pseudo-one-time-pad cipher
implementation. It’s now calledChunky2048! TheOneTimePadclass’ name was updated toChunky2048to match the change.ThePreemptiveHMACValidationclass & its related logic in theStreamHMACclass was removed. The chaining of validator output
into the keystream makes running the validator over the ciphertext
separately or prior to the decryption process very costly. It would
either mean recalculating the full hash of the ciphertext a second
time to reproduce the correct outputs during each block, or a large
linear memory increase to hold all of its digests to be fed in some
time after preemtive validation. It’s much simpler to remove that
functionality & potentially replace it with something else that fits
the user’s applications better. For instance, thecurrent_digest&acurrent_digestmethods can produce secure, 32-byte authentication
tags at any arbitrary blocks throughout the cipher’s runtime, which
validate the cipehrtext up to that point. Or, thenext_block_id&anext_block_idmethods, which are a more robust option because
each id they produce validates the next ciphertext block before
updating the internal state of the validator. This acts as an
automatic message ordering algorithm, & leaves the deciphering
party’s state unharmed by dropped packets or manipulated ciphertext.Theupdate_key&aupdate_keymethods were also added to theStreamHMACclass. They allow the user to update the validators’
internal key with new entropy or context information during its
runtime.TheComprendeclass now takes achainedkeyword-only argument
which flags an instance as a chained generator. This flag allows
instances to communicate up & down their generator chain using the
sharedNamespaceobject accessible by theirmessagesattribute.The chainableComprendegenerator functions had their internals
altered to allow them to receive, & pass down their chain, values
sent from a user using the standard coroutinesend&asendmethod syntax.Comprendeinstances no longer automatically reset themselves every
time they enter their context managers or when they are iterated over.
This makes their interface more closely immitate the behavior of
async/sync generator objects. To get them to reset, thearesetorresetmethods must be used. The message chaining introduced in
this update allows chains ofComprendeasync/sync generators to
inform each other when the user instructs one of them to reset.The standard library’shmacmodule is now used internally to thegenerics.pymodule’ssha_512_hmac,sha_256_hmac,asha_512_hmac&asha_256_hmacfunctions. They still allow any type of data to be
hashed, but also now default to hashingbytestype objects as
they are given.The newDomainsclass, found ingenerics.py, is now used to
encode constants into deterministic pseudo-random 8-byte values for
helping turn hash function outputs into domain-specific hashes. Its
use was included throughout the library. This method has an added
benefit with respect to this package’s usage of SHA-3. That being, thebitratefor bothsha3_512&sha3_256are(2 * 32 * k) + 8bytes, wherek = 1forsha3_512&k = 2forsha3_256.
This means that prepending an 8-byte domain string to their inputs
also makes it more efficient to add some multiple of key material
to make the input data precisely equal thebitrate. More info on
domain-specific hashing can be foundhere.A newDomainsKDFclass incipehrs.pywas added to create a
more standard & secure method of key derivation to the library which
also incorporates domain separation. Its use was integrated thoughout
theAsyncDatabase&Databaseclasses to mitigate any further
vulnerabilities of their internal key-derivation functions. The
database classes now also use bytes-type keys internally, instead
of hex strings.ThePasscryptclass now contains methods which create & validate
passcrypt hashes which have their settings & salt attached to them.
Instances can now also be created with persistent settings that are
automatically sent into instance methods.Minor ChangesMany fixes of docstrings, typos & tutorials.Many refactorings: name changes, extracted classes / functions,
reorderings & moves.Various code clean-ups, efficiency & usability improvements.Many constants used throughout the library were given names defined
in thecommons.pymodule.Removed extraneous functions throughout the library.The asymmetric key generation & exchange functions/protocols were
moved from theciphers.pymodule tokeygens.py.Add missing modules to the MANIFEST.rst file.Added aUniformPrimesclass to the__datasetsmodule for efficient
access to primes that aren’t either mostly 1 or 0 bits, as is the case for
theprimeshelper table. These primes are now used in theHasherclass’amask_byte_order&mask_byte_ordermethods.Thetime_safe_equality&atime_safe_equalitymethods are now
standalone functions available from thegenerics.pymodule.Addedreset_poolto theProcesses&Threadsclasses. Also
fixed a missing piece of logic in theirsubmitmethod.Added various conversion values & timing functions to theasynchs.pymodule.Themake_uuid&amake_uuidcoroutines had their names changed tomake_uuids&amake_uuids.Created a newDatastreamclass ingenerics.pyto handle buffering
& resizing iterable streams of data. It enables simplifying logic that
must happen some number of iterations before the end of a stream. It’s
utilized in thePaddingclass’ generator functions available as
chainableComprendemethods.Thedata&adatagenerators can now produce a precise number ofsize-lengthblocksas specified by a user. This gets rid of the
confusing usage of the oldstopkeyword-only argument, which stopped
a stream afterapproximatelysizenumber of elements.Improved the efficiency & safety of entropy production in therandoms.pymodule.Changes for version 0.18.1Major ChangesSecurity Patch: Deprecated & replaced an internal kdf for saving
database tags due to a vulnerability. If an adversary can get a user
to reveal the value returned by thehmacmethod when fed the tag
file’s filename & the salt used for that encrypted tag, then they
could deduce the decryption key for the tag. A version check was
added only for backwards compatibility & will be removed on the next
update. All databases should continue functioning as normal, though
all users are advised tore-save their databasesafter upgrading
so the new kdf can be used. This will not overwrite the old files,
so they’ll need to be deleted manually.Replaced usage of the asyncswitchcoroutine withasyncio.sleepbecause it was not allowing tasks to switch as it was designed to.
Many improvements were made related to this change to make the
package behave better in async contexts.Removed the private method in the database classes which held a
reference to the root salt. It’s now held in a private attribute.
This change simplifies the code a bit & allows instances to be
pickleable.Theatimeout&timeoutchainableComprendegenerator
methods can now stop the generators’ executions mid-iteration. They
run them in separate async tasks or thread pools, respectively, to
acheive this.Theawait_on&wait_ongenerators now restart their timeout
counters after every successful iteration that detected a new value
in theirqueue. Thedelaykeyword argument was changed toprobe_frequency, a keyword-only argument.Removed the package’s dependency on theaioitertoolspackage.Made thesympypackage an optional import. If any of its
functionalities are used by the user, the package is only then
imported & this is done automatically.Various streamlining efforts were made to the imports & entropy
initialization to reduce the package’s import & startup time.Minor ChangesFixes of various typos, docstrings & tutorials.Various cleanups, refactorings & efficiency improvements.Added new tests for detecting malformed or modified ciphertexts.Removed extraneous functions ingenerics.py.Add aUNIFORM_PRIME_512value to__datasets.pyfor use in theHasher.mask_byte_order&Hasher.amask_byte_ordermethods.
Those methods were also altered to produce more uniform looking
results. The returned masked values are now also 64 bytes by default.Added anautomate_key_usekeyword-only boolean argument to the init
for theOneTimePad,Keys&AsyncKeysclasses. It can be toggled to
stop the classes from overwriting class methods so they
automatically read the instance’s key attribute. This optionally
speeds up instantiation by an order of magnitude at the cost of
convenience.Fixedasynchs.Threadsclass’ wrongful use of amultiprocessingManager.listobject instead of a regular list.Changed the_delaykeyword-only argument inProcesses&Threadsclasses’ methods toprobe_freqeuncyso users can specify how often
results will be checked for after firing off a process, thread, or
associated pool submission.Now theasubmit&submitmethods inProcesses&Threadscan accept keyword arguments.Addedagather&gathermethods to theThreads&Processesclasses. They receive any number of functions, &args&/orkwargsto
pass to those functions when submitting them to their associated
pools.Changed therunsuminstance IDs from hex strings to bytes & cleaned
up the instance caching & cleaning logic.Altered & made private theasalted_multiply&salted_multiplyfunctions in therandoms.pymodule.Started a new event loop specific to therandoms.pymodule which
should prevent theRuntimeErrorwhenrandom_number_generatoris called from within the user’s running event loop.Added aValueErrorcheck to the(a)cspr(b/n)gfunctions inrandoms.py. This will allow simultaneously running tasks to
request entropy from the function by returning a result from a
newly instantiated generator object.Added checks in the*_encipher&*_deciphergenerators to
help assure users correctly declare the mode for their StreamHMAC
validator instances.Fixed the__len__function in the database classes to count the
number of tags in the database & exclude their internal maintenaince
files.TheTimeoutErrorraised after decrypting a ciphertext with an
expired timestamp now contains the seconds it has exceeded thettlin avalueattribute.The timestamp used to sign the package now displays the day of
signing instead of the second of signing.The(a)sum_sha_*&(a)sum_passcryptgenerators were altered to
reapply the suppliedsalton every iteration.Stabilized the usability of thestopkeyword-only argument in theadata&datagenerators. It now directly decides the total
number of elements in asequenceallowed to be yielded.Changes for version 0.18.0Major ChangesSecurity Patch: Rewrote the HMAC-like creation & authentication
process for all of the package’s ciphers. Now, the*_encipher&*_decipherComprendegenerators must be passed a validator
object to hash the ciphertext as it’s being created / decrypted.
TheStreamHMACclass was created for this purpose. It’s initalized
with the user’s long-term key, the ephemeral salt & the pid value.
The pid value can now effectively be used to validate additional data.
These changes force the package’s cipher to be used as an AEAD cipher.Security Patch: The package’s*_hmachash functions & theComprendeclass’ hash generators were rewritten to prepend salts & keys to data
prior to hashing instead of appending. This is better for several
important reasons, such as: reducing the amortizability of costs in
trying to brute-force hashes, & more closely following the reasoning
behind the HMAC spec even though sha3 has a different security profile.Algorithm Patch: Theakeys,keys,abytes_keys, &bytes_keysalgorithms have been patched to differentiate each iteration’s two
sha3_512 hashes from one another in perpetuity. They contained a design
flaw which would, if both sha3_512 objects landed upon the same
1600-bit internal state, then they would produce the same keystreams
from then on. This change in backwards incompatible. This flaw is
infeasible to exploit in practice, but since the package’s hashes &
ciphertext validations were already channging this release, there was
no reason to not fix this flaw so that it’s self-healing if they ever
do land on the same internal states.ThePasscryptclass & its algorithm were made more efficient to
better equalize the cost for users & adversaries & simplifies the
algorithm. Any inefficiencies in an implementation would likely cause
the adversary to be able to construct optimized implementations to
put users at an even greater disadvantage at protecting their inputs
to the passcrypt algorithm. It used thesum_sha_256hash function
internally, & since it was also changing in a non-backwards
compatible way with this update, it was the best time to clean up
the implementation.Updated the package’s description & its docstrings that refer to
the package’s cipher as an implementation of the one-time-pad. It’s
not accurate since the package uses pseudo-random hash functions to
produce key material. Instead, the package’s goal is to create a
pseudo-one-time-pad that’s indistinguishable from a one-time-pad.
TheOneTimePadclass will keep its name for succinctness.Newamake_token,make_token,aread_token&read_tokenclass & instance methods added to theOneTimePadclass. These
tokens are urlsafe base64 encoded, are encrypted, authenticated &
contain timestamps that can enforce a time-to-live for each token.Non-backwards compatible changes to the database classes’ filenames,
encryption keys & HMACs. The*_hmachash functions that the
databases rely on were changing with this update, so additionally the
filenames table used to encode the filenames was switched from theBASE_36_TABLEto theBASE_38_TABLE. Both tables are safe for
uri’s across all platforms, but the new table can encode information
slightly more efficiently.Major refactorings & signature changes across the package to make
passing keys & salts to*_hmacfunctions & theComprendeclass’ hash generators explicit.Removed theofkeyword argument from all of theComprendeclass’ generators. It was overly complicating the code, & was not
entirely clear or useful for settings outside of thetags&atagsgenerators.Removedpybase64from the package & its dependencies list. The
built-in pythonbase64module works just fine.Sorted theWORDS_LIST,ASCII_ALPHANUMERIC, &BASE_64_TABLEdatasets.Thesalt&asaltfunctions have been renamed togenerate_salt&agenerate_saltfor clarity’s sake, & to reduce naming
collisions.Added another redundancy to thearandom_number_generator&random_number_generatorfunctions. Now the async tasks it prepares
into a list are pseudo-randomly shuffled before being passed intoasyncio.gather.Minor ChangesAdded a logo image to the package.Separated the FAQ section fromPREADME.rst.Theprimes&bitsdatasets are now represented in hex in the
source code.Added aBASE_38_TABLEdataset to the package.The database classes now fill an ephemeral dictionary of filenames
that couldn’t be used to successfully load a tag file, available from
within the_corrupted_filesattribute.TheComprendeclass’acache_check&cache_checkcontext
manager methods are now calledaauto_cache&auto_cache.Added newbytes_count&abytes_countgenerators togenerics.pymodule which increment each iteration & yield the results as bytes.Removed theakeypair&keypairfunctions from the package.
Their successors are theasingle_use_key&single_use_keymethods
in theAsyncKeys&Keysclasses. The attempt is to clarify &
put constraints on the interface for creating a bundle of key
material that has a single-use-only salt attached, as well as the pid
value.Moved ciphertext encoding functions into theBytesIOclass from
the globalgenerics.pymodule.SplitPrimeGroupsinto two classes, one higher-level class by the
same name & aBasePrimeGroupsclass. The former also has some
added functionality for masking the order of bytes in a sequence
using an modular exponentiation.TheHasherclass now has functionality added to mask the order
of a bytes sequence with a modular multiplication.Fixed the name of the project in the attribution lines in several
source files.Reconciled tests with the major changes in this release.The old identity key for the package that was signed by the gnupg
identity key was shredded & replaced with a new signed key.Several bug fixes to thesetup.pyautomated code signing.Changes for version 0.17.0Major ChangesSecurity Patch: The HMAC verifiers on ciphertexts did not include
thesaltorpidvalues when deriving the HMAC. This
associated data can therefore be changed to cause a party to
decrypt a past ciphertext with a salt or pid of an attacker’s
choosing. This is a critical vulnerability & it is highly recommended
all users update. The fix is to hash the ciphertext,salt&pidtogether & sending that hash into the validator to have
the HMAC created / tested. This change will cause all prior
ciphertexts to be marked invalid by the validator.Refactored the names of the Comprende cipher methods to better
communicate their intended use as lower level tools that cannot be
used on their own to obtain authenticated, CCA or CPA secure
encryption.Added more comprehensive tests forX25519&Ed25519classes,
as well as the protocols that utilize theX25519ecdh exchange.
Fixed some bugs in the process.X25519instances that contain a secret key now have access to
protocol methods which automatically pass their key in as a keyword
argument. This simplifies their usage further.Incorporated the newHasherclass into the package’s random
number generator to improve its entropy production.Minor ChangesVarious fixes to typos, docstrings & tutorials.New tutorials & docs added.Changed the default table inByteIO‘sjson_to_ascii,ajson_to_ascii,ascii_to_json&aascii_to_jsonto theURL_SAFE_TABLEto
facilitate the creation of urlsafe_tokens.Removed all code in theRopakeclass that was used to create a default
database to store a default salt for users. All of that functionality
is expected to be handled by the database classes’ token & profile
creation tools.Fixed bug in package signing script that called hex from a string.Updated the package signing script to include these metadata in the
signatures of the ephemeral keys: name of the package, version, the
date in seconds.Added metadata to thesetup.cfgfile.Make passcrypt objects available from thekeygensmodule.Add more consistent ability withinRopakeclass to specify a
time-to-live for protocol messages.Added check to make sure instances ofX25519&Ed25519are
not trying to import a new secret key once they already have one.
This won’t be allowed in favor of creating a new object for a new
secret key.Fixed bug in database classes’ bytes ciphers which called themselves
recursively instead of calling the global functions of the same name.Changes for version 0.16.0Major ChangesAllDatabase&AsyncDatabasefilenames have been converted to
base36 to aid in making the manifest files & the databases as a whole
more space efficient. These changes are not backwards compatible.More work was done to clean up the databases & make them more
efficient, as well as equalize the sizes of the database files to
mitigate leaking metadata about what they might contain.Added newX25519&Ed25519classes that greatly simplify the
usage of the cryptography module’s 25519 based tools. They also help
organize the codebase better – whereRopakewas holding onto
all of the asymmetric tooling even though those tools were not part
of the Ropake protocol.New base & helperAsymmetric25519&BaseEllipticCurveclasses
were added as well to facilitate the reorganization.Many methods inRopakewere turned private to simplify & clean up
the interface so its intended use as a protocol is more clear for users.Added the time-to-live functionality toRopakedecryption functions.
TheTIMEOUTattribute on the class can also be changed to import
a global time-to-live for allRopakeciphertexts.Removed allnc_hash functions from the package/generics.py module.TheNamespaceclass now has akeysmethod so that namespaces
can be unpacked using star-star syntax.Because of the ongoing failures of gnupg, we are moving away from
signing our packages with gnupg. Our new Ed25519 keys will be from
the cryptography package, & we’ll sign those with our gnupg key as a
secondary form of attestation. Our package signing will be automated
in the setup.py file & the methods we use will be transparent in the
code. The new signatures for each package version will be placed in
the fileSIGNATURES.txt.Minor ChangesMany fixes & additions to docstrings & tutorials.Massive refactorings, cleanups & typo fixes across the library,
especially in the database classes,Ropake& theciphersmodule.Added comprehensive functional tests for the Ropake class.AddedBASE_36_TABLEto thecommonsmodule.Fixed metadata issues in setup.py that caused upload issues to pypi.Thegenerate_profile,load_profile,agenerate_profile&aload_profiledatabase methods now accept arbitrary keyword arguments
that get passed into the database’s __init__ constructor.username&passwordare now required keyword-only arguments
to theagenerate_profile_tokens&generate_profile_tokensclassmethods.Theaload&loaddatabase methods now take amanifestkwarg
that when toggledTruewill also refresh the manifest file from
disk.Now when a database object is ordered to delete itself, the entirety
of the instance’s caches & attribute values are cleared & deleted.Filled out the references to strong key generators & protocols in thekeygensmodule.Changes for version 0.15.0Major ChangesSecurity Patch: The previous update left the default salt stored by
theRopakeclass on the user filesystem as an empty string  for
new files that were created since theasalt&saltfunctions
were switched to producing 256-bit values instead of 512-bits. This
bug has now been fixed.An 8 byte timestamp is now prepended to each plaintext during the
padding step. The decryption functions now take attlkwarg which
will measure & enforce a time-to-live for ciphertexts under threat ofTimeoutError.Added new profile feature to the database classes. This standardizes
& simplifies the process for users to open databases using only
low-entropy “profile” information such asusername,password,*credentials& an optionalsalta user may have access to.
The newagenerate_profile_tokens,generate_profile_tokens,agenerate_profile,generate_profile,aprofile_exists,profile_exists,aload_profile,load_profile,adelete_profile&delete_profilefunctions are the public part of this new feature.Some more database class attributes have been turned private to clean
up the api.Fixed typo in__exit__method ofDatabaseclass which referenced
a method which had its name refactored, leading to a crash.Shifted the values in theprimesdictionary such that the key for
each element in the dictionary is the exclusive maximum of each prime
in that element. Ex: primes[512][-1].to_bytes(64, “big”) is now valid.
Whereas before, primes[512] was filled with primes that were 64 bytes
and 1 bit long, making them 65 byte primes. This changes some of the
values of constants in the package & therefore some values derived
from those constants.Slimmed down the number of elements in theprimes&bitsdictionaries, reducing the size of the package a great deal.primesnow contains two primes in each element, the first is the minimum
prime of that bit length, the latter the maximum.AddedURLSAFE_TABLEto the package.Madesalt&pid&ttlkeyword only arguments in key
generators & encryption / decryption functions, further tighening up
the api.Minor ChangesAddedthis_secondfunction toasynchsmodule for integer time.Addedapadding_key,padding_key,aplaintext_stream&plaintext_streamfunctions to theciphersmodule.Addedapadding_key,padding_keyto thekeygensmodule &AsyncKeys&Keysclasses.Addedaxi_mix,xi_mix,acheck_timestamp,check_timestamp,
to thegenericsmodule.Addedacsprbg,csprbg,asalt,salt,apadding_key,padding_key,aplaintext_stream&plaintext_streamfunctions
to OneTimePad class asstaticmethod& instance methods.Addedacheck_timestamp&check_timestampfunctions to theBytesIOclass.Addedadeniable_filename&deniable_filenameto thepathsmodule.Removed check for falsey data in encryption functions. Empty data is
& should be treated as valid plaintext.Various refactorings, docstring fixes & efficiency improvements.Added some new tests for database profiles.Changes for version 0.14.0Major ChangesSecurity patch: Theapad_bytes,pad_bytes,adepad_bytes&depad_bytesfunctions were changed internally to execute in a
more constant time. The variations were small for 256-byte buffers
(the default), but can grow very wide with larger buffers. The salt
in the package’s encryption utilities is now used to derive the
plaintext’s padding, making each padding unique.Unified the types of encodings the library’s encryption functions
utilize for producing ciphertext. This includes databases. They now
all use theLIST_ENCODING. This greatly increases the efficiency
of the databases’ encryption/decryption, save/load times. And this
encoding is more space efficient. This change is backwards
incompatible.TheLIST_ENCODINGspecification was also changed to produce
smaller ciphertexts. The salt is no longer encrypted & included as
the first 256 byte chunk of ciphertext. It is now packaged along with
ciphertext in the clear & is restricted to being a 256-bit hex
string.The interfaces for theDatabase&AsyncDatabasewere cleaned
up. Many attributes & functions that were not intended as the public
interface of the classes were made “private”. Also, the no longer
used utilities for encrypting & decrypting under the MAP_ENCODING
were removed.Updated theabytes_xor,bytes_xor,axor&xorgenerators
to shrink the size of theseedthat’s fed into thekeystream. This
allows the one-time-pad cipher to be more cpu efficient.Minor ChangesFixed various typos, docstrings & tutorials that have no kept up
with the pace of changes.Various refactorings throughout.Theakeypair&keypairfunctions now produce aNamespacepopulated with a 512-bit hex key & a 256-bit hex salt to be more
consistent with their intended use-case with the one-time-pad cipher.Removedaencode_salt,encode_salt,adecode_salt&decode_saltfunctions since they are no longer used in conjunction
with LIST_ENCODING ciphertexts.Updated tests to recognize these changes.Gave theOneTimePadclass access to aBytesIOobject under a
newioattribute.Changes for version 0.13.0Major ChangesSecurity Patch:xor&axorfunctions that define the
one-time-pad cipher had a vulnerability fixed that can leak <1-bit of
plaintext. The issue was in the way keys were built, where the
multiplicative products of two key segments were xor’d together. This
lead to keys being slightly more likely to be positive integers,
meaning the final bit had a greater than 1/2 probability of being a0. The fix is accompanied with an overhaul of the one-time-pad
cipher which is more efficient, faster, & designed with a better
understanding of the way bytes are processed & represented. The key
chunks now do not, & must not, surpass 256 bytes & neither should
any chunk of plaintext output. Making each chunk deterministically
256 bytes allows for reversibly formatting ciphertext to & from
bytes-like strings. These changes are backwards incompatible with
prior versions of this package & are strongly recommended.Addedbytes_xor&abytes_xorfunctions which take in key
generators which produce key segments of type bytes instead of hex
strings.AsyncDatabase&Databasenow save files in bytes format,
making them much more efficient on disk space. They use the newBytesIOclass in thegenericsmodule to transparently convert
to & from json & bytes. This change is also not backwards compatible.Removedacipher,cipher,adecipher,decipher,aorganize_encryption_streams,organize_encryption_streams,aorganize_decryption_streams,organize_decryption_streams,aencrypt,encrypt,adecrypt,decrypt,asubkeys&subkeysgenerators from theciphersmodule & package to slim
down the code, remove repetition & focus on the cipher tools that
include hmac authentication.Removed deprecated diffie-hellman methods inRopakeclass.Removed the staticpower10dictionary from the package.The default secret salt for theRopakeclass is now derived from the
contents of a file that’s in the databases directory which is chmod’d to
0o000 unless needed.Madeaclient_message_key,client_message_key,aserver_message_key,
&server_message_keyRopakeclass methods to help distinguish
client-to-server & server-to-client message keys which prevents replay
attacks on the one-message ROPAKE protocol.Added protocol coroutines to theRopakeclass which allow for easily
engaging in 2DH & 3DH elliptic curve exchanges for servers & clients.Efficiency improvements to theaseeder&seedergenerator functions
in therandomsmodule. This affects theacsprng&csprngobjects
& all the areas in the library that utilize those objects.Changed the repr behavior ofComprendeinstances to redact all args &
kwargs by default to protect cryptographic material from unintentionally
being displayed on user systems. The repr can display full contents by
calling theenable_debuggingmethod of theDebugControlclass.All generator functions decorated withcomprehensionare now given
arootattribute. This allows direct access to the function without
needing to instantiate or run it as aComprendeobject. This saves
a good deal of cpu & time in the overhead that would otherwise be
incurred by the class. This is specifically more helpful in tight &/or
lower-level looping.Minor ChangesVarious refactorings across the library.Fixed various typos, bugs & inaccurate docstrings throughout the library.Addchown&chmodfunctions to theasynchs.aosmodule.Now makes newmultiprocessing.Managerobjects in theasynchs.Processes&asynchs.Threadsclasses to avoid errors that occur when using a stale
object whose socket connections are closed.ChangedRopakeclass’adb_login&db_loginmethods toadatabase_login_key&database_login_key. Also, fix a crash bug in
those methods.ChangedRopakeclass’aec25519_pub,ec25519_pub,aec25519_priv&ec25519_privmethods toaec25519_public_bytes,ec25519_public_bytes,aec25519_private_bytes&ec25519_private_bytes.Added low-level private methods toRopakeclass which do derivation
& querying of the default class key & salt.Behavior changes to theainverse_int&inverse_intfunctions in thegenericsmodule to allow handling bases represented instrorbytestype strings.Behavior & name changes to theabinary_tree&binary_treefunctions in thegenericsmodule toabuild_tree&build_tree. They now allow making
uniform trees of any width & depth, limited only by the memory in a
user’s machine.Provided newacsprbg&csprbgobjects to the library that return 512-bits
of cryptographically secure pseudo-randombytestype strings. They are
made by the newabytes_seeder&bytes_seedergenerators.Thecsprng,acsprng,csprbg&acsprbgobjects were
wrapped in functions that automatically restart the generators if they’re
stalled / interrupted during a call. This keeps the package from melting
down if it can no longer call the CSPRNGs for new entropy.Cleaned up & simplifiedtable_keyfunctions in thekeygensmodule.Changed the output ofasafe_symm_keypair&safe_symm_keypairfunctions
to contain bytes values not their hex-only representation. Also removed
these functions from the main imports of the package since they are slow
& their main contribution is callingarandom_number_generator&random_number_generatorto utilize a large entropy pool when starting
CSPRNGs.Added new values to thebitsdictionary.Addedapad_bytes,pad_bytes,adepad_bytes&depad_bytesfunctions which useshake_256to pad/depad plaintext bytes to & from
multiples of 256 bytes. They take in a key to create the padding.
This method is intended to also aid in protecting against padding
oracle attacks.Changes for version 0.12.0Major ChangesThe OPAKE protocol was renamed to ROPAKE, an acronym for Ratcheting
Opaque Password Authenticated Key Exchange. This change was necessary
since OPAKE is already a name for an existing PAKE protocol. This change
also means theOpakeclass name was changed toRopake.TheRopakeclass’ registration algorithm was slightly modified to
use the generated Curve25519shared_keyan extra time in the key
derivation process. This shouldn’t break any currently authenticated
sessions.Theasyncio_contextmanagerpackage is no longer a listed dependency
insetup.py. The main file from that package was copied over into the/aiootpdirectory in order to remove the piece of code that caused
warnings to crop up when return values were retrieved from async
generators. This change will put an end to this whack-a-mole process of
trying to stop the warnings with try blocks scattered about the codebase.Addedasave_tag,save_tag,asave_file&save_filemethods
to the database classes so that specific entries can be saved to disk
without having to save the entire database which is much more costly. The
manifest file isn’t saved to disk when these methods are used, so if a
tag file isn’t already saved in the database, then the saved files will
not be present in the manifest or in the cache upon subsequent loads of
the database. The saved file will still however be saved on the
filesystem, though unbeknownst to the database instance.TheNamespaceclass now redacts all obvious key material in instance
repr’s, which is any 64+ hex character string, or any number with 64+
decimal digits.Removed the experimental recursive value retrieval withinComprende’s__aexamine_sent_exceptions&__examine_sent_exceptionsmethods.
This change leads to more reliable & faster code, in exchange for an
unnecessary feature being removed.Bug fix of theauuids&uuidsmethods by editing the code in
theasyncio_contextmanagerdependency & using the patched package
instead of thecomprehensiondecorator for thearelay&relaymethods ofComprende. Their internal algorithms was also updated to
be simpler, but are incompatible with the outputs of past versions of
these methods.Minor ChangesVarious refactorings & documentation additions / modifications throughout
the library.Various small bug fixes.The shared keys derived from theRopakeprotocol are now returned in
aNamespaceobject instead of a raw dictionary, which allows the
values to be retrieved by dotted &/or bracketed lookup.Theatest_hmac&test_hmacalgorithms / methods were made more
efficient & were refactored. Now they callatime_safe_equality&time_safe_equalityinternally, which are new methods that can apply
the non-constant time but randomized timing comparisons on any pairs of
values.Changes for version 0.11.0Major ChangesThe Opake protocol was made greatly more efficient. This was done by
replacing the diffie-hellman verifiers with a hash & xor commit & reveal
system. Most hashing was made more efficient my using quicker & smallersha_512function instead ofnc_512, & streamlining the protocol.TheOpake.client&Opake.client_registrationmethods now take
an instantiated client database instead of client credentials which
improves security, efficiency & usability. This change reduces the amount
of exposure received by user passwords & other credentials. It also
simplifies usage of the protocol by only needing to carry around a
database instead of a slew of credentials, which is also faster, since
the credentials are passed through the cpu & memory hardpasscryptfunction everytime to open the database.Minor ChangesHeavy refactorings & documentation additions / modifications of theOpakeclass. Removed theOpake.ainit_database&Opake.init_databasemethods, & made thesaltdefault argument parameter inOpake.aclient_database,Opake.client_database,Opake.adb_login&Opake.db_logininto a keyword only argument so any extra user definedcredentialsare able to be passed without specifying a salt.The decorators for theComprende.arelay&Comprende.relaymethods
were changed from@asyncio_contextmanager.async_contextmanagerto@comprehension()to stop that package from raising exceptions when
we retrieve return values from async generators.Changes for version 0.10.1Major ChangesAddedProcesses&Threadsclasses toasynchs.pywhich abstract
spawning & getting return values from async & sync functions intended to
be run in threads, processes or pools of the former types. This simplifies
& adds time control to usages of processes & threads throughout the
library.Reduced the effectiveness of timing analysis of the modular exponentiation
in theOpakeclass’ verifiers by making the process return values
only after discrete intervals of time. Timing attacks on that part of the
protocol may still be viable, but should be significantly reduced.Bug fix inComprendewhich should take care of warnings raised from
theaiocontextpackage when retrieving async generator values by
raisingUserWarningwithin them.Minor ChangesHeavy refactorings of theOpakeclass.Various refactorings & cleanups around the package.Further addreturn_exceptions=Trueflag to gather calls inciphers.py.Addedis_registration&is_authenticationwhich take a client
hello message that begin theOpakeprotocol, & returnFalseif
the message is not either a registration or authentication message,
respectively, & return"Maybe"otherwise, since these functions can’t
determine without running the protocol whether or not the message is
valid.Changes for version 0.10.0Major ChangesAdded a new oblivious, one-message, password authenticated key exchange
protocol class inaiootp.ciphers.Opake. It is a first attempt at the
protocol, which works rather well, but may be changed or cleaned up in a
future update.Added thecryptographypackage as a dependency for elliptic curve
25519 diffie-hellman key exchange in theOpakeprotocol.Fix buggy data processing functions ingenerics.pymodule.Addedsilentflag toAsyncDatabase&Databasemethods, which
allows their instances to finish initializing even if a file is missing
from the filesystem, normally causing aFileNotFoundError. This makes
trouble-shooting corrupted databases easier.Added newaiootp.paths.SecurePathfunction which returns the path to
a unique directory within the database’s default directory. The name of
the returned directory is a cryptographic value used to create & open the
default database used by theOpakeclass to store the cryptographic
salt that secures the class’ client passwords. It’s highly recommended
to override this default database by instantiating the Opake class with
a custom user-defined key. The instance doesn’t need to be saved, since
all the class’ methods are either class or static methods. The__init__method only changes the class’ default database to one opened with the
user-definedkey&/ordirectorykwargs, & should really only be
done once at the beginning of an application.Minor ChangesVarious refactorings & cleanups around the package.AddedComprendeclass feature to return the values from even the
generators within an instance’s arguments. This change better returns
values to the caller from chains ofComprendegenerators.Fixedcommons.BYTES_TABLEmissing values.Addedcommons.DH_PRIME_4096_BIT_GROUP_16&commons.DH_GENERATOR_4096_BIT_GROUP_16constants for use in theOpakeprotocol’s public key verifiers.Added other values to thecommons.pymodule.Added new very large no-collision hash functions to thegenerics.pymodule used to xor with diffie-hellman public keys in theOpakeclass.Added newwait_on&await_onComprendegenerators togenerics.pywhich waits for a queue or container to be populated & yields it whenever
it isn’t empty.Changes for version 0.9.3Major ChangesSpeed & efficiency improvements in theComprendeclass &azip.Minor ChangesVarious refactorings & code cleanups.Addedapop&popComprendegenerators to the library.Switched the default character table in theato_base,to_base,afrom_base, &from_basechainable generator methods from the 62
characterASCII_ALPHANUMERICtable, to the 95 characterASCII_TABLE.Made the digits generators inrandoms.pyautomatically create a new
cryptographically secure key if a key isn’t passed by a user.Some extra data processing functions added togenerics.py.Changes for version 0.9.2Major ChangesAddedpasscrypt&apasscryptinstance methods toOneTimePad,Keys, &AsyncKeysclasses. They produce password hashes that are
not just secured by the salt & passcrypt algorithm settings, but also by
their main symmetric instance keys. This makes passwords infeasible to
crack without also compromising the instance’s 512-bit key.Minor ChangesFurther improvements to the random number generator inrandoms.py.
Made its internals less sequential thereby raising the bar of work needed
by an attacker to successfully carry out an order prediction attack.Added checks in thePasscryptclass to make sure both a salt &
password were passed into the algorithm.SwitchedPermissionErrorexceptions inPasscrypt._validate_argstoValueErrorto be more consistent with the rest of the class.Documentation updates / fixes.Changes for version 0.9.1Minor ChangesNow any falsey values for thesaltkeyword argument in the library’skeys,akeys,bytes_keys,abytes_keys,subkeys, &asubkeysinfinite keystream generators, & other functions around the
library, will cause them to generate a new cryptographically secure
pseudo-random value for the salt. It formerly only did this whensaltwasNone.Theseeder&aseedergenerators have been updated to introduce
512 new bits of entropy fromsecrets.token_byteson every iteration
to ensure that the CSPRNG will produce secure outputs even if its
internal state is somehow discovered. This also allows for simply calling
the CSPRNG is enough, there’s no longer a strong reason to pass new
entropy into it manually, except to add even more entropy as desired.Madesizethe last keywordCHECKSUMS.txt argument inencrypt&aencryptto better mirror the signatures for rest of the library.Addedtoken_bits&atoken_bitsfunctions torandoms.pywhich
are renamings ofsecrets.randbits.Refactored & improved the security ograndoms.py’s random number
generator.Changes for version 0.9.0Major ChangesAdded hmac codes to ciphertext for the following functions:json_encrypt,ajson_encrypt,bytes_encrypt,abytes_encrypt,Database.encrypt&AsyncDatabase.aencrypt. This change greatly
increases the security of ciphertext by ensuring it hasn’t been modified
or tampered with maliciously. One-time pad ciphertext is maleable, so
without hmac validation it can be changed to successfully allow
decryption but return the wrong plaintext. These functions are the
highest level abstractions of the library for encryption/decryption,
which made them excellent targets for this important security update.
As well, it isn’t easily possible for the library to provide hmac codes
for generators that produce ciphertext, because the end of a stream of
ciphertext isn’t known until after the results have left the scope
of library code. So users will need to produce their own hmac codes for
generator ciphertext unless we find an elegant solution to this issue.
These functions now all return dictionaries with the associated hmac
stored in the"hmac"entry. The bytes functions formerly returned
lists, now their ciphertext is available from the"ciphertext"entry.
And, all database files will have an hmac attached to them now. These
changes were designed to still be compatible with old ciphertexts but
they’ll likely be made incompatible by the v0.11.x major release.Only truthy values are now validkeykeyword arguments in the
library’skeys,akeys,bytes_keys,abytes_keys,subkeys,
&asubkeysinfinite keystream generators. Also now seeding extra entropy
intocsprng&acsprngwhensaltis falsey within them.Only truthy values are now valid forpassword&saltarguments inapasscrypt,passcrypt& their variants.Minor ChangesUpdates to documentation &README.rsttutorials.Thekb,cpu, &hardnessarguments insum_passcrypt&asum_passcryptchainable generator methods were switched to keyword
only arguments.Changes for version 0.8.1Major ChangesAddedsum_passcrypt&asum_passcryptchainable generator methods
toComprendeclass. They cumulatively apply the passcrypt algorithm
to each yielded value from an underlying generator with the passcrypt’d
prior yielded result used as a salt. This allows making proofs of work,
memory & space-time out of iterations of the passcrypt algorithm very
simple.Minor ChangesVarious inaccurate docstrings fixed.Various refactorings of the codebase.Madekb,cpu, &hardnessarguments into keyword only arguments
inAsyncDatabase&Databaseclasses.Thelengthkeyword argument in functions around the library was
changed tosizeto be consistent across the whole package. Reducing
the cognitive burden of memorizing more than one name for the same concept.Various efficiency boosts.Edits toREADME.rst.Addedencode_salt,aencode_salt,decode_salt&adecode_saltfunctions to the library, which gives access to the procedure used to
encrypt & decrypt the random salt which is often the first element
produced in one-time pad ciphertexts.Added cryptographically secure pseudo-random values as default keys in
encryption functions to safeguard against users accidentally encrypting
data without specifying a key. This way, such mistakes will produce
ciphertext with an unrecoverable key, instead of without a key at all.Changes for version 0.8.0Major ChangesFixtest_hmac,atest_hmacfunctions in the keys & database
classes. The new non-constant-time algorithm needs a random salt to be
added before doing the secondary hmac to prevent some potential exotic
forms of chosen plaintext/ciphertext attacks on the algorithm. The last
version of the algorithm should not be used.TheKeys&AsyncKeysinterfaces were overhauled to remove the
persistance of instance salts. They were intended to be updated by users
with thereset&aresetmethods, but that cannot be guaranteed
easily through the class, so it is an inappropriate interface since
reusing salts for encryption is completely insecure. The instances do
still maintain state of their main encryption key, & new stateful methods
for key generation, likemnemonic&table_key, have been added.
Thestate&astatemethods have been removed.GaveOneTimePadinstances new stateful methods from theciphers.pymodule &keygens.pykeys classes. Its instances now remember the main
symmetric key behind thekeyproperty & automatically passes it as a
keyword argument to the methods inOneTimePad.instance_methods.Minor ChangesUpdateCHANGES.rstfile with the updates that were not logged for
v0.7.1.BYTES_TABLEwas turned into a list so that the byte characters can
be retrieved instead of their ordinal numbers.Changes for version 0.7.1Major ChangesFix a mistake in the signatures ofpasscrypt&apasscrypt. The args ``kb,cpu&hardnesswere changed into keyword only arguments
to mitigate user mistakes, but the internal calls to those functions were
still using positional function calls, which broke the api. This issue
is now fixed.Changes for version 0.7.0Major ChangesReplaced usage of barerandommodule functions, to usage of an
instance ofrandom.Randomto keep from messing with user’s settings
on that module.Finalized the algorithm for thepasscrypt&apasscryptfunctions.
The algorithm is now provably memory & cpu hard with a wide security
margin with adequate settings. The algorithm isn’t likely change with
upcoming versions unless a major flaw is found.The default value for thecpuargument inpasscrypt&apasscryptis now3& now directly determines how many hash iterations are done
for each element in the memory cache. This provides much more
responsiveness to users & increases the capacity to impact resource cost
with less tinkering.Switched theAsyncKeys.atest_hmac&Keys.test_hmacmethods to a
scheme which is not constant time, but which instead does not leak useful
information. It does this by not comparing the hmacs of the data, but of
a pair of secondary hmacs. The timing analysis itself is now dependant
on knowledge of the key, since any conclusions of such an analysis would
be unable correlate its findings with any supplied hmac without it.Addedtest_hmac&atest_hmacto the database classes, & changed
their hmac algorithm fromsha3_512tosha3_256.Minor ChangesVarious code cleanups, refactorings & speedups.Several fixes to inaccurate documentation.Several fixes to inaccurate function signatures.Addedmnemonic&amnemonickey generators tokeygens.pywith
a wordlist 2048 entries long. A custom wordlist can also be passed in.Minor changes inComprendeto track down a bug in the functions that
use the asyncio_contextmanager package. It causes a warning when asking
async generators to return (not yield) values.Some refactoring ofrandom_number_generator&arandom_number_generator.Changes for version 0.6.0Major ChangesReplaced the usage ofos.urandomwithin the package withsecrets.token_bytesto be more reliable across platforms.Replaced several usages ofrandom.randrangewithinrandoms.pyto
calls tosecrets.token_byteswhich is faster & more secure. It
now also seedsrandommodule periodically prior to usage.Changed the internal cache sorting algorithm ofpasscrypt&apasscryptfunctions. The key function passed tolist.sort(key=key)now not only updates thehashlib.sha3_512proof object with
each element in the cache, but with it’s own current output. This change
is incompatible with previous versions of the functions. The key function
is also trimmed down of unnecessary value checking.The default value for thecpuargument inpasscrypt&apasscryptis now40_000. This is right at the edge of when the argument begins
impacting the cpu work needed to comptute the password hash when thekbargument is the default of1024.Switched theAsyncKeys.atest_hmac&Keys.test_hmacmethods to a
constant time algorithm.Minor ChangesVarious code cleanups, refactorings & speedups.Added aconcurrent.futures.ThreadPoolExecutorinstance to theasynchsmodule for easily spinning off threads. It’s available underasynchs.thread_pool.Addedsort&asortchainable generator method to theComprendeclass. They support sorting by akeysorting function as well.Changed the name ofasynchs.executor_wrappertoasynchs.wrap_in_executor.Changed the name ofrandoms.non0_digit_stream,randoms.anon0_digit_stream,randoms.digit_stream&randoms.adigit_streamtorandoms.non_0_digits,randoms.anon_0_digits,randoms.digits&randoms.adigits.Several fixes to inaccurate documentation.apasscrypt&Passcrypt.anewnow use the synchronous version of the
algorithm internally because it’s faster & it doesn’t change the
parallelization properties of the function since it’s already run
automatically in another process.Addedshuffle,ashuffle,unshuffle, &aunshufflefunctions
torandoms.pythat reorder sequences pseudo-randomly based on theirkey&saltkeyword arguments.Fixed bugs inAsyncKeys&debuggers.py.Addeddebugger&adebuggerchainable generator methods to theComprendeclass which benchmarks & inspects running generators with
an inline syntax.Changes for version 0.5.1Major ChangesFixed a bug in the methodsauuids&uuidsof the database classes
that assigned to a variable within a closure that was nonlocal but which
wasn’t declared non-local. This caused an error which made the methods
unusable.Addedpasscrypt&apasscryptfunctions which are designed to be
tunably memory & cpu hard password-based key derivation function. It was
inspired by the scrypt protocol but internally uses the library’s tools.
It is a first attempt at the protocol, it’s internal details will likely
change in future updates.Addedbytes_keys&abytes_keysgenerators, which are just like
the library’skeysgenerator, except they yield the concatenatedsha3_512.digestinstead of thesha3_512.hexdigest.Added new chainable generator methods to theComprendeclass for
processing bytes, integers, & hex strings into one another.Minor ChangesVarious code cleanups.New tests added to the test suite forpasscrypt&apasscrypt.TheComprendeclass’alist&listmethods can now be passed
a boolean argument to return either amutablelist directly from the
lru_cache, or a copy of the cached list. This list is used by the
generator itself to yield its values, so wilely magic can be done on the
list to mutate the underlying generator’s results.Changes for version 0.5.0Major ChangesAdded interfaces inDatabase&AsyncDatabaseto handle encrypting
& decrypting streams (Comprendegenerators) instead of just raw json
data. They’re methods calledencrypt_stream,decrypt_stream,aencrypt_stream, &adecrypt_stream.Changed the attribute_METATAGused byDatabase&AsyncDatabaseto name the metatags entry in the database. This name is smaller, cleaner
& is used to prevent naming collisions between user entered values & the
metadata the classes need to organize themselves internally. This change
will break databases from older versions keeping them from accessing their
metatag child databases.Added the methodsauuids&uuidstoAsyncDatabase&Databasewhich return coroutines that accept potentially sensitive identifiers &
turns them into saltedsizelength hashes distinguished by asalt& acategory.Minor ChangesVarious code & logic cleanups / speedups.Refactorings of theDatabase&AsyncDatabaseclasses.Various inaccurate docstrings fixed.Changes for version 0.4.0Major ChangesFixed bug inaiootp.abytes_encryptfunction which inaccurately called
a synchronousComprendeend-point method on the underlying async
generator, causing an exception and failure to function.Changed the procedures inakeys&keysthat generate their internal
key derivation functions. They’re now slightly faster to initialize &
more theoretically secure since each internal state is fed by a seed
which isn’t returned to the user. This encryption algorithm change is
incompatible with the encryption algorithms of past versions.Minor ChangesVarious code cleanups.Various inaccurate docstrings fixed.Keyword arguments inKeys().test_hmac&AsyncKeys().atest_hmachad their order switched to be slightly more friendly to use.Added documentation toREADME.rston the inner workings of the
one-time-pad algorithm’s implementation.MadeCompende.arandom_sleep&Compende.random_sleepchainable
generator methods.Changed theCompende.adelimit_resize&Compende.delimit_resizealgorithms to not yield inbetween two joined delimiters in a sequence
being resized.Changes for version 0.3.1Minor ChangesFixed bug where a static method inAsyncDatabase&Databasewas
wrongly labelled a class method causing a failure to initialize.Changes for version 0.3.0Major ChangesTheAsyncDatabase&Databasenow use the more secureafilename&filenamemethods to derive the hashmap name and encryption streams
from a user-defined tag internal to theiraencrypt/adecrypt/encrypt/decryptmethods, as well as, prior to them getting called.
This will break past versions of databases’ ability to open their files.The package now has built-in functions for using the one-time-pad
algorithm to encrypt & decrypt binary data instead of just strings
or integers. They are available inaiootp.abytes_encrypt,aiootp.abytes_decrypt,aiootp.bytes_encrypt&aiootp.bytes_decrypt.TheComprendeclass now has generators that do encryption & decryption
of binary data as well. They are available from anyComprendegenerator
by theabytes_encrypt,abytes_decrypt,bytes_encrypt&bytes_decryptchainable method calls.Minor ChangesFixed typos and inaccuracies in various docstrings.Added a__ui_coordination.pymodule to handle inserting functionality
from higher-level to lower-level modules and classes.Various code clean ups and redundancy eliminations.AsyncKeys&Keysclasses now only update theirself.saltkey
by default when theirareset&resetmethods are called. This
aligns more closely with their intended use.Addedarandom_sleep&random_sleepchainable methods to theComprendeclass which yields outputs of generators after a random
sleep for each iteration.Added several other chainable methods to theComprendeclass for
string & bytes data processing. They’re viewable inComprende.lazy_generators.Added new, initial tests to the test suite.Changes for version 0.2.0Major ChangesAdded ephemeral salts to theAsyncDatabase&Databasefile
encryption procedures. This is a major security fix, as re-encryption
of files with the same tag in a database with the same open key would
use the same streams of key material each time, breaking encryption if
two different versions of a tag file’s ciphertext stored to disk were
available to an adversary. The database methodsencrypt,decrypt,aencrypt&adecryptwill now produce and decipher true one-time
pad ciphertext with these ephemeral salts.Theaiootp.subkeys&aiootp.asubkeysgenerators were revamped
to use thekeys&akeysgenerators internally instead of using
their own, slower algorithm.AsyncDatabasefile deletion is now asynchronous by running thebuiltins.os.removefunction in an async thread executor. The
decorator which does the magic is available ataiootp.asynchs.executor_wrapper.Minor ChangesFix typos in__root_salt&__aroot_saltdocstrings. Also replaced
thehash(self)argument for theirlru_cache&alru_cachewith a secure hmac instead.addgi_frame,gi_running,gi_code,gi_yieldfrom,ag_frame,ag_running,ag_code&ag_awaitproperties toComprendeclass to mirror async/sync generators more closely.Removeajson_encrypt,ajson_decrypt,json_encrypt,json_decryptfunctions’ internal creation of dicts to contain the
plaintext. It was unnecessary & therefore wasteful.Fix docstrings inOneTimePadmethods mentioningparentkwarg which
is a reference to deleted, refactored code.Fix incorrect docstrings in databasesnamestream&anamestreammethods.AddedASYNC_GEN_THROWNconstant toComprendeclass to try to stop
an infrequent & difficult to debugRuntimeErrorwhen async generators
do not stop after receiving anathrow.Database tags are now fully loaded when they’re copied using the methodsinto_namespace&ainto_namespace.Updated inaccurate docstrings inmap_encrypt,amap_encrypt,map_decrypt&amap_decryptOneTimePadmethods.Addedacustomize_parametersasync function toaiootp.genericsmodule.Various code clean ups.Changes for version 0.1.0Minor ChangesInitial version.Major ChangesInitial version.Known Issues……………………………..Table Of ContentsThe test suite for this software is under construction, & what tests
have been published are currently inadequate to the needs of
cryptography software.This package is currently in beta testing & active development,
meaning major changes are still possible when there are really good
reasons to do so. Contributions are welcome. Send us a message if
you spot a bug or security vulnerability:gonzo.development@protonmail.chrmlibre@riseup.neted25519-key: 70d1740f2a439da98243c43a4d7ef1cf993b87a75f3bb0851ae79de675af5b3bx25519-key: 4457276dbcae91cc5b69f1aed4384b9eb6f933343bb44d9ed8a80e2ce438a450