Skip to content

Commit

Permalink
Stop using Tomcat Base64 util (#1294)
Browse files Browse the repository at this point in the history
- Removes explicit dependency on Tomcat's Base64 implementation
- Adds new tests to verify that the encoding/decoding works

Resolves #1293
{patch}

Signed-off-by: Esta Nagy <nagyesta@gmail.com>
  • Loading branch information
nagyesta authored Dec 28, 2024
1 parent e538cc5 commit e15a9fb
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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
Expand All @@ -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;
}
},
Expand Down Expand Up @@ -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);
}
};

Expand Down Expand Up @@ -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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<Arguments> instanceProvider() {
return Stream.<Arguments>builder()
Expand All @@ -62,6 +75,19 @@ public static Stream<Arguments> instanceProvider() {
.build();
}

public static Stream<Arguments> base64Provider() {
return Stream.<Arguments>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
Expand Down Expand Up @@ -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);
}

}

0 comments on commit e15a9fb

Please sign in to comment.