VIA PadLock—Wicked Fast Encryption

This inexpensive processor offers support for the Advanced Encryption Standard, so you can do state-of-the-art encryption at wire speed.
Assembler Example

Now that we know all the theory, it's time for a real example. To begin, here are some lines of pure assembler:

.comm   iv,16,16
.comm   key,16,16
.comm   data,16,16
.comm   cword,16,16

    movl    $data, %esi  #; Source address
    movl    %esi, %edi   #; Destination
    movl    $iv, %eax    #; IV
    movl    $key, %ebx   #; Cipher key
    movl    $cword, %edx #; Control word
    movl    $1, %ecx     #; Block count
    rep xcryptcbc

This piece of code encrypts one block of data with a cipher key and an initialization vector, following the parameters set in control word cword. Notice that we use the same address for both source and destination data, therefore we encrypt in-place. Because the field data has a size of only a single block, we set the ECX register to one.

C Language Example

To use PadLock directly in a C program, we can write the PadLock routines to separate assembler source file, then compile to standalone modules and finally link to our binary. It often is easier, though, to use the GCC inline assembler and write the instructions directly in the C code. See Resources for a link to a tutorial on the inline assembler.

static inline void *
padlock_xcryptcbc(char *input, char *output,
    void *key, void *iv, void *control_word,
    int count)
    asm volatile ("xcryptcbc"
       : "+S"(input), "+D"(output), "+a"(iv)
       : "c"(count), "d"(control_word), "b"(key));
    return iv;

This code instructs the compiler to load the given values of input, count and other parameters into the appropriate registers. It then is told to issue the xcryptcbc instruction and, finally, to return the value found in the EAX register as a pointer to the new initialization vector.

To be successful here, we also must fill in the control word structure correctly. First of all, it is a good idea to clear the union to avoid using any irrelevant values that might be in the memory:

memset(&cword, 0, sizeof(cword));

Now let's fill in the fields one by one. The first one in the list is rounds. This item specifies how many times AES processing should be run with the input block, each round using a unique part of the expanded key. To comply with the FIPS AES standard, use 10 rounds for 128-bit keys, 12 rounds for 192 bits and 14 rounds for 256 bits. Should the key_size variable contain the length of the cipher key in bytes, this is how we get the rounds value:

cword.b.rounds = 10 + (key_size - 16) / 4;

The next field is algo. This is reserved to let you choose future encryption algorithms instead of AES, although AES is the only option at the moment. Therefore, leave zero here.

The keygen field must be set to one if we prepare the expanded key ourselves. Zero means that PadLock should generate it instead, but that is possible only for 128-bit keys:

cword.b.keygen = (key_size > 16);

The item interm enables the storing of intermediate results after each round of the algorithm is run. I suspect the CPU architects used this field for debugging their core, and I don't see much sense in setting this in the program.

Encryption is distinguished from decryption by the bit encdec. Zero is encryption; one is decryption.

Finally, we must set the key size in the two bits of ksize:

cword.b.ksize = (key_size - 16) / 8;

That's it. With this prepared control word structure and properly aligned buffers, we can call padlock_xcryptcbc(). If the electrons are on our side, in a short while we receive the encrypted data.


PadLock documentation is available publicly on the VIA Web site; there you can find further information about PadLock programming caveats. The complete example program for encrypting one block of data, including verification of the result, can be found on my PadLock in Linux home page. See Resources for additional links.

Resources for this article: /article/8137.

Michal Ludvig ( recently moved from Prague in the Czech Republic to Auckland on the other side of the world to work as a senior engineer for Asterisk Ltd. He enjoys exploring the secrets of New Zealand with his wife and daughter.


Michal Ludvig works for Enterprise IT Ltd in New Zealand as a senior Linux engineer. He's got root access to some of the largest New Zealand corporations, but since he tends to forget his passwords, he is, in general, pretty harmless.