
The Cryptographic Doom Principle - lobo_tuerto
http://www.thoughtcrime.org/blog/the-cryptographic-doom-principle/
======
richo
If you believe that "don't roll your own crypto" is some kind of absurd mantra
the security industry uses to keep us in business, I recommend that you roll
your own crypto, and keep us in business.

~~~
a1a
Schneier's Law comes to mind

"Anyone, from the most clueless amateur to the best cryptographer, can create
an algorithm that he himself can't break."

[https://www.schneier.com/blog/archives/2011/04/schneiers_law...](https://www.schneier.com/blog/archives/2011/04/schneiers_law.html)

~~~
kleer001
Oh, that's what that is!

I had found a similar thing making my own puzzles, "It's easy to make a puzzle
you can't solve, but it's hard to make a puzzle that's fun."

Well, that' not entirely the same thing, but they overlap I guess.

------
mnw21cam
I think there's a more fundamental cryptographic principle. Don't implement
cryptography, unless you are an absolute top expert. Even then, think twice,
and get another absolute top cryptography expert to check your working. Use a
pre-existing cryptography package that has been written properly instead.

~~~
madez
This is a common idea and it's flawed.

Let KC be a well-known and implemented cipher and CC a custom cipher written
by you. Instead of communicating like this:

A -> KC-encrypt -> transport -> KC-decrypt -> B

You can use:

A -> KC-encrypt -> CC-encrypt -> transport -> CC-decrypt -> KC-decrpyt -> B

The advantage is it breaks automated cryptoanalysis in case KC is broken.

A better idea than the one you stated is: don't rely solely on custom
cryptography.

~~~
kelson
This is almost always less secure than KC alone, when KC is a well-known
secure cipher.

A simple example would be a CC that hex-encodes the plaintext before applying
some transformation on the data (before you laugh, this exists in enterprise
systems today). This means CC would effectively expand the underlying data
200% (0xA1 -> 0x4131) and substantially degrade the security of a block-based
cipher (32-bit block -> effectively 16-bits).

Here's a link to a practical case of unsafe composition (in hashing):
[http://blog.ircmaxell.com/2015/03/security-issue-
combining-b...](http://blog.ircmaxell.com/2015/03/security-issue-combining-
bcrypt-with.html)

A bit more detail on randomly composing encryption algorithms:
[http://blog.cryptographyengineering.com/2012/02/multiple-
enc...](http://blog.cryptographyengineering.com/2012/02/multiple-
encryption.html)

edit: It would be better to compose CC(KC(P)) so CC can't leak any information
about P or degrade KC. Any reluctance to show the world the output of CC
should suggest the low-practical-value of CC.

~~~
madez
CC doesn't get to see the plaintext in the construct I explained.

CC is just a bijective function on (blocksize of KC) bits.

The author of the mentioned blog ignores the fact that cascading ciphers like
I described breaks automated cryptoanalysis which is a necessity for mass
surveillance in a world with wide-spread cryptography.

~~~
schoen
I think cascading ciphers might be a good idea, but if you're following
Kerckhoff's rule, if your system achieves significant use and there is a
cryptographic weakness, you should assume an adversary will exploit it even if
it's different from the weaknesses of other systems.

I guess there's an economic argument to be made that _millions_ or _billions_
of pairs of communicating parties could develop their own individual means of
at least obfuscating their communications so that nobody could expect to find
searchable plaintext after decryption. But the economic effort that the pairs
of parties invested in creating their obfuscations may have been wasted
because if the same level of time or effort had instead been spent to improve
mainstream cryptography, it might have yielded major qualitative security
improvements for the "official" stuff.

~~~
madez
I'm well aware that it doesn't stop a devoted attacker. But it needs a devoted
attacker. That is the import point which you also recognized (beside many
others). Even a devoted attacker has it harder because cracking a code with
known algorithm and unknown key is easier than cracking a code with unknown
algorithm and unknown key. Even more if the unknown algorithm is not
available.

I think your argument that the effort put in custom ciphers maybe should be
put in mainstream ciphers instead is interesting.

Tinkering around with custom ciphers can teach you a lot. Maybe you have not
the knowledge or no idea how to attack/improve mainstream ciphers.

However, if you can make a difference for mainstream ciphers, of course that's
what we need.

~~~
schoen
Just to put the issue in an extreme perspective, suppose that the best
mathematically possible attacks against AES-256 in some setting only reduce
the attacker's work by the same factor as the best mathematically possible
attacks against AES-128. (There's no proof of this now, but it's conceivable
that it's true.) In that case, the decision to use AES-256 in a particular
application instead of AES-128 improves security against cryptanalysis of AES
by a factor of 2¹²⁸ steps for the attacker. (Maybe cryptanalysis of AES isn't
actually the weak point anyway, but let's set that aside because that's what
inventing new ciphers tries to address.)

If this hypothesis is true, the work that Daemen and Rijmen did to invent
AES-256 and the work that a particular implementer did to implement it will
produce an almost inconceivably vast security benefit against this particular
threat.

The reason this is important is the kind of disproportionality between the
effort of Daemen and Rijmen and the AES reviewers and implementers, and the
magnitude of the resulting security benefit. They might have spent a total of
500 person-years on making AES-256 work well, and received a security
improvement of 340 trillion trillion trillion trillion-fold _relative to
whatever the security of AES-128 is_. Whereas a homegrown cipher that isn't
very mathematically sound might be developed with 1 person-year of effort and
end up make an attacker do, let's say, 100 trillion operations. In my
hypothesis, Daemen and Rijmen and other folks then got somewhere between a
trillion trillion trillion and a trillion trillion trillion trillion trillion
trillion trillion times better security return on their effort.

Now you might reasonably point out that if you use a standard, known cipher,
the attacker's costs for a direct brute force attack are purely computational
and don't involve research and development, or attempting to suborn or hack
your correspondents or colleagues to discover the principles of operation or
your system. Whereas if you do have a homegrown mechanism in play, an attacker
incurs these other _kinds_ of novel and sort of one-off costs, notably
including making other human beings think about stuff more.

The point that I've taken from a lot of the security experts who've talked
about this, though, is that the scaling benefits are the important factor
here, again especially if you want to make a system that many people could use
for a long time. When the limiting factor is computer time, which is really
only likely to be true for systems created, refined, and reviewed by experts,
you can sometimes get the really absurd security ratios that are hard to even
think about, and require your adversary to spend more money than exists in the
world, build more computers than can be made from all the silicon on Earth,
consume more energy than the Sun outputs, etc., etc. When the limiting factor
is human reasoning, you might say "but that would require human cryptographers
to think about my system for 1 year!". But if that's so, that may actually
happen, and in any case you can't easily get the order of magnitude of the
costs and resources required up to "inhuman" levels.

The point I'd take from your idea is that it could be valuable to try to make
adversaries incur _diverse_ costs in attacking your system, especially if you
don't know what capabilities and resources your adversaries do and don't have.
This is kind of akin to what's happened with key derivation, where people have
proposed KDFs that are very CPU-intensive and also KDFs that are very memory-
intensive, and if there are other sorts of resources that you could make an
attacker burn, there are probably people trying to invent KDFs that burn
those, too. It's not clear to me that there's a genuinely scalable way to
require human analytical effort as one of those resources, but if there is,
that could be a useful property for communications systems to have for defense
in depth. But making up a new cipher by hand for every system is probably not
going to provide that property very reliably, or be a very effective use of
resources, again when other uses of resources can improve security to a
staggering extent.

------
kkl
The "Don't roll your own crypto" mantra is overly ambiguous and enforces the
culture of elitism in information security. I hope that something displaces
this regurgitated "advice" with something more helpful. I know Moxie's article
is a few years old but it is a step in the right direction regardless.

\--EDIT--

I don't think I was perfectly clear in my original comment. I attempted to
expand on my position in a follow-up comment:
[https://news.ycombinator.com/edit?id=9376131](https://news.ycombinator.com/edit?id=9376131)

~~~
tptacek
The modern argument isn't "don't roll your own crypto". It's "don't build with
crypto until you've learned how to break crypto". There are plenty of
resources for people to learn how to do that online. Skipping that step and
then shipping weak crypto is inexcusable.

~~~
derekp7
What about using existing crypto libraries (such as OpenSSL) to add crypto to
an existing project? I'm adding encryption to an open source backup tool I'm
working on, planning on using AES from OpenSSL. Would it be enough to document
exactly what I'm doing, and put out a call for an audit of the methods that
are being used? I really want to make sure I get this right.

~~~
tptacek
Same as "rolling your own crypto"; in fact, that's generally, except in
extreme cases, exactly what we're referring to when we talk about people
rolling their own.

~~~
derekp7
So what are my options then? I could put out an initial version that shows
what I want to accomplish, then either have it reviewed heavily, or see if I
can get someone who's more of an expert to give it a go based on those
specifications. Here's the problems I have so far, which I know I'm out of my
depth:

1) In order to keep the backup software's deduplication functionality (and to
minimize the server trusting the client), I need to have the IV
(initialization vector) be a computed value based on the file's contents (so
that multiple copies of the same file on the clients will encrypt to the same
contents going to the backend server). I know that _This will leak some data_
(i.e., you may not want an attacker to know that a given set of files are the
same contents). So I plan on making this optional -- either the user gets to
take advantage of dedup, or better encryption.

2) To do number 1 above, I was planning on taking a hash of the file,
encrypting that with the users key, then using that as a predictable IV. You
will still have a unique IV per unique file, but I don't know enough to see if
this can leak any other data. It looks like RFC 5297 describes an approach
similar to this, but I think it is for a different use case.

3) I need the backup server to know which version of an encryption key the
client used. That is, if the client changes keys between backups, I need the
server to instruct the client to do a full backup, not incremental. So I can
either have the client provide a version number for the key (or if using a
keyfile, use the datestamp of the file as a version string), or I can encrypt
a given string using the key, and use a hash of the encrypted string as the
key version number. (Note, in no case will I ever be storing a hash of the
plaintext of the client's files on the backup server, as that too can leak
information)

My apologies if the above makes any experts here cringe, but as I mentioned my
constraint is to have same-content files encrypted to the same target contents
(for dedup purposes), although I will give the user to turn that off and use a
random IV for better security (and give up dedup).

