

Author: “No Bugs” Hare Follow: Job Title: Sarcastic Architect Hobbies: Thinking Aloud, Arguing with Managers, Annoying HRs,

Calling a Spade a Spade, Keeping Tongue in Cheek

Traditionally, “Obscurity” is a foul word in security. In cryptography, if you admit that you’re using “Security by Obscurity” – you’ll very likely to be ostracized. And for a good reason too – having Obscurity as the only tool to ensure Security is indeed a Really Bad Idea™.1

On Kerckhoffs’s Principle and Obscurity

Kerckhoff’s principle (coming from 1883 or so), says that

the cryptosystem should be secure even if everything except for the key is known to the attacker.

So far so good, I don’t have any problems with this principle as it is stated. However, it is way too often interpreted as “hey, trying to hide anything except for the key – doesn’t make sense according to Kerkckhoff’s principle, and therefore we don’t need it”. And this is one thing I cannot agree with (not to mention that it is not what Kerckhoff’s principle really says).

The reason for my opposition to the “obscuring anything but the key is bad” reasoning above, is based on one real-world observation: even those algorithms/protocols/libraries which are perceived to be unbreakable, are broken in practice. In other words –

In real-world, even theoretically good security is not good enough.

“Whether we like it or not, programs DO have bugs in themWhether we like it or not, programs DO have bugs in them. Moreover, it is just plain bugs (and not protocol-level crypto-vulnerabilities such as CBC padding oracle) which are responsible for a vast majority of the successful real-world attacks.2 If you have any doubts about it – take a look at [Verizon.DataBreachInvestigationsReport], you’ll see the picture; BTW, if you don’t have any doubts – make sure to read this report anyway, it is a goldmine of information about statistics of the attack patterns.

Defense in Depth at Primitive/Protocol Level, Anyone?

In theory, it is recognized that “defense in depth” (a.k.a. “multi-layer security”) is generally a Good Thing™. However, in practice – except for large organizations – it is rarely used.

In a vast majority of cases, we’re relying on one single library to be secure – and with devastating results too.

This is especially true when it comes to basic crypto-primitives and protocols. Let’s take TLS – it is one protocol, and as soon as whatever-library-implementing-it has a bug in it – well, half of the world can easily get into large economy-size trouble. One of the most egregious examples of such a vulnerability was infamous Heartbleed attack. We’ll use it as a “litmus test” to estimate efficiency of the mitigation measures we’ll be speaking about.

Obscurity Pockets

Definition.

Let’s define “Obscurity Pocket” as a bunch of functions provided to an “obscurizable” crypto primitive (or crypto protocol), with a set of rules the functions must follow. “Obscurizable” crypto primitive will use these functions during its operation, while providing strict crypto guarantees that as long as the rules are followed – such a security-wise “obscured” crypto primitive CANNOT BE WORSE than a non-obscured one.

X-TLS as An Example

Let’s see how it could apply to a “secure channel” crypto protocol – the one having functionality similar to that of TLS. BTW, let’s note that “secure channel” primitive is certainly not the only one where Obscurity Pockets can be applied; we’ll discuss other crypto primitives (specifically – symmetric crypto, hash, and RNG) in Part II of this article.

Let’s name our incarnation of an “obscurizable” secure channel “X-TLS”. Our X-TLS would use TLS as its basic primitive – but will additionally allow for two “Obscurity Pockets”. The first (“internal”) Obscurity Pocket processes plain-text stream before feeding it to TLS – and the second one (“external”) processes TLS output (i.e. a cipherstream).

Prototypes for both Obscurity Pocket functions can look (in a pseudo-language) as follows:

byte[] streamObscurityPocket( Object state, byte[] input )

Here, state is a thing which is internal to streamObscurityPocket (and opaque to the X-TLS). It is initialized on the stream start by a separate initStreamObscurityPocket() function returning state Object.

The rules-which-our-external-Obscurity-Pocket-should-follow, is simple:

State returned by initStreamObscurityPocket(), MUST be a constant. For “internal” Obscurity Pocket, the rule MAY be optionally relaxed, allowing to use information from the application-which-provides-stream-to-X-TLS.

“ streamObscurityPocket() MUST NOT have any side effects (this includes prohibition on any reading of any information besides its own parameters)

streamObscurityPocket() MUST be reversible;3 in addition, a pair of reversing functions initStreamUnobscurityPocket()/streamUnobscurityPocket() (also complying with all the rules above) MUST be provided too.

The rules for internal-Obscurity-Pocket are more complicated;

State returned by initStreamObscurityPocket(), MAY be a constant – or MAY use information from the application-which-provides-stream-to-X-TLS.

streamObscurityPocket() MUST NOT have any side effects (this includes prohibition on any reading of any information besides its own parameters)

streamObscurityPocket() MUST be 1-to-1 (to prevent side-channel compression-based attacks). 4 Moreover – its execution time MUST NOT depend on the nature of the data processed (to prevent time-based side-channel attacks). in addition, a pair of reversing functions initStreamUnobscurityPocket()/streamUnobscurityPocket() (also complying with all the rules above) MUST be provided too.

Moreover – its execution time MUST NOT depend on the nature of the data processed (to prevent time-based side-channel attacks).

Having these functions – X-TLS will simply apply “internal” streamObscurityPocket() to the stream before feeding it to the TLS, and the “external” one – to the stream which is already processed by TLS (before sending TLS-encrypted stream to TCP or something).

By default (i.e. if developer does nothing to add obscurity), both Obscurity Pockets can be identity functions, essentially doing nothing – and therefore in this case our X-TLS will work exactly like regular TLS.

Security of X-TLS

To demonstrate security of the X-TLS, let’s first write down two assumptions about TLS security (just those we need for our purposes):

TLS security is provided for (almost) any plaintext stream. Well, at the very least, plaintexts-which-are-not-allowed should be documented – and last time I checked, the only restrictions on the plaintexts were related to the side-channel attacks (more specifically – compression-related and time-related).

TLS security does not depend on the way ciphertext stream is passed from one endpoint to another one. If some in-transit modifications to the ciphertext (and any modifications to the ciphertext could be done by attacker by definition) could affect TLS security – well, TLS would be in a Really Big Trouble™.



Armed with these assumptions – security of X-TLS becomes quite obvious: 5 (a) “internal” Obscurity Pocket can be seen just as something-which-modifies-plaintext-stream (and the first assumption above allows us to do it); (b) “external” Obscurity Pocket modifies (effectively “scrambles”) a ciphertext stream – and this shouldn’t affect TLS security either (per second assumption above).

BTW, having X-TLS security to be not worse than security of TLS, absolves us from any potential violation of Kerckhoff’s principle: we do not rely on obscurity for the system to be secure; instead – we’re saying that

X-TLS cannot be worse than plain TLS; however – it could be better

Simplest Obscurity Pocket: XOR Scrambler

The most trivial way of obscuring X-TLS would be to:

Take an 8-bit (32-bit, 64-bit, whatever) random constant C

“ Implement streamObscurityPocket() as a XOR of repeated-constant-C with input Implementation-wise, if size of C is not 1 byte – then, as sizes of input array parameter of streamObscurityPocket() and streamUnobscurityPocket() are not guaranteed to match 1-to-1, we’ll need to use state to store information about the current offset of the stream compared to C. Still, the whole implementation will fit into 20 lines of code or so.



Let’s name such a trivial obscurity mechanism a “XOR Scrambler”.

A Tiny Bit More Complicated One: PRNG Scrambler.

In some scenarios, we could seed a PRNG with our constant C – and use the PRNG to XOR the stream. Note that PRNG doesn’t really need to be a crypto-quality PRNG – in quite a few cases, even a linear congruential PRNG6 will do (and linear congruential one can be written in one single line of code too).

Let’s note that these examples are just a few simplistic implementations to illustrate the idea – but as we’ll see below, even such simple implementations will help significantly under certain attack scenarios.

Improved Resilience of X-TLS

Now let’s discuss vulnerability of X-TLS (with even the simplest XOR scrambler with 8-bit constant C) against common attacks. First of all, we should say that (as it was demonstrated above) security of X-TLS cannot be worse than that of TLS.

This is a very important point; however, to get any further in our analysis – we need to think a bit about Economy of Hack.

Economy of Hack

For the purposes of this article – we’ll restrict ourselves to attacks on usual commercial entities (businesses etc.), which are normally targeted by usual crowd, such as extorters, competitors, etc., leaving aside government-level attacks. While the latter may be of interest in certain cases – quite a few of us developers work neither for the government nor for businesses-which-might-interest-government; in addition – even governments can be threatened not only by other governments, but by average-Joe-hackers too.

Script Writers and Script Users

“most of the time, there are two different types of people directly or indirectly involved in the attackFirst of all, let’s make an observation that most of the time, there are two different types of people directly or indirectly involved in the attack:

“Script writers” are those folks who’re finding attack vectors, and are developing exploits. There are not that many “script writers” out there, and they’re rarely mounting attacks themselves. However, they may sell their scripts (and quite a few of them are doing it too).

“Script users” are those Bad Guys™ who’re taking existing exploits and are using them to attack real-world systems. An extreme example of a“script user” is a “script kiddie” (the one who cannot make any kind of an adjustment to the attacking program), but certainly not all “script users” qualify as “script kiddies”. There are (much) more sophisticated “script users” out there; however, most of the time, they still lack skills (or time, or both) to find the exploits themselves.

The gap between “script writers” and “script users” is rather wide, and while exceptions do occur –

the vast majority of the attacks out there requite two separate people to be involved (directly or indirectly): “script writer” AND “script user”

Zero-Day Attacks Available Commercially

Among other things, this gap between “script writers” and “script users” has led to markets of zero-day attacks. It is a classical example of specialization in economics: everybody is doing what they do best: “script writers” are finding exploits and make money from selling them, and “script users” are making money from using these exploits.7

In turn, such specialization only makes the gap between “script writers” and “script users” wider.

What makes it Possible?

All those things above are well-known. But let’s take a look – what makes this kind of economy possible? There are quite a few things which are needed to enable the patterns above, but one is quite obvious: it is lack of diversity of those who’re attacked.

“In a hypothetical world where attackers would need to create a unique attack script for each system attacked – such an economy would be a non-starter.The whole system described above (with “script writers” producing attacks, with attacks bought by less tech-savvy “script users”) can work only because “script writers” do NOT care against which system their attacks will be used – they’re sure that somebody will be able to use the attack against some system out there. In a hypothetical world where attackers would need to create a unique attack script for each system attacked – such an economy would be a non-starter.

Or, rephrasing pretty much the same thing from a bit different perspective: with the attack being able to target millions of business targets – we can say that the value of such a wide attack is increased; or, the other way around, the cost of the attack per system decreases.

X-TLS vs Hacks

Now let’s see how our X-TLS (even the very simplest one) will fare against typical attack scenarios. There are two common scenarios of such attacks.

In the first attack scenario, the attacker (more specifically – “script user”) tries to breach into just some target – and this pattern, BTW, is by far the most common attack scenario against businesses. In such a case, even the very simplest XOR Scrambler8 will be sufficient to send the attacker packing (he just has too many other juicy targets to choose from). In other words – in such “find some target” attacks (and assuming currently existing target landscape) – even a smallest deviation from standard will help to get rid of the attacker(!).

BTW, most of attacks exploiting Heartbleed were of this first kind too (at some point, the hacking community just realized that there are ripe targets out there – and went on a phishing expedition). However – exactly as with any other “phishing expedition”, even the simplest “external” Obscurity Pocket (such as XOR Scrambler with an 8-bit constant C) would block a standard attack script entirely.

In the second attack pattern – the “script user” is targeting your business specifically. While this is not that common – it does happen. Still, even in this case X-TLS will require a non-zero additional effort to break; more than that – this effort will need to be made by “script user” – and, as noted above, their skills vary significantly, so if your X-TLS is sophisticated enough – it has a non-zero chance to survive even in a targeted attack scenario. Sure, if it is NSA folks who’re after you – it won’t help,9 but otherwise – you do have a fighting chance.

X-TLS – Potential Bugs

As we discussed above – formally, X-TLS is at least as secure as the usual TLS. However, it stands only as long as there are no fatal bugs in Obscurity Pockets – and this is an assumption which shouldn’t be taken lightly.

Still, as we have seen above – Obscurity Pockets we need, are extremely simple (like 20 lines of code, literally) – and I contend that it is possible to write a 20-line self-contained and very-straightforward function without making a serious bug within. The beauty of Obscurity Pocket is that developer doesn’t really need to know anything about cryptography – instead, she should just comply with a set of very-obvious rules, and then X-TLS will do the rest.

“writing an Obscurity Pocket – which is like 20’000x smaller and its requirements are very simple and straightforward – should be very doable even for not-so-specialists-on-writing-secure-code among us.Sure, there will be opponents with the arguments along the lines of “hey, even professionals cannot manage to write a secure code, and you’re trying to trust usual developers with it”. I would respectfully disagree with this line of reasoning – stating that while implementing a full-scale crypto protocol such as TLS is indeed a daunting task (OpenSSL is reported to have over 400’000 lines of code), writing an Obscurity Pocket – which is like 20’000x smaller and its requirements are very simple and straightforward – should be very doable even for not-so-specialists-on-writing-secure-code among us. In addition, this problem may be further mitigated by using “Pocket Generators” for Obscurity Pockets (see discussion in “On Pocket Generators” section below).

X-TLS Resilience Summary

To summarize our findings above, three things can be observed about X-TLS (once again, given current landscape; we’ll discuss “what will happen if everybody is using X-TLS”, a tiny bit later):

Formally, X-TLS is at least as secure as an ordinary TLS (that is, not accounting for bugs in Obscurity Pockets).

Informally – it might help against certain common attack scenarios. In particular: If attacker is trying to get any target – then any X-TLS would help. This, in particular, exactly what happens whenever a significant vulnerability is revealed (think Heartbleed) – and an “external” X-TLS would block it too. If the attacker is trying to get specifically your business – then it becomes a shield-vs-sword battle – with you still having a fighting chance if your Obscurity is good enough. Your chances become even better because: Most of the time, the attacker is not “script writer” (those guys would eat your Obscurity for breakfast) – but a “script user” (and with them – you can have a fighting chance) in addition to your Obscurity, the attacker still needs to find a hole in the classical TLS (and at the same time too) – which makes his life much more complicated. Sure, there is a chance that he has already got through your Obscurity earlier and now is just waiting for some zero-day attack to pop up – but TBH, such dedication is rather rare for attackers-aiming-your-usual-business. In addition – changing your Obscurity on regular basis might help a little bit against such attackers too. On the downside – Obscurity Pockets have a potential to introduce bugs; however – given their extremely small size and ability to double- and triple-check them – I am perfectly sure that the benefits of Obscurity Pockets outweigh associated risks by far. At least that very limited anecdotic evidence which I have – strongly supports this perception; and to get any better data – we’d need to start using Obscurity Pockets on a large scale ;-).



On Pocket Generators

“Pocket Generator” is just an automated way to generate Obscurity Pocket. After Pocket Generator runs – it provides a valid Obscurity Pocket as a source code (which then will be compiled and inserted into executable(s)). It may either use some configuration – or may use random generation to produce the code.

“we don’t really need to be sure that the resulting function is secure in any manner; instead – we just need to provide some function satisfying very simple rulesOne thing which enables Pocket Generators is that for Obscurity Pockets, we don’t really need to be sure that the resulting function is secure in any manner; instead – we just need to provide some function satisfying very simple rules (in particular, a function being a bijection-without-side-effects will satisfy all the requirements above).

And to generate a bijective function, we could do any of the following (in any order, including the random one):

XOR with constant (part of key 10 , etc.)

, etc.) ADD constant (part of key) (implying addition modulo 2^32, 2^64 etc.)

Bit-wise rotations

Multiplication by an odd constant modulo 2^N

Bit-wise shift followed by XOR-with-original

Round of Feistel network (using not-necessarily-bijective function – which enables even more choices when generating the function to be used by Feistel round)

XOR with PRNG output (with any kind of PRNGs, including the outright insecure ones)

Symmetric encryption algorithms (regardless of how-secure-they-are, which enables using such security abominations as TEA, single-rounds-of-existing-algos, and even standalone S-Boxes)

As we can see, the vocabulary we can use to generate just some bijective function – is quite extensive (and can be extended further too). This, in turn, allows for an enormous space of the generatable Obscurity Pockets.

Why not just generate random scrambling key instead?

One question which will (almost) inevitably arise if speaking about the code generation for randomized scrambling – is that “why we cannot use the same algorithm all the time and just generate random scrambling key?” The answer here is simple – if the only thing which changes, is the key – it will be much easier to identify it within Client executable – and to use it to break the scrambling. Moreover, such an approach will increase many-fold chances for automated detection and descrambling (and is a Really Bad Thing™ – see discussion below). Extracting an algorithm from the code is generally much more difficult – which is good for our purposes (yes, we’re already speaking Obscurity here).

Scaling, or “What If Everybody Starts Using Obscurity Pockets”

Our previous analysis was based on the implicit assumption that we will be the only ones using X-TLS (or at least there will be only a few of us). Now, let’s see what will happen if everybody and his rabbit will start doing it; in other words – we’ll be discussing how Obscurity Pockets will scale when used by more and more people (though still assuming that each Obscurity Pocket is unique).

My analysis (no warranties of any kind) shows that as more and more Clients (and more generally – web sites11) start to use Obscurity Pockets – the process will unfold along the following lines:

“script users” will start observing that scripts-without-adjustments don’t work anymore

“script writers” will respond by trying to produce the scripts that automate breaking the obfuscation. In particular, XOR Scrambler with 8-bit constant C will survive only a few hours, linear congruential Scrambler – for a few days. However, more sophisticated Obscurity Pockets (in particular – those based on “Pocket Generators”) will be much more difficult to break in an automated manner (that is, assuming that Obscurity Pockets are well-obscured – with “how to do it” being discussed in Part II). “ my more-or-less educated guess is that while manual breaking of an Obscurity Pocket will be still possible, automating the break will be off-limits at least for a long while. When “script writers” manage to write automate breaker for generated code (which will happen sooner or later) – Pocket Generators will be updated, buying additional time of obscurity. Moreover – the cost of updating Pocket Generators will be lower than the cost of automated code breakers, which generally means that a game even in the worst-for-us case will result in at least a stalemate in the long run. This is related to several practical observations (those with experience of disassembling of release-optimized C++ code will hopefully agree) – and to another observation that while “Pocket Generator” is trying to solve “forward problem”, those-who’re-trying-to-break-its-code – are essentially trying to solve “reverse problem”, which is much more difficult than the forward one (in particular, because C++ compiler acts as a highly non-linear – and ever-changing too – element within the “forward problem”, which in turn makes founding its inverse an extremely complicated exercise). As a result, if everybody starts using Obscurity Pockets – my guess is that we’ll obtain a new universe, where only the most sophisticated “script users” (those able to do reverse-engineering themselves) will be able to mount an attack. And if/when this happens – we’ll see the number of real-world attacks going down. This may in turn lead to the creation of a third specialized profession in the hacking world – “breaking obscurity for hire”; however, as long as this requires breaking obscurity for each site separately – it won’t be viable to mount “phishing expeditions”, but will be used only in “attack this specific site” type of scenarios. Another way to see the same thing is to describe it in terms of hacking economy: as soon as specialization in economy falls apart (as if “only automotive engineers can drive cars”) – the efficiency of the economy in question goes down drastically. For our purposes – it means that hacking economy will spend more efforts on causing the same amount of damage, and this is a Good Thing™. “ If all the people would be the same - pandemics such as Black Death would easily take the whole humankind down; it is diversity among humans which allowed us to survive.



Litmus test: Heartbleed

Let’s see what would happen in a hypothetical scenario if Heartbleed attack would happen after everybody is using Obscurity Pockets (unique per site, of course). I’d say that:

Heartbleed would be still found at about the same time (there are no reasons for analysis-which-got-it to be any different; after all, those-who-analyse-it, won’t be bound by obscurities).

However, when Heartbleed is published – the impact would be much milder than what-we’ve-seen One of the worst aspects of Heartbleed was that it was easy to write a script which goes around and phishes those-servers-which-don’t-have-their-OpenSSL-patched-yet. With every site using a different Obscurity Pocket (and non-automatically-breakable one too), such a phishing expedition would be a non-starter.



I would argue that it means that Obscurity Pockets would be a good-thing-to-have (for the Internet community as a whole) when facing really bad vulnerabilities such as Heartbleed.

To be Continued…

Part II – discussing “what is a good Obscurity Pocket” (including “how to implement it for a web app”), and Obscurity-Pocket-As-Security – will follow.

Acknowledgement

Cartoons by Sergey Gordeev from Gordeev Animation Graphics, Prague.