Author: Paolo Lulli <paolo@lulli.net>
Symmetric and PKI enc/dec working
%!v(PANIC=String method: strings: negative Repeat count)
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..2f90af11be34977f529b564f85b04fc12b68252a --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +target/* +.dqt +.idea/* +dependency-reduced-pom.xml diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..a203e795a1fa1e07fb1cb43536343c43f5f46679 --- /dev/null +++ b/pom.xml @@ -0,0 +1,98 @@ +<?xml version="1.0"?> +<project> + <modelVersion>4.0.0</modelVersion> + <groupId>net.lulli</groupId> + <artifactId>cert-encoder</artifactId> + <version>0.0.1</version> + <repositories> + <repository> + <id>code.lulli.net</id> + <url>https://code.lulli.net/maven</url> + </repository> + </repositories> + <build> + <plugins> + <plugin> + <artifactId>maven-compiler-plugin</artifactId> + <configuration> + <source>17</source> + <target>17</target> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-shade-plugin</artifactId> + <version>3.3.0</version> + <executions> + <execution> + <phase>package</phase> + <goals> + <goal>shade</goal> + </goals> + <configuration> + <minimizeJar>false</minimizeJar> + <transformers> + <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/> + <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> + <manifestEntries> + <Main-Class>net.lulli.nojs.server.ServerRunner</Main-Class> + <Build-Number>1.0</Build-Number> + </manifestEntries> + </transformer> + </transformers> + <filters> + <!-- avoid issue shading BouncyCastle signed jars --> + <filter> + <artifact>*:*</artifact> + <excludes> + <exclude>META-INF/*.SF</exclude> + <exclude>META-INF/*.DSA</exclude> + <exclude>META-INF/*.RSA</exclude> + </excludes> + </filter> + </filters> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + <extensions> + <extension> + <groupId>org.apache.maven.wagon</groupId> + <artifactId>wagon-ssh</artifactId> + <version>3.5.3</version> + </extension> + </extensions> + </build> + <distributionManagement> + <repository> + <id>${repository.id}</id> + <name>${repository.name}</name> + <url>${repository.url}</url> + </repository> + <site> + <id>${repository.id}</id> + <name>${repository.name}</name> + <url>${repository.site.url}</url> + </site> + </distributionManagement> + <!-- ****************************************** --> + <dependencies> + <dependency> + <groupId>org.bouncycastle</groupId> + <artifactId>bcpkix-jdk15to18</artifactId> + <version>1.77</version> + </dependency> + <dependency> + <groupId>org.json</groupId> + <artifactId>json</artifactId> + <version>20231013</version> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.13.2</version> + <scope>test</scope> + </dependency> + </dependencies> +</project> diff --git a/src/main/java/net/lulli/encrypt/Pems.java b/src/main/java/net/lulli/encrypt/Pems.java new file mode 100644 index 0000000000000000000000000000000000000000..52ee1e2fc6e4e42effbb7dab35fe7efc2d0976cc --- /dev/null +++ b/src/main/java/net/lulli/encrypt/Pems.java @@ -0,0 +1,76 @@ +package net.lulli.encrypt; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.security.KeyFactory; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; +import java.util.Base64; + +public class Pems { + private Pems(){} + + public static X509Certificate readX509Certificate(String certificate) throws Exception { + InputStream targetStream = new ByteArrayInputStream(certificate.getBytes()); + return (X509Certificate) CertificateFactory + .getInstance("X509") + .generateCertificate(targetStream); + } + + public static X509Certificate certificateFromFile(String fileName) { + try { + var keyContent = Files.readString(Paths.get(fileName)); + return readX509Certificate(keyContent); + } catch (Exception e) { + throw new IllegalStateException(e.getMessage()); + } + } + public static PublicKey publicKeyFromFile(String fileName) { + try { + var keyContent = Files.readString(Paths.get(fileName)); + return readX509PublicKey(keyContent); + } catch (Exception e) { + throw new IllegalStateException(e.getMessage()); + } + } + + public static PrivateKey privateKeyFromFile(String fileName) { + try { + var keyContent = Files.readString(Paths.get(fileName)); + return readPKCS8PrivateKey(keyContent); + } catch (Exception e) { + throw new IllegalStateException(e.getMessage()); + } + } + + public static PublicKey readX509PublicKey(String key) throws Exception { + String publicKeyPEM = key + .replace("-----BEGIN PUBLIC KEY-----", "") + .replaceAll(System.lineSeparator(), "") + .replace("-----END PUBLIC KEY-----", ""); + + byte[] encoded = Base64.getDecoder().decode(publicKeyPEM); + + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encoded); + return (PublicKey) keyFactory.generatePublic(keySpec); + } + + public static PrivateKey readPKCS8PrivateKey(String key) throws Exception { + String privateKeyPEM = key + .replace("-----BEGIN PRIVATE KEY-----", "") + .replaceAll(System.lineSeparator(), "") + .replace("-----END PRIVATE KEY-----", ""); + + byte[] encoded = Base64.getDecoder().decode(privateKeyPEM); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded); + return (PrivateKey) keyFactory.generatePrivate(keySpec); + } +} diff --git a/src/main/java/net/lulli/encrypt/pki/PkiEncryptionManager.java b/src/main/java/net/lulli/encrypt/pki/PkiEncryptionManager.java new file mode 100644 index 0000000000000000000000000000000000000000..9fc02bd941791443d39e7790f588e99c72440e55 --- /dev/null +++ b/src/main/java/net/lulli/encrypt/pki/PkiEncryptionManager.java @@ -0,0 +1,179 @@ +package net.lulli.encrypt.pki; + +import net.lulli.encrypt.Pems; +import org.bouncycastle.cert.jcajce.JcaCertStore; +import org.bouncycastle.cms.*; +import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder; +import org.bouncycastle.cms.jcajce.JceCMSContentEncryptorBuilder; +import org.bouncycastle.cms.jcajce.JceKeyTransEnvelopedRecipient; +import org.bouncycastle.cms.jcajce.JceKeyTransRecipientInfoGenerator; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.operator.ContentSigner; +import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; +import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder; +import org.bouncycastle.util.Store; +import org.bouncycastle.util.encoders.Base64; + +import java.io.*; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.security.KeyStore; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.Security; +import java.security.cert.X509Certificate; +import java.util.ArrayList; + +public class PkiEncryptionManager { + public static final PkiEncryptionManager INSTANCE = new PkiEncryptionManager(); + private PkiEncryptionManager() {} + + public void signFile(File fileToSign) { + try { + char[] password = "yourpass".toCharArray(); + String certificateAlias = ""; + String keyAlias = ""; + var keystoreFile = "full/path/to/your/original/certificate.pfx"; + + Security.addProvider(new BouncyCastleProvider()); + KeyStore ks = loadKeyStore(keystoreFile, password); + + X509Certificate cert = (X509Certificate) ks.getCertificate(certificateAlias); + PrivateKey privatekey = (PrivateKey) ks.getKey(keyAlias, password); + + String signatureFileName = fileToSign.getName().toString() + ".signature"; + + byte[] buffer = loadFileIntoBuffer(fileToSign); + + byte[] signeddata = generateSignature(cert, cert.getPublicKey(), privatekey, buffer); + + writeSignatureToFile(signatureFileName, signeddata); + } catch (Exception e) { + throw new IllegalStateException(e.getMessage()); + } + } + + private static byte[] loadFileIntoBuffer(File fileToSign) { + try { + byte[] buffer = new byte[(int) fileToSign.length()]; + try (DataInputStream in = new DataInputStream(new FileInputStream(fileToSign))) { + in.readFully(buffer); + } + return buffer; + } catch (Exception e) { + throw new IllegalStateException(e.getMessage()); + } + } + + private static byte[] generateSignature(X509Certificate cert, PublicKey publicKey, PrivateKey privatekey, byte[] buffer) { + try { + ArrayList<X509Certificate> certList = new ArrayList<X509Certificate>(); + certList.add(cert); + Store<?> certs = new JcaCertStore(certList); + CMSSignedDataGenerator signGen = new CMSSignedDataGenerator(); + + ContentSigner sha1signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider("BC").build(privatekey); + signGen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().build()).build(sha1signer, cert)); + signGen.addCertificates(certs); + CMSTypedData content = new CMSProcessableByteArray(buffer); + CMSSignedData signedData = signGen.generate(content, false); + byte[] signeddata = signedData.getEncoded(); + return signeddata; + } catch (Exception e) { + throw new IllegalStateException(e.getMessage()); + } + } + + public byte[] encryptData(byte[] data, X509Certificate encryptionCertificate) { + try { + Security.addProvider(new BouncyCastleProvider()); + + if (null != data && null != encryptionCertificate) { + var cmsEnvelopedDataGenerator = new CMSEnvelopedDataGenerator(); + + //JceKeyTransRecipientInfoGenerator jceKey = new JceKeyTransRecipientInfoGenerator(encryptionCertificate); + cmsEnvelopedDataGenerator.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(encryptionCertificate).setProvider("BC")); + var cmsProcessableByteArray = new CMSProcessableByteArray(data); + var outputEncryptor = new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES256_CBC).setProvider("BC").build(); + var cmsEnvelopedData = cmsEnvelopedDataGenerator.generate(cmsProcessableByteArray, outputEncryptor); + return cmsEnvelopedData.getEncoded(); + } + return null; + } catch (Exception e) { + throw new IllegalStateException(e.getMessage()); + } + } + + + public void decryptCms(PrivateKey privateKey, byte[] encryptedData, String destinationFile) { + try { + var decryptedDestination = new File(destinationFile); + //byte[] encryptedData = Files.readAllBytes(encrypted.toPath()); + + var cmsEnvelopedDataParser = new CMSEnvelopedDataParser(encryptedData); + + var singleRecipient = getSingleRecipient(cmsEnvelopedDataParser); + var jceKeyTransEnvelopedRecipient = new JceKeyTransEnvelopedRecipient(privateKey); + + try (InputStream decryptedStream = singleRecipient.getContentStream(jceKeyTransEnvelopedRecipient).getContentStream()) { + Files.copy(decryptedStream, decryptedDestination.toPath()); + } + + System.out.println(String.format("Decrypted to file :'%s'", decryptedDestination.getAbsolutePath())); + } catch (Exception e) { + throw new IllegalStateException(e.getMessage()); + } + } + + private static RecipientInformation getSingleRecipient(CMSEnvelopedDataParser parser) { + var recInfos = parser.getRecipientInfos().getRecipients(); + var recipientIterator = recInfos.iterator(); + if (!recipientIterator.hasNext()) { + throw new RuntimeException("Could not find recipient"); + } + return recipientIterator.next(); + } + + private static void writeSignatureToFile(String fileName, byte[] signeddata) { + try { + var fileOutputStream = new FileOutputStream(fileName); + byte[] outputString = Base64.encode(signeddata); + int fullLines = (int) Math.floor(outputString.length / 64); + for (int i = 0; i < fullLines; i++) { + fileOutputStream.write(outputString, i * 64, 64); + fileOutputStream.write("\r\n".getBytes()); + } + + fileOutputStream.write(outputString, fullLines * 64, outputString.length % 64); + fileOutputStream.close(); + } catch (Exception e) { + throw new IllegalStateException(e.getMessage()); + } + } + + private static KeyStore loadKeyStore(String keystoreFile, char[] password) { + try { + var keyStore = KeyStore.getInstance("PKCS12"); + keyStore.load(new FileInputStream(keystoreFile), password); + return keyStore; + } catch (Exception e) { + throw new IllegalStateException(e.getMessage()); + } + } + + /* + public static void main(String[] args) throws Exception { + var plainText = "this is a sample text"; + X509Certificate x509Certificate = Pems.certificateFromFile("/home/plulli/.x509crypt/local/certs/local.crt"); + //var enc = EncDec.encrypt(plainText, x509Certificate.getPublicKey().getEncoded()); + byte[] enc = encryptData(plainText.getBytes(), x509Certificate); + System.out.printf("Cleartext: [%s]\n Encrypted: [%s]\n", plainText, new String(enc)); + + Files.write(Paths.get("/tmp/output2.txt.enc"), enc); + + PrivateKey privateKey = Pems.privateKeyFromFile("/home/plulli/.x509crypt/local/certs/local.key"); + decryptCms(privateKey, enc, "/tmp/output2.txt"); + } + + */ +} diff --git a/src/main/java/net/lulli/encrypt/symmetric/SymmetricEncryptionManager.java b/src/main/java/net/lulli/encrypt/symmetric/SymmetricEncryptionManager.java new file mode 100644 index 0000000000000000000000000000000000000000..e124e2dc0768011c7adbf762955dd4f57cf02441 --- /dev/null +++ b/src/main/java/net/lulli/encrypt/symmetric/SymmetricEncryptionManager.java @@ -0,0 +1,77 @@ +package net.lulli.encrypt.symmetric; + +import javax.crypto.Cipher; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.security.MessageDigest; +import java.security.SecureRandom; + +public class SymmetricEncryptionManager { + public static final SymmetricEncryptionManager INSTANCE = new SymmetricEncryptionManager(); + private SymmetricEncryptionManager() {} + + public byte[] encrypt(String plainText, byte[] key) { + try { + byte[] clean = plainText.getBytes(); + + int ivSize = 16; + byte[] iv = new byte[ivSize]; + var random = new SecureRandom(); + random.nextBytes(iv); + var ivParameterSpec = new IvParameterSpec(iv); + + // Hashing key. + var messageDigest = MessageDigest.getInstance("SHA-256"); + messageDigest.update(key); + byte[] keyBytes = new byte[16]; + System.arraycopy(messageDigest.digest(), 0, keyBytes, 0, keyBytes.length); + var secretKeySpec = new SecretKeySpec(keyBytes, "AES"); + + // Encrypt. + var cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); + cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec); + byte[] encrypted = cipher.doFinal(clean); + + // Combine IV and encrypted part. + byte[] encryptedIVAndText = new byte[ivSize + encrypted.length]; + System.arraycopy(iv, 0, encryptedIVAndText, 0, ivSize); + System.arraycopy(encrypted, 0, encryptedIVAndText, ivSize, encrypted.length); + + return encryptedIVAndText; + } catch (Exception e) { + throw new IllegalStateException(e.getMessage()); + } + } + + public byte[] decrypt(byte[] encryptedIvTextBytes, byte[] key) { + try { + int ivSize = 16; + int keySize = 16; + + // Extract IV. + byte[] iv = new byte[ivSize]; + System.arraycopy(encryptedIvTextBytes, 0, iv, 0, iv.length); + var ivParameterSpec = new IvParameterSpec(iv); + + // Extract encrypted part. + int encryptedSize = encryptedIvTextBytes.length - ivSize; + byte[] encryptedBytes = new byte[encryptedSize]; + System.arraycopy(encryptedIvTextBytes, ivSize, encryptedBytes, 0, encryptedSize); + + // Hash key. + byte[] keyBytes = new byte[keySize]; + var messageDigest = MessageDigest.getInstance("SHA-256"); + messageDigest.update(key); + System.arraycopy(messageDigest.digest(), 0, keyBytes, 0, keyBytes.length); + var secretKeySpec = new SecretKeySpec(keyBytes, "AES"); + + // Decrypt. + var cipherDecrypt = Cipher.getInstance("AES/CBC/PKCS5Padding"); + cipherDecrypt.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec); + return cipherDecrypt.doFinal(encryptedBytes); + + } catch (Exception e) { + throw new IllegalStateException(e.getMessage()); + } + } +} diff --git a/src/test/java/EncryptionTest.java b/src/test/java/EncryptionTest.java new file mode 100644 index 0000000000000000000000000000000000000000..7443f8bd2f3b8d4b69c843df050e3b55a1a91f7e --- /dev/null +++ b/src/test/java/EncryptionTest.java @@ -0,0 +1,53 @@ +import net.lulli.encrypt.Pems; +import net.lulli.encrypt.pki.PkiEncryptionManager; +import net.lulli.encrypt.symmetric.SymmetricEncryptionManager; +import org.junit.Ignore; +import org.junit.Test; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.security.PrivateKey; +import java.security.cert.X509Certificate; +import java.util.Arrays; + +public class EncryptionTest { + + @Test + public void symmetricEncryptDecrypt() { + var symmetricEncryptionManager = SymmetricEncryptionManager.INSTANCE; + var plainTest = "This is some long cleartext"; + var key = "abcdefghijklmnopqrstuvz".getBytes(Charset.forName("UTF-8")); + + byte[] encrypted = symmetricEncryptionManager.encrypt(plainTest, key); + + byte[] decrypted = symmetricEncryptionManager.decrypt(encrypted, key); + + assert Arrays.equals(plainTest.getBytes(), decrypted); + } + + @Ignore //TODO + @Test + public void pkiEncryptDecrypt() throws Exception { + var pkiEncryptionManager = PkiEncryptionManager.INSTANCE; + + File outputEncryptedFile = File.createTempFile("pkiEncrDecr.", ".enc"); + File outputDencryptedFile = File.createTempFile("pkiEncrDecr", ".dec"); + var plainText = "this is a sample text"; + String certString = Files.readString(Paths.get(getClass().getResource("local.crt").toURI()), Charset.forName("utf-8")); + + String keyString = Files.readString(Paths.get(getClass().getResource("local.key").toURI()), Charset.forName("utf-8")); + X509Certificate x509Certificate = Pems.readX509Certificate(certString); + + byte[] enc = pkiEncryptionManager.encryptData(plainText.getBytes(), x509Certificate); + System.out.printf("Cleartext: [%s]\n Encrypted: [%s]\n", plainText, new String(enc)); + + Files.write(Paths.get(outputEncryptedFile.getAbsolutePath()), enc); + + PrivateKey privateKey = Pems.readPKCS8PrivateKey(keyString); + pkiEncryptionManager.decryptCms(privateKey, enc, outputDencryptedFile.getAbsolutePath()); + + } +} diff --git a/src/test/resources/local.crt b/src/test/resources/local.crt new file mode 100644 index 0000000000000000000000000000000000000000..7b82fd80890590bb43a772b299c284a680839e2b --- /dev/null +++ b/src/test/resources/local.crt @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFYTCCA0kCFBGl8TU2PlZ5mx7Q/5AAkisMU0ezMA0GCSqGSIb3DQEBCwUAMG0x +CzAJBgNVBAYTAlNFMRIwEAYDVQQIDAlTdG9ja2hvbG0xDjAMBgNVBAcMBUZsb2J5 +MRwwGgYDVQQKDBNLZXZ3ZSBUZWNobm9sb2d5IEFCMQwwCgYDVQQLDANEZXYxDjAM +BgNVBAMMBWxvY2FsMB4XDTI0MDQwNTIxNDIwN1oXDTI1MDQwNTIxNDIwN1owbTEL +MAkGA1UEBhMCU0UxEjAQBgNVBAgMCVN0b2NraG9sbTEOMAwGA1UEBwwFRmxvYnkx +HDAaBgNVBAoME0tldndlIFRlY2hub2xvZ3kgQUIxDDAKBgNVBAsMA0RldjEOMAwG +A1UEAwwFbG9jYWwwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDWRP0V +OivcmAZtGgif3Q/xnn3FqYIypiGt4Fq8Qz780zvPFMJ8SnBpfQh1Xhy6XRtqCB/i +NqYwOnhMo+UyqiFWCOHfVtn/oLpEurM5jHrJmULVyL5Pucx3zHelrFGQkvOt9HMj +2hwGC/1MZl4Aksg9WDqhDSJ6pwdgsmd0UGXDYTGbRPNdu7ywAu8RLqgyY1NkNstB +7sMoqCZd8NFjiGxjfDXoPZ/1mGcQzj24UjX8tH+bIJhoFrRvadWoHfA9GWJM1n+H +P4JEfGTL30WhWW4PntTBvPI6ro8y5LY6jtj+OV45WKe2lkFi/xO8wpwi7skcTK76 +anH6VKOLW7/uy21pbWt7yyx0e7TqExE0I2RoIohtUJ49VbBdexhEdsHt0q1T4RR5 +qAPEQNAduEqr1UH511Etly+Az2PJE9ZqeDbxQdvu0FjK8Tbws+mAVyDBZQ30e1op +/31e7v+8suPyRf8v/wq5Ut9Vse7d81rHE83CPvjqzvN49p+nylrySrnuP0qL1HU7 +tD239FU2szMpxkc6f/v/vQzNFfCylZdKd9/k4l3v7t4ECoLNZ8esnYLrHbJuNhN7 +VGOUsTcAwEFK9n5zOpcS2oU3lO12Cq6vr7OoxY4DGkY0fsye/eVHpUwI/ltVa3jU +i49Esn9fsEraflDTz9ru0u3BIvWuHKG714LtSQIDAQABMA0GCSqGSIb3DQEBCwUA +A4ICAQAexne/vcaEaqyZ8ZNH7RpBwFGtCAJtZiCncbIr1Ih80VGHSgmP/hStxIpl +7Nf8aAm2G0WBQldX7EryJwmTXuoyp9kahJbaCOpzknc+Ckck5mO5X6+u8HvkQ6rt +SzPmQc+RL86v/nYiTVj85oLH2IHA+Ui+DqiUc+oUd8tF4bLH++ocKsfjt1+nPEU9 +ClL2jV80ZVoYjKx/0JpPFRVRr09AZktbR1KijCu0KcCq8ZyE+DYAVUlzV5u73Oih +a/CjXinVYHmaG1td4gXoTB+zF58SOi5Uo/6ccgGoNFixhLJqx4ZtluspWm0aO/yD +kijTjR4zdvEx+xtnOgjwHNFs6cx4SVF+xehPTxvChCIweqmlm4uJEj7oT4fkC3Tn +zs1Vq4ERzHDexxWDBZF9Qi3yvvkIXIahx3rKh9c436gFuI8IEdVdYBrt4qJUQclL +xJQKi0kB8m1tcjp1SH1YgOLR2p4ziv403MeebqVOTaMhI/0KFU1RBPoHc8zM8pKE +TA3VFt1W2EIDyg+c52EE/LSAytuKT7hfWSFsaws+4uHJmf2F4mOl/bn5DCH6yOE7 +sWcDnSTOXlHmTaFwYMpKd6J7AsroxxpsMfF38ah3Ji8ZOqewA+jwO8V84X9eI/bx +gZUtOzHBQhLULySehgBt1CyUPWoawR16n46vXQ4viX4ndldmlQ== +-----END CERTIFICATE----- diff --git a/src/test/resources/local.key b/src/test/resources/local.key new file mode 100644 index 0000000000000000000000000000000000000000..7a6ce209765b5d640a793872b52d8976a1a7d4da --- /dev/null +++ b/src/test/resources/local.key @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +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 +3rV4KEVHvpYDNFOy8iTrQU4y2EE9pA== +-----END PRIVATE KEY-----