Can I simulate iterated AES-ECB with other block cipher modes?

I am trying to write some code using the Web Crypto API (http://www.w3.org/TR/WebCryptoAPI/#algorithm-overview) which provides only some of the block cipher modes for AES, intentionally excluding AES-ECB (presumably because it is not normally a good choice for anything).

My need is to use AES-ECB-nopadding as part of a key strengthening step, i.e. iterate 6000+ times to introduce some constant extra time into the decryption, resulting in a strengthened key that I can use to decrypt the rest of the data. My code is providing compatibility with an existing password system that does this (Keepass) so I don't have any choice as to what steps or algorithms to use.

Given lack of native support, can I simulate this with one of the other block ciphers, or will I have to load a third party library that includes the ECB block cipher?

I tried so far using CTR with a zero counter and never incrementing the counter. This failed due to some technical limitations (it did not support those parameters).

I think it may work to use CBC with a zero IV and just doing a single block at a time. Will that work (theoretically)?

-
Has been some time since I looked at keepass2, but from what I remember it was equivalent to two independent uses of CBC with zero bytes as data. –  CodesInChaos Dec 28 '14 at 10:45

First lets acknowledge this is a horrible hack - you really should find a way to do what you want more directly or risk code maintenance issues and likely bugs in the future.

Second, while the question isn't about your key strengthening step it seems like you should ask about the security. There are lots of good key derivation methods out there and I don't consider iterating encryption to be a good one.

One Block CBC

Lets look at the algebraic structure of CBC on one block:

$\text{cbc}(v, p) = E(v \oplus p)$

Thus if $v = 0$ $\text{cbc}(0,p) = E(0 \oplus p) = E(p)$ which is the same as ECB.

CTR

The CTR idea fail because plaintext is never part of the block encrypted by the cipher:

$\text{ctr}(v, p) = E(v) \oplus p$

$\text{let } v = 0$

$\text{ctr}(0,p) = E(0) \oplus p$

-
And maybe also how to decrypt? –  Paŭlo Ebermann Dec 27 '14 at 19:31
@PaŭloEbermann It's of course the same for CBC, but for password strengthening you only need one way encryption. Still, for other readers it may be a good idea to include it. –  Maarten Bodewes Dec 28 '14 at 3:32
Thanks, I was able to use this technique and it worked :) –  Steve Campbell Dec 28 '14 at 16:01

To simulate $n$ times iterated ECB encryption, you can set your input plaintext block as the IV, encrypt a "plaintext" consisting of $n$ all-zero blocks using either CBC or CFB mode (which are identical for all-zero plaintext), and take the $n$-th block of the resulting ciphertext (discarding the rest of the output).

Note that, if your CBC mode implementation automatically appends padding to the plaintext, the resulting ciphertext will be one block longer than the plaintext. In that case, you should discard the final block, and still take the $n$-th (i.e. second-to-last) block of ciphertext as the output.

Also note that, if $n$ is large, it may be more efficient to use an all-zero plaintext of $k \le n$ blocks, and repeat the process as many times as needed. Typically, you would like to keep $k$ low enough that the ciphertext and the all-zero plaintext fit into the CPU cache, but not so low that the overhead of invoking the CBC/CFB encryption code will become significant. For a modern desktop CPU, something like $128 \le k \le 1024$ might be reasonable, but it really depends on the hardware you're targeting. If in doubt, it's probably better to err on the low side.

-
Verified, this works as well, thanks! –  Steve Campbell Jan 17 at 1:22