New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Crypto.Util.Counter.new returns a dictionary instead of an object (how to keep track of/get IV value for AES-CTR?) #679
Comments
I checked older versions and it seems pycryptodome has been using a dict since the beginning. The documentation for Crypto.Ciphers.AES says regarding the iv parameter: |
For CTR mode, the name of the attribute is See the examples here: https://pycryptodome.readthedocs.io/en/latest/src/cipher/classic.html#ctr-mode |
Hey, sorry to re-iterate, but my question wasn't literal - the problem is the Not to complain, but considering the long response time I decided to write my own Python wrapper for AES instead to solve this issue. Wrote it within a couple of hours, should have taken much less, about 5 minutes actually, but I overcomplicated things and ended up spending a couple of hours. So the issue in your software isn't solved, but the issue is solved for me as I decided to write my own software that actually works like it should instead. Again sorry for being cheeky, I don't appreciate it when people think I'm wasting their time by not reading anything I said properly and being dismissive off hand. Good luck with your software. |
If I do:
I get:
Which is clearly not empty. Next time, if you have an issue, the best way to receive help is to provide an example demonstrating the issue and how you got to it. But I am glad you sorted out the problem in the end. |
Sorry that you missed it, but I clearly did in my second comment, stating that the nonce attribute is empty. As far as the actual bug report now, setting aside who said what first which ended up being more important than the issue in the end since you completely missed what I said the first time (not just the spirit but literally what I said, that the nonce attribute always showed an empty bytes value, feel free to read back if you still haven't caught it)... I cannot replicate the bug at the moment using your code. I definitely never used this code snipped though, I used the code snippet from here https://pycryptodome.readthedocs.io/en/latest/src/util/util.html#crypto-util-counter-module I can't replicate having an empty nonce attribute -- actually let me re-iterate one more time just before you miss the crucial part right above here first: the nonce attribute is completely missing in the code snippet I provided. But, technically I can't replicate the empty nonce attribute with this code, since it's not even there. Good luck, hope not to encounter someone like you again with such relentless conviction in yourself and arrogance, namaste. |
Also in case you still managed to miss the snippet and would like to blame me again for your own poor ability to read what's right in front of your nose, here's the code I used to notice there's no nonce attribute in cipher in this code snippet:
You can substitute the last line with cipher.nonce if you wish and you'll get an object has no attribute error. Anyway feel free to spare me any explanation, I obviously don't care anymore, we're both just engaging in a pissing contest at this point since you started off with all the aggression, can't seem to fathom that you could be in the wrong, and probably will even fail to recognize you're participating in a pissing contest right now, speaking volumes about just how deep you're in it, but anyway, take care, hf. |
I spent a while looking at this. It has to do with whether counter is passed or not.
What is unclear to me is why the blank
we already know the nonce when we are creating the counter, so why not simply pass it around to whatever else needs it? It might also be silly for the counter's nonce to be available through the cipher. Here the nonce is passed to the counter as a prefix, but the counter also takes |
Thanks for replicating.
Well, basically convenience, it's easier than having to implement your own class that takes in the unencrypted data, checks the length, and calculates how much to increment the nonce with, honestly it's at least 50% of the whole implementation (at least in the case of my implementation which was 2 line of CY, about 20 lines of PY and about 7 lines of C++ - didn't take much code at all, and that includes all necessary asserts to make sure the datatype is right), so feels kind of a waste to have to implement the whole nonce functionality on your own, not to mention I honestly think it's a little weird of a question to ask in the first place - why is it a problem that your library doesn't have any functionality to track the nonce in CTR mode? Really? Anyway, thanks for replicating, (sincerely) best of luck. Also, just a tip: another option is to try to keep backwards compatibility with pycrypto whenever possible. |
As far as I understand it, pycryptodome does track it internally, because otherwise the
My question is why do you as the user need to access the internal nonce. What do you do with the changed/incremented nonce? If you encrypt more data with it, why not just reuse the cipher object? |
Sure, but the nonce isn't available so it's worthless. It doesn't do/achieve anything for us except for internal state.
You need it in CTR to keep track of what nonce is used up and should not be re-used between releases. |
I am well aware that you need a different nonce every time :)
What is the difference between doing this and just constructing one cipher object that is used for all encrypting/decrypting? To me, continuous incrementing sounds like exactly what you would get if you just keep reusing the same cipher. Is it because you are encrypting with pycryptodome and you need to send the current nonce value in the beginning of each chunk of encrypted data? If that is the case, why not use random nonces? |
What do you mean, pickle the cipher object or something? Anyway as you can see the maintainer of this repo isn't interested in fixing his software and I'm not interested in trying to convince him to, it's his loss if he doesn't want his software to work properly and can't own up and apologize for having a stinking attitude in the first place when a bug report is made. But to answer your last question, random nonces are less secure. I don't know by how much, I don't want to have to do the math involved, but the more releases the higher the chance for collision and significantly so (birthday problem). I like that you think outside the box, but I think outside the box thoroughly as well and I don't think there's any solution here without having access to the nonce. |
I didn't mean that the cipher object should be pickled, and I agree that would be ridiculous :) This is how I imagine it:
I think the problem is that you want to send the nonce together with the data. The server is supposed to say "let's use nonce X+len(A)" when it sends data B, but there is no way to ask pycryptodome what X+len(A) is. This makes me wonder: do you really need to send the nonce in the beginning of every message if it increments predictably? Because of compatibility with other software that uses the same protocol? Also, thanks for taking the time to ELI5 this to me :) |
Somehow this sounds like an XY problem. Is this strict nonce-keeping really an issue with a sufficiently sized random nonce? Consider the following code: from Cryptodome.Cipher import AES
from os import urandom
NONCE_LENGTH = 12
def encrypt(key: bytes, data: bytes) -> bytes:
nonce = urandom(NONCE_LENGTH)
return nonce + AES.new(key, mode=AES.MODE_CTR, nonce=nonce).encrypt(data)
def decrypt(key: bytes, cipher: bytes) -> bytes:
nonce = cipher[:NONCE_LENGTH]
return AES.new(key, mode=AES.MODE_CTR, nonce=nonce).decrypt(cipher[NONCE_LENGTH:])
if __name__ == "__main__":
data = b'123'
key = b'\x81'*16
encrypted = encrypt(key, data)
decrypted = decrypt(key, encrypted)
assert decrypted == data 96-bit random nonces are used here. This allows up to |
Theoretically no I suppose, but I'm not going to rewrite my code in C++ for this.
Np, I'm 5 myself so I like when people ELI5 I suppose. There's a lot of smart people around, but there's also a lot of less smart people around, I might be one of them depending on where you set the bar, but it's often not easy to know exactly how smart or knowledgeable someone is in such a brief conversation so I like to default to ELI5 I suppose if that makes sense.
I would like to know what math you used to come to this conclusion. I'm guessing you shifted 4 bytes off the 16 bytes and determined that's the probability for a collision now, I'm not sure, I don't even remember what the purpose of this slicing of the nonce was in theory to be honest so I'd need a reminder, I just use the entire 16 bytes. Edit: Never mind, you're right about the probability, or supposedly it's 2^-48, even worse for my case. Edit2: And just to be clear, this is still clearly a bug. Why have an attribute called 'nonce' that always returns b''? |
Python version: 3.9.2
Pycryptodome version: 3.15.0
Arrived here migrating from pycrypto which has recently stopped working (syntax error in the code) unless I used to run python2 for my program, I'm not entirely sure.
Issue: Crypto.Util.Counter.new(...) returns a dictionary when the documentation clearly says "Returns: An object that can be passed with the :data:
counter
parameter to a CTR mode cipher."The text was updated successfully, but these errors were encountered: