Hardware Engineers and Their Software
Over the years I have dealt with a lot of different security hardware, from tokens (PCMCIA cards, USB devices, etc.) and coprocessors, to crypto accelerators and "HSMs" (Hardware Security Modules). With the hardware product comes the software interface. If you're building a product that wants to take advantage of the chip or device, your code will call the supplied set of functions that will actually send the messages to the hardware informing it of the operations to perform.
Over the years I have complained bitterly about some of the software interfaces I have come across. I have seen some software that I thought was awful. I would be angry that a company would build a device, invite people to use it, then make the software interface so terrible.
Let me interject something here. I write software for a living. Most of the software I have written has gotten good reviews, but I must admit, there have been some bad reviews in there. Or sometimes the review was not so much bad, as the reviewer was a bit frustrated by complexity. For example, I read part of a book about Crypto APIs, and one of the APIs was BSAFE. Although I was not the original designer of BSAFE, I was a major contributor to that product. Furthermore, I'm on board with the design. I think it is a great design. (In fact, the Voltage toolkit is my design and the similarities to BSAFE are very evident, although I think I did make some improvements). Anyway, this book said that one of the best things about BSAFE is that it could do anything you could possibly want to do in crypto. The worst thing about it is that it can do anything you could possibly want to do in crypto. That made it complicated. Simple tasks were not necessarily simple. The point is, when I complain about someone else's software, I fully admit that someone can look at my designs and complain about aspects of it. I'm not saying my code has no flaws or problems for the customer.
But some of that software from the hardware vendors was terrible.
Well, now I might not be so quick to label it "terrible". Recently, I was talking with a hardware engineer. He said something that I think explains a lot of the "awfulness". He said the H/W person will design the software interface to mimic what the hardware does. Put another way, the difference between a hardware engineer and a software engineer is that the H/W engineer designs software based on what the hardware can do, the S/W engineer will design software based on what the user wants to do.
Who is the user? For the security hardware, the user is the application developer. That's the same user of the Voltage toolkit. So let's look at an example of two interfaces performing SHA-256.
Let's say you have an app that needs to perform SHA-256. Maybe it's for a digital signature, or maybe for a checksum, or maybe it's for a key derivation function. You need to digest something.
The Voltage toolkit says, "build an object that can perform SHA-256, then call Init, Update, Final. Provide the data to digest as a byte array. If you need to digest something else, keep the object around and reuse it, just call Init again to start over. If you have so much data that you want to perform the operation in parts, or maybe the data is from multiple sources and you don't want to collect it into a single buffer, call Update, Update, and so on until you have no more data, then call Final." In the end you have 32 bytes, the digest.
The interface to a hardware device might say, "provide 64 bytes and the eight h-values and the return is the updated h-values".
Great, what does that mean?
It turns out there is some rationality to that interface. You see, SHA-256 works this way.
Start with 32 bytes, represented as eight 32-bit words, these are the h-values. Give them an initial value.
Take the first 64 bytes of input and perform a function on them, call this function SHA256Transform. This SHA256Transform combines the h-values with the 64-byte input to update the h-values.
Now operate on the next 64 bytes of input, and the next, and so on. Each call to SHA256Transform will use the h-values that were the result of the last call and combine them with the new input to create a new set of h-values.
When there's no more output, apply padding. If the input data was not a multiple of 64 bytes, you need to pad so that you have a complete block on which the algorithm can operate (SHA256Transform can only operate on 64 bytes, no more, no less). Even if the input was a multiple of 64 bytes, you must apply padding (the padding scheme increases the security of the algorithm).
After the padded block has been processed, the result is the 32 bytes that make up the last set of h-values.
Suppose you're a hardware vendor and you want to make a chip that can perform SHA-256. You'd really only do the SHA256Transform in hardware. Your chip would not do the work of breaking the input data into 64-byte blocks, nor would it perform the padding. The time-consuming and compute-intensive operation is the SHA256Transform. All the chip would be built to perform is the Transform operation.
When it comes time to build the software interface, what do you do? Do you build something that takes in byte array input and returns a digest (as the Voltage toolkit does)? Or do you put together a function call that is a "mirror image" of the hardware, namely the SHA256Transform?
A software engineer would probably say that while a SHA256Transform can be useful, that alone does not generate a digest. Most users will want to simply call a routine that takes in input and generates a digest. So the right thing to do is to perform all that "bookkeeping" as well as the transform.
The hardware engineer might say, "What do you mean? The hardware does the Transform function, therefore the interface should be the Transform function. Why should the interface do the bookkeeping if the hardware doesn't?"
The answer is that someone will have to do the bookkeeping. If the hardware interface does not do it, then the customer will. Or more precisely, each customer will. Suppose the hardware vendor has 50 customers. Each customer will write their own version of the bookkeeping code. That's 50 versions of the same code, quite a duplication of effort. Everyone has to "re-invent the wheel". Doesn't it make much more sense to do that work once?
This does not explain all the awful software I've seen come from the hardware vendors, but it does explain some of it. I don't agree with the philosophy, "The software interface is designed to do what the hardware can do, no more, no less." I suspect most people would think it is not the right philosophy a business venture should take. But at least I can understand it.