Crypto Who?

I have need to do some cryptography on Windows. Now, most of the time, the answer is “interop to OpenSSL and…”. Well, for various reasons, I don’t want to simply interop to OpenSSL. One of the benefits of being on Windows is that in fact it has a very rich, well tested, and modern set of crypto libraries. It’s hammered on constantly, from both client as well as server side applications. I’m fairly confident in the strength and robustness of the libraries there. The problem is, how do you get at them easily from Lua?

Well, in the past, there was this CAPI (Cryptographic API) mess of things. And really, it was a mess of things. Very static, not extensible, and lots of insider knowledge needed in order to get things to work. Then along came the new thing, Cryptography Next Generation (CNG). I know, Microsoft is so lame when it comes to naming things. What happens for the next next generation? At any rate, this newer set of interfaces makes things a bit easier, and more flexible, depending on your perspective.

But, this interface has its Windowness about it, just like everything else Windows.  So, of course I want to wrap this stuff up in such a way that it’s relatively easy to use from Lua.

The simplest example.  I want to get a set of 4 random bytes.  Ideally, I want to do this:

local rngBuff = BCrypt.GetRandomBytes(4)

And that’s it.  So how to?

First of all, you need the basic interop to Bcrypt.dll.  It’s on all Windows machines since Vista, and there’s a BCrypt.h file, which is ripe for FFI goodness.  So, the first thing is to create a BCrypt.lua file which has the appropriate lua ffi.cdef[[]] stuff.  You need all the typedefs and constants, and function prototypes.  I’ve created a project on GitHub that contains exactly this.  LJIT2WinCNG contains more than just the basic ffi definitions though.  Although it’s necessary to have these basics, it’s hardly fulfilling, and doesn’t provide the best possible interface for a Lua programmer.

Here’s the actual code:

GetRandomBytes = function(howmany)
  howmany = howmany or 4
  local rngBuff = ffi.new("uint8_t[?]", howmany)
  local status =  BCLib.BCryptGenRandom(nil, rngBuff, howmany, 
    BCRYPT_USE_SYSTEM_PREFERRED_RNG);
  
  if status >= 0 then
    return rngBuff, howmany
  end
  return nil, status
end

In this case, the wrapper is pretty straight forward. It doesn’t do that much work for you, but from a Lua programmer’s perspective, I’d much rather just call ‘GetRandomBytes(nBytes)’ and get a nil, or a buffer of random bytes, without worrying about the actual function to call, which algorithm to use, status return values, etc.

OK, that’s a good start.

But, to really get into this BCrypt stuff, you have to start using CryptAlgorithm providers and other fun stuff, so you can do hash, and keys, and encrypt, decrypt, etc. Now you have to delve deeper. One of the starting points is the BCRYPT_ALG_HANDLE, which is returned from the function BCryptOpenAlgorithmProvider(). Well, now you’ve just entered into a nightmarish world where you have to call one function, get a pointer to a pointer, call a ‘free’ function when you’re no longer using the thing, etc. This is enough to put you off your feed, and discourage you from using such an API. But, along comes LuaJIT to the rescue.

I want an easy little structure that deals with this Algorithm handle thing for me. So, here it is:


local BCLib = ffi.load("Bcrypt.dll");

ffi.cdef[[
typedef PVOID BCRYPT_ALG_HANDLE;
typedef struct BCryptAlgorithm {
	BCRYPT_ALG_HANDLE Handle[1];
} BCryptAlgorithm
]]

local BCryptAlgorithm = ffi.typeof("struct BCryptAlgorithm")
local BCryptAlgorithm_mt = {
  __gc = function(self)
    print("BCryptAlgorithm: GC")
    if self.Handle ~= nil and self.Handle[0] ~= nil then
      BCLib.BCryptCloseAlgorithmProvider(self.Handle[0], 0)
    end
  end;

  __new = function(ctype, ...)
    print("BCryptAlgorithm: NEW");
    local params = {...}
    local algoid = params[1]
    local impl = params[2]

    if not algoid then
      return nil
    end

    local lphAlgo = ffi.new("BCRYPT_ALG_HANDLE[1]")
    local algoidptr = ffi.cast("const uint16_t *", algoid)
    local status = BCLib.BCryptOpenAlgorithmProvider(lphAlgo, algoidptr, impl, 0);

    if not BCrypt.BCRYPT_SUCCESS(status) then
      print("BCryptAlgorithm(), status: ", status);
      return nil
    end

    local newone = ffi.new("struct BCryptAlgorithm", lphAlgo)
    return newone;
  end;

  __index = {
  }
};
BCryptAlgorithm = ffi.metatype(BCryptAlgorithm, BCryptAlgorithm_mt);

Which can be used like this:

local algo = BCryptAlgorithm(BCrypt.BCRYPT_RNG_ALGORITHM)

There are a couple of things to note about this structure. The first thing is the two metamethods, the ones that begin with ‘__’, __gc, and __new. The __new() metamethod is called when you ‘construct’ one of these things “BCryptAlgorithm(BCrypt.BCRYPT_RNG_ALGORITHM)”. You know, just like a constructor in C++, but this is much more powerful because you can control how the thing is actually allocated. In this case, I try to allocate the provider, and if that’s not successful, I just return nil. If it’s successful, I hold onto the handle for later disposal and usage.

Then there’s the __gc(). That will get called when the structure goes out of scope and the garbage collector wants to reclaim it. that’s a perfect place to call the BCryptCloseAlgorithmProvider() function, to free up the handle properly.

That makes it very convenient to construct these provider handles, and use them subsequently, without having to worry about the nitty gritty calls deep within the BCrypt library. Just do what comes naturally to Lua programming.

The __new() metamethod is part of the ‘latest’ LuaJIT HEAD as of July 18 2012, so it’s not in the beta 10 release, but will be in whatever is the next beta release. This, combined with the __gc() method makes for a perfect combination.

With this ability to construct these structures, and the taming of the basic FFI interfaces, doing Crypto in a native Windows sort of way suddenly doesn’t seem so hard. That’s quite a relief. I don’t like building external libraries. There’s always some specialized knowledge to deal with them. Here, I can use the native crypto stuff in Windows, in an easy way that feels natural to my lazy Lua programming.

And there you have it.



Leave a comment