a friend of mine lost her password for a BitGo account. her "Key Card" contains her private key in the form (actual info redacted for security reasons):
User Key:
{"iv":"IDMkr...UH4g0TBCofAcIg","v":1,"iter":10000,"ks":256,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"lI8k...vhX0","ct":"Kf...LOmgbn67w2CRYBhcXtX
0wdPF3D7ThCKaeZhTymin9hcMD5eL...AosmmvfA8npiDIHWgvdbHAk"}
and it's clear that the "ct" (ciphertext) was encrypted using AES 256 CCM. I've found a module (https://github.com/spark/node-aes-ccm) that will help me decrypt the private key ("ct") but the docs for the module are not very helpful:
decrypt(key, iv, ciphertext, aad, auth_tag)
key, iv, plaintext, aad, and auth_tag are all Buffer objects. decrypt will return an object like the following:
{
plaintext: Buffer,
auth_ok: Boolean
}
so other than that the parameters are buffers, there's no description for them... however, it seems I've got everything I need except the key. from reading the docs on a related module (https://github.com/xorbit/node-aes-gcm):
key is a 16, 24 or 32-byte Buffer object containing the AES key used
for encryption
I gather this is the key with which the private key was encrypted, but where would I get that and how does it relate to the lost password?
any help greatly appreciated
* Addendum I *
my friend figured out the password so following Ben's advice below I thought to try it. the code is straightforward:
var sjcl = require('sjcl-all');
var s = sjcl.decrypt("ThePassword", {
"iv":"IDMkrTa5UH4g0TBCofAcIg",
"v":"1",
"iter":"10000",
"ks":"256",
"ts":"64",
"mode":"ccm",
"adata":"",
"cipher":"aes",
"salt":"lI8kABgvhX0",
"ct":"KfJUrLOmgbn67w2CRYBhcXtX0wdPF3D7ThCKaeZhTymin9hcMD5eLHIUAosmmvfA8npiDIHWgvdbHAk"
}
);
console.log(s);
but when I run it, it pukes with the exception below:
/Users/ekkis/Development/decrypt/node_modules/sjcl-all/sjcl.js:66
c="{",d="";for(b in
a)if(a.hasOwnProperty(b))switch(b.match(/^[a-z0-9]+$/i)||p(new
sjcl.exception.invalid("json encode: invalid property
name")),c+=d+'"'+b+'":',d=",",typeof a[b]){case "number":case
"boolean":c+=a[b];break;case
"string":c+='"'+escape(a[b])+'"';break;case
"object":c+='"'+sjcl.codec.base64.fromBits(a[b],0)+'"';break;default:p(new
sjcl.exception.bug("json encode: unsupported type"))}return
c+"}"},decode:function(a){a=a.replace(/\s/g,"");a.match(/^{.*}$/)||p(new
sjcl.exception.invalid("json decode: this isn't json!"));
TypeError: a.replace is not a function
at Object.decode (/Users/ekkis/Development/decrypt/node_modules/sjcl-all/sjcl.js:66:438)
at Object.decrypt (/Users/ekkis/Development/decrypt/node_modules/sjcl-all/sjcl.js:65:473)
at Object. (/Users/ekkis/Development/decrypt/buff.js:3:14)
at Module._compile (module.js:571:32)
at Object.Module._extensions..js (module.js:580:10)
at Module.load (module.js:488:32)
at tryModuleLoad (module.js:447:12)
at Function.Module._load (module.js:439:3)
at Module.runMain (module.js:605:10)
at run (bootstrap_node.js:425:7)
so it complains that the json isn't json. but it looks fine to me! any help greatly appreciated
This encrypted JSON blob is produced by the SJCL library (https://www.npmjs.com/package/sjcl). A decryption would be done using sjcl.decrypt("password", json_blob). However, if your friend hasn't already been in touch with BitGo [support at bitgo.com], I recommend that route first.
Related
I am trying to communicate with a web service. In order to do that, I need to encrypt a message using the public key that I received from the web service. The doc says the following about the public key format:
Format: X.509 encoded key in ANS.1 (sic!)
(ANS.1 is ASN.1 I guess).
The public key is:
-----BEGIN CERTIFICATE-----MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDE+ApyETIF1cXzKnU144P6lg/FcilmuQS2wBvaWp6t9OovthGmrsszd7eo4rL6Nitj1YOKETTtnwm4T+1EEyBrgwcfXAlm3FasTC/HIzhRRa+F8Yuz+UZkGvgP8Qa6B0vRob2BjhWx1PfwuWHQxGvAjiqUJ/dEMjocFuCrY5NZqwIDAQAB-----END CERTIFICATE-----
I tried to use this is a NodeJS code with the following:
const key = crypto.createPublicKey({
key: Buffer.from(publicKey),
format: 'der',
type: 'pkcs1'
});
But I received the following error:
node:internal/crypto/keys:607
handle.init(kKeyTypePublic, data, format, type, passphrase);
^
Error: error:0D0680A8:asn1 encoding routines:asn1_check_tlen:wrong tag
at Object.createPublicKey (node:internal/crypto/keys:607:12)
at Object.<anonymous> (/XXXXXXXX/wsClient.js:16:20)
at Module._compile (node:internal/modules/cjs/loader:1149:14)
at Module._extensions..js (node:internal/modules/cjs/loader:1203:10)
at Module.load (node:internal/modules/cjs/loader:1027:32)
at Module._load (node:internal/modules/cjs/loader:868:12)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)
at node:internal/main/run_main_module:23:47 {
opensslErrorStack: [
'error:0D09B00D:asn1 encoding routines:d2i_PublicKey:ASN1 lib',
'error:0D07803A:asn1 encoding routines:asn1_item_embed_d2i:nested asn1 error'
],
library: 'asn1 encoding routines',
function: 'asn1_check_tlen',
reason: 'wrong tag',
code: 'ERR_OSSL_ASN1_WRONG_TAG'
}
I can't even convert this public key using openssl into any usable format. The only way to see inside it for me was to use the following online tool:
https://lapo.it/asn1js/
Here I can at least see that the public key is valid, but I don't know how to use it in NodeJS. Converting it is also an accaptable solution for me.
After some painful hours it turns out that two things had to be done:
replace "BEGIN CERTIFICATE" with "BEGIN PUBLIC KEY" and the same for the end
They also needed to be in a separate line
After that NodeJS Crypto is able to parse the key.
Interestingly phpseclib was able to parse the key in the original format and then output it in the correct one, that's how I realized the solution.
I need to access to the API of a service provider (for my company)
So, they gave me a 'doc' and a SSL certificate in multiple form (.jks, .p12, .pem)
I work with NodeJS so I took the .pem, inside there is 2 certificates and 1 encrypted private key.
I split the .pem in 3 files, mycert.crt.pem, mycert.key.pem, mycert2.crt.pem
(I checked on https://www.sslshopper.com/certificate-key-matcher.html to know which cert use with the key)
So my NodeJS, I used the least possible module to avoid module problem :
const cert = fs.readFileSync(path.resolve('cert', 'mycert.crt.pem'))
const key = fs.readFileSync(path.resolve('cert', 'mycert.key.pem'))
let options = {
hostname: 'https://serviceproviderurl.com',
path: 'v1/api/example',
method: 'POST',
key: key,
cert: cert
}
let req = https.request(options, function (res) {
console.log(res.statusCode)
res.on('data', function (d) {
process.stdout.write(d)
})
})
req.end()
And the error message :
Error: error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt
at Object.createSecureContext (_tls_common.js:151:17)
at Object.connect (_tls_wrap.js:1407:48)
at Agent.createConnection (https.js:125:22)
at Agent.createSocket (_http_agent.js:234:26)
at Agent.addRequest (_http_agent.js:193:10)
at new ClientRequest (_http_client.js:276:16)
at Object.request (https.js:309:10)
at Object.<anonymous> (/mnt/c/Project/test.js:74:17)
at Module._compile (internal/modules/cjs/loader.js:959:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:995:10) {
opensslErrorStack: [
'error:0907B00D:PEM routines:PEM_read_bio_PrivateKey:ASN1 lib',
'error:2306A075:PKCS12 routines:PKCS12_item_decrypt_d2i:pkcs12 pbe crypt error',
'error:23077074:PKCS12 routines:PKCS12_pbe_crypt:pkcs12 cipherfinal error'
],
library: 'digital envelope routines',
function: 'EVP_DecryptFinal_ex',
reason: 'bad decrypt',
code: 'ERR_OSSL_EVP_BAD_DECRYPT'
I think I missed something with the 3 certificates. Also they didn't gave me a passphrase, is it normal ?
I don't have a good knowledge about SSL certificate use and I hope you can help me.
Thank you
I am getting following error while trying to update the entity in google cloud datastore:
InvalidKey: A key should contain at least a kind.
at keyToKeyProto (/Volumes/Drive B/dev/zapi/node_modules/#google-cloud/datastore/src/entity.js:696:11)
at Array.map (<anonymous>)
at DatastoreRequest.createReadStream (/Volumes/Drive B/dev/zapi/node_modules/#google-cloud/datastore/src/request.js:226:23)
at DatastoreRequest.get (/Volumes/Drive B/dev/zapi/node_modules/#google-cloud/datastore/src/request.js:461:8)
at /Volumes/Drive B/dev/zapi/node_modules/#google-cloud/common/build/src/util.js:681:32
at new Promise (<anonymous>)
at Datastore.wrapper [as get] (/Volumes/Drive B/dev/zapi/node_modules/#google-cloud/common/build/src/util.js:662:20)
at fetchEntity (/Volumes/Drive B/dev/zapi/node_modules/gstore-node/lib/model.js:204:36)
at Function.get (/Volumes/Drive B/dev/zapi/node_modules/gstore-node/lib/model.js:174:16)
at Promise (/Volumes/Drive B/dev/zapi/node_modules/gstore-node/lib/utils.js:39:35)
at new Promise (<anonymous>)
at Function.wrapper (/Volumes/Drive B/dev/zapi/node_modules/gstore-node/lib/utils.js:27:16)
at resolve (/Volumes/Drive B/dev/zapi/graphql/mutations/user/linkConsult.js:101:44)
I don't know why is this coming for.
Thanks in advance.
When you trying to access key and key is not available when no data available, it gives the error
"Error Message : InvalidKey: A key should contain at least a kind"
To avoid this error first make sure that [datastrore.KEY] is available.
Thanks
I want to add to this answer with a little more detail. Here are some other helpful points to investigate if you run into this error when using the datastore.save method. The entity needs the correct key property like the example below.
// remember to use the key method on the google data store instance
const entity = {
key: dataStore.key('Name of your Kind') // this is Kind property you see on the GCP dashboard,
data: {
example: 'this is an example',
...
}
};
// then save the entity
const dbResult = await dataStore.save(entity)
I am following the tutorial Windows Azure SDK for Node.js - Compute Management to manage virtual machines.
I downloaded the pem file using azure account cert export to <Subscription GUID>.pem.
The script currently contains:
var subscriptionId ="<Subscription GUID>";
var pem = "<Subscription GUID>.pem";
var computeManagementClient = computeManagement.createComputeManagementClient(computeManagement.createCertificateCloudCredentials({
subscriptionId: subscriptionId,
pem: fs.readFileSync(pem)
}));
And when I run it from Node.js it produces the error:
C:\Apps\azure\node_modules\azure-mgmt-compute\node_modules\azure-common\lib\util\validate.js:416
throw new Error('Required argument ' + name + ' for function ' + func + ' is
^
Error: Required argument credentials.pem for function CertificateCloudCredentials is not defined
at throwMissingArgument (C:\Apps\azure\node_modules\azure-mgmt-compute\node_modules\azure-common\lib\util\validate.js:416:9)
at ArgumentValidator._.extend.string (C:\Apps\azure\node_modules\azure-mgmt-compute\node_modules\azure-common\lib\util\validate.js:426:7)
at C:\Apps\azure\node_modules\azure-mgmt-compute\node_modules\azure-common\lib\services\credentials\certificateCloudCredentials.js:35:9
at Object.validateArgs (C:\Apps\azure\node_modules\azure-mgmt-compute\node_modules\azure-common\lib\util\validate.js:478:3)
at new CertificateCloudCredentials (C:\Apps\azure\node_modules\azure-mgmt-compute\node_modules\azure-common\lib\services\credentials\certificateCloudCredentials.js:32:14)
at Object.exports.createCertificateCloudCredentials (C:\Apps\azure\node_modules\azure-mgmt-compute\lib\compute.js:54:10)
at Object.<anonymous> (C:\Apps\azure\setup.js:14:97)
at Module._compile (module.js:456:26)
at Object.Module._extensions..js (module.js:474:10)
at Module.load (module.js:356:32)
The issue is with pem: fs.readFileSync(pem). The SDK is not converting the node buffer to a string. There is an issue on Github.
Until this is fixed use toString on the buffer:
pem: fs.readFileSync(pem).toString()
I want to en- and decrypt a token to be able to determine if it could be a valid token without accessing the DB.
My code is working for tokens that look "completely different" but if I only change one letter, a result is returned (no error thrown) thus looking like the token is valid ...!?
This is my code (plus changing the letter manually):
var crypto = require("crypto");
var cryptSecret = "a!=ksljdk34ajSDkl";
var token = "1d3889647173d415e24195ce5cafc36c1edcc053";
function _encodeUrlSaveBase64(str) {
return str.replace(/\+/g, "-").replace(/\//g, "_").replace(/\=+$/, "");
}
function _decodeUrlSaveBase64(str) {
str = (str + "===").slice(0, str.length + (str.length % 4));
return str.replace(/-/g, "+").replace(/_/g, "/");
}
function _encrypt(data) {
var cipher = crypto.createCipher("aes256", cryptSecret);
var str = cipher.update(data, "utf8", "base64") + cipher.final("base64");
str = _encodeUrlSaveBase64(str);
return str;
}
function _decrypt(data) {
var str = _decodeUrlSaveBase64(data);
var decipher = crypto.createDecipher("aes256", cryptSecret);
str = decipher.update(str, "base64", "utf8") + decipher.final("utf8");
return str;
}
console.log("token: ", token);
var encrypted = _encrypt(token);
console.log("encrypted:", encrypted);
// change fourth letter to upper-case B (instead of lower-case)
encrypted = "bYzBYnU8FX7Rxs6Hae-yZkXvlwlRnhMQdLrT07e6YBy79nrK8FIpbKbxsYsXUmbk";
console.log("changed :", encrypted);
console.log("decrypt :", _decrypt(encrypted));
and it outputs:
token: 1d3889647173d415e24195ce5cafc36c1edcc053
encrypted: bYzbYnU8FX7Rxs6Hae-yZkXvlwlRnhMQdLrT07e6YBy79nrK8FIpbKbxsYsXUmbk
changed : bYzBYnU8FX7Rxs6Hae-yZkXvlwlRnhMQdLrT07e6YBy79nrK8FIpbKbxsYsXUmbk
decrypt : �g�
1��/b���e2.195ce5cafc36c1edcc053
where it should normally throw an error like this:
TypeError: error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt
at Decipher.Cipher.final (crypto.js:302:27)
at _decrypt (/***/test.js:25:59)
at Object.<anonymous> (/***/test.js:35:27)
at Module._compile (module.js:449:26)
at Object.Module._extensions..js (module.js:467:10)
at Module.load (module.js:349:32)
at Function.Module._load (module.js:305:12)
at Function.Module.runMain (module.js:490:10)
at startup (node.js:123:16)
at node.js:1128:3
Am I doing anything wrong or is this just the way this works?
You need to distinguish between encryption (hide something) and signing (validate something). In your case you are hiding the content of the token. A simple solution for validating a token is a hash using a secret:
hashvalue = tokenvalue + hashfunction(tokenvalue + secret)
When validating, cut out the tokenvalue and calculate the hashvalue again, if it does not match someone must have tampered the token. A popular example of this is LTPA v1.
This scheme has some shortcomings, the biggest would be that every party needs the secret to validate the tokens and is therefore able to create a new valid token. IBM switched to public key for LTPA v2 because of this.