如何在Lua中将十六进制字符串转换为uint64?含SIP CallID场景
Let's break this down into two parts: first the general hex-to-uint64 problem in Lua, then applying it to your SIP CallID request ID scenario.
General Solution: Hex String to uint64_t in Lua
Lua doesn’t come with a native uint64_t type, but we can work around this by parsing and truncating the hex string to fit the 64-bit unsigned integer format. Since SHA1 hashes are 20 bytes (40 hex characters), we’ll need to cut this down to 8 bytes (16 hex characters) to fit into a uint64. You’ll want to pick either the first 8 bytes or last 8 bytes of the hash—just make sure this choice is consistent across your system to maintain compatibility.
Here’s a basic function to handle the conversion:
function hex_to_uint64(hex_str) -- Truncate to 16 hex chars (8 bytes = 64 bits) -- Swap to string.sub(hex_str, -16) if you want the last 8 bytes local truncated_hex = string.sub(hex_str, 1, 16) -- Convert hex to a number; note this is exact only up to 2^53 local uint64_val = tonumber(truncated_hex, 16) return uint64_val end
If you need full 64-bit precision (for values larger than 2^53, which can’t be represented exactly in Lua’s default number type), use LuaJIT’s FFI for exact uint64 handling:
local ffi = require("ffi") ffi.cdef[[ typedef unsigned long long uint64_t; ]] function hex_to_uint64_exact(hex_str) -- Grab the last 8 bytes of the SHA1 hash local truncated_hex = string.sub(hex_str, -16) -- Cast to a proper uint64_t via FFI local uint64_val = ffi.cast("uint64_t", tonumber(truncated_hex, 16)) return uint64_val end
Specific Use Case: SIP CallID to uint64_t Request ID
Your current code uses shell commands to generate the SHA1 hash, which works but can be slow and carries shell injection risks if the CallID has special characters. Let’s fix and optimize this, then add the uint64 conversion step.
Option 1: Improved Shell Command Approach
First, complete your existing function properly, with input escaping and hash cleanup:
function common_get_request_id(callId) -- Escape special characters to avoid shell injection local escaped_callId = string.gsub(callId, '["\\$`]', "\\%0") local command = string.format('echo -n "%s" | openssl sha1 | sed "s/(stdin)= //g"', escaped_callId) local handle = assert(io.popen(command, "r")) local output = handle:read("*all") handle:close() -- Trim any extra whitespace/newlines from the hash output local sha1_hex = string.gsub(output, "%s+", "") -- Convert to uint64 (adjust truncation as per your compatibility rules) local truncated_hex = string.sub(sha1_hex, 1, 16) local request_id = tonumber(truncated_hex, 16) return request_id end
Option 2: Pure Lua (No Shell Calls)
For better performance and portability, use a Lua crypto library like luaossl or luacrypto to generate the SHA1 hash directly:
local crypto = require("crypto") -- Make sure luacrypto is installed via LuaRocks function common_get_request_id(callId) -- Generate SHA1 hash directly in Lua (no shell overhead) local sha1_hex = crypto.digest("sha1", callId) -- Convert to uint64 (using last 8 bytes here as an example) local truncated_hex = string.sub(sha1_hex, -16) local request_id = tonumber(truncated_hex, 16) return request_id end
Quick Tips:
- Consistency: Double-check which part of the SHA1 hash you need to use (first vs last 8 bytes) to match your internal compatibility requirements.
- Precision: If your system needs exact uint64 values beyond 2^53, stick with the LuaJIT FFI approach instead of relying on
tonumber. - Security: Always escape user-provided input like CallID when using shell commands to prevent malicious injection.
内容的提问来源于stack exchange,提问作者ssk

