Error: no importer for key when importing "pem" key - jose

The app follows the instruction on node-jose 2.0.0 for import .pem key. Here is the documentation:
To import and existing Key from a PEM or DER:
// input is either a:
// * String serialization of a JSON JWK/(base64-encoded) PEM/(binary-encoded) DER
// * Buffer of a JSON JWK/(base64-encoded) PEM/(binary-encoded) DER
// form is either a:
// * "json" for a JSON stringified JWK
// * "private" for a DER encoded 'raw' private key
// * "pkcs8" for a DER encoded (unencrypted!) PKCS8 private key
// * "public" for a DER encoded SPKI public key (alternate to 'spki')
// * "spki" for a DER encoded SPKI public key
// * "pkix" for a DER encoded PKIX X.509 certificate
// * "x509" for a DER encoded PKIX X.509 certificate
// * "pem" for a PEM encoded of PKCS8 / SPKI / PKIX //<<=="pem"
keystore.add(input, form).
then(function(result) {
// {result} is a jose.JWK.Key
});
The key was generated already with .pem form and its content is stored in nodejs config file as following in variable process.env.josePrivateKey:
-----BEGIN PRIVATE KEY-----
NC4CAQAwBQYcK2VwBCIEIIWUb0/MoKaBxQkmmPlHIGyPfDQb/U3D6jQ+gMUGtvpa
-----END PRIVATE KEY-----
Here is the code to add the pem key to keystore:
const jose = require('node-jose');
let keystore = jose.JWK.createKeyStore();
let privkey = await keystore.add(process.env.josePrivateKey, "pem"); //<<==this code throws error
However there is an error:
(node:11572) UnhandledPromiseRejectionWarning: Error: no importer for key
at JWKStore.value (C:\d\code\js\xyz\node_modules\node-jose\lib\jwk\keystore.js:305:21)
at initKeystore (C:\d\code\js\xyz\startup\accessstorageinfo.js:9:34) //<<==code as above
at Object.<anonymous> (C:\d\code\js\xyz\startup\accessstorageinfo.js:14:1)
at Module._compile (internal/modules/cjs/loader.js:1063:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
at Module.load (internal/modules/cjs/loader.js:928:32)
at Function.Module._load (internal/modules/cjs/loader.js:769:14)
at Module.require (internal/modules/cjs/loader.js:952:19)
at require (internal/modules/cjs/helpers.js:88:18)
at Object.<anonymous> (C:\d\code\js\xyz\server.js:13:1)
What is missing here for key importing?

(as of March 2021) node-jose does not support the following keys: Ed25519, Ed448, X25519, or X448. It also does not support the secp256k1 EC curve. For any of those it will return the error you're encountering. As a result it does not support the JWS Algorithms EdDSA or ES256K.
On the other hand https://github.com/panva/jose supports all of the above in Node.js runtime.

Related

Any util in jose to convert key from PEM to JWK for Ed25519?

An Ed25519 PEM key pair was generated as below:
-----BEGIN PRIVATE KEY-----
NC4CAQAwBQYcK2VwBCIEIIWUb0/MoKaBxQkmmPlHIGyPfDQb/U3D6jQ+gMUGtvpa
-----END PRIVATE KEY-----
-----BEGIN PUBLIC KEY-----
NCowBQYDK2VwAyEAWFnlEbTVgD4TilnSzyDmZK16dm1IeQURtHFcLhSwmDo=
-----END PUBLIC KEY-----
In jose 3.11.1, the parseJwk, taking JWK input, is used to generate keys used in signing and verification. Is there utility in jose converting PEM key to JWK used in paseseJwk or with a 3rd party utility? I didn't find one for nodejs project.
To get a KeyObject you don't need your keys in JWK format. It works with node's KeyObject instances. So you can easily do
const { createPublicKey, createPrivateKey } = require('crypto')
const publicKey = createPublicKey(pemPublicKey)
const privateKey = createPrivateKey(pemPrivateKey)
This is documented in the KeyLike interface the library uses in its docs.

DER Encoding Public Key created by cryptopp is different then openssl

I've been trying to create a DER encoded public key using an RSA private key. The way I normally create it is using the command line:
openssl rsa -pubout -outform DER -in ~/.keys/api_key.pem -out der_pub.der
When I use CryptoPP to create this file, they are slightly different. It seems it has an extra section. The one created by openssl has a little extra section. I'm assuming this is the BIT STRING mentioned in the CryptoPP API. https://www.cryptopp.com/docs/ref/class_r_s_a_function.html
void DEREncodePublicKey (BufferedTransformation &bt) const
encode subjectPublicKey part of subjectPublicKeyInfo, without the BIT STRING header
This is what my code looks like:
...
CryptoPP::RSA::PrivateKey rsaPrivate;
rsaPrivate.BERDecodePrivateKey(queue, false /*paramsPresent*/, queue.MaxRetrievable());
CryptoPP::ByteQueue bq;
rsaPrivate.DEREncodePublicKey(bq);
CryptoPP::FileSink fs1("cryptopp_pub.der", true);
bq.TransferTo(fs1);
CryptoPP::RSA::DEREncodePublicKey encodes subjectPublicKey part of subjectPublicKeyInfo, without the BIT STRING header
Try CryptoPP::RSA::PublicKey::DEREncode. Being careful to apply this to only the public key, as RSA::PrivateKey does overload the DEREncode method.
Here I'm using CryptoPP 8.2
Load DER encoded private key from disk
CryptoPP::RSA::PrivateKey private_key;
{
CryptoPP::FileSource file{"my.key", true};
private_key.BERDecodePrivateKey(file, false, -1);
}
Save out DER encoded public key
CryptoPP::FileSink sink{"my.pub", true};
CryptoPP::RSA::PublicKey{private_key}.DEREncode(sink);
OpenSSL:
# generate a new RSA private key (DER format)
openssl genrsa | openssl rsa -outform DER -out my.key
# hash/fingerprint the public key
openssl rsa -in my.key -inform DER -pubout -outform DER | openssl sha256
writing RSA key
362945ad4a5f87f27d3db3b4adbacaee0ebc3f778ee2fe76ef4fb09933148372
# compare against hash of our code sample's generated public key
cat my.pub | openssl sha256
362945ad4a5f87f27d3db3b4adbacaee0ebc3f778ee2fe76ef4fb09933148372
As another example; if we want CryptoPP to generate a SHA256 fingerprint:
std::string hash_out_str;
{
CryptoPP::SHA256 sha256;
CryptoPP::HashFilter filter{
sha256,
new CryptoPP::HexEncoder{
new CryptoPP::StringSink{hash_out_str}
}
};
CryptoPP::RSA::PublicKey{private_key}.DEREncode(filter); // intentionally slice to ensure we aren't exposing a public key
filter.MessageEnd();
}
std::cout << hash_out_str << '\n';
Outputs:
362945AD4A5F87F27D3DB3B4ADBACAEE0EBC3F778EE2FE76EF4FB09933148372
i.e., we need to copy/slice to a RSA::PublicKey to invoke the OpenSSL compatible DER encoding method

SWCrypt public key VS PKCS8PEM Key

I want to user SWCrypt for RSA encryption and decryption. i should send my public key base64 decoded to server. but when i try send generated public key base64 i can't get this error in server side:
let (privateKey, publicKey) = try CC.RSA.generateKeyPair(2048)
let publicKeyBase64 = publicKey.base64EncodedString()
error: java.security.InvalidKeyException: IOException: algid parse error, not a sequence
but when send PEMPublicKey getting successfully response.
let publicKeyPEM = SwKeyConvert.PublicKey.derToPKCS8PEM(publicKey)
what is difference between publicKeyBase64 and publicKeyPEM?
sample of generated key:
MIIBCgKCAQEAuWwCZpNXJtT2spBsDwrQaTFGVAjicM341Qzg+1whtlj9J60c/7HYe6AcGHa8Dinkiuk7Whs1Wpa34aa223WQsa+kFSNwkC6oDUXhewan3VEsv1uedzHc8JPlTXnItJsP8cIETFgHpdKWk462hU09mVCTtQTix0BEb8snS96wERvKq957OeaGtFasfT/bQfY0mbDu6eEMqswmfX8j84kuTfwWtqt6mLMTJaDwnsGc5WY1zkau68IQ/CBiiLpZ5hSVMs2pPj3Ao0+wNhR5MlMgdcwrU62SHWcMJ5cYssFgWZyZSvO3n/yW43fE5a1i+9Tm2trveGIdMR4d/MoA79/8IQIDAQAB
sample of generated PEM key :
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuWwCZpNXJtT2spBsDwrQaTFGVAjicM341Qzg+1whtlj9J60c/7HYe6AcGHa8Dinkiuk7Whs1Wpa34aa223WQsa+kFSNwkC6oDUXhewan3VEsv1uedzHc8JPlTXnItJsP8cIETFgHpdKWk462hU09mVCTtQTix0BEb8snS96wERvKq957OeaGtFasfT/bQfY0mbDu6eEMqswmfX8j84kuTfwWtqt6mLMTJaDwnsGc5WY1zkau68IQ/CBiiLpZ5hSVMs2pPj3Ao0+wNhR5MlMgdcwrU62SHWcMJ5cYssFgWZyZSvO3n/yW43fE5a1i+9Tm2trveGIdMR4d/MoA79/8IQIDAQAB
how can send generated public key simple of PEM key format?
thanks.
X509 is a standard for Public Key Infraestructure, not a encoding format. You can encode a X509 public key in PEM (base64), DER(binary) or XML. Also the binary data of the public key can be represented in PCKS#1 or X509 SubjectPublicKeyInfo.
In my knowledge PKCS#8 is a standard for private keys. See PKCS #8: Private-Key Information Syntax Standard. So I guess SWCrypt is really using X509 SubjectPublicKeyInfo (Maybe i have not read some RFCs), which is what your server is waiting for.
let publicKeyPEM = SwKeyConvert.PublicKey.derToPKCS8PEM(publicKey)
SubjectPublicKeyInfo encapsulates the public key into a ASN.1 structure adding a header. If you encode the raw data of the public key (DER) using publicKey.base64EncodedString, that header is not added and your server does not know how to manage it.

Load RSA private key generated by openssl to MacOS SecKeyRef fails

I am working on a project that needs to read a RSA private key (DER format) into a MacOS's SecKeyRef object.
I generate the key by
openssl genrsa -out private.pem 1024
openssl rsa -in private.pem -outform DER -out private.der
I load the private.der to MacOS by using SecKeyCreateWithData:
unsigned char *keyBytes; // contains all the bytes from the file "private.der"
int keyBytesLen; // length of the data loaded
NSData keyData = [NSData dataWithBytes:keyBytes length:keyBytesLen];
NSDictionary* options = #{(id)kSecAttrKeyType: (id)kSecAttrKeyTypeRSA,
(id)kSecAttrKeyClass: (id)kSecAttrKeyClassPrivate,
(id)kSecAttrKeySizeInBits: #1024};
SecKeyRef privateKey = SecKeyCrecateWithData((__bridge CFDataRef) keyData, (__bridge CFDictionaryRef) options, &error);
OSstatus status = SecKeyDecrypt(privateKey, .... some encrypted message);
// status returns -50 (errSecParam)
So I notice the privateKey is loaded successfully, but it fails to decrypt the encrypted message. I am 100% sure other parameters I have put into SecKeyDecrypt() function is correct because it works if I generate the privateKey by macOS's built-in function rather than loading from a DER-format file generated by openssl.
I also notice that when I dump the key (binary format), the first few bytes (version header) is different from the key generated by MacOS's built-in function and openssl. If the key is generated by MacOS (ex: SecKeyGeneratePair) and outputed by SecKeyCopyExternalRepresentation, the first few bytes look like:
3082 025d 0201 0002 8181 ...
while the key generated by openssl looks like:
3082 025c 0201 0002 8181 ...
I know (based on PKCS#1) that these bytes represent the "version" of the private key but not sure how to interpret it.
Any help or similar working example to load key generated by openssl to MacOS's API will be appreciated

How to use erlang public_key:decrypt_private?

I try to encrypt text with public RSA key and decrypt this text using a private RSA key. When I encrypt user public key it works.
encode public_key
encrypt_public_key(PlainText, PublicKey) ->
[ RSAEntry2 ] = public_key:pem_decode(PublicKey),
PubKey = public_key:pem_entry_decode( RSAEntry2 ),
public_key:encrypt_public(PlainText, PubKey).
But when I try to decrypt this text using a private key, it does not work, and I don't know why.
decode private key
decrypt_private_key(CryptText,PrivateKey) ->
[ RSAEntry2 ] = public_key:pem_decode(PrivateKey),
PrivKey = public_key:pem_entry_decode( RSAEntry2 ),
Result = public_key:decrypt_private(CryptText, PrivKey, rsa_pkcs1_padding ),
Result.
How i encode and try to decode
PublicKey = ems_util:open_file(?SSL_PATH ++ "/" ++ binary_to_list(<<"public_key.pem">>)),
CryptoText = ems_util:encrypt_public_key(ResponseData2,PublicKey),
PrivateKey = ems_util:open_file(?SSL_PATH ++ "/" ++ binary_to_list(<<"private_key.pem">>)),
%erro in this line
TextPlain = ems_util:decrypt_private_key(TextCrypt,PrivateKey).
Error
=ERROR REPORT==== 17-Mar-2017::10:59:29 ===
Ranch listener ems_http_server1, connection process <0.2159.0>, stream 1 had its request process <0.2160.0> exit with reason function_clause and stacktrace [{public_key,decrypt_private,[<<55,66,78,123,456,2456>>,<<55,173,2367,140,71>>,asn1_NOVALUE}],[{file,"public_key.erl"},{line,313}]},{ems_util,decrypt_private_key,2,[{file,"src/util/ems_util.erl"},{line,614}]},{ems_auth_user,do_barer_authorization,1,[{file,"src/auth/ems_auth_user.erl"},{line,51}]},{ems_dispatcher,lookup_request,1,[{file,"src/distpatcher/ems_dispatcher.erl"},{line,70}]},{ems_http_handler,init,2,[{file,"src/http/ems_http_handler.erl"},{line,22}]},{cowboy_handler,execute,2,[{file,"src/cowboy_handler.erl"},{line,39}]},{cowboy_stream_h,execute,3,[{file,"src/cowboy_stream_h.erl"},{line,172}]},{cowboy_stream_h,proc_lib_hack,3,[{file,"src/cowboy_stream_h.erl"},{line,157}]}]
I don't know what's happening.
I describle the solution for my problem. The problem is the public and the private keys are generated wrongly. The right way to generate a pair key rsa using openssl is:
openssl genrsa -out private.pem 2048
openssl rsa -in private.pem -out public.pem -outform PEM -pubout
These commands generate a correct key pair and the code now ir working correctly.

Resources