Nmap Development mailing list archives

Re: [NSE][PATCH] OpenSSL bindings for NSE


From: Sven Klemm <sven () c3d2 de>
Date: Wed, 08 Oct 2008 14:14:50 +0200

Fyodor wrote:
On Mon, Sep 22, 2008 at 05:47:21PM -0600, David Fifield wrote:
On Fri, Sep 19, 2008 at 09:12:24AM +0200, Sven Klemm wrote:
Hi everyone,

here is the latest OpenSSL bindings patch for nmap including support for 
multiprecision integer arithmetics, message digests, hmac, symmetric 
encryption, symmetric decryption.
Documentation for the new functions is also included.
Hi Sven. This is looking great. The documentation is especially
appreciated. This module will open a lot of doors for script developers
and I'd like to see it integrated.

I completely agree with David here and think Sven's OpenSSL module is
a winner!  We just need to figure out these last nagging issues (such
as how to degrade gracefully for people w/o OpenSSL).

I've attached a new version which handles all mentioned issues.
The action of the SSH-hostkey script is overwritten if no OpenSSL is
available. The action produces a warning about missing OpenSSL when
verbosity >= 3 the advantage of modifying the action is you only get
the warning when the script would really trigger. But it could also be
 modified to produce the warning at include time.
The patch also removes references to nse_hash and modifies the pop3
library to work with and without OpenSSL. The pop3 functions requiring
OpenSSL will immediately return an error code indicating OpenSSL is
missing if OpenSSL is missing.

Cheers,
Sven
Index: Makefile.in
===================================================================
--- Makefile.in (.../nmap)      (revision 10553)
+++ Makefile.in (.../nmap-exp/sven/nse_openssl) (revision 10553)
@@ -62,9 +62,14 @@
 UNINSTALLZENMAP=@UNINSTALLZENMAP@
 
 ifneq (@LIBLUA_LIBS@,)
-NSE_SRC=nse_main.cc nse_nsock.cc nse_init.cc nse_fs.cc nse_nmaplib.cc nse_debug.cc nse_pcrelib.cc nse_binlib.cc 
nse_hash.cc nse_bit.cc
-NSE_HDRS=nse_main.h nse_nsock.h nse_init.h nse_fs.h nse_nmaplib.h nse_debug.h nse_macros.h nse_pcrelib.h nse_binlib.h 
nse_hash.h nse_bit.h
-NSE_OBJS=nse_main.o nse_nsock.o nse_init.o nse_fs.o nse_nmaplib.o nse_debug.o nse_pcrelib.o nse_binlib.o nse_hash.o 
nse_bit.o
+NSE_SRC=nse_main.cc nse_nsock.cc nse_init.cc nse_fs.cc nse_nmaplib.cc nse_debug.cc nse_pcrelib.cc nse_binlib.cc 
nse_bit.cc
+NSE_HDRS=nse_main.h nse_nsock.h nse_init.h nse_fs.h nse_nmaplib.h nse_debug.h nse_macros.h nse_pcrelib.h nse_binlib.h 
nse_bit.h
+NSE_OBJS=nse_main.o nse_nsock.o nse_init.o nse_fs.o nse_nmaplib.o nse_debug.o nse_pcrelib.o nse_binlib.o nse_bit.o
+ifneq (@OPENSSL_LIBS@,)
+NSE_SRC+=nse_openssl.cc
+NSE_HDRS+=nse_openssl.h
+NSE_OBJS+=nse_openssl.o
+endif
 endif
 
 export SRCS = main.cc nmap.cc targets.cc tcpip.cc nmap_error.cc utils.cc idle_scan.cc osscan.cc osscan2.cc output.cc 
scan_engine.cc timing.cc charpool.cc services.cc protocols.cc nmap_rpc.cc portlist.cc NmapOps.cc TargetGroup.cc 
Target.cc FingerPrintResults.cc service_scan.cc NmapOutputTable.cc MACLookup.cc nmap_tty.cc nmap_dns.cc traceroute.cc 
portreasons.cc $(NSE_SRC) @COMPAT_SRCS@
Index: scripts/SSH-weak_key.nse
===================================================================
--- scripts/SSH-weak_key.nse    (.../nmap)      (revision 0)
+++ scripts/SSH-weak_key.nse    (.../nmap-exp/sven/nse_openssl) (revision 10553)
@@ -0,0 +1,97 @@
+--- checks SSH hostkeys for weak keys. Uses blacklists from openssh-blacklist 
+-- package located under /usr/share/ssh.
+--
+--@output
+--|_ SSH weak keys: 2048 f0:58:ce:f4:aa:a4:59:1c:8e:dd:4d:07:44:c8:25:11 (RSA)
+
+require("stdnse")
+require("shortport")
+require("datafiles")
+require("fingerprint")
+
+id = "SSH weak keys"
+author = "Sven Klemm <sven () c3d2 de>"
+description = "Show weak SSH hostkeys"
+license = "Same as Nmap--See http://nmap.org/book/man-legal.html";
+categories = {"safe"}
+runlevel = 2.0
+
+hostrule = function( host ) return true end
+
+local weak_keys = {}
+local mutex = nmap.mutex(id)
+
+--- read list of weak ssh key fingerprints
+local read_datafile = function( db )
+  mutex "lock"
+  if not weak_keys[db] then
+    local file = "ssh-weakkeys-" .. db
+
+    local status, parsed = datafiles.parse_file( file, {["^[a-f0-9]+"]= "" })
+    if status then
+      weak_keys[db] = parsed
+    else
+      weak_keys[db] = {}
+      stdnse.print_debug( "No weak key datafile found for %s.", db )
+    end
+  end
+  mutex "done"
+end
+
+--- get value of the first entry of a table
+local table_first_key = function( t )
+  for key in pairs(t) do
+    return key
+  end
+end
+
+--- Derive the fingerprint length of a datafile from the first entry of the
+-- table of this keytype. This method allows different fingerprint lengths for 
+-- each key algorithm - key length pair.
+--@param t table with fingerprints
+local fingerprint_length = function( t )
+  if table_first_key( t ) then return #table_first_key( t ) end
+end
+
+--- check whether this is a known weak key for a specific algorithm
+local check_key = function( db, fp )
+  if not weak_keys[db] then read_datafile( db ) end
+  datalength = fingerprint_length( weak_keys[db] )
+  if datalength then
+    fp = fp:sub( #fp - datalength + 1, #fp )
+    if weak_keys[db][fp] then
+      return true
+    end
+  end
+end
+
+--- lookup whether key is a known weak key
+local known_weak_key = function( key )
+  local check_fp, db
+  if key.key_type == 'ssh-dss' then
+    db = ("DSA-%d"):format( key.bits )
+  elseif key.key_type == 'ssh-rsa' then
+    db = ("RSA-%d"):format( key.bits )
+  else
+    stdnse.print_debug( "Unsupported key type: " .. key.key_type )
+    return false
+  end
+  return check_key( db, stdnse.tohex( key.fingerprint ) )
+end
+
+action = function(host, port)
+  if not nmap.registry['SSH Hostkey'] then return end
+  local output = {}
+  local keys = nmap.registry['SSH Hostkey'][host.ip]
+
+  for _, key in ipairs( keys ) do
+    if known_weak_key( key ) then
+      table.insert(output, fingerprint.hex(key.fingerprint,key.algorithm,key.bits))
+    end
+  end
+
+  if #output > 0 then
+    return table.concat( output, '\n' )
+  end
+end
+
Index: scripts/SSH-hostkey.nse
===================================================================
--- scripts/SSH-hostkey.nse     (.../nmap)      (revision 0)
+++ scripts/SSH-hostkey.nse     (.../nmap-exp/sven/nse_openssl) (revision 10553)
@@ -0,0 +1,104 @@
+--- Shows SSH Hostkeys 
+--
+-- Shows fingerprint or fingerprint and key depending on verbosity level.
+-- Puts the found hostkeys in nmap.registry for other scripts to use them.
+-- You can control the output with the ssh_hostkey script argument. Possible
+-- values are bubble,visual,full and all.
+--
+--@usage
+-- nmap host --script SSH-hostkey --script-args ssh_hostkey=full
+-- nmap host --script SSH-hostkey --script-args ssh_hostkey=all
+-- nmap host --script SSH-hostkey --script-args ssh_hostkey='visual bubble'
+--
+--@output
+-- 22/tcp open  ssh
+-- |  SSH Hostkey: 2048 f0:58:ce:f4:aa:a4:59:1c:8e:dd:4d:07:44:c8:25:11 (RSA)
+-- 22/tcp open  ssh
+-- |  SSH Hostkey: 2048 f0:58:ce:f4:aa:a4:59:1c:8e:dd:4d:07:44:c8:25:11 (RSA)
+-- |  +--[ RSA 2048]----+
+-- |  |       .E*+      |
+-- |  |        oo       |
+-- |  |      . o .      |
+-- |  |       O . .     |
+-- |  |      o S o .    |
+-- |  |     = o + .     |
+-- |  |    . * o .      |
+-- |  |     = .         |
+-- |  |    o .          |
+-- |_ +-----------------+
+-- 22/tcp open  ssh
+-- |  SSH Hostkey: 2048 xuvah-degyp-nabus-zegah-hebur-nopig-bubig-difeg-hisym-rumef-cuxex (RSA)
+-- |_ ssh-rsa 
AAAAB3NzaC1yc2EAAAABIwAAAQEAwVuv2gcr0maaKQ69VVIEv2ob4OxnuI64fkeOnCXD1lUx5tTA+vefXUWEMxgMuA7iX4irJHy2zer0NQ3Z3yJvr5scPgTYIaEOp5Uo/eGFG9Agpk5wE8CoF0e47iCAPHqzlmP2V7aNURLMODb3jVZuI07A2ZRrMGrD8d888E2ORVORv1rYeTYCqcMMoVFmX9l3gWEdk4yx3w5sD8v501Iuyd1v19mPfyhrI5E1E1nl/Xjp5N0/xP2GUBrdkDMxKaxqTPMie/f0dXBUPQQN697a5q+5lBRPhKYOtn6yQKCd9s1Q22nxn72Jmi1RzbMyYJ52FosDT755Qmb46GLrDMaZMQ==
+
+id = "SSH Hostkey"
+author = "Sven Klemm <sven () c3d2 de>"
+description = "Show SSH Hostkeys"
+license = "Same as Nmap--See http://nmap.org/book/man-legal.html";
+categories = {"safe","default","intrusive"}
+
+require("shortport")
+require("stdnse")
+
+-- openssl is required for this script
+if pcall(require,"openssl") then
+  require("ssh1")
+  require("ssh2")
+  require("fingerprint")
+else
+  action = function()
+    stdnse.print_debug( 3, "Skipping %s script because OpenSSL is missing.", id )
+  end 
+end
+
+portrule = shortport.port_or_service(22, "ssh")
+
+
+--- put hostkey in the nmap registry for usage by other scripts
+--@param host nmap host table
+--@param key host key table
+local add_key_to_registry = function( host, key )
+  nmap.registry[id] = nmap.registry[id] or {}
+  nmap.registry[id][host.ip] = nmap.registry[id][host.ip] or {}
+  table.insert( nmap.registry[id][host.ip], key )
+end
+
+action = action or function(host, port)
+  local output = {}
+  local keys = {}
+  local _,key
+  local format = nmap.registry.args.ssh_hostkey or "hex"
+  local all_formats = format:find( 'all', 1, true )
+
+  key = ssh1.fetch_host_key( host, port )
+  if key then table.insert( keys, key ) end
+
+  key = ssh2.fetch_host_key( host, port, "ssh-dss" )
+  if key then table.insert( keys, key ) end
+
+  key = ssh2.fetch_host_key( host, port, "ssh-rsa" )
+  if key then table.insert( keys, key ) end
+
+  for _, key in ipairs( keys ) do
+    add_key_to_registry( host, key )
+    if format:find( 'hex', 1, true ) or all_formats then
+      table.insert( output, fingerprint.hex( key.fingerprint, key.algorithm, key.bits ) )
+    end
+    if format:find( 'bubble', 1, true ) or all_formats then
+      table.insert( output, fingerprint.bubblebabble( openssl.sha1(key.fp_input), key.algorithm, key.bits ) )
+    end
+    if format:find( 'visual', 1, true ) or all_formats then
+      -- insert empty line so table is not destroyed if this is the first
+      -- line of output
+      if #output == 0 then table.insert( output, " " ) end
+      table.insert( output, fingerprint.visual( key.fingerprint, key.algorithm, key.bits ) )
+    end
+    if nmap.verbosity() > 1 or format:find( 'full', 1, true ) or all_formats then
+      table.insert( output, key.full_key )
+    end
+  end
+
+  if #output > 0 then
+    return table.concat( output, '\n' )
+  end
+end
+
Index: nse_init.cc
===================================================================
--- nse_init.cc (.../nmap)      (revision 10553)
+++ nse_init.cc (.../nmap-exp/sven/nse_openssl) (revision 10553)
@@ -8,8 +8,11 @@
 #include "nse_pcrelib.h"
 #include "nse_bit.h"
 
+#ifdef HAVE_OPENSSL
+#include "nse_openssl.h"
+#endif
+
 #include "nse_binlib.h"
-#include "nse_hash.h"
 
 #include "nbase.h"
 
@@ -286,8 +289,10 @@
     {NSE_PCRELIBNAME, luaopen_pcrelib}, // pcre library
     {"nmap", luaopen_nmap}, // nmap bindings
     {NSE_BINLIBNAME, luaopen_binlib},
-    {NSE_HASHLIBNAME, luaopen_hashlib},
     {BITLIBNAME, luaopen_bit}, // bit library
+#ifdef HAVE_OPENSSL
+    {OPENSSLLIBNAME, luaopen_openssl}, // openssl bindings
+#endif
   };
 
   luaL_openlibs(L); // opens all standard libraries
Index: nselib/ssh1.lua
===================================================================
--- nselib/ssh1.lua     (.../nmap)      (revision 0)
+++ nselib/ssh1.lua     (.../nmap-exp/sven/nse_openssl) (revision 10553)
@@ -0,0 +1,60 @@
+
+-- @author = Sven Klemm <sven () c3d2 de>
+-- @copyright See nmaps COPYING for licence
+
+module(... or "ssh1",package.seeall)
+
+local bin = require "bin"
+local openssl = require "openssl"
+
+--- fetch SSH1 host key
+--@param host nmap host table
+--@param port nmap port table
+fetch_host_key = function(host, port)
+  local socket = nmap.new_socket()
+  local catch = function() socket:close() end
+  local try = nmap.new_try(catch)
+
+  try(socket:connect(host.ip, port.number))
+  -- fetch banner
+  try(socket:receive_lines(1))
+  -- send our banner
+  try(socket:send("SSH-1.5-Nmap-SSH1-Hostkey\r\n"))
+
+  local data, packet_length, padding, offset
+  data = try(socket:receive())
+  socket:close()
+  offset, packet_length = bin.unpack( ">i", data )
+  padding = 8 - packet_length % 8
+  offset = offset + padding
+
+  if padding + packet_length + 4 == data:len() then
+    -- seems to be a proper SSH1 packet
+    local msg_code,host_key_bits,exp,mod,length,fp_input
+    offset, msg_code = bin.unpack( ">c", data, offset )
+    if msg_code == 2 then -- 2 => SSH_SMSG_PUBLIC_KEY
+      -- ignore cookie and server key bits
+      offset, _, _ = bin.unpack( ">A8i", data, offset )
+      -- skip server key exponent and modulus
+      offset, length = bin.unpack( ">S", data, offset )
+      offset = offset + math.ceil( length / 8 )
+      offset, length = bin.unpack( ">S", data, offset )
+      offset = offset + math.ceil( length / 8 )
+
+      offset, host_key_bits = bin.unpack( ">i", data, offset )
+      offset, length = bin.unpack( ">S", data, offset )
+      offset, exp = bin.unpack( ">A" .. math.ceil( length / 8 ), data, offset )
+      exp = openssl.bignum_bin2bn( exp )
+      offset, length = bin.unpack( ">S", data, offset )
+      offset, mod = bin.unpack( ">A" .. math.ceil( length / 8 ), data, offset )
+      mod = openssl.bignum_bin2bn( mod )
+
+      fp_input = mod:tobin()..exp:tobin()
+
+      return {exp=exp,mod=mod,bits=host_key_bits,key_type='rsa1',fp_input=fp_input,
+              full_key=exp:todec()..' '..mod:todec(),algorithm="RSA1",
+              fingerprint=openssl.md5(fp_input)}
+    end
+  end
+end
+
Index: nselib/ssh2.lua
===================================================================
--- nselib/ssh2.lua     (.../nmap)      (revision 0)
+++ nselib/ssh2.lua     (.../nmap-exp/sven/nse_openssl) (revision 10553)
@@ -0,0 +1,187 @@
+
+-- @author = Sven Klemm <sven () c3d2 de>
+-- @copyright See nmaps COPYING for licence
+
+module(... or "ssh2",package.seeall)
+
+require "bin"
+require "base64"
+require "openssl"
+require "stdnse"
+
+-- table holding transport layer functions
+transport = {}
+
+-- table of SSH2 constants
+local SSH2
+
+--- pack multiprecision integer for sending
+--@param bn openssl bignum 
+--@return packed multiprecision integer
+transport.pack_mpint = function( bn )
+  local bytes, packed
+  bytes = bn:num_bytes()
+  packed = bn:tobin()
+  if bytes % 8 == 0 then
+    bytes = bytes + 1
+    packed = string.char(0) .. packed
+  end
+  return bin.pack( ">IA", bytes, packed )
+end
+
+--- build a ssh2 packet
+--@param payload payload of the packet
+--@return packet to send on the wire
+transport.build = function( payload )
+  local packet_length, padding_length
+  padding_length = 8 - ( (payload:len() + 1 + 4 ) % 8 )
+  packet_length = payload:len() + padding_length + 1
+  return bin.pack( ">IcAA", packet_length, padding_length, payload, openssl.rand_pseudo_bytes( padding_length ) )
+end
+
+--- extract the payload from a received SSH2 packet
+--@param received SSH2 packet
+--@return payload of the SSH2 packet
+transport.payload = function( packet )
+  local packet_length, padding_length, payload_length, payload, offset
+  offset, packet_length, padding_length = bin.unpack( ">Ic", packet )
+  payload_length = packet_length - padding_length - 1
+  offset, payload = bin.unpack( ">A" .. payload_length, packet, offset )
+  return payload
+end
+
+--- build kexdh_init packet
+transport.kexdh_init = function( e )
+  return bin.pack( ">cA", SSH2.SSH_MSG_KEXDH_INIT, transport.pack_mpint( e ) )
+end
+
+--- build kex_init packet
+transport.kex_init = function( cookie, options )
+  options = options or {}
+  kex_algorithms = "diffie-hellman-group1-sha1"
+  host_key_algorithms = options['host_key_algorithms'] or "ssh-dss,ssh-rsa"
+  encryption_algorithms = "aes128-cbc,3des-cbc,blowfish-cbc,aes192-cbc,aes256-cbc,aes128-ctr,aes192-ctr,aes256-ctr"
+  mac_algorithms = "hmac-md5,hmac-sha1,hmac-ripemd160"
+  compression_algorithms = "none"
+  languages = ""
+
+  local payload = bin.pack( ">cAaa", SSH2.SSH_MSG_KEXINIT, cookie, kex_algorithms, host_key_algorithms )
+  payload = payload .. bin.pack( ">aa", encryption_algorithms, encryption_algorithms )
+  payload = payload .. bin.pack( ">aa", mac_algorithms, mac_algorithms )
+  payload = payload .. bin.pack( ">aa", compression_algorithms, compression_algorithms )
+  payload = payload .. bin.pack( ">aa", languages, languages )
+  payload = payload .. bin.pack( ">cI", 0, 0 )
+
+  return payload
+end
+
+--- parse kexinit package
+-- returns an empty table in case of an error
+transport.parse_kex_init = function( payload ) 
+  local _, offset, msg_code, parsed, fields, fieldname
+  parsed = {}
+
+  -- check for proper msg code
+  offset, msg_code = bin.unpack( ">c", payload )
+  if msg_code ~= SSH2.SSH_MSG_KEXINIT then return {} end
+
+  offset, parsed.cookie = bin.unpack( ">A16", payload, offset )
+
+  fields = {'kex_algorithms','server_host_key_algorithms',
+    'encryption_algorithms_client_to_server','encryption_algorithms_server_to_client',
+    'mac_algorithms_client_to_server','mac_algorithms_server_to_client',
+    'compression_algorithms_client_to_server','compression_algorithms_server_to_client',
+    'languages_client_to_server','languages_server_to_client'}
+  for _, fieldname in pairs( fields ) do
+    offset, parsed[fieldname] = bin.unpack( ">a", payload, offset )
+  end
+
+  return parsed
+end
+
+
+--- fetch SSH2 host key
+--@param host nmap host table
+--@param port nmap port table
+--@param key_type key type to fetch
+--@return table containing the key and fingerprint
+fetch_host_key = function( host, port, key_type )
+  local socket = nmap.new_socket()
+  local catch = function() socket:close() end
+  local try = nmap.new_try(catch)
+  -- oakley group 2 prime taken from rfc 2409
+  local prime = 
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF"
+
+  try(socket:connect(host.ip, port.number))
+  -- fetch banner
+  try(socket:receive_lines(1))
+  -- send our banner
+  try(socket:send("SSH-2.0-Nmap-SSH2-Hostkey\r\n"))
+
+  local cookie = openssl.rand_bytes( 16 )
+  local packet = transport.build( transport.kex_init( cookie, {host_key_algorithms=key_type} ) )
+  try(socket:send( packet ))
+
+  local kex_init = try(socket:receive_bytes(1))
+  kex_init = transport.parse_kex_init( transport.payload( kex_init ) )
+
+  if not tostring(kex_init.server_host_key_algorithms):find( key_type, 1, true ) then
+    -- server does not support host key type
+    stdnse.print_debug( 2, "Hostkey type '%s' not supported by server.", key_type )
+    return
+  end
+
+  local e, g, x, p
+  -- e = g^x mod p
+  g = openssl.bignum_dec2bn( "2" )
+  p = openssl.bignum_hex2bn( prime )
+  x = openssl.bignum_pseudo_rand( 1024 )
+  e = openssl.bignum_mod_exp( g, x, p )
+
+  packet = transport.build( transport.kexdh_init( e ) )
+  try(socket:send( packet ))
+
+  kexdh_reply = try(socket:receive_bytes(1))
+  kexdh_reply = transport.payload( kexdh_reply )
+  -- check for proper msg code
+  if kexdh_reply:byte(1) ~= SSH2.SSH_MSG_KEXDH_REPLY then
+    return
+  end
+
+  local _,public_host_key,bits,algorithm
+  _, _, public_host_key = bin.unpack( ">ca", kexdh_reply )
+
+  if key_type == 'ssh-dss' then
+    algorithm = "DSA"
+    local p
+    _, _, p = bin.unpack( ">aa", public_host_key )
+    bits = openssl.bignum_bin2bn( p ):num_bits()
+  elseif key_type == 'ssh-rsa' then
+    algorithm = "RSA"
+    local n
+    _, _, _, n = bin.unpack( ">aaa", public_host_key )
+    bits = openssl.bignum_bin2bn( n ):num_bits()
+  else
+    stdnse.print_debug( "Unsupported key type: %s", key_type )
+  end
+
+  return { key=public_host_key, key_type=key_type, fp_input=public_host_key, bits=bits,
+           full_key=('%s %s'):format(key_type,base64.enc(public_host_key)),
+           algorithm=algorithm, fingerprint=openssl.md5(public_host_key) }
+end
+
+-- constants
+
+SSH2 = {
+  SSH_MSG_DISCONNECT = 1,
+  SSH_MSG_IGNORE = 2,
+  SSH_MSG_UNIMPLEMENTED = 3,
+  SSH_MSG_DEBUG = 4,
+  SSH_MSG_SERVICE_REQUEST = 5,
+  SSH_MSG_SERVICE_ACCEPT = 6,
+  SSH_MSG_KEXINIT = 20,
+  SSH_MSG_NEWKEYS = 21,
+  SSH_MSG_KEXDH_INIT = 30,
+  SSH_MSG_KEXDH_REPLY = 31,
+}
+
Index: nselib/pop3.lua
===================================================================
--- nselib/pop3.lua     (.../nmap)      (revision 10553)
+++ nselib/pop3.lua     (.../nmap-exp/sven/nse_openssl) (revision 10553)
@@ -3,15 +3,24 @@
 
 module(... or "pop3",package.seeall)
 
+local HAVE_SSL = false
+
 require 'base64'
 require 'bit'
+require 'stdnse'
+
+if pcall(require,'openssl') then
+  HAVE_SSL = true
+end
+  
 
 
 err = {
    none = 0,
    userError = 1,
    pwError = 2,
-   informationMissing = 3
+   informationMissing = 3,
+   OpenSSLMissing = 4,
 }
 
 ---
@@ -112,8 +121,8 @@
 function login_apop(socket, user, pw, challenge)
    if type(challenge) ~= "string" then return false, err.informationMissing end
 
-   local apStr = hash.md5(challenge .. pw)
-   socket:send("APOP " .. user .. " " .. apStr .. "\r\n")
+   local apStr = stdnse.tohex(openssl.md5(challenge .. pw))
+   socket:send(("APOP %s %s\r\n"):format(user, apStr))
       
    status, line = socket:receive_lines(1)
    
@@ -169,33 +178,6 @@
 end
 
 ---
--- Calculate HMAC-MD5 hash
---@param key Key for hash calculation
---@param msg Message to be hashed
---@return HMAC-MD5 of given message
-function hmacMD5(key, msg)
-   local ipad = {}
-   local opad = {}
-
-   if (string.len(key) > 64) then
-      key = hash.md5binary(key)
-   end
-
-   -- create both pads, XORing with key
-   for i = 1, string.len(key) do
-      ipad[i] = string.char(bit.bxor(0x36, string.byte(string.sub(key, i))))
-      opad[i] = string.char(bit.bxor(0x5c, string.byte(string.sub(key, i))))
-   end
-   for i = #ipad + 1, 64 do
-      ipad[i] = string.char(0x36)
-      opad[i] = string.char(0x5c)
-   end
-
-   -- calc HMAC-md5
-   return hash.md5(table.concat(opad) .. hash.md5bin(table.concat(ipad) .. msg))
-end
-
----
 -- Try to login using AUTH command using SASL/CRAM-MD5 method
 --@param socket Socket connected to POP3 server
 --@param user User string
@@ -209,7 +191,7 @@
    
    local challenge = base64.dec(string.sub(line, 3))
 
-   local digest = hmacMD5(pw, challenge)
+   local digest = stdnse.tohex(openssl.hmac('md5', pw, challenge))
    local authStr = base64.enc(user .. " " .. digest)
    socket:send(authStr .. "\r\n")
       
@@ -221,3 +203,15 @@
       return false, err.pwError
    end
 end
+
+--- overwrite functions requiring OpenSSL if we got no OpenSSL
+if not HAVE_SSL then
+
+  local no_ssl = function()
+    return false, err.OpenSSLMissing
+  end
+
+  login_apop = no_ssl
+  login_sasl_crammd5 = no_ssl
+end
+
Index: nselib/fingerprint.lua
===================================================================
--- nselib/fingerprint.lua      (.../nmap)      (revision 0)
+++ nselib/fingerprint.lua      (.../nmap-exp/sven/nse_openssl) (revision 10553)
@@ -0,0 +1,99 @@
+
+-- @author = Sven Klemm <sven () c3d2 de>
+-- @copyright See nmaps COPYING for licence
+
+module(... or "fingerprint",package.seeall)
+
+local bit = require "bit"
+local math = require "math"
+local stdnse = require "stdnse"
+
+--- format key as hexadecimal fingerprint
+hex = function( fingerprint, algorithm, bits )
+  fingerprint = stdnse.tohex(fingerprint,{separator=":",group=2})
+  return ("%d %s (%s)"):format( bits, fingerprint, algorithm )
+end
+
+--- format key as bubblebabble fingerprint
+bubblebabble = function( fingerprint, algorithm, bits )
+  local vowels = {'a','e','i','o','u','y'}
+  local consonants = {'b','c','d','f','g','h','k','l','m','n','p','r','s','t','v','z','x'}
+  local s = "x"
+  local seed = 1
+
+  for i=1,#fingerprint+2,2 do
+    local in1,in2,idx1,idx2,idx3,idx4,idx5
+    if i < #fingerprint or #fingerprint / 2 % 2 ~= 0 then
+      in1 = fingerprint:byte(i)
+      idx1 = (bit.band(bit.rshift(in1,6),3) + seed) % 6 + 1
+      idx2 = bit.band(bit.rshift(in1,2),15) + 1
+      idx3 = (bit.band(in1,3) + math.floor(seed/6)) % 6 + 1
+      s = s .. vowels[idx1] .. consonants[idx2] .. vowels[idx3]
+      if i < #fingerprint then
+        in2 = fingerprint:byte(i+1)
+        idx4 = bit.band(bit.rshift(in2,4),15) + 1
+        idx5 = bit.band(in2,15) + 1
+        s = s .. consonants[idx4] .. '-' .. consonants[idx5]
+        seed = (seed * 5 + in1 * 7 + in2) % 36
+      end
+    else
+      idx1 = seed % 6 + 1
+      idx2 = 16 + 1
+      idx3 = math.floor(seed/6) + 1
+      s = s .. vowels[idx1] .. consonants[idx2] .. vowels[idx3]
+    end
+  end
+  s = s .. 'x'
+  return ("%d %s (%s)"):format( bits, s, algorithm )
+end
+
+--- format key as visual fingerprint
+-- ported from http://www.openbsd.org/cgi-bin/cvsweb/~checkout~/src/usr.bin/ssh/key.c
+visual = function( fingerprint, algorithm, bits )
+  local i,j,field,characters,input,fieldsize_x,fieldsize_y,s
+  fieldsize_x, fieldsize_y = 17, 9
+  characters = {' ','.','o','+','=','*','B','O','X','@','%','&','#','/','^','S','E'}
+
+  -- initialize drawing area
+  field = {}
+  for i=1,fieldsize_x do
+    field[i]={}
+    for j=1,fieldsize_y do field[i][j]=1 end
+  end
+
+  -- we start in the center and mark it
+  x, y = math.ceil(fieldsize_x/2), math.ceil(fieldsize_y/2)
+  field[x][y] = #characters - 1;
+
+  -- iterate over fingerprint 
+  for i=1,#fingerprint do
+    input = fingerprint:byte(i)
+    -- each byte conveys four 2-bit move commands 
+    for j=1,4 do
+      if bit.band( input, 1) == 1 then x = x + 1 else x = x - 1 end
+      if bit.band( input, 2) == 2 then y = y + 1 else y = y - 1 end
+
+      x = math.max(x,1); x = math.min(x,fieldsize_x)
+      y = math.max(y,1); y = math.min(y,fieldsize_y)
+
+      if field[x][y] < #characters - 2 then
+        field[x][y] = field[x][y] + 1
+      end
+      input = bit.rshift( input, 2 )
+    end
+  end
+
+  -- mark end point
+  field[x][y] = #characters;
+
+  -- build output
+  s = ('\n+--[%4s %4d]----+\n'):format( algorithm, bits )
+  for i=1,fieldsize_y do
+    s = s .. '|'
+    for j=1,fieldsize_x do s = s .. characters[ field[j][i] ] end
+    s = s .. '|\n'
+  end
+  s = s .. '+-----------------+\n'
+  return s
+end
+
Index: docs/scripting.xml
===================================================================
--- docs/scripting.xml  (.../nmap)      (revision 10553)
+++ docs/scripting.xml  (.../nmap-exp/sven/nse_openssl) (revision 10553)
@@ -1164,6 +1164,233 @@
         <indexterm class="endofrange" startref="nse-pcre-indexterm"/>
     </sect2>
        
+      <sect2 id="nse-openssl">
+        <indexterm class="startofrange" id="nse-openssl-indexterm"><primary><varname>openssl</varname> NSE 
module</primary></indexterm>
+        <indexterm><primary>OpenSSL</primary><secondary>in NSE</secondary></indexterm>
+        <title>OpenSSL NSE bindings</title>
+
+        <para>
+       The <literal>openssl</literal> module provides functions for 
+       dealing with multiprecision integers. The functions reside inside the 
+       <literal>openssl</literal> namespace.
+         </para>
+
+       <variablelist>
+
+           <varlistentry>
+             <term><option>openssl.bignum_num_bits( bignum )</option></term>
+             <listitem>
+               <para>Returns the size of <literal>bignum</literal> in bits.</para>
+             </listitem>
+           </varlistentry>
+
+           <varlistentry>
+             <term><option>openssl.bignum_num_bytes( bignum )</option></term>
+             <listitem>
+               <para>Returns the size of <literal>bignum</literal> in bytes.</para>
+             </listitem>
+           </varlistentry>
+
+           <varlistentry>
+             <term><option>openssl.bignum_set_bit( bignum, position )</option></term>
+             <listitem>
+               <para>Sets bit at <literal>position</literal> in <literal>bignum</literal>.</para>
+             </listitem>
+           </varlistentry>
+
+           <varlistentry>
+             <term><option>openssl.bignum_clear_bit( bignum, position )</option></term>
+             <listitem>
+               <para>Clears bit at <literal>position</literal> in <literal>bignum</literal>.</para>
+             </listitem>
+           </varlistentry>
+
+           <varlistentry>
+             <term><option>openssl.bignum_is_bit_set( bignum, position )</option></term>
+             <listitem>
+               <para>Get bit at <literal>position</literal> in <literal>bignum</literal>.</para>
+             </listitem>
+           </varlistentry>
+
+           <varlistentry>
+             <term><option>openssl.bignum_set_negative( bignum, negative )</option></term>
+             <listitem>
+               <para>Set sign of <literal>bignum</literal>. If <literal>negative</literal> is <literal>false</literal> 
the sign becomes positive otherwise it becomes negative.</para>
+             </listitem>
+           </varlistentry>
+
+           <varlistentry>
+             <term><option>openssl.bignum_is_negative( bignum )</option></term>
+             <listitem>
+               <para>Check sign of <literal>bignum</literal>.</para>
+             </listitem>
+           </varlistentry>
+
+           <varlistentry>
+             <term><option>openssl.bignum_bin2bn( string )</option></term>
+             <listitem>
+               <para>Converts binary encoded <literal>string</literal> into a <literal>bignum</literal>.</para>
+             </listitem>
+           </varlistentry>
+
+           <varlistentry>
+             <term><option>openssl.bignum_dec2bn( string )</option></term>
+             <listitem>
+               <para>Converts decimal encoded <literal>string</literal> into a <literal>bignum</literal>.</para>
+             </listitem>
+           </varlistentry>
+
+           <varlistentry>
+             <term><option>openssl.bignum_hex2bn( string )</option></term>
+             <listitem>
+               <para>Converts hex-encoded <literal>string</literal> into a <literal>bignum</literal>.</para>
+             </listitem>
+           </varlistentry>
+
+           <varlistentry>
+             <term><option>openssl.bignum_bn2bin( bignum )</option></term>
+             <listitem>
+               <para>Converts <literal>bignum</literal> into a binary encoded string.</para>
+             </listitem>
+           </varlistentry>
+
+           <varlistentry>
+             <term><option>openssl.bignum_bn2dec( bignum )</option></term>
+             <listitem>
+               <para>Converts <literal>bignum</literal> into a decimal encoded string.</para>
+             </listitem>
+           </varlistentry>
+
+           <varlistentry>
+             <term><option>openssl.bignum_bn2hex( bignum )</option></term>
+             <listitem>
+               <para>Converts <literal>bignum</literal> into a hex-encoded string.</para>
+             </listitem>
+           </varlistentry>
+
+           <varlistentry>
+             <term><option>openssl.bignum_rand( bits )</option></term>
+             <listitem>
+               <para>Returns random <literal>bignum</literal> with <literal>bits</literal> bit size.</para>
+             </listitem>
+           </varlistentry>
+
+           <varlistentry>
+             <term><option>openssl.bignum_pseudo_rand( bits )</option></term>
+             <listitem>
+               <para>Returns pseudo random <literal>bignum</literal> with <literal>bits</literal> bit size.</para>
+             </listitem>
+           </varlistentry>
+
+           <varlistentry>
+             <term><option>openssl.bignum_mod_exp( a, p, m )</option></term>
+             <listitem>
+               <para>Returns bignum which is the result of <literal>a</literal>^<literal>p</literal> mod 
<literal>m</literal>.</para>
+             </listitem>
+           </varlistentry>
+
+           <varlistentry>
+             <term><option>openssl.rand_bytes( bytes )</option></term>
+             <listitem>
+               <para>Returns a string of <literal>bytes</literal> length with random data.</para>
+             </listitem>
+           </varlistentry>
+
+           <varlistentry>
+             <term><option>openssl.rand_pseudo_bytes( bytes )</option></term>
+             <listitem>
+               <para>Returns a string of <literal>bytes</literal> length with pseudo random data.</para>
+             </listitem>
+           </varlistentry>
+
+           <varlistentry>
+             <term><option>openssl.md2( message )</option></term>
+             <listitem>
+               <para>Returns the MD2 digest of <literal>message</literal>.</para>
+             </listitem>
+           </varlistentry>
+
+           <varlistentry>
+             <term><option>openssl.md4( message )</option></term>
+             <listitem>
+               <para>Returns the MD4 digest of <literal>message</literal>.</para>
+             </listitem>
+           </varlistentry>
+
+           <varlistentry>
+             <term><option>openssl.md5( message )</option></term>
+             <listitem>
+               <para>Returns the MD5 digest of <literal>message</literal>.</para>
+             </listitem>
+           </varlistentry>
+
+           <varlistentry>
+             <term><option>openssl.sha1( message )</option></term>
+             <listitem>
+               <para>Returns the SHA1 digest of <literal>message</literal>.</para>
+             </listitem>
+           </varlistentry>
+
+           <varlistentry>
+             <term><option>openssl.ripemd160( message )</option></term>
+             <listitem>
+               <para>Returns the RIPEMD160 digest of <literal>message</literal>.</para>
+             </listitem>
+           </varlistentry>
+
+           <varlistentry>
+             <term><option>openssl.digest( algorithm, message )</option></term>
+             <listitem>
+               <para>Returns the digest specified by <literal>algorithm</literal> of <literal>message</literal>.</para>
+             </listitem>
+           </varlistentry>
+
+           <varlistentry>
+             <term><option>openssl.hmac( algorithm, key, message )</option></term>
+             <listitem>
+               <para></para>
+             </listitem>
+           </varlistentry>
+
+           <varlistentry>
+             <term><option>openssl.encrypt( algorithm, key, iv, data, padding = false )</option></term>
+             <listitem>
+               <para>Encrypt <literal>data</literal> with the encryption algorithm <literal>algorithm</literal>, 
<literal>key</literal> and the initialization vector <literal>iv</literal>.</para>
+             </listitem>
+           </varlistentry>
+
+           <varlistentry>
+             <term><option>openssl.decrypt( algorithm, key, iv, data, padding = false )</option></term>
+             <listitem>
+               <para>Decrypt <literal>data</literal> with the encryption algorithm <literal>algorithm</literal>, 
<literal>key</literal> and the initialization vector <literal>iv</literal>.</para>
+             </listitem>
+           </varlistentry>
+
+           <varlistentry>
+             <term><option>openssl.supported_ciphers()</option></term>
+             <listitem>
+               <para>Returns a table with the names of the supported cipher algorithms.</para>
+             </listitem>
+           </varlistentry>
+
+           <varlistentry>
+             <term><option>openssl.supported_digests()</option></term>
+             <listitem>
+               <para>Returns a table with the names of the supported digest algorithms.</para>
+             </listitem>
+           </varlistentry>
+
+           <varlistentry>
+             <term><option>openssl.DES_string_to_key( string data )</option></term>
+             <listitem>
+               <para>Converts <literal>data</literal> which must be a 7-byte string into a 8-byte DES key and sets the 
parity.</para>
+             </listitem>
+           </varlistentry>
+
+       </variablelist>
+        <indexterm class="endofrange" startref="nse-openssl-indexterm"/>
+    </sect2>
+
        <sect2 id="nse-lib-ipOps">
        <title>IP Operations</title>
         <indexterm><primary><varname>ipOps</varname> NSE module</primary></indexterm>
Index: nse_openssl.h
===================================================================
--- nse_openssl.h       (.../nmap)      (revision 0)
+++ nse_openssl.h       (.../nmap-exp/sven/nse_openssl) (revision 10553)
@@ -0,0 +1,19 @@
+#include "../nmap_config.h"
+
+#if HAVE_OPENSSL
+
+#ifndef OPENSSLLIB
+#define OPENSSLLIB
+
+#define OPENSSLLIBNAME "openssl"
+
+extern "C" {
+#include "lua.h"
+#include "lauxlib.h"
+}
+
+LUALIB_API int luaopen_openssl(lua_State *L);
+
+#endif
+
+#endif

Property changes on: nse_openssl.h
___________________________________________________________________
Added: svn:mergeinfo

Index: mswin32/nmap.vcproj
===================================================================
--- mswin32/nmap.vcproj (.../nmap)      (revision 10553)
+++ mswin32/nmap.vcproj (.../nmap-exp/sven/nse_openssl) (revision 10553)
@@ -291,10 +291,6 @@
                                >
                        </File>
                        <File
-                               RelativePath="..\nse_hash.cc"
-                               >
-                       </File>
-                       <File
                                RelativePath="..\nse_bit.cc"
                                >
                        </File>
@@ -488,10 +484,6 @@
                                >
                        </File>
                        <File
-                               RelativePath="..\nse_hash.h"
-                               >
-                       </File>
-                       <File
                                RelativePath="..\nse_bit.h"
                                >
                        </File>
Index: nse_openssl.cc
===================================================================
--- nse_openssl.cc      (.../nmap)      (revision 0)
+++ nse_openssl.cc      (.../nmap-exp/sven/nse_openssl) (revision 10553)
@@ -0,0 +1,515 @@
+#include "nmap_config.h"
+
+/* OpenSSL library for lua
+ * adapted from lmd5 library (http://www.tecgraf.puc-rio.br/~lhf/ftp/lua/)
+ * Original code written by Luiz Henrique de Figueiredo <lhf () tecgraf puc-rio br>
+ * Adapted for NMap by Thomas Buchanan <tbuchanan () thecompassgrp net>
+ * bignum and rand_bytes functions added by Sven Klemm <sven () c3d2 de>
+ */
+
+#include <openssl/crypto.h>
+#include <openssl/bn.h>
+#include <openssl/rand.h>
+#include <openssl/md2.h>
+#include <openssl/md4.h>
+#include <openssl/md5.h>
+#include <openssl/sha.h>
+#include <openssl/ripemd.h>
+#include <openssl/hmac.h>
+#include <openssl/des.h>
+#include <openssl/evp.h>
+
+#include "nse_openssl.h"
+
+typedef struct bignum_data {
+  BIGNUM * bn;
+} bignum_data_t;
+
+static int l_bignum_bin2bn( lua_State *L ) /** bignum_bin2bn( string s ) */
+{
+  size_t len;
+  const unsigned char * s = (unsigned char *) luaL_checklstring( L, 1, &len );
+  BIGNUM * num = BN_new();
+  BN_bin2bn( s, len, num );
+  bignum_data_t * data = (bignum_data_t *) lua_newuserdata( L, sizeof(bignum_data_t));
+  luaL_getmetatable( L, "BIGNUM" );
+  lua_setmetatable( L, -2 );
+  data->bn = num;
+  return 1;
+}
+
+static int l_bignum_dec2bn( lua_State *L ) /** bignum_dec2bn( string s ) */
+{
+  const char * s = luaL_checkstring( L, 1 );
+  BIGNUM * num = BN_new();
+  BN_dec2bn( &num, s );
+  bignum_data_t * data = (bignum_data_t *) lua_newuserdata( L, sizeof(bignum_data_t));
+  luaL_getmetatable( L, "BIGNUM" );
+  lua_setmetatable( L, -2 );
+  data->bn = num;
+  return 1;
+}
+
+static int l_bignum_hex2bn( lua_State *L ) /** bignum_hex2bn( string s ) */
+{
+  const char * s = luaL_checkstring( L, 1 );
+  BIGNUM * num = BN_new();
+  BN_hex2bn( &num, s );
+  bignum_data_t * data = (bignum_data_t *) lua_newuserdata( L, sizeof(bignum_data_t));
+  luaL_getmetatable( L, "BIGNUM" );
+  lua_setmetatable( L, -2 );
+  data->bn = num;
+  return 1;
+}
+
+static int l_bignum_rand( lua_State *L ) /** bignum_rand( number bits ) */
+{
+  size_t bits = luaL_checkint( L, 1 );
+  BIGNUM * num = BN_new();
+  BN_rand( num, bits, -1, 0 );
+  bignum_data_t * data = (bignum_data_t *) lua_newuserdata( L, sizeof(bignum_data_t));
+  luaL_getmetatable( L, "BIGNUM" );
+  lua_setmetatable( L, -2 );
+  data->bn = num;
+  return 1;
+}
+
+static int l_bignum_pseudo_rand( lua_State *L ) /** bignum_pseudo_rand( number bits ) */
+{
+  size_t bits = luaL_checkint( L, 1 );
+  BIGNUM * num = BN_new();
+  BN_pseudo_rand( num, bits, -1, 0 );
+  bignum_data_t * data = (bignum_data_t *) lua_newuserdata( L, sizeof(bignum_data_t));
+  luaL_getmetatable( L, "BIGNUM" );
+  lua_setmetatable( L, -2 );
+  data->bn = num;
+  return 1;
+}
+
+static int l_bignum_mod_exp( lua_State *L ) /** bignum_mod_exp( BIGNUM a, BIGNUM p, BIGNUM m ) */
+{
+  bignum_data_t * a = (bignum_data_t *) luaL_checkudata(L, 1, "BIGNUM");
+  bignum_data_t * p = (bignum_data_t *) luaL_checkudata(L, 2, "BIGNUM");
+  bignum_data_t * m = (bignum_data_t *) luaL_checkudata(L, 3, "BIGNUM");
+  BIGNUM * result = BN_new();
+  BN_CTX * ctx = BN_CTX_new();
+  BN_CTX_init( ctx );
+  BN_mod_exp( result, a->bn, p->bn, m->bn, ctx );
+  BN_CTX_free( ctx );
+  bignum_data_t * data = (bignum_data_t *) lua_newuserdata( L, sizeof(bignum_data_t));
+  luaL_getmetatable( L, "BIGNUM" );
+  lua_setmetatable( L, -2 );
+  data->bn = result;
+  return 1;
+}
+
+static int l_bignum_num_bits( lua_State *L ) /** bignum_num_bits( BIGNUM bn ) */
+{
+  bignum_data_t * userdata = (bignum_data_t *) luaL_checkudata(L, 1, "BIGNUM");
+  lua_pushnumber( L, BN_num_bits( userdata->bn) );
+  return 1;
+}
+
+static int l_bignum_num_bytes( lua_State *L ) /** bignum_num_bytes( BIGNUM bn ) */
+{
+  bignum_data_t * userdata = (bignum_data_t *) luaL_checkudata(L, 1, "BIGNUM");
+  lua_pushnumber( L, BN_num_bytes( userdata->bn) );
+  return 1;
+}
+
+static int l_bignum_set_bit( lua_State *L ) /** bignum_set_bit( BIGNUM bn, number position ) */
+{
+  bignum_data_t * userdata = (bignum_data_t *) luaL_checkudata(L, 1, "BIGNUM");
+  int position = luaL_checkint( L, 2 );
+  BN_set_bit( userdata->bn, position );
+  return 0;
+}
+
+static int l_bignum_clear_bit( lua_State *L ) /** bignum_clear_bit( BIGNUM bn, number position ) */
+{
+  bignum_data_t * userdata = (bignum_data_t *) luaL_checkudata(L, 1, "BIGNUM");
+  int position = luaL_checkint( L, 2 );
+  BN_clear_bit( userdata->bn, position );
+  return 0;
+}
+
+static int l_bignum_is_bit_set( lua_State *L ) /** bignum_set_bit( BIGNUM bn, number position ) */
+{
+  bignum_data_t * userdata = (bignum_data_t *) luaL_checkudata(L, 1, "BIGNUM");
+  int position = luaL_checkint( L, 2 );
+  lua_pushboolean( L, BN_is_bit_set( userdata->bn, position ) );
+  return 1;
+}
+
+static int l_bignum_set_negative( lua_State *L ) /** bignum_set_negative( BIGNUM bn ) */
+{
+  bignum_data_t * userdata = (bignum_data_t *) luaL_checkudata(L, 1, "BIGNUM");
+  int value = lua_toboolean(L, 2);
+  BN_set_negative( userdata->bn, value );
+  return 0;
+}
+
+static int l_bignum_is_negative( lua_State *L ) /** bignum_is_negative( BIGNUM bn ) */
+{
+  bignum_data_t * userdata = (bignum_data_t *) luaL_checkudata(L, 1, "BIGNUM");
+  lua_pushboolean( L, BN_is_negative( userdata->bn) );
+  return 1;
+}
+
+static int l_bignum_bn2bin( lua_State *L ) /** bignum_bn2bin( BIGNUM bn ) */
+{
+  bignum_data_t * userdata = (bignum_data_t *) luaL_checkudata(L, 1, "BIGNUM");
+  unsigned char * result = (unsigned char *) malloc( BN_num_bytes( userdata->bn ) );
+  if (!result) return luaL_error( L, "Couldn't allocate memory.");
+
+  int len = BN_bn2bin( userdata->bn, result );
+  lua_pushlstring( L, (char *) result, len );
+  free( result );
+  return 1;
+}
+
+static int l_bignum_bn2dec( lua_State *L ) /** bignum_bn2dec( BIGNUM bn ) */
+{
+  bignum_data_t * userdata = (bignum_data_t *) luaL_checkudata(L, 1, "BIGNUM");
+  char * result = BN_bn2dec( userdata->bn );
+  lua_pushstring( L, result );
+  OPENSSL_free( result );
+  return 1;
+}
+
+static int l_bignum_bn2hex( lua_State *L ) /** bignum_bn2hex( BIGNUM bn ) */
+{
+  bignum_data_t * userdata = (bignum_data_t *) luaL_checkudata(L, 1, "BIGNUM");
+  char * result = BN_bn2hex( userdata->bn );
+  lua_pushstring( L, result );
+  OPENSSL_free( result );
+  return 1;
+}
+
+static int l_bignum_free( lua_State *L ) /** bignum_free( bignum ) */
+{
+  bignum_data_t * userdata = (bignum_data_t *) luaL_checkudata(L, 1, "BIGNUM");
+  BN_clear_free( userdata->bn );
+  return 0;
+}
+
+static int l_rand_bytes( lua_State *L ) /** rand_bytes( number bytes ) */
+{
+  size_t len = luaL_checkint( L, 1 );
+  unsigned char * result = (unsigned char *) malloc( len );
+  if (!result) return luaL_error( L, "Couldn't allocate memory.");
+
+  RAND_bytes( result, len );
+  lua_pushlstring( L, (char *) result, len );
+  free( result );
+  return 1;
+}
+
+static int l_rand_pseudo_bytes( lua_State *L ) /** rand_pseudo_bytes( number bytes ) */
+{
+  size_t len = luaL_checkint( L, 1 );
+  unsigned char * result = (unsigned char *) malloc( len );
+  if (!result) return luaL_error( L, "Couldn't allocate memory.");
+
+  RAND_pseudo_bytes( result, len );
+  lua_pushlstring( L, (char *) result, len );
+  free( result );
+  return 1;
+}
+
+static int l_md2(lua_State *L)     /** md2(string s) */
+{
+  size_t len;
+  const unsigned char *s = (unsigned char *) luaL_checklstring( L, 1, &len );
+  unsigned char digest[16];
+ 
+  lua_pushlstring( L, (char *) MD2( s, len, digest ), 16 );
+  return 1;
+}
+
+static int l_md4(lua_State *L)     /** md4(string s) */
+{
+  size_t len;
+  const unsigned char *s = (unsigned char *) luaL_checklstring( L, 1, &len );
+  unsigned char digest[16];
+ 
+  lua_pushlstring( L, (char *) MD4( s, len, digest ), 16 );
+  return 1;
+}
+
+static int l_md5(lua_State *L)     /** md5(string s) */
+{
+  size_t len;
+  const unsigned char *s = (unsigned char *) luaL_checklstring( L, 1, &len );
+  unsigned char digest[16];
+ 
+  lua_pushlstring( L, (char *) MD5( s, len, digest ), 16 );
+  return 1;
+}
+
+static int l_sha1(lua_State *L)     /** sha1(string s) */
+{
+  size_t len;
+  const unsigned char *s = (unsigned char *) luaL_checklstring( L, 1, &len );
+  unsigned char digest[20];
+ 
+  lua_pushlstring( L, (char *) SHA1( s, len, digest ), 20 );
+  return 1;
+}
+
+static int l_ripemd160(lua_State *L)     /** ripemd160(string s) */
+{
+  size_t len;
+  const unsigned char *s = (unsigned char *) luaL_checklstring( L, 1, &len );
+  unsigned char digest[20];
+ 
+  lua_pushlstring( L, (char *) RIPEMD160( s, len, digest ), 20 );
+  return 1;
+}
+
+static int l_digest(lua_State *L)     /** digest(string algorithm, string message) */
+{
+  size_t msg_len;
+  unsigned int digest_len;
+  const char *algorithm = luaL_checkstring( L, 1 );
+  const unsigned char *msg = (unsigned char *) luaL_checklstring( L, 2, &msg_len );
+  unsigned char digest[EVP_MAX_MD_SIZE];
+  const EVP_MD * evp_md;
+  EVP_MD_CTX mdctx;
+
+  evp_md = EVP_get_digestbyname( algorithm );
+  
+  if (!evp_md) return luaL_error( L, "Unknown digest algorithm: %s", algorithm );
+
+  EVP_MD_CTX_init(&mdctx);
+  if (!(
+      EVP_DigestInit_ex( &mdctx, evp_md, NULL ) &&
+      EVP_DigestUpdate( &mdctx, msg, msg_len ) &&
+      EVP_DigestFinal_ex( &mdctx, digest, &digest_len ))) {
+    EVP_MD_CTX_cleanup( &mdctx );
+    return luaL_error( L, "OpenSSL error" );
+  }
+  EVP_MD_CTX_cleanup( &mdctx );
+
+  lua_pushlstring( L, (char *) digest, digest_len );
+  return 1;
+}
+
+static int l_hmac(lua_State *L)     /** hmac(string algorithm, string key, string message) */
+{
+  size_t key_len, msg_len;
+  unsigned int digest_len;
+  const char *algorithm = luaL_checkstring( L, 1 );
+  const unsigned char *key = (unsigned char *) luaL_checklstring( L, 2, &key_len );
+  const unsigned char *msg = (unsigned char *) luaL_checklstring( L, 3, &msg_len );
+  unsigned char digest[EVP_MAX_MD_SIZE];
+  const EVP_MD * evp_md;
+  evp_md = EVP_get_digestbyname( algorithm );
+  
+  if (!evp_md) return luaL_error( L, "Unknown digest algorithm: %s", algorithm );
+
+  HMAC( evp_md, key, key_len, msg, msg_len, digest, &digest_len );
+ 
+  lua_pushlstring( L, (char *) digest, digest_len );
+  return 1;
+}
+
+struct enumerator_data {
+  lua_State * L;
+  int index;
+};
+
+static void enumerate_algorithms( const OBJ_NAME * name, void * arg )
+{
+  struct enumerator_data* data = (struct enumerator_data *) arg;
+  lua_pushstring( data->L, name->name );
+  lua_rawseti( data->L, -2, data->index );
+  data->index++;
+}
+
+static int l_supported_digests(lua_State *L) /** supported_digests() */
+{
+  enumerator_data data;
+  data.L = L;
+  data.index = 1;
+  
+  lua_newtable( L );
+  OBJ_NAME_do_all_sorted( OBJ_NAME_TYPE_MD_METH,enumerate_algorithms, &data );
+
+  return 1;
+}
+
+static int l_supported_ciphers(lua_State *L) /** supported_ciphers() */
+{
+  enumerator_data data;
+  data.L = L;
+  data.index = 1;
+  
+  lua_newtable( L );
+  OBJ_NAME_do_all_sorted( OBJ_NAME_TYPE_CIPHER_METH,enumerate_algorithms, &data );
+
+  return 1;
+}
+
+static int l_encrypt(lua_State *L) /** encrypt( string algorithm, string key, string iv, string data, bool padding = 
false ) */
+{
+  const char *algorithm = luaL_checkstring( L, 1 );
+  const EVP_CIPHER * evp_cipher = EVP_get_cipherbyname( algorithm );
+  if (!evp_cipher) return luaL_error( L, "Unknown cipher algorithm: %s", algorithm );
+
+  size_t data_len;
+  const unsigned char *key = (unsigned char *) luaL_checkstring( L, 2 );
+  const unsigned char *iv = (unsigned char *) luaL_optstring( L, 3, "" );
+  const unsigned char *data = (unsigned char *) luaL_checklstring( L, 4, &data_len );
+  int padding = lua_toboolean( L, 5 );
+
+  EVP_CIPHER_CTX cipher_ctx;
+  EVP_CIPHER_CTX_init( &cipher_ctx );   
+
+  int out_len, final_len;
+  unsigned char * out = (unsigned char *) malloc( data_len + EVP_MAX_BLOCK_LENGTH );
+  if (!out) return luaL_error( L, "Couldn't allocate memory.");
+
+  if (!(
+      EVP_EncryptInit_ex( &cipher_ctx, evp_cipher, NULL, key, *iv ? iv : NULL ) &&
+      EVP_CIPHER_CTX_set_padding( &cipher_ctx, padding ) &&
+      EVP_EncryptUpdate( &cipher_ctx, out, &out_len, data, data_len ) &&
+      EVP_EncryptFinal_ex( &cipher_ctx, out + out_len, &final_len ) )) {
+    EVP_CIPHER_CTX_cleanup( &cipher_ctx );
+    free( out );
+    return luaL_error( L, "OpenSSL error" );
+  }
+
+  lua_pushlstring( L, (char *) out, out_len + final_len );
+
+  EVP_CIPHER_CTX_cleanup( &cipher_ctx );
+  free( out );
+
+  return 1;
+}
+
+static int l_decrypt(lua_State *L) /** decrypt( string algorithm, string key, string iv, string data, bool padding = 
false ) */
+{
+  const char *algorithm = luaL_checkstring( L, 1 );
+  const EVP_CIPHER * evp_cipher = EVP_get_cipherbyname( algorithm );
+  if (!evp_cipher) return luaL_error( L, "Unknown cipher algorithm: %s", algorithm );
+
+  size_t data_len;
+  const unsigned char *key = (unsigned char *) luaL_checkstring( L, 2 );
+  const unsigned char *iv = (unsigned char *) luaL_optstring( L, 3, "" );
+  const unsigned char *data = (unsigned char *) luaL_checklstring( L, 4, &data_len );
+  int padding = lua_toboolean( L, 5 );
+
+  EVP_CIPHER_CTX cipher_ctx;
+  EVP_CIPHER_CTX_init( &cipher_ctx );   
+
+  int out_len, final_len;
+  unsigned char * out = (unsigned char *) malloc( data_len );
+  if (!out) return luaL_error( L, "Couldn't allocate memory.");
+
+  if (!(
+      EVP_DecryptInit_ex( &cipher_ctx, evp_cipher, NULL, key, *iv ? iv : NULL ) &&
+      EVP_CIPHER_CTX_set_padding( &cipher_ctx, padding ) &&
+      EVP_DecryptUpdate( &cipher_ctx, out, &out_len, data, data_len ) &&
+      EVP_DecryptFinal_ex( &cipher_ctx, out + out_len, &final_len ) )) {
+    EVP_CIPHER_CTX_cleanup( &cipher_ctx );
+    free( out );
+    return luaL_error( L, "OpenSSL error" );
+  }
+
+  lua_pushlstring( L, (char *) out, out_len + final_len );
+
+  EVP_CIPHER_CTX_cleanup( &cipher_ctx );
+  free( out );
+
+  return 1;
+}
+
+static int l_DES_string_to_key(lua_State *L) /** DES_string_to_key( string data ) */
+{
+  size_t len;
+  const unsigned char *data = (unsigned char *) luaL_checklstring( L, 1, &len );
+  if ( len != 7 )
+    return luaL_error( L, "String must have length of 7 bytes." );
+
+  DES_cblock key;
+  key[0] = data[0];
+  for( int i = 1; i < 8; i++ )
+    key[i] = data[i-1] << (8-i) | data[i] >> i;
+  
+  DES_set_odd_parity( &key );
+
+  lua_pushlstring( L, (char *) key, 8 );
+  return 1;
+}
+
+
+static const struct luaL_reg bignum_methods[] = {
+  { "num_bits", l_bignum_num_bits },
+  { "num_bytes", l_bignum_num_bytes },
+  { "tobin", l_bignum_bn2bin },
+  { "todec", l_bignum_bn2dec },
+  { "tohex", l_bignum_bn2hex },
+  { "is_bit_set", l_bignum_is_bit_set },
+  { "set_bit", l_bignum_set_bit },
+  { "clear_bit", l_bignum_clear_bit },
+  { "is_bit_set", l_bignum_is_bit_set },
+  { "set_negative", l_bignum_set_negative },
+  { "is_negative", l_bignum_is_negative },
+  { "__gc", l_bignum_free },
+  { NULL, NULL }
+};
+
+static const struct luaL_reg openssllib[] = {
+  { "bignum_num_bits", l_bignum_num_bits },
+  { "bignum_num_bytes", l_bignum_num_bytes },
+  { "bignum_set_bit", l_bignum_set_bit },
+  { "bignum_clear_bit", l_bignum_clear_bit },
+  { "bignum_is_bit_set", l_bignum_is_bit_set },
+  { "bignum_set_negative", l_bignum_set_negative },
+  { "bignum_is_negative", l_bignum_is_negative },
+  { "bignum_bin2bn", l_bignum_bin2bn },
+  { "bignum_dec2bn", l_bignum_dec2bn },
+  { "bignum_hex2bn", l_bignum_hex2bn },
+  { "bignum_rand", l_bignum_rand },
+  { "bignum_pseudo_rand", l_bignum_pseudo_rand },
+  { "bignum_bn2bin", l_bignum_bn2bin },
+  { "bignum_bn2dec", l_bignum_bn2dec },
+  { "bignum_bn2hex", l_bignum_bn2hex },
+  { "bignum_mod_exp", l_bignum_mod_exp },
+  { "rand_bytes", l_rand_bytes },
+  { "rand_pseudo_bytes", l_rand_pseudo_bytes },
+  { "md2", l_md2 },
+  { "md4", l_md4 },
+  { "md5", l_md5 },
+  { "sha1", l_sha1 },
+  { "ripemd160", l_ripemd160 },
+  { "digest", l_digest },
+  { "hmac", l_hmac },
+  { "encrypt", l_encrypt },
+  { "decrypt", l_decrypt },
+  { "DES_string_to_key", l_DES_string_to_key },
+  { "supported_digests", l_supported_digests },
+  { "supported_ciphers", l_supported_ciphers },
+  { NULL, NULL }
+};
+
+LUALIB_API int luaopen_openssl(lua_State *L) {
+
+  OpenSSL_add_all_algorithms();
+
+  luaL_register(L, OPENSSLLIBNAME, openssllib);
+
+  // create metatable for bignum
+  luaL_newmetatable( L, "BIGNUM" );
+  // metatable.__index = metatable
+  lua_pushvalue( L, -1 );
+  lua_setfield( L, -2, "__index" );
+  // register methods
+  luaL_register( L, NULL, bignum_methods );
+
+  lua_pop( L, 1 ); // BIGNUM
+
+  return 1;
+}
+

Property changes on: nse_openssl.cc
___________________________________________________________________
Added: svn:mergeinfo

Attachment: signature.asc
Description: OpenPGP digital signature


_______________________________________________
Sent through the nmap-dev mailing list
http://cgi.insecure.org/mailman/listinfo/nmap-dev
Archived at http://SecLists.Org

Current thread: