I can generate a pair of ecc private and public key pem files:
KeyPair keyPair = generateECCKeyPair();
ECPrivateKey priv = (ECPrivateKey) keyPair.getPrivate();
ECPublicKey pub = (ECPublicKey) keyPair.getPublic();
writePemFile(priv, "ECC PRIVATE KEY", "private.key");
writePemFile(pub, "ECC PUBLIC KEY", "public.pem");
but now I hava a public ecc key in a BigInteger variable,how can I covert it or wrap it into the pem form, which contains header and footer, and bewtween them is the base64 encoded der form of the public key? Here If I'm wrong about the pem file, please correct me.
Related
This question already has answers here:
Get java.security.PrivateKey from private key file generated by hyperledger ca
(1 answer)
How to read .pem file to get private and public key
(10 answers)
Closed 2 months ago.
I am trying to get a bearer token using oAuth2 for connecting to a service account on GCP, I am following this documentation. To sign the JWT, the docs tell me to use "the private key obtained from the Google API Console".
Sign the UTF-8 representation of the input using SHA256withRSA (also known as RSASSA-PKCS1-V1_5-SIGN with the SHA-256 hash function) with the private key obtained from the Google API Console.
I have the below code in Java to read that private key from a file
File privKeyFile = new File(keyPath);
BufferedInputStream bis = new BufferedInputStream(new FileInputStream('myprivatekey.pem'));
byte[] privKeyBytes = new byte[8192]
bis.read(privKeyBytes);
bis.close();
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
KeySpec ks = new PKCS8EncodedKeySpec(privKeyBytes);
RSAPrivateKey privateKey = (RSAPrivateKey) keyFactory.generatePrivate(ks);
But this code is currently giving this exception
java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException:
invalid key format at java_security_KeyFactory$generatePrivate$0.call(Unknown Source)
I tried converting private Key to PKCS#8 format as per this post but when I run this command
openssl pkcs8 -topk8 -inform PEM -outform DER -in myprivatekey.pem -nocrypt > pkcs8_key
I get this error
unable to load key
140735932699592:error:0906D06C:PEM routines:PEM_read_bio:no start line:/BuildRoot/Library/Caches/com.apple.xbs/Sources/libressl/libressl-22.50.3/libressl/crypto/pem/pem_lib.c:704:Expecting: ANY PRIVATE KEY
Was that not a valid RSA key which Google console provided? How can I read that key into my code so I can use it to sign the JWT?
The service account private key is PEM encoded RSA PKCS #8. The PKCS8EncodedKeySpec wants ASN.1 encoding without newlines, header, and tail.
The private key in your post appears valid and in the correct format.
WARNING: if that private key is from Google Cloud, immediately delete the key.
Use code similar to this:
public RSAPrivateKey readPrivateKey(File file) throws Exception {
String key = new String(Files.readAllBytes(file.toPath()), Charset.defaultCharset());
String privateKeyPEM = key
.replace("-----BEGIN PRIVATE KEY-----", "")
.replaceAll(System.lineSeparator(), "")
.replace("-----END PRIVATE KEY-----", "");
byte[] encoded = Base64.decodeBase64(privateKeyPEM);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded);
return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
}
I had generate public key using Java Spring Security, but I can not use that public key to encrypt the data using Nodejs crypto library. I think it is because of its format(X509).
My Nodejs code
module.exports.encryptRsa = (toEncrypt, pemPath) => {
let absolutePath = path.resolve(pemPath);
let publicKey = fs.readFileSync(absolutePath, "utf8");
let buffer = Buffer.from(toEncrypt);
let encrypted = crypto.publicEncrypt(publicKey, buffer);
return encrypted.toString("base64");
};
My Java code
KeyPairGenerator keyGen = KeyPairGenerator.getInstance(keyAlgorithm);
keyGen.initialize(2048);
KeyPair keyPair = keyGen.genKeyPair();
PrivateKey privateKey = keyPair.getPrivate();
PublicKey publicKey = keyPair.getPublic();
byte[] privateKeyBytes = privateKey.getEncoded();
byte[] publicKeyBytes = publicKey.getEncoded();
String formatPrivate = privateKey.getFormat(); // PKCS#8
String formatPublic = publicKey.getFormat(); // X.509
FileWriter fos = new FileWriter("publicKey.pem");
fos.write("-----BEGIN RSA PUBLIC KEY-----\n");
fos.write(enc.encodeToString(publicKeyBytes));
fos.write("\n-----END RSA PUBLIC KEY-----\n");
fos.close();
Java's getEncoded() method returns the public key in format called 'spki' by Node crypto. Java's name for that format is "X.509", an unfortunate choice because it causes confusion with certificates of that name.
The proper PEM header for spki keys is simply -----BEGIN PUBLIC KEY-----. Just get rid of RSA in the header and footer.
I have a scenario where I put RSA/EC private key (created by openssl) in JSON payload. I have my customized parser where I look for banners and fetch the information between them.
Now for RSA key irrespective whether it is PKCS#1 (default openssl) or PKCS#8 following code is working:
KeyFactory factory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = factory.generatePrivate(new PKCS8EncodedKeySpec(privateKeyBytes));
where privateKeyBytes is decoded base64 byte of private key. Private key is in the PEM format I put in JSON payload.
However when I create private key for EC algorithm via openssl, same piece of code is giving following error:
java.security.spec.InvalidKeySpecException:
java.security.InvalidKeyException: IOException : version mismatch:
(supported: 00, parsed: 01)
When I convert created pem to PKCS#8 format via (openssl pkcs8 command) then it works.
Note: My code uses "SUNRSA" provider for RSA algorithm and "SUNEC" provider for EC algorithm.
The RSA KEYS for example are generated in following manner:
Note: KeySize is the size of key you want to generate i.e 1024/2048 etc.
public static KeyPair generateRsaKeyPair(int keySizeInBits) throws NoSuchAlgorithmException {
KeyPairGenerator r = KeyPairGenerator.getInstance("RSA");
r.initialize(keySizeInBits, RandomUtil.getSecureRandom());
KeyPair keypair = r.generateKeyPair();
return keypair;
}
And EC key pair is generated as follows:
Note: CurveType is the type of curve used for EC algorithm key pair generation eg: prime256v1
public static KeyPair generateEcKeyPair(String curveType) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC","BC");
ECGenParameterSpec ecsp = new ECGenParameterSpec(curveType);
kpg.initialize(ecsp, new SecureRandom());
KeyPair kpU = kpg.generateKeyPair();
return kpU;
}
I have a private key file in the .der format. I'm trying to save this private key as a PrivateKey object (with Java) like this:
PrivateKey clientPrivKey = getPrivateKeyFromKeyFile("C:\\Users\\Bob\\Desktop\\Assignments\\Project\\VPN Project\\src\\client-private.der");
This is what the getPrivateKeyFromKeyFile method looks like:
private static PrivateKey getPrivateKeyFromKeyFile(String keyfile) throws Exception
{
Path path = Paths.get(keyfile);
byte[] privKeyByteArray = Files.readAllBytes(path);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privKeyByteArray);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey myPrivKey = keyFactory.generatePrivate(keySpec);
return myPrivKey;
}
But when I try this, I keep getting InvalidKeySpecException because of this line of code:
PrivateKey myPrivKey = keyFactory.generatePrivate(keySpec);
I'm not sure what's the issue here. I opened up the private key file and everything looks fine. It starts with -----BEGIN RSA PRIVATE KEY----- and ends with -----END RSA PRIVATE KEY-----.
And in case it's relevant, I created this private key using this OpenSSL command:
genrsa -out client-private.der 2048
A file generated with
openssl genrsa -out <path to output-file> 2048
is actually not a .der-file, but a .pem-file (see e.g. What are the differences between .pem, .cer and .der?) and the data are not stored in the PKCS8-format, but in the PKCS1-format (see e.g. PKCS#1 and PKCS#8 format for RSA private key).
Keys in the PKCS1-format can not be processed directly using standard Java tools. For this, third-party libraries like BouncyCastle are necessary (see e.g. Read RSA private key of format PKCS1 in JAVA).
Another possibility is to convert the PKCS1-formatted key into a PKCS8-formatted key with OpenSSL first (see e.g. Load a RSA private key in Java (algid parse error, not a sequence)):
openssl pkcs8 -topk8 -inform PEM -outform PEM -in <path to the input-pkcs1-pem-file> -out <path to the output-pkcs8-pem-file> -nocrypt
And then, after (programmatic) deletion of the Beginn-/End-line and after base64-decoding the private key can be generated (see e.g. How to read .pem file to get private and public key) e.g. with
private static PrivateKey getPrivateKeyFromKeyFile(String keyfile) throws Exception
{
Path path = Paths.get(keyfile);
byte[] privKeyByteArray = Files.readAllBytes(path);
// added ----------------------------------------------------------------
String privKeyString = new String(privKeyByteArray);
privKeyString = privKeyString.replace("-----BEGIN PRIVATE KEY-----", "");
privKeyString = privKeyString.replace("-----END PRIVATE KEY-----", "");
privKeyString = privKeyString.replace("\r\n", "");
privKeyByteArray = Base64.getDecoder().decode(privKeyString);
// ----------------------------------------------------------------------
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privKeyByteArray);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey myPrivKey = keyFactory.generatePrivate(keySpec);
return myPrivKey;
}
I have a RSA private key stored as a String that I need to convert into a PrivateKey object for use with an API. I can find examples of people converting from a private-key file to a string but not the other way around.
I managed to convert it to a PrivateKey object but it was in PKCS8, when I need it to be PKCS1, and I know Java doesn't have PKCS1EncodedKeySpec
byte[] key64 = Base64.decodeBase64(privateKeyString.getBytes());
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
KeySpec privateKeySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec);
you can convert pkcs#1 to pkcs#8
openssl pkcs8 -topk8 -in server.key -nocrypt -out server_pkcs8.key
cat server_pkcs8.key
-----BEGIN PRIVATE KEY-----
base64_encode xxx
-----END PRIVATE KEY-----