How to create java.security.PublicKey from AsymmetricKeyParameter - bouncycastle

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
...

Related

Extract public key from PEM encoded x509 public key certificate

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.

Nodejs crypto: Elliptic Curve to sign message and export public key as text

I want to achieve the following with the Nodejs crypto module:
I want to sign a message with my private key on a defined EC and have the signature as raw buffer/hex.
I want to have the respective public key as raw buffer/hex.
I can achieve both goals individually, but I can not achieve them together currently and it seems strange, that this is so hard to achieve with the node crypto module.
With the following code it is easy to generate a signature on a curve, but I cannot manage to decode the publicKey:
//Get pub and priv key from curve
const {publicKey, privateKey} = crypto.generateKeyPairSync('ec', {'namedCurve' : 'secp128r1'});
var message = "Hello";
var signer = crypto.createSign('sha256');
signer.update(message);
// Signature as raw hex. That's what I want.
var sigString = signer.sign(privateKey, 'hex'); // Needs a proper KeyObject
And with this code it is easy to extract the public key for a private key from a curve but the key returned by curve.getPrivateKey is not allowed for signing:
refCurve = crypto.createECDH('secp128r1');
//Public key split into x and y components. That's what I want.
refPubKey = {
x: '0x' + curve.getPublicKey('hex').slice(2,34),
y: '0x' + curve.getPublicKey('hex').slice(-32)
}
It is not possible for me to achieve both at the same time. The problem is, that the curve object can ONLY export as buffer/hex, while all the signature functions in crypto ONLY accept proper KeyObjects. And at the same time it seems not possible to convert both into each other. The KeyObjects have no functionality to export to buffer and it is not possible to create a KeyObject from the raw key, exported from the curve. What am I missing? I was also trying to set the respective private Key on the curve with curve.setPrivateKey(privateKey) but even this does not work.
Alternatively, I would also be open to use another Node library, but those I found do not seem to support the curve that I want to use (SECP128R1)
For example, this is how easy it is with python and the ecdsa library:
sk = SigningKey.generate(curve=SECP128r1, hashfunc=sha256)
vk = sk.verifying_key
message = b"Hello"
m = sha256(message)
//Signature
signature = sk.sign(message)
//Public Key
[vk.to_string()[:16], vk.to_string()[16:]]
Thankful for any help!
You can export the public key with export() in X.509/SPKI format and DER encoded. For a secp128r1 key the last 32 bytes are the concatenation of x and y:
const { publicKey, privateKey } = crypto.generateKeyPairSync('ec', { 'namedCurve': 'secp128r1' });
// ...
var key = publicKey.export({ type: 'spki', format: 'der' });
var rawX = key.subarray(-32, -16);
var rawY = key.subarray(-16);
console.log(key.toString('hex')); // e.g. 3036301006072a8648ce3d020106052b8104001c03220004d15885cfb3c75417bbeb95625da313dcb4d27ecb6f89923ae539faa7c09b4797
console.log(rawX.toString('hex')); // e.g. d15885cfb3c75417bbeb95625da313dc
console.log(rawY.toString('hex')); // e.g. b4d27ecb6f89923ae539faa7c09b4797
This can be checked in an ASN.1 parser, e.g. https://lapo.it/asn1js/.
Note that this curve should not be used because of its length according to NIST.
Another convenient option is the export as JWK, because here x and y can be extracted directly (Base64url encoded). However, only the curves supported by JWK can be exported this way, secp128r1 is not one of them.

No inverse error during encryption (node-rsa)

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.

how convert a public key from string type to PEM

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())

Mapping problem of PKCS11 EC public key to BC PKCS10 object

I have created EC key pair in HSM using PKCS11Interop library, and i need to create PKCS10 Certificate request using this keys. For generation of PKCS10 I use BC, and in this situation i need to set public key as a parameter for PKCS10 request.
In BC i need to get public key as ECPublicKeyParameters for putting in PKCS10 object. I do not know how to map PKCS11 public key to ECPublicKeyParameters.
Or may be there is another method for this type mapping?
Thanks in advance!
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.crypto.util.PublicKeyFactory;
AsymmetricKeyParameter keyParameters = PublicKeyFactory.createKey(publicKey.getEncoded());
if (keyParameters instanceof ECPublicKeyParameters) {
ECPublicKeyParameters ecPublicKeyParameters = (ECPublicKeyParameters) keyParameters;
}

Resources