Nodejs construct the public key using public key string - node.js

I have a public key string as follows
let pk_str = "public key strig here" and I am using the library jose to verify a JWS
(async() => {
const decoder = new TextDecoder();
const jws = vc_proof_value;
const { payload, protectedHeader } = await compactVerify(jws, pk_str);
console.log(protectedHeader)
console.log(decoder.decode(payload))
})();
I am getting the following error when trying to run the script
(node:75986) UnhandledPromiseRejectionWarning: TypeError: Key must be one of type KeyObject, CryptoKey, or Uint8Array. Received type string
Is there a way to construct the key ?

In NodeJS (I refer to NodeJS, since you have tagged this), the public key is passed as KeyObject wich is created with crypto.createPublicKey(). You didn't say much about the key, presumably it's PEM encoded (since it's a string). In this case, you simply have to pass the PEM encoded key:
var key = crypto.createPublicKey(pk_str);
If in the compactVerify() call pk_str is replaced by key, verification works.
In addition to PEM keys (default), JWK and DER keys (X.509/SPKI or PKCS#1) are also supported.

Here is the documentation for the key argument of all applicable functions.

Related

Imported a public RSA key into nodejs

I am trying to transfer a public RSA key generated in swift into my Nodejs server. I generated the RSA key using the following code.
private var clientPriv: SecKey?
private var clientPub: SecKey?
private init(){
let params: [String: Any] = [
String(kSecAttrKeyType): kSecAttrKeyTypeRSA,
String(kSecAttrKeySizeInBits): 4096
]
SecKeyGeneratePair(params as CFDictionary, &clientPub, &clientPriv)
}
I send the key to my server using this code
...
guard let clientPub = clientPub else { return }
let key = SecKeyCopyExternalRepresentation(clientPub, nil)! as Data
let pem = exportToPEM(data: key, withLabel: "PUBLIC KEY")
let data = ["clientPub": pem]
var urlRequest = URLRequest(url: url)
do {
try urlRequest.httpBody = JSONSerialization.data(withJSONObject: data)
urlRequest.httpMethod = "POST"
urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
}catch let err {
print(err)
}
let task = URLSession.shared.dataTask(with: urlRequest){ data, response, error in
guard let data = data, error == nil else {
return
}
...
The exportToPem helper looks like this.
public func exportToPEM(data: Data, withLabel label: String) -> String {
let key = data.base64EncodedString(options: [.lineLength64Characters])
var pem = "-----BEGIN \(label)-----\n"
pem += key
pem += "\n-----END \(label)-----\n"
return pem
}
On my Nodejs side, I am using express to handle my requests and body-parser to parse my json post data in requests. Here is what my Nodejs receiving code looks like.
app.post('/api/init', jsonParser, function (req, res) {
console.log(req.body.clientPub);
CLIENTPUB = crypto.createPublicKey({ key: req.body.clientPub, format: 'pem', type: 'pkcs1' });
console.log(CLIENTPUB);
res.write(JSON.stringify({'server-pub': SERVERPUB.toString()}));
res.end()
});
The problem is that the function crypto.createPublicKey keeps throwing an error, error:0D0680A8:asn1 encoding routines:asn1_check_tlen:wrong tag. I have tried many different ways to write the string of my key but no matter what it seems that the crypto createPublicKey just refuses to take it. I have tried keeping the format with \n every 64 bytes or without \n at all, removing the header/footer altogether, and many other different combinations. I can not figure out why it keeps refusing to accept any format I send it. I have also tried using just the der format but that also gets refused.
Can anyone please offer me any advice on how to get this function to accept my key format?
SecKeyCopyExternalRepresentation() exports the public key in PKCS#1 format, which is correctly specified on the NodeJS side in the createPublicKey() call with 'pkcs1' for the type parameter.
However, the header and footer texts of a PEM encoded key for PKCS#1 format are BEGIN RSA PUBLIC KEY and END RSA PUBLIC KEY, so when calling exportToPEM(), "RSA PUBLIC KEY" must be passed in the second parameter instead of "PUBLIC KEY":
let pem = exportToPEM(data: key, withLabel: "RSA PUBLIC KEY")
BEGIN PUBLIC KEY and END PUBLIC KEY are used for a PEM encoded public key in X.509/SPKI format. This is what the error message wrong tag means.

Failing in convert a mnemonic to a seed for a solana wallet

I'm trying to use a wallet seed on the backend, using nodejs, to connect in blokchain. The Keypair module from "#solana/web3.js" library has a fromSeed method, that I use with input from another method, from the bip39 library, that converts my mnemonic to a seed. This my code
const mnemonic = <My-mnemonic>
console.log(bip39.validateMnemonic(mnemonic)) // true
bip39.mnemonicToSeed(mnemonic).then(buffer => Keypair.fromSeed(buffer)).catch(err => console.log(err))
This is my error
Error: bad seed size
at Function.nacl.sign.keyPair.fromSeed (/home/diazrock/Carrera/Elasbit/NFT's/mint-nft-solana/node_modules/tweetnacl/nacl-fast.js:2329:11)
at Function.fromSeed (/home/diazrock/Carrera/Elasbit/NFT's/mint-nft-solana/node_modules/#solana/web3.js/lib/index.cjs.js:5625:53)
at bip39.mnemonicToSeed.then.buffer (repl:1:55)
Keypair.fromSeed() takes a Unit8Array check
buffer.toJSON().data this returns a 64 length array, So this contains both the public key and private key respectively. Check this
let a = new Uint8Array(buffer.toJSON().data.slice(0,32))
const key = Keypair.fromSeed(a);
I tried the above and this works.
key has a public key and private key component.

Create RSA-SHA256 sign with PEM key

I've been creating a gateway for a legacy service, this legacy service needs a signature as a body parameter of a PUT request, in order to create this sign I need to follow the following steps:
Create a hash with certain text as data, this hash needs to be SHA256.
Encrypt the result of the hash using RSA with a PEM key
Encode the result of the RSA to Base64
Following the previous steps I create the following code
export class Signature {
// class body
public static sign(text: string){
const key = readFileSync('key.pem')
const passphrase = '12345678'
const createdSign = createSign('RSA-SHA256')
createdSign.write(text)
createdSign.end()
return createdSign.sign({ key, passphrase }).toString('base64')
}
}
But I'm not sure if this the correct implementation, taking into consideration the previous steps, and the existence of the hash API in NodeJS.
If someone could tell me if I'm correctly implementing this algorithm.

How to generate a PEM-formatted Key from a 64Byte raw hex-formatted Key

I have the following problem:
After recreating the public key from a signed transaction, I try to encrypt some payload with it.
However the node.js-module named "crypto" is expecting a pem-formatted key in the publicEncrypt(key, payload) function.
My Question:
How can I create the pem-formatted key from a raw hex-encoded key?
Here is the recreated 64 Byte public key:
9f9f445051e788461952124dc08647035c0b31d51f6b4653485723f04c9837adb275d41731309f6125c14ea1546d86a27158eec4164c00bab4724eed925e9c60
Information:
I know, that a pem-format-key consists of base64 encoded data, a header and a footer.
-----BEGIN RSA PUBLIC KEY-----
BASE64 ENCODED DATA
-----END RSA PUBLIC KEY-----
I have also found out that within the base64 encoded data the following DER-structure is present:
RSAPublicKey ::= SEQUENCE {
modulus INTEGER, -- n
publicExponent INTEGER -- e
}
So the only question is how to get from the raw hex-encoded key to this DER-structure.
I would appreciate any help!
Problem solved
Thanks to Maarten Bodewes and his comment regarding the key being secp256k1 and not RSA.
After some further research, I finally managed to encrypt/decrypt a message asymmetrically with secp256k1 keys.
With the help of Cryptos ECDH class I managed to create a key-object and then assign the private key to it. When assigned, you can easily derive the public key with getPublicKey(). All participants would create a key object for themselves and assign their private keys to it. Then they share their retrieved public keys (in my case over a shared medium). In addition I used a npm-package named standard-ecies which provides the ECIES encryption-scheme.
Code:
const crypto = require('crypto');
const ecies = require('standard-ecies');
var buffer = new Buffer("Hello World");
var ecdh = crypto.createECDH('secp256k1');
ecdh.setPrivateKey(privateKey);
var encryptedText = ecies.encrypt(ecdh.getPublicKey(), buffer);
var decryptedText = new Buffer(ecies.decrypt(ecdh, encryptedText));
I should have noticed this, because crypto's encryption function (link to the api-doc) clearly works only with RSA keys and not with secp256k1 keys.
Anyway if someone has a similar issue, I hope this answer helps!

Using xml-crypto with PSHA1

Is it possible to use XML Crypto using a PSHA1 (http://schemas.xmlsoap.org/ws/2005/02/trust/CK/PSHA1) key?
I have both secrets and generate a PSHA1 key string using them, however this fails with:
Error: error:0906D06C:PEM routines:PEM_read_bio:no start line
I'm not what format this key needs to be in to be accepted, it's not a PEM certificate, just a string based on 2 provided nonce's. One provided by the client during the request and one provided by the server in the response.
const sig = new SignedXml();
sig.addReference("/*[local-name()='Envelope']/*[local-name()='Header']/*[local-name()='Security']/*[local-name()='Timestamp']");
sig.signingKey = '<SIGNING_KEY>';
sig.computeSignature(xml);
fs.writeFileSync('signed.xml', sig.getSignedXml());
It fails on the signer.sign line here:
this.getSignature = function(signedInfo, signingKey) {
var signer = crypto.createSign("RSA-SHA1")
signer.update(signedInfo)
var res = signer.sign(signingKey, 'base64')
return res
}
The PSHA1 algorithm isn't implemented in the Crypto Library, but there's a PSHA1 npm package you can use to generate the secret key. After that you can generate a SHA1 hash using the message and key in the standard way.
I asked a very similar question here, which answers the question:
https://stackoverflow.com/a/55053741/5065447

Resources