RNCryptor/RNCryptor

AES - CTR

sust86 opened this issue · 11 comments

I know there was a time where RNCryptor used AES - CTR encryption. Now it's CBC and I think I got the point that it's just more secure since it's not that easy to mess up its parameterisation.

But I need to encrypt video files where I've to use AES - CTR (since it's basically a stream cipher it comes with many advantages for video encryption).
Was there a reason RNCryptor did drop the AES - CTR option completely? Are there any plans to bring it back in any form (reading the description doesn't sounds like there are).

Does anybody know any alternative library to use AES - CTR? I would need to use it in an asynchronous way like RNCryptor offers it in a very elegant way.

Or do I have to fork this project to adapt it for my personal use?

What benefits do you believe you'll get from CTR for video files while
within RNCryptor? While streaming modes can have some benefits, many of
them are lost when you switch to a format like RNCryptor (and also when you
do it on iPhone, which doesn't parallelize CTR the way it could). RNCryptor
(v3 format) includes all it authentication, including password checking, at
the end of the stream. That's fine for transferring file-like data (which
is RNCryptor's focus), but if you mean to actually stream video, that
doesn't work nearly as well as other approaches.

Watch out also for #129. I
haven't dug into that one deeply and could impact you. I'm finally at a
place where I'll be looking at that again.

I won't be putting CTR back into RNCryptor as an option. The fact that I
expose the settings at all was actually a mistake, since RNCryptor defines
a format, not just an implementation. The format doesn't currently include
any encoding of settings (other than the use of password). So modifying the
settings violates the format rules and breaks all other implementations.

Without forking, you can't change the mode, because you have to use
the CCCryptorCreateWithMode() call in RNCryptorEngine. (That breaks 10.6
compatibility, which is what caused me to remove the call entirely.)

-Rob

On Thu, Sep 17, 2015 at 9:38 AM, sust86 notifications@github.com wrote:

I know there was a time where RNCryptor used AES - CTR encryption. Now
it's CBC and I think I got the point that it's just more secure since it's
not that easy to mess up its parameterisation.

But I need to encrypt video files where I've to use AES - CTR (since it's
basically a stream cipher it comes with many advantages for video
encryption).
Was there a reason RNCryptor did drop the AES - CTR option completely? Are
there any plans to bring it back in any form (reading the description
doesn't sounds like there are).

Does anybody know any alternative library to use AES - CTR? I would need
to use it in an asynchronous way like RNCryptor offers it in a very elegant
way.

Or do I have to fork this project to adapt it for my personal use?


Reply to this email directly or view it on GitHub
#161.

Rob Napier
Cocoaphony blog -- http://robnapier.net/blog
iOS Programming Pushing the Limits -- http://robnapier.net/book

Thanks your for quick response Rob!

Let's say I have a pretty large encrypted video file (500 - 1000MB). Now I don't want to encrypt the whole file before being able to play it. I would like to start playing right away. Especially on iPhones, encrypting the whole file might take a while.
Also I would like to be able to do forward / rewind seeking when streaming my video later on.

I did some research and found a short article how to do this on android: http://libeasy.alwaysdata.net/network/#server
They suggest to use stream cipher for video encryption. And for AES it's required to use CTR - NoPadding in order to get random access to any location in the stream.

I also read your comments on stackoverflow about AES - CTR security concerns:
http://stackoverflow.com/questions/24290338/encrypt-and-decrypt-a-random-nsstring-with-aes128-ctr-in-ios-with-a-given-key
"An IV collision immediately leaks information about the plaintext in both packets. For this reason, it is inappropriate to use this mode of operation with static keys. Extraordinary measures would be needed to prevent reuse of an IV value with the static key across power cycles. To be safe, implementations MUST use fresh keys with AES-CTR."
The app encrypts / decrypts videos files from a specific trusted source. Thus I think this scenario shouldn't concern me since it's not really possible to do such "power cycles" with large video files?

CCCryptorCreateWithMode() is exactly what I'm currently trying to use. But there are many parts in your library I would love to utilize. Doing everything myself might not be the best idea since I'm by far no expert in security related things.
I'm currently thinking forking your great work will be the best way for me to have some well built base. To get things started, do you think using your implementation with CCCryptorCreateWithMode (CTR, NoPadding) will work or are there any other changes I'll have to do? (I'm not sure if the current configuration / settings will work with CTR)

I'm sorry because I think this is already a bit off-topic since there are no real issues with RNCryptor. It's a great library!

Thanks for your help Rob. I do really appreciate it!

Yeah, this is pretty much exactly what I suspected you were doing. It's not quite as simple as you're probably hoping.

First, the elephant in the room: In nearly every case that I've had this discussion, I've asked "so, who are you securing this data from?" And the answer, in every case, has been "from my users." That's not encryption. That's DRM. DRM is a completely different problem with completely different solutions (it actually has no real solution, since it requires an ongoing war with your users, but in any case the techniques for fighting your users are very different from the techniques for protecting your users). RNCryptor is designed to provide security, not DRM. See Obfuscating Cocoa and this SO question for more on that.

If you're not at war with your users, then the best solution to this is TLS for transport and device data protection for local storage. There's no need for RNCryptor.

But let's say you're at war with your users and want encryption to help with that. RNCryptor is a decent guide, but is not the right tool for streaming video. Yes, you can turn on CTR mode. That won't give you random access because you can't start an RNCryptor stream in the middle, regardless of the block cipher mode. RNCryptor expects a header, and there won't be one.

The app encrypts / decrypts videos files from a specific trusted source. Thus I think this scenario shouldn't concern me since it's not really possible to do such "power cycles" with large video files?

The problem in CTR is that you need a nonce and a key, and you need to make sure that no two packets ever (in the world, at least in the group that the attacker can see) have the same nonce and key, or both packets can be decrypted. Selecting unique nonces is surprisingly tricky. It's not just the first nonce you have to worry about. It's every nonce. A long stream (like video) can require tens or hundreds of millions of nonces. Making sure that two packets never have the same nonce is harder than it sounds.

When you factor in that your random number generator might be biased, it gets much worse. The "power cycle" issue has to do with the fact that it is very difficult to avoid a biased RNG shortly after you've booted, so random numbers picked soon after a reboot may be much more predictable than you would expect. To do CTR correctly, you really need to both track nonces and rotate keys periodically. That is very different from how RNCryptor works (and why I removed CTR). If you do go down the CTR route, and need real encryption, you should at least study Appendix B of NIST-800-38A.

Weak DRM solutions, though, don't really need good encryption. They just need something that unskilled attackers will give up on. The linked Java examples is wildly insecure since they use a hard-coded key and nonce. That's totally broken on several levels, but for weak DRM it's probably fine. Any serious attacker has lots of ways to decrypt your stream anyway, so "encryption lite" is good enough. But that's all this is. If you want actual encryption, the examples in that article are useless. I haven't looked at the underlying library. I don't know how its internal security is, though it could be fine if used correctly (the examples just don't).

The key feature you would need to reimplement to get random access (and that RNCryptor is poorly suited for) is the rebaseCipher() function. Using CTR alone isn't enough. You may find RNCryptorEngine useful, but it's probably the highest-level class in the system that would really work for you.

Personally I'd research HLS or HTML5 video rather than trying to invent a new solution. HLS has DRM built in, maintained by Apple and enforced by the OS and device. It's far from perfect, but certainly stronger than anything you'd build in a week or two. There has been talk about HTML5 video DRM, though I don't know a lot about that. I don't know if offline storage is directly supported, but you can always implement it via proxies (either via NSURLProtocol, or CocoaHTTPServer.

Good luck!

Well, thats by far a way better and more detailed answer than I would have ever expected. Many thanks for your time!

And you are right, in the end I try to protect data from my users. A well built DRM solution would be the best option I guess. This should be my goal in the long term.

http://robnapier.net/obfuscating-cocoa

I really enjoyed reading this blog post. Thanks for sharing.

If you're not at war with your users, then the best solution to this is TLS for transport and device data protection for local storage. There's no need for RNCryptor.

Device data protection would be sufficient on iOS but it's going to be hard on Mac OSX or Windows.

A long stream (like video) can require tens or hundreds of millions of nonces.
Making sure that two packets never have the same nonce is harder than it sounds.

Okay, I got it. For me the effort to correctly implement AES - CTR doesn't doesn't comply with its benefits.

Personally I'd research HLS or HTML5 video rather than trying to invent a new solution.

Thanks for pointing out this options. I would love to use an already working solution like HLS or HTML5 but I'm limited to some requirements where I can't use any of them.

I think as a first "quick" solution I might try to implement some not highly secure AES - CTR encryption.
I need to provide some basic protection to avoid video files being easily copied and shared. For now it doesn't have to be highly secure. It's more important to avoid poor user experience by long loading / decryption times.

Many thanks for your help Rob!

@sust86 What you need is authenticated streaming encryption (streaming AEAD). Inferno library supports streaming AEAD and fits your scenario.

@sdrapkin @sust86

Inferno does look nice. The author's underlying goals are basically identical to RNCryptor's (tilted towards .NET choices rather than CommonCrypto choices). At first look I think his specific choices are good ones. I haven't studied his CTR implementation, but it looks like a good way to do it safely.

That said, you could pretty easily implement his Streaming AEAD on top of RNCryptor. All he's done is concatenated a bunch of ~80k message blocks. Each block has a full header and HMAC. You could build exactly the same thing by encrypting each block you want using RNCryptor and then concatenating them with a wrapper that said how long the block is (using a fixed length block would be slightly more complicated because RNCryptor uses padding). The overhead would be slightly larger than for Inferno, but not by a lot. It could be done securely without any modifications to RNCryptor. As I say, just take each block of data, encrypt it, and then glue them together, and you get something pretty close to Inferno with just a little bit more overhead (~10-26 bytes per block).

I'm not sure what use Inferno would be directly, though. It's very .NET specific.

@sust86 Did you implement AES-CTR for your requirement or found any other alternative? I have similar requirement to encrypt downloaded video and decrypt them runtime while they are being played where user can even seek bath and forth.

@rnapier Thanks for the info but as @sust86 had similar requirement based on above conversation. Wanted to know what approach he took for the same.

I couldn't come up with any alternative so far!
I started building something based on Robs RNCryptor library. Basically we were modifying it to use AES-CTR in a fairly insecure and easy to implement approach. It's not yet done since I'm stuck in some other things at the moment!

@sust86 @ps-sstumpfl @javal-idyllic I am in the same situation as of yours. Have any of you figured out how to achieve AES-CTR video streaming ?
Kindly share the alternative you people have used for protection to avoid video files being easily copied and shared.