[Cryptography-dev] Low level API for Symmetric Encryption

Donald Stufft donald at stufft.io
Thu Aug 8 00:55:30 CEST 2013


Using an Unauthenticated cipher to remove the distraction of the MAC and AAD.

cipher = AES128CBC(key, iv)
enciphered = "".join(cipher.encrypt(chunk) for chunk in CHUNKS) + cipher.finalize()

cipher = AES128CBC(key, iv)
plaintext = "".join(cipher.decrypt(chunk) for chunk in make_chunks(enciphered)) + cipher.finalize()

There is no internal buffer.

If you do

cipher = AES128CBC(key, iv)
cipher.encrypt(data)
cipher.decrypt(enciphered)

You'll get an error calling decrypt() because the first call to encrypt() toggled the cipher into "encryption mode". And if you call either of them after it's been finalized you'll get an error because it's been finalized.


On Aug 7, 2013, at 6:41 PM, Alex Gaynor <alex.gaynor at gmail.com> wrote:

> I'm not sure I totally follow what you said, can you show an example of using such an API?
> 
> Alex
> 
> 
> On Wed, Aug 7, 2013 at 3:40 PM, Donald Stufft <donald at stufft.io> wrote:
> 
> On Aug 7, 2013, at 6:31 PM, Alex Gaynor <alex.gaynor at gmail.com> wrote:
> 
>> 
>> 
>> 
>> On Wed, Aug 7, 2013 at 3:27 PM, Donald Stufft <donald at stufft.io> wrote:
>> 
>> On Aug 7, 2013, at 6:21 PM, Alex Gaynor <alex.gaynor at gmail.com> wrote:
>> 
>>> A few thoughts:
>>> 
>>> a) I don't like each call to update() returning data, it seems like it should all be buffered in the cipher and then returned at the end.
>> 
>> The idea behind returning data is it enables the ability to stream the cipher (albeit at whatever the block size is for block ciphers). If you just buffer it and return it at the end then you can't really do that. Like a list comprehension vs an generator.
>> 
>> 
>> Different API then? I think most people assume update() won't return anything (also they'll do bufferring slowly with stuff like += on bytes).
> 
> Yea we probably need two separate API's now that I think about it, because you likely want to either do streaming OR internal buffering. As suggested if I was trying to stream 50GB of data through encryption I'd be pretty upset if it was getting stored in an internal buffer chewing up 50Gb worth of ram by the time we're done.
> 
> The other option is to just always have the api take data in, operate on it, and return data and never worry about doing any internal buffering. Probably need a different name than update though.
> 
> This might be a bad idea but we could do ``decrypt()`` and ``encrypt()`` which function as above (take data in, operate on it, return it) and whichever one you call first sets the encrypt vs decrypt flag on that instance (so calling one and than the other would be an error).
> 
>>  
>>> 
>>> b) I assume it raises an error if you try to do anything after finalization?
>> 
>> That'd make the most sense I think, the other alternative is garbage but I think that's bad.
>> 
>> 
>> Garbage bad.
>>  
>>> 
>>> c) I think params like a MAC should just be added to __init__ for ciphers which need them
>> 
>> Well for instance for AES-GCM when encrypting you wouldn't add anything to __init__, you'd just need a way to fetch the MAC data that you can use to authenticate the ciphertext. When decrypting you need a way to pass the MAC data in so it can be authenticated (so this could use __init__).
>> 
>> The same sort of thing exists for authenticated plaintext too, when encrypting you need to pass it in, when decrypting you get it back out.
>> 
>> Yeah I think passing MAC on decrypt to __init__, and a method to get the mac makes the most sense (or have finalize return a tuple?).
>>  
>> 
>>> 
>>> d) I don't have any ideas about specifying encrypt vs. decrypt.
>>> 
>>> Alex
>>> 
>>> 
>>> On Wed, Aug 7, 2013 at 3:16 PM, Donald Stufft <donald at stufft.io> wrote:
>>> So to kick things off I'd like to get AES-GCM exposed and figured it could be a good way to start the ball rolling for figuring out how we want to expose symmetric ciphers at the low level API.
>>> 
>>> I'm thinking cryptography.primitives.aes which has classes named like AES128GCM, AES256CBC, etc. The obvious naming scheme being AlgorithmKeysizeMode.
>>> 
>>> classes look something like
>>> 
>>> class AES128GCM:
>>> 
>>>     # Information about the Cipher
>>>     authenticated = True
>>>     block_size = 128
>>> 
>>>     def __init__(self, key, iv, …)
>>> 
>>>     def update(self, plaintext)  # Updates an internal buffer as well as returns the encrypted chunk of data
>>> 
>>>     def finalize(self)  # Updates the internal buffer witth finalized data and returns the same finalized data
>>> 
>>> 
>>> Some open questions:
>>> 
>>> A lot of these are going to be block ciphers, do we want to do padding for people or expect them to hand us chunks of the correct block size?
>>> 
>>> How do we decrypt vs encrypt. I think that:
>>> 
>>>     cipher = AES128GCM(key, iv)
>>>     enciphered = cipher.update(plaintext) + cipher.finalize()
>>> 
>>>     cipher = AES128GCM(key, iv)
>>>     plaintext = cipher.update(enciphered) + cipher.finalize()
>>> 
>>> Makes a decent API here, but we need a way to make a decryption vs encryption cipher. Possibly something like encrypt=True, or decrypt=True (specifying both being an error)?
>>> 
>>> Some ciphers (AES-GCM included) are authenticated and thus return (and require giving) a MAC in order to authenticate it, some authenticated ciphers also support the ability to pass along unencrypted but still authenticated data as well. I can't think of a decent way of doing this besides just adding functions (or __init__ args) to pass this data in, does anyone else have any ideas?
>>> 
>>> Any other thoughts? I'm just spitballing here so let's see what we can come up with!
>>> 
>>> 
>>> -----------------
>>> Donald Stufft
>>> PGP: 0x6E3CBCE93372DCFA // 7C6B 7C5D 5E2B 6356 A926 F04F 6E3C BCE9 3372 DCFA
>>> 
>>> 
>>> _______________________________________________
>>> Cryptography-dev mailing list
>>> Cryptography-dev at python.org
>>> http://mail.python.org/mailman/listinfo/cryptography-dev
>>> 
>>> 
>>> 
>>> 
>>> -- 
>>> "I disapprove of what you say, but I will defend to the death your right to say it." -- Evelyn Beatrice Hall (summarizing Voltaire)
>>> "The people's good is the highest law." -- Cicero
>>> GPG Key fingerprint: 125F 5C67 DFE9 4084
>>> _______________________________________________
>>> Cryptography-dev mailing list
>>> Cryptography-dev at python.org
>>> http://mail.python.org/mailman/listinfo/cryptography-dev
>> 
>> 
>> 
>> -----------------
>> Donald Stufft
>> PGP: 0x6E3CBCE93372DCFA // 7C6B 7C5D 5E2B 6356 A926 F04F 6E3C BCE9 3372 DCFA
>> 
>> 
>> _______________________________________________
>> Cryptography-dev mailing list
>> Cryptography-dev at python.org
>> http://mail.python.org/mailman/listinfo/cryptography-dev
>> 
>> 
>> 
>> 
>> -- 
>> "I disapprove of what you say, but I will defend to the death your right to say it." -- Evelyn Beatrice Hall (summarizing Voltaire)
>> "The people's good is the highest law." -- Cicero
>> GPG Key fingerprint: 125F 5C67 DFE9 4084
>> _______________________________________________
>> Cryptography-dev mailing list
>> Cryptography-dev at python.org
>> http://mail.python.org/mailman/listinfo/cryptography-dev
> 
> 
> 
> -----------------
> Donald Stufft
> PGP: 0x6E3CBCE93372DCFA // 7C6B 7C5D 5E2B 6356 A926 F04F 6E3C BCE9 3372 DCFA
> 
> 
> _______________________________________________
> Cryptography-dev mailing list
> Cryptography-dev at python.org
> http://mail.python.org/mailman/listinfo/cryptography-dev
> 
> 
> 
> 
> -- 
> "I disapprove of what you say, but I will defend to the death your right to say it." -- Evelyn Beatrice Hall (summarizing Voltaire)
> "The people's good is the highest law." -- Cicero
> GPG Key fingerprint: 125F 5C67 DFE9 4084
> _______________________________________________
> Cryptography-dev mailing list
> Cryptography-dev at python.org
> http://mail.python.org/mailman/listinfo/cryptography-dev


-----------------
Donald Stufft
PGP: 0x6E3CBCE93372DCFA // 7C6B 7C5D 5E2B 6356 A926 F04F 6E3C BCE9 3372 DCFA

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/cryptography-dev/attachments/20130807/599898a0/attachment-0001.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: Message signed with OpenPGP using GPGMail
URL: <http://mail.python.org/pipermail/cryptography-dev/attachments/20130807/599898a0/attachment-0001.pgp>


More information about the Cryptography-dev mailing list