记一次手忙脚乱的base64debug之旅

Posted suedarsam

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了记一次手忙脚乱的base64debug之旅相关的知识,希望对你有一定的参考价值。

这几天做了一个需求,读取上传的公私钥,然后利用私钥采用RSA加密摘要,发送给后端。其中运用到了base64的加解密,RSA加密采用的是node的Crypto模块base64的转码采用的是js-base64, 然而万万没有想到,这里面有坑啊。

(开个玩笑,这个库还是很不错的)

文件的读取

首先是文件的读取,采用的是FileReader, 并且二进制文件的读取应为readAsArrayBuffer,否则会乱码。

readFile(file) 
    return new Promise((resolve, reject) => 
        const reader = new FileReader();
        reader.onload = function(evt) 
            resolve(evt.target.result)
        ;
        reader.readAsArrayBuffer(file);
    )

从这里读取到的数据,调用Object.prototype.toString.call([data]),结果为[object Uint8Array]

ArrayBuffer对象用来表示通用的、固定长度的原始二进制数据缓冲区。ArrayBuffer不能直接操作,而是要通过类型数组对象或DataView 对象来操作,它们会将缓冲区中的数据表示为特定的格式,并通过这些格式来读写缓冲区的内容。

Uint8Array 数组类型表示一个8位无符号整型数组,创建时内容被初始化为0。创建完后,可以以对象的方式或使用数组下标索引的方式引用数组中的元素。

类型数组对象就是Uint8Array之类的TypedArray,我们需要这些对象操作ArrayBuffer

这是一个摸索了很久的点,因为有的公私钥读取可以直接采用reader.readAsText(file)

ArrayBuffer与base64的转换

另一个摸索了很久的东西便是ArrayBufferbase64的转换,缘由于js-base64对这两个的转换并不支持。

ArrayBuffer转base64

很令人捉🐔的是,调用库中的方法Base64.encode([ArrayBuffer]),得出的数据一直不对。
略微看了一下源码。

var _Base64 = global.Base64;
var version = "2.5.1";
// if node.js and NOT React Native, we use Buffer
var buffer;
if (typeof module !== 'undefined' && module.exports) 
    try 
        buffer = eval("require('buffer').Buffer");
     catch (err) 
        buffer = undefined;
    

...
var _encode = buffer ?
    buffer.from && Uint8Array && buffer.from !== Uint8Array.from
    ? function (u) 
        return (u.constructor === buffer.constructor ? u : buffer.from(u))
            .toString('base64')
    
    :  function (u) 
        return (u.constructor === buffer.constructor ? u : new buffer(u))
            .toString('base64')
    
    : function (u)  return btoa(utob(u)) 
;
var encode = function(u, urisafe) 
    return !urisafe
        ? _encode(String(u))
        : _encode(String(u)).replace(/[+\\/]/g, function(m0) 
            return m0 == '+' ? '-' : '_';
        ).replace(/=/g, '');
;

不知是不是采用IIFE的关系,buffer恒为undefined,并且此时!urisafe为真,会流入第一个条件,而的uUint8Array,强制类型转换会导致乱码。

故而不用库,用原生方法。
Buffer.from([key]).toString('base64') 这是ArrayBufferbase64的原生方法。

base64转ArrayBuffer

function _base64ToArrayBuffer(base64) 
    var binary_string =  window.atob(base64);
    var len = binary_string.length;
    var bytes = new Uint8Array( len );
    for (var i = 0; i < len; i++)        
        bytes[i] = binary_string.charCodeAt(i);
    
    return bytes.buffer;

and…

const encryptDigest = crypto.privateEncrypt( key: privateKey ,
    Buffer.from(_base64ToArrayBuffer(digest))
);
const res = crypto.publicDecrypt( key: publicKey , encryptDigest);

res.toString('base64') === digest ?

只要用私钥加密的摘要用公钥能成功解密,并且数据不变,就证明这个流程正确了。

其实用window.atob也可以将ArrayBufferbase64,但是有大小限制,码位应在 0x00 ~ 0xFF 范围内。然而后端小哥说业务不支持ascii格式的,只能作罢。

javascript – 将base64字符串转换为ArrayBuffer

深入学习 Node.js Buffer

以上是关于记一次手忙脚乱的base64debug之旅的主要内容,如果未能解决你的问题,请参考以下文章

记一次Wps_js宏开发之旅——非Excel vba vb宏

记一次struts2漏洞修复带来的问题

记一次Linux服务器上查杀木马经历

记一次Linux服务器上查杀木马经历

记一次新生赛BJDCTF(WP)

记一次作死之旅