Ok, so I was building an application and using RSA to decrypt data encrypted from the browser's webcrypto and I was getting a strange error before the web side even started.. I tried searching the error but I didn't find anything helpful.. I'm using nodejs(v16.10.0
)
//failing nodejs example
var crypto=require('crypto')
var privateKeyStr=`-----BEGIN PRIVATE KEY-----
REAL_PRIVATE_KEY_HERE
-----END PRIVATE KEY-----`
function str2ab(str) {
const buf = new ArrayBuffer(str.length);
const bufView = new Uint8Array(buf);
for (let i = 0, strLen = str.length; i < strLen; i ) {
bufView[i] = str.charCodeAt(i);
}
return buf;
}
function ab2str(buf,getOwnPropertyNames) {
var buff=new Uint8Array(buf)
return Object.getOwnPropertyNames(buff)
.map(i=>String.fromCharCode(buff[i])).join('')
}
atob=(text)=>Buffer.from(text,'base64').toString()
btoa=(text)=>Buffer.from(text).toString('base64')
let pemHead1="-----BEGIN PRIVATE KEY-----", pemFoot1="-----END PRIVATE KEY-----"
var prvKeyText=atob(privateKeyStr.substring(pemHead1.length,privateKeyStr.length-pemFoot1.length));
(async()=>{
prvKey=await crypto.webcrypto.subtle.importKey('pkcs8',str2ab(prvKeyText),{name:"RSA-OAEP",hash:"SHA-256"},true,['decrypt'])
rsa_decrypt=async(secret_text)=>ab2str( await crypto.webcrypto.subtle.decrypt('RSA-OAEP',prvKey,str2ab(atob(secret_text))) )
})()
And this kind of code for webcrypto does work in the browser but it fails in nodejs(v16.10.0
)
//working web example(yes this is not a private key I'm using)
var privateKeyStr=`-----BEGIN PRIVATE KEY-----
MIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQDUXCf0zdHCtVGY
kGAP0cSHZcdt5R A0wiYNYmGa4Q4TmyZxI8w2HjrbREwH51c/rJ7KxEwPmx288zX
yESmswSDENS/mb 5Kvo oHZCLFHzL z VoCBLDUGCMDMEs1nyEDjsXlLXkuceR6Y
n/YSjy/jSA8ens/Q883PseXPetJBtKxmixVS9DKGuLgYuz22XwaKEOB5SD5WIa0f
Rj8WkS5NU 7GBoAFPtCTNcq1D3qKhb4ifoQIeUfKz8ITrNSQ8hUYrkNSOirJj9tk
K4pb/QHu/pKqL7eoFlNiwbP0FhoWdmSPTbU4xYpSAyjT/qT dGOXEIZxI623tDO3
ZNVDPcF9Sm6rGqrsWbUfkBK413ZX6I98g2aktsHsHaNNLrRU6l p0T0l89 bNDt7
r/vgWV0FWbzyXHbZBhDhLj6eWL8lLAPQlYtgkpsZNZkZRT3wdzeRAAm7WVKeODW9
e5wg5WJpJ EkbBZBaLqtXi4P84eNieg2q4nhyiC XyokfNtKreideKnRqp9R84h
O19iu 2MEeiy1mJvqqIwa0bhsSHzr6aO4HBgWDn5ierdLQo2EuFNDblGlao98h26
3BJO5bBurVAczbdYJvT8rLCUEwYsDwAnXMeXs3ezv4hualp3VeExgyiYoPZUIPZS
eh8zbk6Gnaz8mmSkRPyKl4gbDzS5 QIDAQABAoICAA2OtJ5UZYfgu4zZ6sgXxExA
mzLQ5en7jxjokhca1h4iI5zNh7a mzmshORloE5HlG14mmhSE qkNfewuXFLDIax
lGOHFU5lCATniaU/3xt/e8nhC MzR09TT7u3l5WAm2Pt KhvJLSgputnivY0XgJM
n2p9CRd1 TXBTcKpPLMlLbx NKZPIMqpEFfD3HTALFK0MSCNFC27iKnueiierC4T
pbLOx22OTRKY5JAapOAjGbhqC1PfKk4wZVuMNSXrzpz8wx ExyaHIKKMhRDKXk07
w3FKCpeYlUpAw5RZtOCqPlFHzMILGoGR4hFmuHHmTFVgoLSoanbH8mVK8rKQRsHz
KdQ8tLquQpnXf P Vx4hAP9cyjpfJWwQDtv3jq /bJiyrM50wJhYekimLEGfSQ0n
8k5vza1Q27/Rz1lG4A3YGew4ywbpsluY3QfT5tUVN ixtiNC15pbIE4LfUd0MN17
8MeQqHwiRVGBZzvGBebssuVw96kUOhZBGZ7DqjpaJU5WDBhXInkFTQNyPrwp d2K
FhwpAwWgPC7b8AIZPSj14aBr60ZDPv CM2Uug9Yc26ZRP emQVEGl6S1dEPDX/hV
Oe2tkjYtkqzwm1XwB5t0Dsvo60i4A5 NBYXzb8g hSqB9Cbr4uhkVGV1DZdk67bj
5OX wlMLyt04QtIwmBAoIBAQDzkUhryv4Ue/uCz5tXuY/qyUV1tOJFaGYBdVnQ
FIv6mOIHexMlAiSQnd0h CxTu8kx3 rqL3P6p97ErxYQ2YjmhczR0E4CBemLzxzV
CPLAJnKG I5fjSS QIDezSdn5hOZs0fhsGkfQmZ3x0WaYQDwiny5Hzfe4Ddoi4Ta
/Fms1h6rlB7gHY842GqskYgp6LjNoYEwAVMEVag3RwE2KIq034L6OywD LhWOVi
itcWLUlyUzsrBxqgIfSkUFXK6GU8uqOwaZ2GIfn5/smRwaXj1WyJjG1zZT6wZ/Bl
Ku tSImKPYrvctp61Ob7IhwdliNOvvXR7xXTeftZeZVenLrlAoIBAQDfMxTx3/fg
jk4E1b8jCN4CuPoA3tflXrY70TEkNpaiqWdnhkmI7U3yQv70gYNYrbCXf6L5H w7
UH5mrLZmpyhBGeVAGweB0gw5K1nfZtuxYIsKBpefh/iTP5EPokBgGN3TysVyaPph
2uvvKsG0lN6sWDYKFtY5YDG2JoBkq9Ek0NfGu0v/GOmqvGXWn/CNu v9FGUZdUOb
6LuXbxwe/yY5Re02Qcwo2JjJrWqz60OIlnNmJ1XuP9EXsakGv/DOMYnbJylb9txq
cHh2eJxJneLyP8eRsIp6DhQaExgmHqmJbYTIipJXVi5QqtsCeSXYm0ZygtsASjqs
cFWSPGlCgg2FAoIBAQCuCDHR63IOWuRD/GkHjmwZm4SI7Rz78PNpuVraBcRa42Al
bjgoqlZMCrAVdIjfr367pz3n5M4e3FGdAWln0rcx14qYpBkI8waDwhHc2g7xYsdU
T0cTWPtXASnTiIzOfSOmH aNiQojrsMedID0JLmSJbGmaHr4Qgb1KTNdcQ/2Iew6
NpS1GAnc2S2nbjj3kPRy4SI4lcmmgDm4fYCNHPy27jlc6Giz1Aexcl48Qe4bR3KC
QJw3S1Un8/skaM5UNCcZ9FW/WEeYrrA5g2atQctxdm6d/Xu7By16yFmJP9uPWhQE
daLPIqafO35rFF04eq1xt5pXTViwCSmiLfCfcKdNAoIBACFhGUvG6 IYRhCxCqGp
rNIJadIBgZYa4PP3J/s7crGm1gEEczDYFGUbodddGxCDATrW6r JB6IjOpQOVkTp
0LpTrhY1NJ00lYFjO1COqGJRhtmb/Mbt5b3XrtEAudHlRh9rXrXqfy9tNwWQhmGE
NfzeQE6n9aek/Co6fc8QZvmzheGBly7yQde3zx8W0jnQFc3GZAw3nkHNv2g5RKJa
FBRSodQQaQDey5K1rZR0pafioCVx0ocL4jBB8H5C7DdZ7zzoEWZgd7wvT8Sf6veT
diI2aZkfJsZ0Hot7uYvR4BbeWxJGrvYCvHBx7Mjk50UKi7GKYkgb0cSCFDoHcNJy
cqUCggEAGJ 31rAPfxH7FXneYlMY9r2KlzAEWFSVFulDJpQNWEhqCQ1XvgqnVoCv
ymjZ8MqwpfAiu4Tiu9/mWY7qKLSxAJscu3qRpDDAU9qLQV67zHp/7/b5X7 j7Hjb
kg2 8sn/ZfIJLHhLueBniNU41xc2IEe/o52bd17juhj5BYFjiv7on83xcCKiGVxm
Em3IXian5uXHg58lb95XNs8rbpjbcNFC7CGtPFfd/sKH16ciButT6C14lXrEL3vH
i8L9n lbKM3UZDFmLO113GSCP adCmXiqSs6DgTiL71KrbNgtbNp4UvskxCq5xRf
PotgmE7pY/5T04uDwhpWK5TOFnCnXg==
-----END PRIVATE KEY-----`
function str2ab(str) {
const buf = new ArrayBuffer(str.length);
const bufView = new Uint8Array(buf);
for (let i = 0, strLen = str.length; i < strLen; i ) {
bufView[i] = str.charCodeAt(i);
}
return buf;
}
function ab2str(buf,getOwnPropertyNames) {
var buff=new Uint8Array(buf)
return Object.getOwnPropertyNames(buff)
.map(i=>String.fromCharCode(buff[i])).join('')
}
let pemHead1="-----BEGIN PRIVATE KEY-----", pemFoot1="-----END PRIVATE KEY-----"
var prvKeyText=atob(privateKeyStr.substring(pemHead1.length,privateKeyStr.length-pemFoot1.length));
(async()=>{
prvKey=await crypto.subtle.importKey('pkcs8',str2ab(prvKeyText),{name:"RSA-OAEP",hash:"SHA-256"},true,['decrypt'])
console.log("it works normally")
console.log(prvKey) //so clearly I don't understand webcrypto in nodejs v16.10.0
rsa_decrypt=async(secret_text)=>ab2str( await crypto.subtle.decrypt('RSA-OAEP',prvKey,str2ab(atob(secret_text))) )
})()
//if an error happened you would see it.. but in your browser it works normal
CodePudding user response:
This is due to your atob()
and btoa()
methods defined for NodeJS.
Buffer.from()
and Buffer#toString()
apply UTF-8 by default if no other encoding is specified. However, UTF-8 generally corrupts arbitrary binary data. Instead of UTF-8 use binary
as encoding:
atob = (text) => Buffer.from(text, 'base64').toString('binary')
btoa = (text) => Buffer.from(text, 'binary').toString('base64')
With this fix the import works and the error message is no longer displayed.