如何将sgx_read_rand生成的随机字节转为可读取字符串?
你的问题核心在于:sgx_read_rand生成的是原始二进制随机字节,这些字节包含大量不可打印的ASCII字符(甚至可能有null字节),直接转std::string自然会显示乱码;而你用%llu格式化输出得到的数字其实是错误的——因为你把12字节的char数组强行当成了8字节的long long类型读取,这会导致越界读取,得到的数值根本不能完整表示你的12字节盐。
正确的解决方案:二进制字节转可读文本格式
我们需要把原始的随机字节转换成标准的可读字符串格式,常见的有三种实用方式:
方法1:转换为十六进制字符串(推荐)
十六进制是二进制转文本最常用的方式,每个字节用两位十六进制字符表示,12字节的盐会变成24个字符的字符串,既紧凑又能完整保留所有随机信息,非常适合和密码拼接后做哈希等安全操作。
实现代码:
#include <string> #include <sstream> #include <iomanip> #include "sgx_tcrypto.h" // 引入sgx_read_rand的头文件 std::string bytes_to_hex(const unsigned char* bytes, size_t len) { std::stringstream ss; ss << std::hex << std::setfill('0'); for (size_t i = 0; i < len; ++i) { // 用unsigned int避免有符号char的符号扩展问题 ss << std::setw(2) << static_cast<unsigned int>(bytes[i]); } return ss.str(); } // 使用示例 int main() { unsigned char salt_bytes[12]; sgx_status_t ret = sgx_read_rand(salt_bytes, sizeof(salt_bytes)); if (ret != SGX_SUCCESS) { mbedtls_printf("ENCLAVE: Failed to generate random salt!\n"); return -1; } std::string salt_str = bytes_to_hex(salt_bytes, sizeof(salt_bytes)); mbedtls_printf("ENCLAVE: Salt as hex string: %s\n", salt_str.c_str()); // 现在可以和密码字符串直接拼接 std::string password = "your_secure_password"; std::string combined = password + salt_str; mbedtls_printf("ENCLAVE: Password + Salt: %s\n", combined.c_str()); return 0; }
方法2:转换为十进制数值拼接的字符串
如果你更偏好十进制数字的形式,可以把每个字节的十进制值(0-255)用空格分隔拼接成字符串,对应你测试时输出的数值:
std::string bytes_to_decimal(const unsigned char* bytes, size_t len) { std::stringstream ss; for (size_t i = 0; i < len; ++i) { if (i != 0) { ss << " "; } ss << static_cast<unsigned int>(bytes[i]); } return ss.str(); }
使用后会得到类似15 73 8 229 84 80 53 58 100 91 97 232的字符串,完全可读且保留所有随机信息。
方法3:Base64编码
Base64也是一种常用的二进制转文本方式,12字节的盐会转换成16个字符的字符串,比十六进制更紧凑。如果你的项目已经引入mbedtls,可以直接用它的Base64编码函数:
#include "mbedtls/base64.h" std::string bytes_to_base64(const unsigned char* bytes, size_t len) { size_t base64_len = mbedtls_base64_encode_get_buffer_length(len); char* base64_buf = new char[base64_len]; mbedtls_base64_encode(reinterpret_cast<unsigned char*>(base64_buf), base64_len, &base64_len, bytes, len); std::string result(base64_buf, base64_len); delete[] base64_buf; return result; }
为什么之前的%llu方式是错误的?
你用%llu输出*(char *)n时,实际上是把数组的第一个char字节强行转换成long long类型(8字节)读取——这会导致读取数组后面的7个字节,得到的数值只是前8字节的组合,完全丢失了后4字节的随机信息,根本不能代表整个12字节的盐,完全不适合作为盐的字符串表示。
另外,建议你把存储盐的数组类型从char改成unsigned char,这样可以避免符号扩展问题(比如你测试输出中的4294967229其实是有符号char的-27转成unsigned int后的结果,用unsigned char会直接得到229,更直观)。
内容的提问来源于stack exchange,提问作者Kumar Roshan Mehta

