diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/AsymEncryption.java b/sdk/src/main/java/io/opentdf/platform/sdk/AsymEncryption.java index 79617c47..415fc375 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/AsymEncryption.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/AsymEncryption.java @@ -4,7 +4,12 @@ import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; + +import java.io.ByteArrayInputStream; import java.security.*; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; import java.security.spec.InvalidKeySpecException; import java.security.spec.X509EncodedKeySpec; import java.util.Base64; @@ -14,6 +19,8 @@ public class AsymEncryption { private final PublicKey publicKey; private static final String PUBLIC_KEY_HEADER = "-----BEGIN PUBLIC KEY-----"; private static final String PUBLIC_KEY_FOOTER = "-----END PUBLIC KEY-----"; + private static final String PEM_HEADER = "-----BEGIN (.*)-----"; + private static final String PEM_FOOTER = "-----END (.*)-----"; private static final String CIPHER_TRANSFORM = "RSA/ECB/OAEPWithSHA-1AndMGF1Padding"; /** @@ -22,24 +29,51 @@ public class AsymEncryption { * @param publicKeyInPem a Public Key in PEM format */ public AsymEncryption(String publicKeyInPem) { - publicKeyInPem = publicKeyInPem - .replace(PUBLIC_KEY_HEADER, "") - .replace(PUBLIC_KEY_FOOTER, "") - .replaceAll("\\s", ""); - byte[] decoded = Base64.getDecoder().decode(publicKeyInPem); - X509EncodedKeySpec spec = new X509EncodedKeySpec(decoded); - KeyFactory kf; - try { - kf = KeyFactory.getInstance("RSA"); - } catch (NoSuchAlgorithmException e) { - throw new SDKException("RSA is not a valid algorithm!!!???!!!", e); + PublicKey pubKey = null; + + String base64EncodedPem= publicKeyInPem + .replaceAll(PEM_HEADER, "") + .replaceAll(PEM_FOOTER, "") + .replaceAll("\\s", "") + .replaceAll("\r\n", "") + .replaceAll("\n", "") + .trim(); + + + byte[] decoded = Base64.getDecoder().decode(base64EncodedPem); + + // Check if the PEM contains a certificate + if (publicKeyInPem.contains("BEGIN CERTIFICATE")) { + try { + // Parse the certificate + CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); + X509Certificate cert = (X509Certificate) certFactory.generateCertificate(new ByteArrayInputStream(decoded)); + pubKey = cert.getPublicKey(); + } catch (CertificateException e) { + throw new SDKException("x509.ParseCertificate failed: " + e.getMessage(), e); + } + } else { + // Otherwise, treat it as a PKIX public key + X509EncodedKeySpec spec = new X509EncodedKeySpec(decoded); + KeyFactory keyFactory; + try { + keyFactory = KeyFactory.getInstance("RSA"); + } catch (NoSuchAlgorithmException e) { + throw new SDKException("RSA is not a valid algorithm!!!???!!!", e); + } + try { + pubKey = keyFactory.generatePublic(spec); + } catch (InvalidKeySpecException e) { + throw new SDKException("error creating asymmetric encryption", e); + } } - try { - this.publicKey = kf.generatePublic(spec); - } catch (InvalidKeySpecException e) { - throw new SDKException("error creating asymmetric encryption", e); + // Check if the public key is RSA + if (pubKey instanceof java.security.interfaces.RSAPublicKey) { + this.publicKey = pubKey; + } else { + throw new SDKException("Not an RSA PEM formatted public key"); } } diff --git a/sdk/src/test/java/io/opentdf/platform/sdk/AsymEncryptionTest.java b/sdk/src/test/java/io/opentdf/platform/sdk/AsymEncryptionTest.java index 03e8a45c..49e954a0 100644 --- a/sdk/src/test/java/io/opentdf/platform/sdk/AsymEncryptionTest.java +++ b/sdk/src/test/java/io/opentdf/platform/sdk/AsymEncryptionTest.java @@ -30,6 +30,34 @@ void encryptionWithValidPublicKey() throws Exception { assertNotNull(cipherText); } + void encryptionWithValidCert() throws Exception { + String certInPem = "-----BEGIN CERTIFICATE-----\n" + + "MIIC/TCCAeWgAwIBAgIUXW8s3YqpfBwH/obH1WWCyxum+dUwDQYJKoZIhvcNAQEL\n" + + "BQAwDjEMMAoGA1UEAwwDa2FzMB4XDTI0MDgyNjE1NTk1OVoXDTI1MDgyNjE1NTk1\n" + + "OVowDjEMMAoGA1UEAwwDa2FzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC\n" + + "AQEAqoOoHEG22LwxB/9A0OG0ZTizzqjUgNpOBj/z31ynmCI5fJR+bEoAp8fEVa3t\n" + + "8Z9EEMi103u+SCtqG0nsh5A5EZOkEQIJA7f4LxAzo4vcpKAzIDagVat/C7FbkZ2j\n" + + "oqPRWfiXw4WdrsYOT3Ty//ZREqA7VCS2WJ58wvBvAduAd/URKqCrQlA2atmmT49A\n" + + "224xz1Ghl67uQQK7+SWdh9AKF2SW3p5fqTutPBvNf9jrh5yfE60QRxQQ2VfdQMRG\n" + + "Nl0hSfDs7J6l15xzJYivHpaq3jx5EsAoqcnr5tE4vqOdOziOomd9Rlfn2iuiL5BF\n" + + "EMLpa70rjWbI5chxJ09LI86avQIDAQABo1MwUTAdBgNVHQ4EFgQU3k3anh79M5M0\n" + + "oTI7W4yhPJi9ZhswHwYDVR0jBBgwFoAU3k3anh79M5M0oTI7W4yhPJi9ZhswDwYD\n" + + "VR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEADvFBvHAfxkVL13sQ+sz+\n" + + "UnrHjekh9Jm85f1cFbSNjTfTgQ9z8xyWMLdlIhLFk9pOoFxBETi24vm7q/RTH/SX\n" + + "UmB53iV0XyydMqG5SUu7qR0yh3DXc8SdMbMduWXGYr0r8IIYUamcxnRmV+L08bLa\n" + + "kae3VLyPF5CiwuxWR/ixnM4SrxwkB/RrqxFjmpkzlZbqgyW8ISVnQFy3eUkAfM1b\n" + + "OcL/UAwQ2pXmfEFjYBs5mDEpKwGC0DxW4tg0FIsb3bbAvqy8ETklExkOh0VfJP4a\n" + + "CMz9WjmCfS15t0mPzofK8ir20kF0u0sWvviVVlun+8KYdFOG/wzS100cPNn/wqug\n" + + "4w==\n" + + "-----END CERTIFICATE-----";; + AsymEncryption asymEncryption = new AsymEncryption(certInPem); + byte[] plaintext = "Virtru, JavaSDK!".getBytes(); + + byte[] cipherText = asymEncryption.encrypt(plaintext); + + assertNotNull(cipherText); + } + @Test void encryptionWithInvalidPublicKey() { String publicKeyInPem = "InvalidPublicKey";