【杂谈】密码学当中不同语言字节数组的转换
考虑到可能各位读者大佬们都不仅仅会一种语言,或者是在使用密码学算法的过程当中可能会遇到一些跨语言的使用,举一个简单的例子,假设是后端是用go写得,这里需要给前端提供接口,这里可能前端是用的js或者在移动端使用java或者是objective-c,因此呢,大概率需要做密码学库的跨语言转换,这里遇到的比较多的一点,就是最终数据的呈现形式了,因此呢,本文我在这里简单整理下不同语言之间数据类型之间的转换,因为个人水平有限,大概率写法是不一定优雅,也欢迎熟悉这些语言的大佬和我交流,共同进步。
背景介绍
那么,我们用哈希函数作为例子,来展开本文吧,这里选择了大多数开发者都会选择的一个哈希函数MD5来作为具体的用例,虽然说MD5已经不再安全,但是吧,大多数应用之中还是会发现很多使用MD5的地方,这里多说一句,如果涉及到安全要求高一些的系统或者项目,不建议使用MD5哈。
这里,我先用Java写一个MD5的用例吧,然后通过这个用例转换为其他语言的用例,这里呢我尽量不引入其他的库,如果语言本身带有密码学相关库的话。
package com.littleq;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
public class Main {
static byte[] md5(String message) throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance("MD5");
return md.digest(message.getBytes());
}
public static void main(String[] args) throws NoSuchAlgorithmException {
System.out.println(Arrays.toString(md5("")));
// [-44, 29, -116, -39, -113, 0, -78, 4, -23, -128, 9, -104, -20, -8, 66, 126]
}
}
这段Java代码相信读者应该不难理解,就是计算一下MD5,注意这里Java这里返回的是一个字节数组,这里和我们见到过的正常MD5的输出是不一样的,那么我们如何变换下变成我们常见的MD5的样子呢?
package com.littleq;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
public class Main {
public static String byteArrayToHex(byte[] a) {
StringBuilder sb = new StringBuilder(a.length * 2);
for (byte b : a)
sb.append(String.format("%02x", b));
return sb.toString();
}
static byte[] md5(String message) throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance("MD5");
return md.digest(message.getBytes());
}
public static void main(String[] args) throws NoSuchAlgorithmException {
System.out.println(byteArrayToHex(md5("")));
// d41d8cd98f00b204e9800998ecf8427e
System.out.println(Arrays.toString(md5("")));
}
}
好了,这么久正常输出来我们常见的MD5的结果了,接下来我们就从这块来聊一聊从[-44, 29, -116, -39, -113, 0, -78, 4, -23, -128, 9, -104, -20, -8, 66, 126]
如何放到其他语言当中使用。
其他语言的转换
Python
对于Python,对于字节类型的存储范围是0~255
,因此我们如果需要做转换,相对来说比较容易,我们只需要与一个0xFF
就好了。
def from_java_bytes_to_python(data):
return [i & 0xFF for i in data]
def to_hex(data):
return ''.join('{:02x}'.format(x) for x in data)
if __name__ == '__main__':
data = from_java_bytes_to_python([-44, 29, -116, -39, -113, 0, -78, 4, -23, -128, 9, -104, -20, -8, 66, 126])
print(to_hex(data))
# d41d8cd98f00b204e9800998ecf8427e
这里,我们得到的输出和最终Java转成字符串的结果是一致的,这样就好了。
JavaScript
因为js本身的数据就是有符号的,所以直接转换下就可以用了。
function from_java_bytes_to_js(data) {
return Buffer.from(data);
}
function to_hex(data) {
return data.toString('hex');
}
function main() {
const data = from_java_bytes_to_js([-44, 29, -116, -39, -113, 0, -78, 4, -23, -128, 9, -104, -20, -8, 66, 126]);
console.log(to_hex(data));
// d41d8cd98f00b204e9800998ecf8427e
}
main();
Rust
因为rust本身是有有符号的byte的类型的,所以这个不用转换,直接用就好了。
fn to_hex_string(bytes: &[i8]) -> String {
let mut result = String::new();
for byte in bytes {
result.push_str(&format!("{:02x}", byte));
}
result
}
fn main() {
let hex_str = to_hex_string(&[-44, 29, -116, -39, -113, 0, -78, 4, -23, -128, 9, -104, -20, -8, 66, 126]);
println!("{}", hex_str);
// d41d8cd98f00b204e9800998ecf8427e
}
C#
非常幸运的是,对于C#也是有这个类型的,因此呢,我们还是可以直接用的哦。
// See https://aka.ms/new-console-template for more information
using System.Text;
string ToHex(sbyte[] message)
{
StringBuilder sb = new StringBuilder();
foreach (sbyte b in message)
{
sb.Append(b.ToString("x2"));
}
return sb.ToString();
}
Console.WriteLine(ToHex(new sbyte[]{-44, 29, -116, -39, -113, 0, -78, 4, -23, -128, 9, -104, -20, -8, 66, 126}));
// d41d8cd98f00b204e9800998ecf8427e
总结
没错,本文实际上是一篇水文,后续再有读者大佬遇到需要做这类转换,就可以直接用了,溜了,溜了~~
原文始发于微信公众号(Coder小Q):【杂谈】密码学当中不同语言字节数组的转换
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论