Executing Encrypted Code

Bill Frantz frantz at netcom.com
Sat Dec 21 17:11:48 PST 1996


Let me try to sketch a design for an Encrypted Code Computer (ECC).

I will start with what has become the standard architecture for Personal
Computers/Workstations.  That is:

(1) One or more CPU chips, each of which includes a RISC core, memory
management, and L1 cache.
(2) A L2 cache memory chip.
(3) A main memory bus which either includes an I/O bus or,
(4) A separate I/O bus.

If we decrypt the code on the disk, we gain almost no piracy protection
over current systems, so we must decrypt somewhere in the memory hierarchy.
If we decrypt on the main memory bus, then it will be easy to add bus
snooping hardware to catch the unencrypted program as it is accessed.
While average computer user may not do this, the foreign pirates certainly
will.  Basically the same argument applies to decrypting in the L2 cache,
since it will be easy to sample the signals between the L2 cache and the
CPU.

That leaves us with decrypting in the CPU.  Most CPU chips have separate
instruction and data L1 caches.  If we assume separate caches for our
system, it becomes logical to decrypt the code as we load it into the L1
cache.  If we assume that we are using public key cryptography to protect
the programs, where the CPU chip has the only copy of the secret key, then
we have to solve the following problems:

(1) We have to decrypt each code line in a few cycles or the system's
performance will be much worse that a similar system without encryption.
(2) We must decrypt cache lines accessed in a basically random manner.

Point (1) means we probably want to encrypt the code with a symmetric
cypher and then encrypt the symmetric key with the CPU's public key.  There
will need to be a way of telling the CPU, "Here's a new encrypted symmetric
key for code."  To avoid having to do a public key decryption on every
process/program switch, the CPU will need a cache of symmetric keys, and
the OS will have to tell it which key-cache entry to use at any point
during execution of the program.  There will have to be a way to
automatically change the key when servicing an interrupt.

Point (2) means we can't use any of the really good encryption modes, and
are pretty much limited to ECB like modes.  If we use straight ECB mode,
then our program becomes subject to a number of cypher-text only attacks.
If we can arrange our software system so code always executes at a constant
virtual address we can reduce these attacks by salting the code cache
blocks with the virtual address.  However, constant virtual addresses make
DLLs somewhat difficult.


Given this design, we need a symmetric cypher which can be decrypted with a
logic array shallower than about 100 gates (which works out to about 5
clock cycles).  We are still going to pay a performance penalty because we
are adding clocks to a critical performance path, but perhaps we can get
Steve Jobs to sell it to the masses :-).

We still have a major problem if we want a multiprocessor system.  How do
we migrate threads between processors?  It seems that we need to have the
same key on all processors (or license and keep in memory multiple copies
of the code).  If we allow the keys off-chip, then recovering them becomes
much easier.  If we keep them on-chip, then the CPU manufacturer needs to
build CPU chips which share a secret key, with all the attendant inventory
problems etc.  (And, if I can move the CPU chips to different systems, then
I can run a single key of the software on multiple systems.)


-------------------------------------------------------------------------
Bill Frantz       | I still read when I should | Periwinkle -- Consulting
(408)356-8506     | be doing something else.   | 16345 Englewood Ave.
frantz at netcom.com | It's a vice. - R. Heinlein | Los Gatos, CA 95032, USA








More information about the cypherpunks-legacy mailing list