lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


2007/5/9, Jerome Vuarand <jerome.vuarand@ubisoft.com>:
Luís Santos wrote:
> I am trying to extend the new 'modules' feature by allowing the
> 'require' function to load encrypted lua files. I haven´t found any
> clues on how to help the built-in module loading function to load my
> scripts by adding some sort of generic loader function or something
> of the sort, so I have decided to patch the source code to give it
> this capacity. However, I have felt a little unconfortable in doing
> so in a relatively new feature, in fear that I might be updated
> several times in the near future, giving me a little headache.

AFAIK there is no documentation for that aspect of Lua 5.1 module
system. I wrote an article for the upcoming Lua Programming Gems that
will explain all that. But we can discuss that here since the book is
far from being published.

I think that your situation is worth an example. I crafted an sample
module that installs a loader that check for the existence of a hash
file alongside the Lua modules, and verify that the module content
match the hash. It's not real encryption, not even cryptographic
signing, but that's not the point of the example (and you can add
these features easily). The example uses LuaCrypto for hash
computation, but everything else is in pure Lua.

I set up a page on the wiki with the code, and a zip file containing a
complete example. To use the module below simply require it, and then
subsequent requires will look for the hash files.

The page on the wiki :
- http://lua-users.org/wiki/HashedModulesLoader

And the code :

module(..., package.seeall)

local crypto = require 'crypto'

local dtypes = {"md5", "md4", "md2", "sha1", "sha", "sha256", "sha512"}

local function load(modulename)
   -- Find source
   local filename
   local file,hashfile,hashtype
   local errmsg = ""
   for path in string.gmatch(package.path..";", "([^;]*);") do
       filename = string.gsub(path, "%?",
           (string.gsub(modulename, "%.", "\\")))
       file = io.open(filename, "rb")
       -- If we found a module check if it has a hash file
       if file then
           for _,dtype in ipairs(dtypes) do
               hashfile = io.open(filename.."."..dtype, "rb")
               if hashfile then
                   hashtype = dtype
                   break
               end
           end
       end
       if hashfile then
           break
       end
       errmsg = errmsg.."\n\tno file '"..filename.."' (signed)"
   end
   if not file then
       return errmsg
   end
   -- Read source file
   local source = file:read("*a")
   -- Read saved hash
   local hash = hashfile:read("*a"):gsub("[^%x]", "")
   -- Check that the saved hash match the file hash
   assert(crypto.evp.digest(hashtype, source)==hash,
       "module "..modulename.." (from file '"..filename.."')"..
       " does not match its "..hashtype.." hash")
   -- Compile and return the module
   return assert(loadstring(source, filename))
end

-- Install the loader so that it's called just before the normal Lua
-- loader
table.insert(package.loaders, 2, load)