diff --git a/lowkey-vault-app/src/main/java/com/github/nagyesta/lowkeyvault/service/certificate/impl/CertContentType.java b/lowkey-vault-app/src/main/java/com/github/nagyesta/lowkeyvault/service/certificate/impl/CertContentType.java index 27641a34..ffd50a71 100644 --- a/lowkey-vault-app/src/main/java/com/github/nagyesta/lowkeyvault/service/certificate/impl/CertContentType.java +++ b/lowkey-vault-app/src/main/java/com/github/nagyesta/lowkeyvault/service/certificate/impl/CertContentType.java @@ -8,7 +8,6 @@ import com.github.nagyesta.lowkeyvault.service.key.util.KeyGenUtil; import lombok.Getter; import lombok.NonNull; -import org.apache.tomcat.util.codec.binary.Base64; import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey; import org.bouncycastle.openssl.jcajce.JcaPEMWriter; import org.bouncycastle.openssl.jcajce.JcaPKCS8Generator; @@ -26,6 +25,7 @@ import java.security.interfaces.RSAPrivateCrtKey; import java.security.spec.PKCS8EncodedKeySpec; import java.util.Arrays; +import java.util.Base64; import java.util.List; import static com.github.nagyesta.lowkeyvault.model.v7_2.key.constants.KeyType.EC; @@ -72,7 +72,7 @@ public JsonWebKeyImportRequest getKey(@NonNull final String certificateContent, public String asBase64CertificatePackage(@NonNull final Certificate certificate, @NonNull final KeyPair keyPair) throws CryptoException { final byte[] bytes = generateCertificatePackage(certificate, keyPair, DEFAULT_PASSWORD); - return new Base64().encodeAsString(bytes); + return encodeAsBase64String(bytes); } @Override @@ -98,7 +98,7 @@ private byte[] generateCertificatePackage( private KeyStore loadKeyStore(final String certificateContent, final String password) throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException { final KeyStore pkcs12 = KeyStore.getInstance(KEY_STORE_TYPE_PKCS12, KeyGenUtil.BOUNCY_CASTLE_PROVIDER); - pkcs12.load(new ByteArrayInputStream(Base64.decodeBase64(certificateContent)), password.toCharArray()); + pkcs12.load(new ByteArrayInputStream(decodeBase64String(certificateContent)), password.toCharArray()); return pkcs12; } }, @@ -178,7 +178,7 @@ private byte[] extractByteArray(final String certificateContent, final String be final String withoutNewLines = certificateContent.replaceAll("[\n\r]+", ""); final String keyOnly = withoutNewLines.replaceAll(".*" + beginPattern, "") .replaceAll(endPattern + ".*", ""); - return Base64.decodeBase64(keyOnly); + return decodeBase64String(keyOnly); } }; @@ -233,4 +233,12 @@ public static CertContentType byMimeType(final String mimeType) { public abstract String asBase64CertificatePackage(Certificate certificate, KeyPair keyPair) throws CryptoException; public abstract byte[] certificatePackageForBackup(Certificate certificate, KeyPair keyPair) throws CryptoException; + + static byte[] decodeBase64String(final String certificateContent) { + return Base64.getMimeDecoder().decode(certificateContent); + } + + static String encodeAsBase64String(final byte[] bytes) { + return Base64.getMimeEncoder().encodeToString(bytes); + } } diff --git a/lowkey-vault-app/src/test/java/com/github/nagyesta/lowkeyvault/service/certificate/impl/CertContentTypeTest.java b/lowkey-vault-app/src/test/java/com/github/nagyesta/lowkeyvault/service/certificate/impl/CertContentTypeTest.java index 057a054f..0a029f87 100644 --- a/lowkey-vault-app/src/test/java/com/github/nagyesta/lowkeyvault/service/certificate/impl/CertContentTypeTest.java +++ b/lowkey-vault-app/src/test/java/com/github/nagyesta/lowkeyvault/service/certificate/impl/CertContentTypeTest.java @@ -54,6 +54,19 @@ class CertContentTypeTest { + "NjuCqPwdGwuYHGe/SskEqjVYxFoFknPhsn5Y64b1RuJe19qjewYl0NBmBjiEexY1" + "Tg/nnzqHPv4GAnWcp4e9IOAB00LfXwFj4D/lTOuGpdUFeIhjN0dx"; private static final int KEY_SIZE = 2048; + private static final String MIME_BASE64 = "TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdCwg\r\n" + + "c2VkIGRvIGVpdXNtb2QgdGVtcG9yIGluY2lkaWR1bnQgdXQgbGFib3JlIGV0IGRvbG9yZSBtYWdu\r\n" + + "YQphbGlxdWEuIFV0IGVuaW0gYWQgbWluaW0gdmVuaWFtLCBxdWlzIG5vc3RydWQgZXhlcmNpdGF0\r\n" + + "aW9uIHVsbGFtY28gbGFib3JpcyBuaXNpIHV0IGFsaXF1aXAgZXggZWEgY29tbW9kbyBjb25zZXF1\r\n" + + "YXQuCkR1aXMgYXV0ZSBpcnVyZSBkb2xvciBpbiByZXByZWhlbmRlcml0IGluIHZvbHVwdGF0ZSB2\r\n" + + "ZWxpdCBlc3NlIGNpbGx1bSBkb2xvcmUgZXUgZnVnaWF0IG51bGxhIHBhcmlhdHVyLiBFeGNlcHRl\r\n" + + "dXIKc2ludCBvY2NhZWNhdCBjdXBpZGF0YXQgbm9uIHByb2lkZW50LCBzdW50IGluIGN1bHBhIHF1\r\n" + + "aSBvZmZpY2lhIGRlc2VydW50IG1vbGxpdCBhbmltIGlkIGVzdCBsYWJvcnVtLgo="; + private static final byte[] MIME_BYTES = ("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt " + + "ut labore et dolore magna\naliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut " + + "aliquip ex ea commodo consequat.\nDuis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore " + + "eu fugiat nulla pariatur. Excepteur\nsint occaecat cupidatat non proident, sunt in culpa qui officia deserunt " + + "mollit anim id est laborum.\n").getBytes(StandardCharsets.UTF_8); public static Stream instanceProvider() { return Stream.builder() @@ -62,6 +75,19 @@ public static Stream instanceProvider() { .build(); } + public static Stream base64Provider() { + return Stream.builder() + .add(Arguments.of("lorem ipsum".getBytes(StandardCharsets.UTF_8), "bG9yZW0gaXBzdW0=")) + .add(Arguments.of(MIME_BYTES, MIME_BASE64)) + .add(Arguments.of("1".getBytes(StandardCharsets.UTF_8), "MQ==")) + .add(Arguments.of("12".getBytes(StandardCharsets.UTF_8), "MTI=")) + .add(Arguments.of("123".getBytes(StandardCharsets.UTF_8), "MTIz")) + .add(Arguments.of("1234".getBytes(StandardCharsets.UTF_8), "MTIzNA==")) + .add(Arguments.of("12345".getBytes(StandardCharsets.UTF_8), "MTIzNDU=")) + .add(Arguments.of("123456".getBytes(StandardCharsets.UTF_8), "MTIzNDU2")) + .build(); + } + @Test void testGetMimeTypeShouldReturnTheMimeTypeOfTheSourceWhenCalledOnPkcs12() { //given @@ -433,8 +459,31 @@ void testCertificatePackageForBackupShouldThrowExceptionWhenCalledWithValidKeyAn //then + exception } + @ParameterizedTest + @MethodSource("base64Provider") + void testEncodeAsBase64StringShouldProduceTheExpectedBase64String(final byte[] input, final String expected) { + //given + + //when + final String actual = CertContentType.encodeAsBase64String(input); + + //then + Assertions.assertEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("base64Provider") + void testDecodeBase64StringShouldProduceTheExpectedByteArray(final byte[] expected, final String input) { + //given + + //when + final byte[] actual = CertContentType.decodeBase64String(input); + + //then + Assertions.assertArrayEquals(expected, actual); + } + private static String toBase64(final Certificate certificate) throws CertificateEncodingException { return new String(Base64.encode(certificate.getEncoded()), StandardCharsets.UTF_8); } - }