記一次手忙腳亂的base64debug之旅

這幾天作了一個需求,讀取上傳的公私鑰,而後利用私鑰採用RSA加密摘要,發送給後端。其中運用到了base64的加解密,RSA加密採用的是node的Crypto模塊base64的轉碼採用的是js-base64, 然而萬萬沒有想到,這裏面有坑啊。 javascript

(開個玩笑,這個庫仍是很不錯的)html

文件的讀取

首先是文件的讀取,採用的是FileReader, 而且二進制文件的讀取應爲readAsArrayBuffer,不然會亂碼。java

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]node

ArrayBuffer對象用來表示通用的、固定長度的原始二進制數據緩衝區。ArrayBuffer不能直接操做,而是要經過類型數組對象或DataView 對象來操做,它們會將緩衝區中的數據表示爲特定的格式,並經過這些格式來讀寫緩衝區的內容。
Uint8Array 數組類型表示一個8位無符號整型數組,建立時內容被初始化爲0。建立完後,能夠以對象的方式或使用數組下標索引的方式引用數組中的元素。git

類型數組對象就是Uint8Array之類的TypedArray,咱們須要這些對象操做ArrayBuffergithub

這是一個摸索了好久的點,由於有的公私鑰讀取能夠直接採用reader.readAsText(file)後端

ArrayBuffer與base64的轉換

另外一個摸索了好久的東西即是ArrayBufferbase64的轉換,原因於js-base64對這兩個的轉換並不支持。api

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

相關文章
相關標籤/搜索