By using the crypto module, it is easy to create a private/public key Pair in node. But how can I compute the »fingerprint« of a key?
OpenCrypto has something like that:
crypt.getFingerprint(key, options).then(function (fingerprint) {
console.log(fingerprint)
})
What is the equivalent of nodes crypto module for that?
OpenCrypto.getFingerprint exports a public RSA key in the X509 DER format and creates a hash for these data. The same applies to a private RSA key with the difference that the private key is exported in the Pkcs8 DER format. The digest can be specified in the options (default: SHA 512) and also whether the data are returned as buffer or as hexadecimal string (default: hexadecimal string).
In the NodeJS code, keys can be generated with crypto.generateKeyPair, whereby the key format can be specified explicitly. If the keys aren't already in the appropriate formats (X509 DER and Pkcs8 DER) key conversions can be performed to produce the same fingerprints that OpenCrypto.getFingerprint creates. Suitable functions for these operations are crypto.createPublicKey or crypto.createPrivateKey. Finally the hash has to be generated with crypto.createHash.
Update:
The fingerprint is nothing else than a hash value, e.g. with the digest SHA-512 (as in OpenCrypto.getFingerprint):
var fingerprint = crypto.createHash('sha512').update(key).digest('hex'); // Fingerprint (hash) as hexadecimal string
where key is a public or private key in any format (string, Buffer, ...). If the key is given as X509 DER (public) or as PKCS8 DER (private), then the fingerprint matches that of OpenCrypto.getFingerprint.
If the key is in another format, the fingerprint can also be determined in this way. However, if the fingerprint should match the value provided by OpenCrypto.getFingerprint, the key must of course be converted into the formats used by OpenCrypto.getFingerprint before the hash is generated. This conversion isn't very complex, e.g. the conversion of a public PKCS1 PEM key (publicKey) into a X509 DER key (publicKeyDER) including the generation of the hash:
var publicKeyDER = crypto.createPublicKey(publicKey, { type: 'pkcs1', format: 'pem' }).export({ type: 'spki', format: 'der' }); // Convert a public PKCS1 PEM key into a X509 DER key
var fingerprint = crypto.createHash('sha512').update(publicKeyDER).digest('hex'); // Fingerprint (hash) as hexadecimal string
The bottom line is that these are functionally the same operations that are performed in OpenCrypto.getFingerprint. To my knowledge, there is no OpenCrypto.getFingerprint counterpart in the NodeJS crypto module. But with only little effort you can write your own function using the above crypto functions.
Related
I have been attempting to retrieve the raw public key and place it in an object of type bytearray without success.
from cryptography import x509
from cryptography.hazmat.primitives.serialization import Encoding
from cryptography.hazmat.primitives.serialization import PublicFormat
cert = x509.load_pem_x509_certifcate(pem_encoded_cert)
pk = cert.public_key()
I have been attempting to retrieve the raw public key and place it in an object of type bytearray without success; e.g.
in_buf = bytearray(pk.public_bytes(Encoding.OpenSSH, PublicFormat.OpenSSH))
I cannot find a combination of Encoding and PublicFormat that provides the raw public key bytes; is the above the correct approach or is there a better solution?
Thanks in advance.
I am trying to convert https://clover.app.box.com/s/rz18bni3bpmdrc8wc92xm4w8h9grrtty from Java to node.js
I am using the node-rsa package and getting error:0306E06C:bignum routines:BN_mod_inverse:no inverse when trying to encrypt using an imported public key.
According to the clover example, I want to
Parse the Base64 public key string (returned by the CDN). Obtain the modulus and exponent.
Generate an RSA public key using the modulus and exponent values.
Prepend the prefix value to the card number.
Using the public key, encrypt the combined prefix and card number.
Base64 encode the resulting encrypted data into a string.
I was able to get the modulus and exponent, and it matches the result in Java:
modulus: 24130287975021244042702223805688721202041521798556826651085672609155097623636349771918006235309701436638877260677191655500886975872679820355397440672922966114867081224266610192869324297514124544273216940817802300465149818663693299511097403105193694390420041695022375597863889602539348837984499566822859405785094021038882988619692110445776031330831112388738257159574572412058904373392173474311363017975036752132291687352767767085957596076340458420658040735725435536120045045686926201660857778184633632435163609220055250478625974096455522280609375267155256216043291335838965519403970406995613301546002859220118001163241
exponent: 415029
Now I want to create a public key with it, and encrypt a message:
const key = new NodeRSA();
// generate RSA public key using mod and exp values
key.importKey({
n: Buffer.from('24130287975021244042702223805688721202041521798556826651085672609155097623636349771918006235309701436638877260677191655500886975872679820355397440672922966114867081224266610192869324297514124544273216940817802300465149818663693299511097403105193694390420041695022375597863889602539348837984499566822859405785094021038882988619692110445776031330831112388738257159574572412058904373392173474311363017975036752132291687352767767085957596076340458420658040735725435536120045045686926201660857778184633632435163609220055250478625974096455522280609375267155256216043291335838965519403970406995613301546002859220118001163241', 'hex'),
e: Buffer.from('415029', 'hex')
}, 'components-public');
// using public key, encrypt message
// base64 encode encrypted data to string
const encryptedString = key.encrypt(Buffer.from('message', 'hex'), 'base64', 'hex');
However, I am getting the no inverse error mentioned above. It seems to be caused by the modulus. If I change it to something shorter, the error goes away.
I have a problem and I want some help.
I need to send a message from sender to receiver, and this message content signed data and public key and other things. note that I use the certificate x509 (the public key is from the certificate). On the receiver side, I must verify the signature of the data ( true or not). So, I use the public key of the sender for verification. But I had a problem, the public key is a string format. and i try to convert it . but unfortunately, i don't found any solution.
this the message that will be send:
data['message'] = data
data['_signature'] = self.sign_data(data)
data['_public_key'] = str ( self.certificate.public_key())
You cannot convert the public key (certificate.public_key()) into string by using str, because this method will return key object.
if you need to encode the public key as PEM string, then you have to do it correctly, by serialization into PEM:
public_pem = public_key.public_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo
)
Then from other side, you could load the PEM key and use it:
from cryptography.hazmat.primitives import serialization
public_key2 = serialization.load_pem_public_key(public_pem, default_backend())
Hi I'm trying to write a public key to a PEM file.
org.bouncycastle.openssl.jcajce.JcaPEMWriter seem to be the right tool, but it uses org.bouncycastle.openssl.jcajce.JcaMiscPEMGenerator which expects keys that is an instance of java.security.PublicKey.
Unfortunately, all the rest of the project I'm working on uses AsymmetricKeyParameter for public keys. I checked inside it has everything you would want to know from a public key, including point G and curve order, but it's not compatible with java.security.PublicKey.
Is there a way to use JcaPEMWriter if what I have is instances of AsymmetricKeyParameter? I use ECDSA key by the way.
(I am at first surprised at this because BouncyCastle's JcaPEMWriter isn't compatible with their own class, AsymmetricKeyParameter)
It doesn't look like the JcaPEMWriter can directly handle an AsymmetricKeyParameter object. But it is relatively easy to convert an AsymmetricKeyParameter object to a PublicKey object.
For this BouncyCastle's EC5Util class can be applied which handles the conversion from ECDomainParameters to ECParameterSpec and from BouncyCastle's ECPoint to Java's ECPoint.
The PublicKey object can then be exported as before with the JcaPEMWriter as an X.509/SPKI PEM encoded public key:
// AsymmetricKeyParameter object containing the public EC key
AsymmetricKeyParameter asymmetricKeyParameter = ...
// Convert AsymmetricKeyParameter object to PublicKey object
ECPublicKeyParameters ecPublicKeyParameters = (ECPublicKeyParameters)asymmetricKeyParameter;
ECParameterSpec ecParameterSpec = EC5Util.convertToSpec(ecPublicKeyParameters.getParameters());
ECPoint ecPoint = EC5Util.convertPoint(ecPublicKeyParameters.getQ());
ECPublicKeySpec ecPublicKeySpec = new ECPublicKeySpec(ecPoint, ecParameterSpec);
PublicKey publicKey = KeyFactory.getInstance("EC").generatePublic(ecPublicKeySpec);
// Export PublicKey object with JcaPEMWriter in X.509/SPKI format, PEM encoded
...
i'm new to cryptography.
I'm creating the RSA key-pairs using crypto.generateKeyPairSync()
const crypto = require('crypto')
const { publicKey, privateKey } = crypto.generateKeyPairSync('rsa', {
modulusLength: 2048,
publicExponent: 3,
publicKeyEncoding: {
type: 'pkcs1',
format: 'pem'
},
privateKeyEncoding: {
type: 'pkcs1',
format: 'pem'
}
})
console.log(publicKey)
console.log(privateKey)
// print "n", "e", "d" keys
This works fine but the i need to extract the "n", "e", "d" keys so that an other app can encrypt and decrypt the messages. It would be great if this is possible without any 3rd-party libraries only the native NodeJS crypto module.
Also if it's not possible to extract the "n", "e", "d" keys, would it be possible to create a new public and private key using existing "n", "e", "d" keys from an other app?
This works fine but the i need to extract the "n", "e", "d" keys so that an other app can encrypt and decrypt the messages. It would be great if this is possible without any 3rd-party libraries only the native NodeJS crypto module.
First of all, the modulus n, public exponent e and private exponent d are not keys, they are components that are used to make up a key. As an RSA key contains at least two components you need some kind of method to distinguish them from each other. You need some kind of data structure which separates the components, which is exactly what the PKCS#1 ASN.1 specifications provide. Just specifying that you will deliver an RSA key using a PEM formatted PKCS#1 should be enough.
The private key, as the name suggests, should really not be shared. There is no such thing as a shared private key after all. Keys are generated for one specific entity, and are usually kept where they are generated (possibly exempting encrypted backup).
If you use only n and d then you will probably leave out any generated CRT parameters for the private key, which means that in the best case the RSA key operations don't run. In the worst case the RSA implementation is extremely picky and won't run at all.
Finally, as the documentation correctly indicates, you should be using 'spki' as output format (the public key as used within certificates, called the SubjectPublicKeyIdentifier, specified in the X.509 standards) and 'pkcs8' as they contain an indication of the key type used. These are probably better supported by other applications than PKCS#1.
If they are not able to decode it themselves then simply copy the base 64 into this site (online ASN.1 decoder) and copy the relevant values. You can find the order of the values (for 'pkcs1') in the PKCS#1 standard.
You could use the library pem-jwk to extract the components of the public/private keys like this:
const pem2jwk = require('pem-jwk').pem2jwk
console.log(pem2jwk(pemPublicKey));
OUTPUT:
{
kty: '...',
n: '...',
e: '...'
}
console.log(pem2jwk(pemPrivateKey));
OUTPUT:
{
kty: '...',
n: '...',
e: '...',
d: '...',
p: '...',
q: '...',
dp: '...',
dq: '...',
qi: '...'
}