-
Notifications
You must be signed in to change notification settings - Fork 25
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
pycrypto is vulnerable and unmaintained #68
Comments
Is there a concrete reason to believe the "vulnerable" part is true? "unmaintained" seems accurate, though 😢 |
Well… the vulnerability has been showed at the 32C3 (so nearly a year), confirmed by gentoo security team and probably other distros and myself. I don’t know if it’s useable in pure-python-otr. Also I think using cryptography could be better instead of using pycryptodome. I’m not really a fan of having tons of “primitive” libraries which does the same thing, especially for crypto. |
Okay.
First: the vulnerability is only precent in a portion of code that handles ECB block cipher mode.
Nobody should use ECB anymore, and OTR sure doesn't.
I had a look at the stream code (in a rush), and didn't see anything similar enough to make me insta-panic for now.
The closest was https://github.com/dlitz/pycrypto/blob/7acba5f3a6ff10f1424c309d0d34d2b713233019/src/stream_template.c#L143 and it doesn't look dangerous to me.
I have very very very little experience with buffer overflows, so this doesn't mean there isn't an exploit possible for this code else where, or even in the very line I just linked there.
So from what I can personnally see, there is no cause for immediate alarm in the strict case of pure python OTR.
Still, we should be woried that such vulnerabilities are present in our underlying code, that they are public but not fixed after 1y, and that vast portions of pycrypto (I think.) and more so pure python otr (I *know*.) haven't seen proper review.
I'd say the first priority woud be for anyone with more experience with buffer overflows than me to investigate further if the code *we* call hasn't got any that you guys can see.
The next priority would be to see what options do we have in regards to pycrypto's maintainment state.
As much as I love cryptography, I cleary don't have time to take care of something like pycrypto. I'd love to help, but right now I'm not ever maintaining properly pure-python-otr...
Basically pure-python-otr has someone who receives, reads, and reacts to github mails and pullrequests.
From what I see pycrypto hasn't got even that.
so... thoughts?
ps: I'll be physically present at 33C3 in Hamburg to bring this topic up again and discuss it until we find a viable plan that doesn't consist on looking away and hoping for the best.
|
Ok, so during 33C3 I rushed a very quick "hackathon" over this issue. first, pycryptodome appears to be a very good option.
So I ran this list on pycryptodome, feel free to do the same with other replacement candidates you want to suggest ;)
Please keep in mind that all these criterias are not mandatory. I haven't set "weights" or "scores", so we can discuss the importance of these points together. Regarding the counter mechanics, the way pycroptodome's counter increments does not fit OTRv3's specs, where we need two 8 bits halfs of counter that we increment and separately depending on exterior factors. One ugly way of doing would be to re-create the AES object in pycryptodome for each new message (with a new crafted counter). This is not optimal and might raise issues if, at some point, the last 8 bits overflow and the pycryptodome internal counter incrementation starts messing with the first half (from what I remember seeing on pycryptodome on tof of my head as I write this from my notes!) When looking at this, @mathieui and I looked at how the libotr reference implementation handled its counters, and at first glance it handled counter reset and incrementation in a different way than either pycryptodome and the OTRv3 specs do. So either we misunderstood something in the convoluted C code libotr is (read: we're probably not very good at reading and understanding C!), or something in our implementations is lax enough so that communications do not break. From my notes the latter is most probable, as we exchange the first half of the counters over the wire (IIRC), having different ways of incrementing and resetting them would not break communication (even if one of the implementations interracting does not really respect the official specs) So yeah, there is still a bit of work to go before we can "drop-in" pycryptodome, but for now I think it's stil lthe best course of action. I consider having the best unit test coverage we can an important part of this transition to detect breakages early, so I'll probably wait for unit tests to catch up before I actually merge pycryptodome integration anywhere near the master branch. As always, everything said here is open to being discussed and I'd love to have additional feedback before we invest time and sweat on this option :) |
I had hoped for more opinions and debate, but it's fine :) Just an update to confirm my intention to go forth with pycryptodome ASAP.
I'll try to have 1) done within this week if life allows it :) |
So, some thoughts around this: There is a talk from the latest RWC, 2018 which talks about the different cryptographic libraries in python: https://www.youtube.com/watch?v=ALUq2Kc2YxA by Yasemin Acar.
But I see that Salsa and SHAKE are over there. So, around how the counter works for OTRv3: During the AKE, you set an initial counter value of 0 (of 16 bits). After that, for each data message sent with the same How it is incremented in the C code can be found here, and gets actually incremented here, just as you are planning to send a data message. It gets checked here, so you can check that this is not a replay. I see that the checks are happening here at the python library. It seems to be increased with this function, which probably should be checked. |
Great digging!! Somehow we must have missed otrl_dh_incctr at the time. So that clears things up. Other great news: This allows us to setup the CTR mode with our strictly incremented session counter, as a prefix, specifying a proper length to separate this session counter from the rest (thus taking care of the fear the the block counter could overflow over to the session counter, pycryptodome would not allow it from what I understand.), and let pycryptodome handle the lower part of the counter itself, as it should. I don't know if this changed "recently" or if we missed it too at the time, a quick look at the changelog indicates that the counter code has changed a few times recently, so I'll just pretend that pycryptodome heard us and added this feature at some point <3 TL;DR: I don't see any obstacle left to switching over to pycryptodome, the AESCTR suits our needs as far as I can tell, and having to handle new thrown exceptions and details will force us to clean our code anyway :) So that's probably a good thing. This work will have to be done in a separate branch, that we SHOULDN'T merge until we are confident we have enough tests to be sure we didn't screw up something in a big way, and then probably leave this in a staging branch for a while for people to review and try to break it. As a side-node, pycryptodome still lacks a ed448 implementation that's necessary to at some point attempt an OTRv4 (draft) implementation, but the lib is quite active so I feel confident that if we request this and promise to help with implementing it and testing it, pycryptodome would help, review and merge it. This is still quite a lot of work, so let's focus on doing OTRv3 properly first. I cleared up my weekend for 7-8 april to do some cleaning up, actually shipping a release with the latest fixes, and starting the work towards pycryptodome. |
Quick update to say that work towards using pycryptodome has started at last. I'll be messing around these days, and you might even start seeing some commits in a separate branch (it'll break functionality almost completely for some time) Very sorry about all the delays and the vaporware. |
In a dedicated branch (PLEASE DON'T USE IT FOR ANYTHING ELSE THAN TESTING, I BEG YOU), I started using pycryptodome's Counter "object" (now a dict, by the way?). The next issue now is a small difference in how pycryptodome exposes DSA internal values (x, y, p, q and g). https://github.com/Legrandin/pycryptodome/blob/master/lib/Crypto/PublicKey/DSA.py#L180 I'll add anything that breaks at runtime to the tests. |
For some reason, I'm not getting github notifications, so I did not see this.
Awesome! We finished the pure C implementation: https://github.com/otrv4/libgoldilocks
So, from OTRv3 I guess what is missing mostly are instance tags (from what I checked). Everything else seems to follow the spec.
This seems great! |
Long overdue news update. I finally got back to it, and a few things stick out.
doesn't work anymore. It was a trick I got from discussions on IRC, relying on the fact that the counter object over at pycryptodome had become a python dict. I needed to validate its type, so I compared it with a set() function. Well this doesn't work anymore.
Turns out it is a dict: https://github.com/Legrandin/pycryptodome/blob/master/lib/Crypto/Util/Counter.py#L65
I haven't found a way to properly validate this type yet, looking over at pycryptodome's, I see this: https://github.com/Legrandin/pycryptodome/blob/master/lib/Crypto/Cipher/_mode_ctr.py#L367 I don't feel comfortable avoiding this check as feeding weird types into the CTR mode sounds like a recipe for disaster, until I found a solution I commented out this check LOCALLY for my own test purposes, I will never intentionally commit the commented type check. If I ever do so, it's a mistake. The first was trivial to fix: The next one not so much: pure-python-otr/src/potr/crypt.py Line 235 in 1d51424
Obviously counter.inc() is a call to the legacy potr-specific Counter methods, which don't exist anymore. The bad news here is, as stated earlier, I don't seem to have access to internal values of the pycryptodome Counter object, despite it being a (normal?) python dict. I need to create a new counter with an incremented prefix value (the first 8 bytes), but to do so I must be able to get its current value. I could maintain my own counter, external to the counter object, but a mistake there would be fatal. Both for compatibility and security. So I'll only do so if I find no other way... I might contact the pycryptodome team for pointers. I didn't spot any test errors regarding the DSA issues anymore, maybe it has been fixed upstream to restore compatibility, but I didn't check further, I'll focus on that when the counters issues are sorted out. As always: PS: my goal is to have the current potr working correctly through pycryptodome for christmas/35C3, so we can focus on finishing OTRv3 implementation and finally get moving towards OTRv4, I have no idea how far from that milestone I am right now :( |
Something very obvious hit me in the plane on my way back from 35C3 (no, not a bird.) Remember when I said, on my previous post:
Well, turns out my testing environment got contaminated by a mix of pycryptodome and the old pycrypto library, resulting in erratic behaviors, broken tests that actually weren't and compatibility issues that should not have been. cleaned up the environment and the counter object type check works as expected, and I am actually back to the last issue I had previously identified: the new way of exposing DSA values in pycryptodome. I am reverting commit 1d51424 for clarity and legibility, as tests now pass without this change as they should. I am sorry for this confusion and time spend chasing ghosts, if anything it's a good reminder that there is no adult person in charge of this project, please don't use it for anything dangerous :( |
…rom pycryptodome" This reverts commit 1d51424. See #68 (comment)
Is this still happening? I found this issue came up with a conflict between two weechat plugins. Namely poljar/weechat-matrix and this one. See poljar/weechat-matrix has poljar/matrix-nio which depends on Legrandin/pycryptodome which of course conflicts with python-otr/pure-python-otr dependence on dlitz/pycrypto. |
Short answer: YES!
Long answer: I'm short on spare time right now and over the past few
months, made worse by the tragic loss of my raspberry pi serving as my
IRC/XMPP client. I need to set things up once again, reappear in the OTR
channels and resume work on the pycryptodome migration that was quite
far ahead IIRC.
I've been dragging this for incredibly long, help would really be
welcome... It gets lonely and demotivating :(
I hope I can post some progress over this weekend.
I think most people need a proof of life or they might call the cops ^^'
SORRY.
Excerpts from Daniel Nathan Gray's message of September 29, 2019 7:28 pm:
… Is this still happening? I found this issue came up with a conflict between two weechat plugins. Namely [poljar/weechat-matrix](https://github.com/poljar/weechat-matrix) and this one. See [poljar/weechat-matrix](https://github.com/poljar/weechat-matrix) has [poljar/matrix-nio](https://github.com/poljar/matrix-nio) which depends on [Legrandin/pycryptodome](https://github.com/Legrandin/pycryptodome) which of course conflicts with [python-otr/pure-python-otr](https://github.com/python-otr/pure-python-otr) dependence on [dlitz/pycrypto](https://github.com/dlitz/pycrypto).
--
You are receiving this because you commented.
Reply to this email directly or view it on GitHub:
#68 (comment)
|
This is great news. Having to choose between weechat-otr or weechat-matrix sucks big time.
It's nice to know you're still alive 👍 I looked at your github commit history and thought something bad might have happened.
I do get that, especially as anyone who's developing these days is doing so for Matrix. Things like OTR are not all that 'cool'. Matrix does still have a few rough edges and OTR can be nice for simplicity sake. I also have a few friends on IRC I use this in 1:1 with. One of them is completely blind (and has been since birth), he uses irssi's otr support. Adopting new software is a very complex task for him so it would be great to still have this to keep in touch. I would help if I can. I have to admit I don't know a lot about crypto specifics and my python abilities are rudimentary. If there's something you want me to do, I'll try my best to look into it.
Well it's nice to know you're in good health still. I can think of a couple of examples in the past where developers have 'fallen off the face of the earth' to later find out they had serious mental breakdown issues or died somehow. |
Maybe the patch would be of a help?
|
I can imagine, this is not how things should go :(
Nothing of the sort! Don't worry :)
Check out OTRv4, it's cool as all hell ;) Can't wait to finally be able to work on implementing it here!
I can understand that, at least I know libotr (used for irssi integration) is in a much better state than this python implementation, so you friend is in good hands ;)
Sadly the current roadblocks are a bit of python wizardry. Not even advanced crypto stuff for now (but everytime this work forces me to look closer at code I didn't write in here I make sure to check that I don't find security issues).
(this person lied. I should know, I am that person .___.)
To be honest I am in constant partial-burnout on this project for a few years now. Everytime I touch it I relapse and hide from it in shame for a few months. Allocating time for it is hard enough, but running away from it makes everything worse. People at the #OTR irc channel over at irc.oftc.net (and the other parts of this community) are always in touch and within shouting distance to make sure I'm okay. This really is a great community, which makes disappointing them all the more painful :( I'M OKAY, I'm not in any serious danger. When I smell burnout I protect myself and this project just gets a few more weeks of inactivity ^^' That's going to be it for this post, I don't really enjoy whining but I thought some transparency was in order as to the reasons for the lack of progress and activity. I'm not in any danger, but this project is, and I really, really still want to save it. Ok, let's get back to the technical part and get some actual shit done. |
@aidecoe Hey! Thanks for dropping by! Actually, when I test my current pycryptodome work branch ( https://github.com/python-otr/pure-python-otr/tree/bugfix/issue%2368-use-pycryptodome ) I handle the pycryptodome dependance manually to make 100% sure I don't mess with my test environment again, but your changes will come in handy once the branch works, thanks! As for the AES part, actually this modification isn't necessary, looking at my pycryptodome branch you can see the import and function calls don't need to change https://github.com/python-otr/pure-python-otr/blob/bugfix/issue%2368-use-pycryptodome/src/potr/compatcrypto/pycrypto.py#L47 Thanks for the help though! |
I really should be in bed by now but I couldn't just leave it at posting comments without showing some progress ;) So, first thing, I'm working on the DSA signature now. I also modified the DSA signing function to conform to the new way signatures are called: Don't get too excited about that last commit though:
The reason it doesn't work is that, along with other cool ideas, pycryptodome developpers actually check that all input for DSA signatures are hash values. they do that by checking that the input for any DSA "message" to sign has a specific "oid" attribute containing a very specific hash identifier. This is good. Currently, the input we feed the DSA signing function is a plain string, thus I get the following exception:
This would in theory not be that much work, but the issue is actually a bit more tricky than that.
We're signing the result of a SHA256HMAC(), which does not bear an "oid" attribute, thus the DSA signature fails as it believes it's not signing a proper hash. Basically, pycryptodome's logic allows for DSA signatures on pure hash outputs, but not HMAC outputs. This is the wall I hit on january 1st and the reason why I initially didn't commit my workdir changes. I might be mistaken, bear in mind I'm slowly recollecting my thought process from almost one year ago, and it's 2AM in the morning in between two exhausting workdays, so I my description might be a little off, I'll make edits later if necessary :) I don't think this is going to ba a huge roadblock, I'll re-check that my analysis is correct, that there is not a simple fix I could do that would make a lot more sense. If not, I'll contact the pycryptodome people, this looks like a very simple omission on their part and I doubt it would be hard for them to fix it in a backwards-compatible way :) I'll stop there for tonight, but this is not the last you'll hear of this! |
hey, appreciate the update. Stay in good health!
I also appreciate the commentary as it allows us to know whats going on (and learn something from your experience. We might even perhaps get people who might know the answers to apply their experience.
This is what happens when you don't write things down 😀.
Awesome, keep up the good work. This ticket should also help to remind you if you forget later on or get stuck on something. |
Please use https://github.com/pyca/cryptography instead, pycrypto is broken on python 3.8 |
@koolfy made any progress how's things?
@Ryozuki Looks like that was fixed. 3.9.2 (10 November 2019)New features
3.9.1 (1 November 2019)New features
There's been a bunch of releases since then, including one 4 days ago. |
@dngray I am resuming work right now, sorry for the delay, things got complicated and crowded on my side of things, I'll be posting an update and maybe even good news very shortly. Current status is: "koolfy has 1kg of yerba mate, a long weekend and a cleared up schedule (at last!)" |
All right, there was no sane way of working around this, I took a long time to look at pycryptodome and how we were using it to be certain of my understanding of the situation before creating an issue upstream, but there it is. Right now we depend on the outcome of this discussion over at pycrypotodome to move forward, I'll keep you posted as soon as a branch or a commit comes up on their side allowing me to make something work. In any case some minor changes will be needed on my side as well to accomodate for this change upstream, as we pretty much immediately collapse the HMAC object into its binary string attribute: https://github.com/python-otr/pure-python-otr/blob/master/src/potr/compatcrypto/pycrypto.py#L44 I have local code doing just that right now, not worth a commit, but waiting for the .oid attribute :) I'll state it again, without @mmb 's contributions and tests, every single step in this process would be stepping on a minefield, the help it provides me since day 1 cannot be overstated. I would probably not even dare with this migration, as these simple tests caught many stupid mistakes on my part. If you want to help in the meantime, I'd say the single most valuable thing I could merge right now is more tests that you might think could be missing and useful. Maybe I should measure code coverage to have a better idea of what more could be added. |
This is awesome news, and I'm glad you've persevered! Many will be happy to have this functionality regained. |
Very short progress report: From the pycryptodome github issue, I was told that the RFC for the signature method I was using did not actually allow for HMACs to be used as input data, while deterministic signatures (RFC-6979) should. This raises two questions:
on 2), I suspect not, but I'll need to be certain, haven't checked yet, as 1) is the bad news here What should have been a very quick (if late) test to finally plow through this signature issue turned into an antire bug-hunt evening within pycryptodome. I won't duplicate the boring explanation here, but you can read the details there: Legrandin/pycryptodome#414 (comment) TL;DR: as it turns out, pycryptodome doesn't actually allow signing HMAC objects in this way, because of a data structure handling cleverness, the code actually expects the input data to be a naked hash object, and a hmac construct will break that assumption. This shouldn't be a blocking issue, but I'm unsure of the right way to work around this, so I won't submit an ugly PR and let the maintainer come up with an elegant solution. If I'm not dead wrong on this bug it should be resolved quickly, my main worry is that my comment might not get noticed, as I can't reopen the bug :p It would be cool to be the first ones to run into this bug, bonus points for contributing to upstream libraries \o/ I'll keep you posted in less than a month this time, I swear. |
Hi, Just to be notice, on Debian, PyCrypto going to be removed (that is the plan) [0] And exist a patch to Depends on pycryptodome [1] [2] Not uploaded yet cheers [0] https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=971306 |
Hi everybody, there's some advances on this issue? Cheers, |
@eamanu I have found that time and courage, unfortunately the conclusion is quite quick: I don't feel competent to write a pull request to pycryptodome that would have a chance of getting accepted and I am perfectly capable of introducing devastating vulnerabilities in pycryptodome if left unchecked (maybe stupidities that would survive their review? Certainly motivation enough to not package a cystom pycryptodome fork by myself in any way to "just make potre work on some environments", so that's a non-starter forme). Again, I am mostly at fault for the state of this lib right now. I dont want to give up though, I really want to see this through, and reach OTRv4 implementation some day. I would love nothing more than looking like a fool, if it means releasing a feature-complete OTRv2/3 python implementation built on top of a crypto primitives lib that is actually still maintained/packaged/shipped. |
Progress has been made by bit and a PR was merged that should finish the pycryptodome integration. I need to test it some more in its current form before this can be merged back progressively towards a new main stable version that can be released :) Maybe when this is sorted out I can get moving again towards full OTRv3 compatibility and look at OTRv4 feasibility! |
The latest version of Alpine Linux (3.18) no longer can build wheel for |
See this thread : pycrypto/pycrypto#173
The text was updated successfully, but these errors were encountered: