From 0ca6cb87dfd69b3f39024c714c8fde9b2dd9acbf Mon Sep 17 00:00:00 2001
From: Veniamin Gvozdikov <g.veniamin@googlemail.com>
Date: Thu, 8 Jun 2017 17:06:39 +0300
Subject: [PATCH] Add string.hex() method

* Add string.hex() method
* Add hmac.*_hex to crypto.lua
* Update crypto/digest to use string.hex()

Closes #2510
---
 src/lua/crypto.lua |  8 +++++++-
 src/lua/digest.lua | 16 +++-------------
 src/lua/string.lua | 15 +++++++++++++++
 3 files changed, 25 insertions(+), 14 deletions(-)

diff --git a/src/lua/crypto.lua b/src/lua/crypto.lua
index 8191c75591..b6b2d65407 100644
--- a/src/lua/crypto.lua
+++ b/src/lua/crypto.lua
@@ -1,6 +1,6 @@
 -- crypto.lua (internal file)
 
-local ffi = require 'ffi'
+local ffi = require('ffi')
 local buffer = require('buffer')
 
 ffi.cdef[[
@@ -354,6 +354,12 @@ for class, digest in pairs(hmacs) do
             return res
         end
     })
+    hmac_api[class .. '_hex'] = function (key, str)
+        if type(str) ~= 'string' then
+            error("Usage: hmac."..class.."_hex(key, string)")
+        end
+        return string.hex(hmac_api[class](key, str))
+    end
 end
 
 hmac_api = setmetatable(hmac_api,
diff --git a/src/lua/digest.lua b/src/lua/digest.lua
index 57d04719d9..c86acacd7c 100644
--- a/src/lua/digest.lua
+++ b/src/lua/digest.lua
@@ -1,6 +1,6 @@
 -- digest.lua (internal file)
 
-local ffi = require 'ffi'
+local ffi = require('ffi')
 local crypto = require('crypto')
 
 ffi.cdef[[
@@ -39,16 +39,6 @@ local digest_shortcuts = {
     md4     = 'MD4',
 }
 
-local hexres = ffi.new('char[129]')
-
-local function str_to_hex(r)
-    for i = 0, r:len() - 1 do
-        ffi.C.snprintf(hexres + i * 2, 3, "%02x",
-            ffi.cast('unsigned char', r:byte(i + 1)))
-    end
-    return ffi.string(hexres, r:len() * 2)
-end
-
 local PMurHash
 local PMurHash_methods = {
 
@@ -190,7 +180,7 @@ local m = {
             error("Usage: digest.sha1_hex(string)")
         end
         local r = ffi.C.SHA1internal(str, #str, nil)
-        return str_to_hex(ffi.string(r, 20))
+        return string.hex(ffi.string(r, 20))
     end,
 
     guava = function(state, buckets)
@@ -217,7 +207,7 @@ for digest, name in pairs(digest_shortcuts) do
         if type(str) ~= 'string' then
             error('Usage: digest.'..digest..'_hex(string)')
         end
-        return str_to_hex(crypto.digest[digest](str))
+        return string.hex(crypto.digest[digest](str))
     end
 end
 
diff --git a/src/lua/string.lua b/src/lua/string.lua
index 0eca339ace..775da2eb51 100644
--- a/src/lua/string.lua
+++ b/src/lua/string.lua
@@ -278,6 +278,20 @@ local function string_endswith(inp, tail, _start, _end)
     return memcmp(c_char_ptr(inp) + _start, c_char_ptr(tail), tail_len) == 0
 end
 
+local function string_hex(inp)
+    if type(inp) ~= 'string' then
+        error(err_string_arg:format(1, 'string.hex', 'string', type(inp)), 2)
+    end
+    local len = inp:len() * 2
+    local res = ffi.new('char[?]', len + 1)
+
+    local uinp = ffi.cast('const unsigned char *', inp)
+    for i = 0, inp:len() - 1 do
+        ffi.C.snprintf(res + i * 2, 3, "%02x", ffi.cast('unsigned', uinp[i]))
+    end
+    return ffi.string(res, len)
+end
+
 -- It'll automatically set string methods, too.
 local string = require('string')
 string.split      = string_split
@@ -286,3 +300,4 @@ string.rjust      = string_rjust
 string.center     = string_center
 string.startswith = string_startswith
 string.endswith   = string_endswith
+string.hex        = string_hex
-- 
GitLab