Convert jwk to pem in nest.js - nestjs

I have this jwk key that I wanto convert into pem:
const jwkey = {
kty: 'RSA',
kid: 'eecb0ced-4d49-4100-9547-841e4100b756',
n: '...very long string',
e: 'AQAB',
alg: 'RS256',
use: 'sig',
};
I have tried the libraries like jose, node-rsa and jwk-To-Pem but somehow all of them are failing and throws error here and there while configuring.
I literally have no idea how to configure it.
below is the example of node-rsa conversion:
const key = new NodeRSA();
key.importKey(
{
n: Buffer.from(jwkey.n, 'base64'),
e: Buffer.from(jwkey.e, 'base64'),
},
'components'
);
const pem = key.exportKey('pkcs1-private-pem');

You could use 'jwk-to-pem' module.
const jwkToPem = require("jwk-to-pem")
const jwkey = {
kty: "RSA",
alg: "RS512",
kid: "26887d3ee3293c526c0e6dd05f122df53aa3f13d7dad06d25e266fa6f51db79fb52422aaf79f121476237e98dcd6640350fee47fec70e783544ec9a36e4605bc",
use: "sig",
n: "14m79mVwIE0JxQdKrgXVf7dVcBS90U0TvG7Yf7dG4NJocz1PNUrKrzGhe_FryOe0JahL_sjA2_rKw7NBCpuVx_zSPFRw6kqjewGicjXGus5Fmlf3zDuqwV4BWIFHyQexMPOly0agFfcM0M0MgBULXjINgBs9MwnRv7JVfRoGqXHsNM45djFDd3o4liu4LPlge_DquZUFLNu-BYAyAlWkz0H2TepZhGrN9VEPmxzQkNzXc1R4MpZvbxrRRgaAA2z094ik3hk86JhfyFq-LDcueZhtshmrYZ95LWgMlQ7PixkeK1HkeEYMt20lmNzR8B8KabimYmibxA4Ay9gpRwfp-Q",
e: "AQAB",
}
console.log("jwkey : ", jwkey)
const pem = jwkToPem(jwkey)
console.log("create pem : ", pem)

I have tried the libraries like jose
The following will always work for an RSA public key, using jose.
const jwk = {
kty: 'RSA',
n: 'pksialyL7vdNKFhL9Nu1uVs49L8vKqtRB3O_hSA_bICHKvNLX9_5NtoN1oDV7Mjz_rBOxM3AcnPV97OJPBrHKbQxhX3P5PN0LTqVLh0_Pcn5s7KHRpT1-jhHad5FaeJ2WdBRUhr8cEbVnYvAEmGfB3kduyPGNqSAbJC0PtEEJZlNralFLyJV0wEC1t7a9hRAXXkL52D_UbKnF05Gjn1XioHOKxEjlZirzrj0z8SUHXAD8UPJMAGvzakBRb_K46hcdl8G9_7t3RLjVyGwVwnZOWBZosUU4jOtQx0OZtDEO4rbw4yDMA4cHJs1FCDDsXi_r1tlZ5EKSzU51YDVx3txNQ',
e: 'AQAB'
}
const key = await jose.importJWK({
...jwk,
ext: true,
}, 'RS256')
const pem = await jose.exportSPKI(key)
console.log(pem)
// -----BEGIN PUBLIC KEY-----
// MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApksialyL7vdNKFhL9Nu1
// uVs49L8vKqtRB3O/hSA/bICHKvNLX9/5NtoN1oDV7Mjz/rBOxM3AcnPV97OJPBrH
// KbQxhX3P5PN0LTqVLh0/Pcn5s7KHRpT1+jhHad5FaeJ2WdBRUhr8cEbVnYvAEmGf
// B3kduyPGNqSAbJC0PtEEJZlNralFLyJV0wEC1t7a9hRAXXkL52D/UbKnF05Gjn1X
// ioHOKxEjlZirzrj0z8SUHXAD8UPJMAGvzakBRb/K46hcdl8G9/7t3RLjVyGwVwnZ
// OWBZosUU4jOtQx0OZtDEO4rbw4yDMA4cHJs1FCDDsXi/r1tlZ5EKSzU51YDVx3tx
// NQIDAQAB
// -----END PUBLIC KEY-----

Related

Decrypt pgp message using only public key

In the following use case, It shows that using the private key when encrypting a message is optional but when decrypting the message, they make the private key mandatory!
How can I encrypted and decrypt a message using only one key, the public key?
const openpgp = require('openpgp'); // use as CommonJS, AMD, ES6 module or via window.openpgp
(async () => {
// put keys in backtick (``) to avoid errors caused by spaces or tabs
const publicKeyArmored = `-----BEGIN PGP PUBLIC KEY BLOCK-----
...
-----END PGP PUBLIC KEY BLOCK-----`;
const privateKeyArmored = `-----BEGIN PGP PRIVATE KEY BLOCK-----
...
-----END PGP PRIVATE KEY BLOCK-----`; // encrypted private key
const passphrase = `yourPassphrase`; // what the private key is encrypted with
const publicKey = await openpgp.readKey({ armoredKey: publicKeyArmored });
const privateKey = await openpgp.decryptKey({
privateKey: await openpgp.readPrivateKey({ armoredKey: privateKeyArmored }),
passphrase
});
const encrypted = await openpgp.encrypt({
message: await openpgp.createMessage({ text: 'Hello, World!' }), // input as Message object
encryptionKeys: publicKey,
signingKeys: privateKey // optional
});
console.log(encrypted); // '-----BEGIN PGP MESSAGE ... END PGP MESSAGE-----'
const message = await openpgp.readMessage({
armoredMessage: encrypted // parse armored message
});
const { data: decrypted, signatures } = await openpgp.decrypt({
message,
verificationKeys: publicKey, // optional
decryptionKeys: privateKey
});
console.log(decrypted); // 'Hello, World!'
// check signature validity (signed messages only)
try {
await signatures[0].verified; // throws on invalid signature
console.log('Signature is valid');
} catch (e) {
throw new Error('Signature could not be verified: ' + e.message);
}
})();

Is it possible to generate RSA keys from a string?

I am using the node-rsa package to do asymmetric encryption with the RSA function.
Currently, I am generating my public and private keys like so:
generateKeys = function() {
const key = new NodeRSA({ b: 1024 });
return {
public: key.exportKey('public'),
private: key.exportKey('private'),
}
}
Is there any possible way to generate a key from a given string? I want to do this so that my users can easily write down their private key, which is important to my project. After all, it is nearly impossible to write down a private key that is 1024 characters long.
I am hoping for something like this:
const key = new NodeRSA({ b: 1024 }, "Secret goes here")
I think this may be possible because the sha256 function can accept any string to hash. I know RSA encryption isn't really a hashing function, so I am not sure if the same effect is possible.
Any help is appreciated!
It seems that there is a simple way of doing this. There is a package called cryptico
that can do the thing.
First install the package:
npm i cryptico
Example
const cryptico = require('cryptico');
const PassPhrase = "The Moon is a Harsh Mistress.";
// The length of the RSA key, in bits.
const Bits = 1024;
const RSAkey = cryptico.generateRSAKey(PassPhrase, Bits);
const PublicKeyString = cryptico.publicKeyString(RSAkey);
A better and complete example can be found here
Update
So, if you need an ASYMMETRIC encryption (As I know that works with a pair of keys which are called publickey and privatekey) you can simply use a pure Node.js implementation.
Example
const { generateKeyPairSync, publicEncrypt, privateDecrypt } = require('crypto');
const PassPhrase = "The Moon is a Harsh Mistress.";
const Bits = 1024;
const encryptWithRSA = (input, publickey) => {
const buffer = Buffer.from(input, 'utf-8');
const encrypted = publicEncrypt(publicKey, buffer);
return encrypted.toString("base64");
}
const decryptWithRSA = function (input, privatekey) {
const buffer = Buffer.from(input, 'base64');
const decrypted = privateDecrypt(
{
key: privatekey,
passphrase: PassPhrase,
},
buffer,
)
return decrypted.toString("utf8");
};
const { privateKey, publicKey } = generateKeyPairSync('rsa', {
modulusLength: Bits,
publicKeyEncoding: {
type: 'spki',
format: 'pem'
},
privateKeyEncoding: {
type: 'pkcs8',
format: 'pem',
cipher: 'aes-256-cbc',
passphrase: PassPhrase
}
});
const encrypted = encryptWithRSA('yes i know', publicKey)
console.log(encrypted);
console.log(decryptWithRSA(encrypted, privateKey));
Output (The encrypted value is random as you know)
t3Gw+PlKn84gx2wkj99we345C6ZjIElpgDkzXjio2aWRwI28qTMev14H7o219P6Lw9STGnfK4FgTYO/cvLGlzplqRv6X5AgrstwsGQN88wmKHe5+6cxlpzPFNPWLUqtAvsIOPZe+ghaRGCkOT2ETUp4PiqwOTJ2EtmyVqQHt+f4=
yes i know

Generate Signature using Private Key and "SHA256 with RSA" algorithm in Node.js

Our system will be calling an API with Authentication server. This server is built in java and requires a lot of key encryption. One requirement is to generate a Signature with client's(it's us) private key using "SHA256 with RSA" algorithm. I have done this in Java but not sure if it's right. Rur server is written in Nodejs. How can I translate below Java code to Node.js?
public static String signSHA256RSA(String input, String strPk) throws Exception {
Security.addProvider(new BouncyCastleProvider());
// Remove markers and new line characters in private key
String realPK = strPk.replaceAll("-----END PRIVATE KEY-----", "")
.replaceAll("-----BEGIN PRIVATE KEY-----", "")
.replaceAll("\n", "");
byte[] b1 = Base64.getDecoder().decode(realPK);
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(b1);
KeyFactory kf = KeyFactory.getInstance("RSA");
Signature privateSignature = Signature.getInstance("SHA256withRSA");
privateSignature.initSign(kf.generatePrivate(spec));
privateSignature.update(input.getBytes("UTF-8"));
byte[] s = privateSignature.sign();
return Base64.getEncoder().encodeToString(s);
}
NodeJS has a built in utilities in the crypto package that could help you with that
More on that here https://nodejs.org/api/crypto.html#crypto_class_sign
here's an example from the docs
const { privateKey, publicKey } = crypto.generateKeyPairSync('ec', {
namedCurve: 'sect239k1'
});
const sign = crypto.createSign('SHA256');
sign.write('some data to sign');
sign.end();
const signature = sign.sign(privateKey, 'hex');
const verify = crypto.createVerify('SHA256');
verify.write('some data to sign');
verify.end();
console.log(verify.verify(publicKey, signature, 'hex'));
// Prints: true
Here is the complete Flow
Generate Public and Private keys
const crypto = require('crypto');
const fs = require('fs');
const { privateKey, publicKey } = crypto.generateKeyPairSync('rsa', {
modulusLength: 2048,
publicKeyEncoding: {
type: 'pkcs1',
format: 'pem'
},
privateKeyEncoding: {
type: 'pkcs1',
format: 'pem'
}
});
// Writing keys to files.
fs.writeFileSync("./private.key", privateKey);
fs.writeFileSync("./public.key", publicKey);
Sign and Verify using Public and Private keys
const crypto = require('crypto');
const fs = require('fs');
// Reading keys from files.
const privateKey = fs.readFileSync('./private.key');
const publicKey = fs.readFileSync('./public.key');
const data = Buffer.from("My Name is MHamzaRajput");
const signature = crypto.sign('RSA-SHA256', data, privateKey).toString("base64");
console.log("Signing done", signature);
const verify = crypto.verify('RSA-SHA256', data, publicKey, Buffer.from(signature, "base64"));
console.log("verfy done", verify);

how to deterministically generate a key from a passphrase with nodejs crypto module

I want to generate a key pair, in NodeJS v10.16.3, using the crypto module, from the hash of a passphrase or seed.
I'm getting a public and private key and I'm able to sign with it.
They look like this;
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEaScBwOHQRRIDzPb3cnz3TZfHYOG7
pM7M8PkZFq7DjElFUrkavQf9NSopuJcIZ0EOmlQq8jPLbLdHoUO9M9a1Pw==
-----END PUBLIC KEY-----
The code to create this;
Basically from the doc found here;
https://nodejs.org/api/crypto.html#crypto_crypto_generatekeypair_type_options_callback
var seed = "a very long and random passphrase or seed";
let sha256 = require('js-sha256');
seed = sha256(seed);
const { generateKeyPair } = require('crypto');
generateKeyPair('ec', {
namedCurve: 'P-256',
publicKeyEncoding: {
type: 'spki',
format: 'pem'
},
privateKeyEncoding: {
type: 'pkcs8',
format: 'pem',
cipher: 'aes-256-cbc',
passphrase: seed
}
}, (err, publicKey, privateKey) => {
if (err) { throw err; }
console.log('Node Private : ', privateKey);
console.log('Node public : ', publicKey);
const fs = require('fs');
fs.writeFile("test.dat", privateKey, function(err) {
if(err) {
return console.log(err);
}
console.log("The file was saved!");
});
});
How can I generate a keypair using a seed so I can reproduce that same key again? The seed I am using is not changing but the key is.
If I want to create addresses by hashing the public key. I wouldn't be able to reproduce the same hash.
I want to do something similar to what is done with crypto wallet right now.

create RSA SHA256 using crypto for jsonwebtoken on nodejs

I see how to create HMAC 256 encrypted JWTs in NodeJS using Crypto, and the jsonwebtoken library. It's pretty easy
//encrypt & sign with HS256
const jwt = require('jsonwebtoken');
const pass = crypto.randomBytes(256).toString('hex');
const A = {algorithm:'HS256'};
const token = jwt.sign({ foo: 'bar' }, pass, A);
//decrypt & verify
jwt.verify(token, pass, A, function(err, decoded)
{
console.log('decode ',decoded);
console.log('err ',err);
res.send({error:err, text:decoded});
});
I would like to replace 'pass' with an 'RSA 256 SHA', and A with {algorithm:'RS256'}
In node crypto JS's documentation I see the command
const sign = crypto.createSign('RSA-SHA256');
to create the rsa-sha256
However then the documentation has the function
getPrivateKeySomehow()
Which is not defined or part of crypto.getPrivateKeySomehow()
So I guess I just need help getting the RSA-SHA-256 string returned from crypto, so that I can pass that into jsonwebtoken to sign my JWT.
Note: I do not want to read a private.key from a static file on my server because i see having a single private key for all my users as too big a security risk, hence why i am generating my own 256 bytes passwords and storing them off-site (not included in this post)
also, i'm not sure if i should do something like this (without using something like openssl from command line?)
const begin = '-----BEGIN RSA PRIVATE KEY-----\n';
const enc = crypto.randomBytes(256).toString('base64') + '\n';
const end = '-----END RSA PRIVATE KEY-----'
const pass = sign.sign(begin + enc + end);
const A = {algorithm:'RS256'};
const token = jwt.sign({ foo: 'bar' }, pass, A);
Take a look at this example bellow:
signExample = (str) => {
crypto.generateKeyPair('rsa', {
modulusLength: 1024,
publicKeyEncoding: {
type: 'spki',
format: 'pem'
},
privateKeyEncoding: {
type: 'pkcs8',
format: 'pem'
}
}, (err, publicKey, privateKey) => {
// sign String
var signerObject = crypto.createSign("RSA-SHA256");
signerObject.update(str);
var signature = signerObject.sign({key:privateKey,padding:crypto.constants.RSA_PKCS1_PSS_PADDING}, "base64");
console.info("signature: %s", signature);
//verify String
var verifierObject = crypto.createVerify("RSA-SHA256");
verifierObject.update(str);
var verified = verifierObject.verify({key:publicKey, padding:crypto.constants.RSA_PKCS1_PSS_PADDING}, signature, "base64");
console.info("is signature ok?: %s", verified);
});
}
Steps:
First you create an key pair with crypto.generateKeyPair('rsa', { ... desired key options
Create a Sign object - crypto.createSign("RSA-SHA256")
The string wanted to be signed - SignerObject.update(str)
Sign the string with your private key - signerObject.sign(
Option to salt - padding:crypto.constants.RSA_PKCS1_PSS_PADDING

Resources