Formatting RSA keys for OpenSSL in Java - java

Background
RSA key generation with OpenSSL on Linux using the command,
openssl genrsa -out mykey.pem 1024
created the following:
"-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQChs9Fepy5FgeL0gNJ8GHcKRHsYnM2Kkw19zwydDQNyh2hrHWV2
B11wpLFp8d0imcl2Wjb0oV/AxOhb3unQgNzs66LVuXJwS8icp3oIJZtExs6tkxzE
s5mnU68wMeCYtJqHIZOmNblVWvpJMLNAwAVi3oLfnzDDbzjnDapm8M21nQIDAQAB
AoGAZ11P1+acUHgvwMXcRtFIvvp5iYkqZouL00EYOghIjNx75gTbh7A7jbbpZeTi
y6xsuMgAWy4QzGPSeG+tHMhS7+dYQNPuKSv5KtK3V7ubXz/I3ZN1etRVecA56QNw
7HKv6b7srolt08kogGIwpbbfl/mhfJHnv4Jeqd5lNMnK4e0CQQDWFZo4h22OlSaH
ZGd3i4rwLrA0Ux5bkdh7YH0uEeE/nGzpVs1DPhsN8UCyq9LAiKYLlXeeCvwurKwo
OgKlUCkzAkEAwVy2KignoRInFTAaYH8PQRfD835q+oC0Iu21BF68ne06U6wu+wWk
bWiYxTOOb+TGZfA1vA6OAvGVGoXs1bHF7wJBAItGiop0MKYuCl7Sxy1SrxUKir+/
w2Q3QesiHs41+6Byl7hGLEuuv9MWPM0AU5/GRqAKoUNESkPjOi0BcG8z81kCQGGn
OvCreugjzM0skAWv5bpQEExGyixdF5yURFlCpytzBYQAb3Gi9dmze4QMd6EW/wO4
fsrM5vehnlXY0TVTJM0CQQCMPVhub8LSo7T/lCzypvb/cgxJfyITRKcM2asrXud5
r27kbzsXqYum4huHqyFkb3pZammsYA/z89HchylfrD4U
-----END RSA PRIVATE KEY-----"
The following code under Java 6,
KeyPairGenerator keyGen = null;
try {
keyGen = KeyPairGenerator.getInstance("RSA");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
KeyPair pair = keyGen.generateKeyPair();
privateKey = new Base64Encoder().encode(pair.getPrivate().getEncoded());
publicKey = new Base64Encoder().encode(pair.getPublic().getEncoded());`
output the following:
"MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAIsJlqFOP+jPyYvrGwh+dff30a3p
uHysMfHYi1MyNSFCsT/2QbOc/k9U/X28WRCMeFwEEnReLULXA9Ywox8GycI/ApMX+DjKBrrLDbpr
ATLiu9+NMK4VSytKFI87P07HAni3RkiO4rFNEINVQ7t38ZmHavuXHjMkLEAK4dyLQO9NAgMBAAEC
gYBN/jv0EmwBUgYSKflJI39TcT263B+0N/fwXXOSYNiy5rF9WstyUP/LSrbEAJLJmLKvk00y391t
4CVz0ma+sdUdAPlS7Nmx9f3BThGOGcDmpjVo1y4e1afWtyu66ba/XDeuf7q5Y/h/pr20/gXl9Gz2
yefQrzU9xXGKZhE/lxJ2IQJBAMELpeAal+Fa+u0InGrowVmV+lge8RZqKRfCDzPPna465E5Qcekb
J0ShsarP5lnUfrNH5g8GLaDGQwYE/UoIpPkCQQC4YRfck5uMlI1K3F9YC3XvmFAJnf9YexoPfNSu
dznOD4rxlwzW/5daPOR0jjlyIRDH/QuUoPIIEn1mt3dnz7X1AkBZciozgl7pPhySA7FmH96mwcUz
W3LdrebIaVRd707iUctDNibxmXFCbaFCwf27laf3LdM9FuHBYtvfSCSMTyERAkEAlNAQsUAVmKZB
T72D2o0Nd/7oAosaD7DzvLJU+idSaWUUEJ+IhnKuFu/0t7oe1WWopLEwypoIHsnFmsTTQ99ajQJA
Scwh3P3RTN4F6Jz1SxRSe6L729xI8xkbco5EsMq5v5BZeoGynqdPUUZdAPcaO2k5UagaSejvzgna
8xIqR7elVQ=="
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCLCZahTj/oz8mL6xsIfnX399Gt6bh8rDHx2ItT
MjUhQrE/9kGznP5PVP19vFkQjHhcBBJ0Xi1C1wPWMKMfBsnCPwKTF/g4yga6yw26awEy4rvfjTCu
FUsrShSPOz9OxwJ4t0ZIjuKxTRCDVUO7d/GZh2r7lx4zJCxACuHci0DvTQIDAQAB"
Questions
How do I put "armor" around the private and public keys created through Java code?
Why is each line of the keys generated through Java code longer than those output by OpenSSL?
Does it make any difference? One of the tools, that other team is using, fails while signing a message using private key generated by Java code mentioned above. However, it works just fine that tool uses the private key generated by OpenSSL.
Is there a way I can export a compatible key with Java?

The OpenSSL private key is in a non-standard format, while the Java code is creating a standard, PKCS-#8–encoded private key.
OpenSSL can convert the standard key format to the non-standard form. You can write Java code to do the same, but it requires some third-party libraries and a good knowledge of ASN.1 helps too.
To convert a PKCS #8 key to OpenSSL format, use OpenSSL's pkcs8 utility.
openssl pkcs8 -nocrypt -inform der < pvt.der > pvt.pem
To convert an RSA key stored as a DER-encoded SubjectPublicKeyInfo to PEM format, use OpenSSL's rsa utility.
openssl rsa -pubin -inform der < pub.der > pub.pem
This assumes that the private key is stored in "binary" (DER) format, not Base-64 encoded. The Java code to create and store keys like this would look something like:
KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA");
KeyPair pair = gen.generateKeyPair();
FileOutputStream ospvt = new FileOutputStream("pvt.der");
try {
ospvt.write(pair.getPrivate().getEncoded());
ospvt.flush();
} finally {
ospvt.close();
}
FileOutputStream ospub = new FileOutputStream("pub.der");
try {
ospub.write(pair.getPublic().getEncoded());
ospub.flush();
} finally {
ospub.close();
}

Related

Decrypt File in Java Encrypted via openssl generated (S/Mime) key pair

I am trying to decrypt files that were encrypted using an openssl generated public key. I have the key pair that was generated in openssl and can decrypt files with the private key within openssl. However, I am now tasked with decrypting the files in a Java application, using the same private key that was generated via openssl. I have gotten as far as reading the private key into an java.security.PrivateKey object successfully, using Bouncy Castle libraries. I have written (with the help of code I found in various stack overflow posts) three decryption methods, but get various exceptions with each one. I will provide the openssl commands below and also the Java code I used to read in the private key and one of the decrytion methods I've tried.
Generate key pair with openssl:
openssl genrsa -aes256 -out my-private-key.pem 4096
openssl req -new -x509 -days 730 -key my-private-key.pem -out my-public-key.pem
encrypt file
openssl smime -binary -encrypt -in test.file -out test.file.enc my-public-key.pem
decrypt file
openssl smime -binary -decrypt -inkey ecn-private-key.pem -in test.file.enc -out test.file.dec
(Enter pass phrase for my-private-key.pem)
public key header
-----BEGIN CERTIFICATE-----
private key header
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-256-CBC,4EFFB692F0BEBF75B183DB1371979B97
// read private key - this is successful
private static PrivateKey readPrivateKeyPEM(File file, String password) throws IOException,
GeneralSecurityException, OperatorCreationException, PKCSException {
try (FileReader reader = new FileReader(file)) {
PEMParser parser = new PEMParser(reader);
Object object = parser.readObject();
if (object == null) {
throw new IllegalArgumentException("No key found in " + file);
}
BouncyCastleProvider provider = new BouncyCastleProvider();
JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider(provider);
PEMDecryptorProvider decryptionProvider = new
JcePEMDecryptorProviderBuilder().setProvider(provider).build(password.toCharArray());
PEMKeyPair keypair = ((PEMEncryptedKeyPair) object).decryptKeyPair(decryptionProvider);
return converter.getPrivateKey(keypair.getPrivateKeyInfo());
}
}
// The following method attempts to decrypt file with private key read in above
fails
// this fails
public static void decrypt(PrivateKey privateKey, File encrypted, File decryptedDestination)
throws IOException, CMSException {
byte[] encryptedData = Files.readAllBytes(encrypted.toPath());
CMSEnvelopedDataParser parser = new CMSEnvelopedDataParser(encryptedData);
RecipientInformation recInfo = getSingleRecipient(parser);
Recipient recipient = new JceKeyTransEnvelopedRecipient(privateKey);
try (InputStream decryptedStream = recInfo.getContentStream(recipient).getContentStream()) {
Files.copy(decryptedStream, decryptedDestination.toPath());
}
}
The stack trace is:
Exception in thread "main" org.bouncycastle.cms.CMSException: Unexpected object reading content.
at org.bouncycastle.pkix#1.68/org.bouncycastle.cms.CMSContentInfoParser.(Unknown Source)
at org.bouncycastle.pkix#1.68/org.bouncycastle.cms.CMSEnvelopedDataParser.(Unknown Source)
at org.bouncycastle.pkix#1.68/org.bouncycastle.cms.CMSEnvelopedDataParser.(Unknown Source)
at com.att.floodportal.openssl.EncryptAndDecrypt.decrypt(EncryptAndDecrypt.java:32)
at com.att.floodportal.openssl.JavaSecurityPemUtils.main(JavaSecurityPemUtils.java:77)
Caused by: java.lang.ClassCastException: class org.bouncycastle.asn1.DLApplicationSpecific cannot be cast to class org.bouncycastle.asn1.ASN1SequenceParser (org.bouncycastle.asn1.DLApplicationSpecific and org.bouncycastle.asn1.ASN1SequenceParser are in module org.bouncycastle.provider#1.68 of loader 'app')
Thank You

InvalidKeySpecException: How do I extract a private key from a .der file?

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;
}

How to generate same type of ecdsa keypair in java as generated by openssl?

I am executing the following command to generate ecdsa keypair on my machine:
openssl ecparam -genkey -name secp256k1 -noout -outform DER -out private.key and on executing this next command openssl ec -inform DER -in private.key -noout -text, I get the following output:
read EC key
Private-Key: (256 bit)
priv:
//private key
pub:
04:64:0a:f7:e6:e1:a9:7f:d3:b2:ec:ad:f1:41:96:
ee:c1:c2:e7:02:4a:54:42:ab:e8:da:9f:88:e1:02:
46:aa:32:91:38:b5:9e:37:fc:96:d9:36:02:07:de:
74:59:c4:a8:e0:2b:21:3a:d4:70:7d:5e:92:54:22:
65:80:0f:df:fd
ASN1 OID: secp256k1
Now what I'm interested in is the above public key without colons i.e. 04640af7e6e1a97fd3b2ecadf14196eec1c2e7024a5442abe8da9f88e10246aa329138b59e37fc96d9360207de7459c4a8e02b213ad4707d5e92542265800fdffd. I need to send to this public key to an api call which validates whether the key is valid or not. The key generated by openssl when sent with the api call is accepted by the server as valid.
But the public ecdsa key generated in java when sent with the api call is rejected. I'm using following code to generate keypair
public KeyPair getECDSAKeyPair() throws NoSuchProviderException, NoSuchAlgorithmException,
InvalidAlgorithmParameterException {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("ECDSA", "SC");
ECGenParameterSpec spec = new ECGenParameterSpec("secp256k1");
keyPairGenerator.initialize(spec, new SecureRandom());
return keyPairGenerator.generateKeyPair();
}
public String getHexPublicKeyString(KeyPair keypair) {
PublicKey publicKey = keypair.getPublic();
return Hex.toHexString(publicKey.getEncoded());
}
My question is how can I generate same type of ECDSA keypair as generated by the OpenSSL? And what is the difference between the keys generated by OpenSSL and the code generated by java such that key generated by OpenSSL is accepted whereas key generated by java is rejected?
I was able to generate the required public through following method using SpongyCastle:
public static String getHexEncodedPublicKey(PublicKey publicKey) throws IOException, InvalidKeyException {
ECPublicKeyParameters ecPublicKeyParameters
= (ECPublicKeyParameters) ECUtil.generatePublicKeyParameter(publicKey);
byte[] encoded = ecPublicKeyParameters.getQ().getEncoded(false);
return Hex.toHexString(encoded);
}

Outputting encrypted PK8 private key from Java BouncyCastle

I am trying to generate an encrypted private key and CSR using Java in Matlab. Matlab adds some minor complexity, but this is mostly a Java problem. I start with a private key:
java.security.Security.addProvider(org.bouncycastle.jce.provider.BouncyCastleProvider());
keyGen = java.security.KeyPairGenerator.getInstance('RSA', 'BC');
keyGen.initialize(2048, java.security.SecureRandom());
keypair = keyGen.generateKeyPair();
privateKey = keypair.getPrivate();
If I encrypt the key and output it as PEM:
m=org.bouncycastle.openssl.PKCS8Generator.PBE_SHA1_3DES;
encryptorBuilder = org.bouncycastle.openssl.jcajce.JceOpenSSLPKCS8EncryptorBuilder(m);
encryptorBuilder.setRandom(java.security.SecureRandom());
encryptorBuilder.setPasssword(password);
oe = encryptorBuilder.build();
gen = org.bouncycastle.openssl.jcajce.JcaPKCS8Generator(privateKey,oe);
privKeyObj = gen.generate();
fos = java.io.FileWriter('private.pem');
pem = org.bouncycastle.openssl.jcajce.JcaPEMWriter(fos);
pem.writeObject(privKeyObj);
pem.flush();
fos.close();
I get a perfectly good key. The problem is that I want to use the key with jdbc, so I need a DER formatted pk8 key. I cannot figure out how to get this out of BouncyCastle. A kludge workaround that succeeds:
textWriter = java.io.StringWriter();
pem = org.bouncycastle.openssl.jcajce.JcaPEMWriter(textWriter);
pem.writeObject(privateKey);
pem.flush();
thekey = char(textWriter.toString());
cmd = ['echo "' thekey '"|openssl pkcs8 -topk8 -out private.pk8 -inform PEM -outform DER -passout pass:' password];
system(cmd);
Now, obviously this exposes both the unencrypted private key and the password. I've tried all manner of things to coerce privKeyObj to DER, but they typically leave me with:
$openssl pkcs8 -inform DER -outform PEM -in private.pk8 -out private.pem
Error decrypting key
140735211835472:error:0D0680A8:asn1 encoding routines:ASN1_CHECK_TLEN:wrong tag:tasn_dec.c:1201:
140735211835472:error:0D06C03A:asn1 encoding routines:ASN1_D2I_EX_PRIMITIVE:nested asn1 error:tasn_dec.c:765:
140735211835472:error:0D08303A:asn1 encoding routines:ASN1_TEMPLATE_NOEXP_D2I:nested asn1 error:tasn_dec.c:697:Field=version, Type=PKCS8_PRIV_KEY_INFO
The intent of this code is to generate a CSR on the end user's machine which I then sign, and which is encrypted with MAC address of the machine (and a salt), so that the program will only run on the authorized machine, and only authorized machines will be able to access my PostgreSql database.
Suggestions?
I figured it out. In my original code, I had used BcPKCS12PBEOutputEncryptorBuilder. Wrong! The correct call is to JcePKCSPBEOutputEncryptorBuilder. The correct code (in MATLAB, but converting to Java is simple) is:
java.security.Security.addProvider(org.bouncycastle.jce.provider.BouncyCastleProvider());
keyGen = java.security.KeyPairGenerator.getInstance('RSA', 'BC');
keyGen.initialize(2048, java.security.SecureRandom());
keypair = keyGen.generateKeyPair();
privateKey = keypair.getPrivate();
builder=org.bouncycastle.pkcs.jcajce.JcaPKCS8EncryptedPrivateKeyInfoBuilder(privateKey);
m=org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC;
encryptorBuilder = org.bouncycastle.pkcs.jcajce.JcePKCSPBEOutputEncryptorBuilder(m);
password = 'test';
outputBuilder = encryptorBuilder.build(password);
privKeyObj = builder.build(outputBuilder);
fos = java.io.FileOutputStream('testkey.pk8');
fos.write(privKeyObj.getEncoded());
fos.flush();
fos.close();
This generates a DER formatted PCS#8 file.
openssl pkcs8 -inform DER -outform PEM -in testkey.pk8 -out testkey.pem
Now returns the PEM private key. To read the key:
myPath = java.nio.file.Paths.get(pwd,'testkey.pk8');
encodedKey = java.nio.file.Files.readAllBytes(myPath);
privKeyObj =org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo(encodedKey);
cp=org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter();
cp.setProvider('BC');
decryptorBuilder = org.bouncycastle.pkcs.jcajce.JcePKCSPBEInputDecryptorProviderBuilder();
inputBuilder = decryptorBuilder.build(password);
info = privKeyObj.decryptPrivateKeyInfo(inputBuilder);
decodedKey=cp.getPrivateKey(info);
Note that in MATLAB, you don't need to declare the type of the returned object, and you don't need to put "new" in front of a constructor.

RSA Encryption: Java to PHP

I'm trying to implement RSA Encryption in both Java and PHP, but I can't seem to get PHP to recognize my Java public/private keys. Here is the java code to Encode/Decode the Public and Private Keys:
public static byte[] EncodePublicKey(PublicKey _publickey) throws Exception
{
return _publickey.getEncoded();
}
public static PublicKey DecodePublicKey(byte[] _encodedkey) throws Exception
{
KeyFactory fac = KeyFactory.getInstance("RSA");
X509EncodedKeySpec encodedKey = new X509EncodedKeySpec(_encodedkey);
return fac.generatePublic(encodedKey);
}
public static byte[] EncodePrivateKey(PrivateKey _privatekey) throws Exception
{
return _privatekey.getEncoded();
}
public static PrivateKey DecodePrivateKey(byte[] _encodedkey) throws Exception
{
KeyFactory fac = KeyFactory.getInstance("RSA");
PKCS8EncodedKeySpec encodedKey = new PKCS8EncodedKeySpec(_encodedkey);
return fac.generatePrivate(encodedKey);
}
I first tried using the PEAR Crypt_RSA functions, but it doesn't support X.509 or PKCS8 (it just simply base64 encodes the serialized modulus, exponent and key type). I then tried the OpenSSL "openssl_get_publickey" function but it doesn't appear to recognize the format either.
Any help would be greatly appreciated o.O
You need to convert the binary format (DER) from Java to PEM for OpenSSL (and the PHP bindings). You can test your Java key files using the OpenSSL command line by specifying the -inform DER option on the command line.
<?
function pem2der($pem_data) {
$begin = "KEY-----";
$end = "-----END";
$pem_data = substr($pem_data, strpos($pem_data, $begin)+strlen($begin));
$pem_data = substr($pem_data, 0, strpos($pem_data, $end));
$der = base64_decode($pem_data);
return $der;
}
function der2pem($der_data) {
$pem = chunk_split(base64_encode($der_data), 64, "\n");
$pem = "-----BEGIN PUBLIC KEY-----\n".$pem."-----END PUBLIC KEY-----\n";
return $pem;
}
// load the public key from a DER-encoded file
$pubkey = der2pem(file_get_contents("pubkey"));
?>
For more information about using OpenSSL keys in Java, check out this link.
The PHP functions require PEM encoded keys. It's trivial to convert DER encoded keys into PEM.
Here is my code to convert PKCS#8 private key to PEM,
function pkcs8_to_pem($der) {
static $BEGIN_MARKER = "-----BEGIN PRIVATE KEY-----";
static $END_MARKER = "-----END PRIVATE KEY-----";
$value = base64_encode($der);
$pem = $BEGIN_MARKER . "\n";
$pem .= chunk_split($value, 64, "\n");
$pem .= $END_MARKER . "\n";
return $pem;
}
For public key in X509, replace PRIVATE with PUBLIC in markers.
http://code.google.com/p/simplersalibrary/ is a simple tool, if you want encrypt something in Java and decrypt in PHP or encrypt in java and decrypt in PHP, simplersa can also generate the pem files for PHP.
You can also try to use CastleCrypt, which allows a easy to use RSA Encryption in JAVA AND PHP: https://github.com/wessnerj/CastleCrypt
For the key generation you may want to try it with openssl:
openssl genrsa -out privateKey.pem 2048
openssl pkcs8 -topk8 -nocrypt -in privateKey.pem -outform der -out privateKey.der
openssl rsa -in privateKey.pem -pubout -outform PEM -out publicKey.pem
openssl rsa -in privateKey.pem -pubout -outform DER -out publicKey.der
This commands gives you private and public key in both DER and PEM Format. For JAVA you have to use the .der keys and for PHP the .pem keys.

Categories