eBook – Guide Spring Cloud – NPI EA (cat=Spring Cloud)
announcement - icon

Let's get started with a Microservice Architecture with Spring Cloud:

>> Join Pro and download the eBook

eBook – Mockito – NPI EA (tag = Mockito)
announcement - icon

Mocking is an essential part of unit testing, and the Mockito library makes it easy to write clean and intuitive unit tests for your Java code.

Get started with mocking and improve your application tests using our Mockito guide:

Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Reactive – NPI EA (cat=Reactive)
announcement - icon

Spring 5 added support for reactive programming with the Spring WebFlux module, which has been improved upon ever since. Get started with the Reactor project basics and reactive programming in Spring Boot:

>> Join Pro and download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Jackson – NPI EA (cat=Jackson)
announcement - icon

Do JSON right with Jackson

Download the E-book

eBook – HTTP Client – NPI EA (cat=Http Client-Side)
announcement - icon

Get the most out of the Apache HTTP Client

Download the E-book

eBook – Maven – NPI EA (cat = Maven)
announcement - icon

Get Started with Apache Maven:

Download the E-book

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

eBook – RwS – NPI EA (cat=Spring MVC)
announcement - icon

Building a REST API with Spring?

Download the E-book

Course – LS – NPI EA (cat=Jackson)
announcement - icon

Get started with Spring and Spring Boot, through the Learn Spring course:

>> LEARN SPRING
Course – RWSB – NPI EA (cat=REST)
announcement - icon

Explore Spring Boot 3 and Spring 6 in-depth through building a full REST API with the framework:

>> The New “REST With Spring Boot”

Course – LSS – NPI EA (cat=Spring Security)
announcement - icon

Yes, Spring Security can be complex, from the more advanced functionality within the Core to the deep OAuth support in the framework.

I built the security material as two full courses - Core and OAuth, to get practical with these more complex scenarios. We explore when and how to use each feature and code through it on the backing project.

You can explore the course here:

>> Learn Spring Security

Course – LSD – NPI EA (tag=Spring Data JPA)
announcement - icon

Spring Data JPA is a great way to handle the complexity of JPA with the powerful simplicity of Spring Boot.

Get started with Spring Data JPA through the guided reference course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (cat=Spring Boot)
announcement - icon

Refactor Java code safely — and automatically — with OpenRewrite.

Refactoring big codebases by hand is slow, risky, and easy to put off. That’s where OpenRewrite comes in. The open-source framework for large-scale, automated code transformations helps teams modernize safely and consistently.

Each month, the creators and maintainers of OpenRewrite at Moderne run live, hands-on training sessions — one for newcomers and one for experienced users. You’ll see how recipes work, how to apply them across projects, and how to modernize code with confidence.

Join the next session, bring your questions, and learn how to automate the kind of work that usually eats your sprint time.

Course – LJB – NPI EA (cat = Core Java)
announcement - icon

Code your way through and build up a solid, practical foundation of Java:

>> Learn Java Basics

Partner – LambdaTest – NPI EA (cat= Testing)
announcement - icon

Distributed systems often come with complex challenges such as service-to-service communication, state management, asynchronous messaging, security, and more.

Dapr (Distributed Application Runtime) provides a set of APIs and building blocks to address these challenges, abstracting away infrastructure so we can focus on business logic.

In this tutorial, we'll focus on Dapr's pub/sub API for message brokering. Using its Spring Boot integration, we'll simplify the creation of a loosely coupled, portable, and easily testable pub/sub messaging system:

>> Flexible Pub/Sub Messaging With Spring Boot and Dapr

1. Overview

In this tutorial, we’ll learn how to manage cryptographic keys and certificates in Java using the KeyStore API.

2. Keystores

A Keystore in Java is a secure storage mechanism used to manage cryptographic keys and certificates. It’s a collection of key entries, each identified by an alias, and can store private keys, public keys, secret keys, and trusted certificates.

Java provides different types of keystores, each having its specific format and use case:

  • JKS (Java Keystore): The default keystore type used by Java. It’s primarily used for storing key pairs (private and public keys) and certificates
  • PKCS12: A more widely used format for storing keys and certificates. It’s a standard format supported by many applications and tools, making it more interoperable
  • JCEKS (Java Cryptography Extension Keystore): Used for storing secret keys that require stronger encryption than JKS
  • BKS (Bouncy Castle Keystore): A keystore format provided by the Bouncy Castle cryptographic provider

By default, the Java runtime includes a cacerts file which is typically located in JAVA_HOME/jre/lib/security/cacerts that acts as a trusted certificate store. This file contains certificates from trusted Certificate Authorities (CAs).

The default password for accessing the cacerts file is changeit. However, it’s not recommended to use the default password for production environments. We can configure the keystore password using the -Dkeystore.password system property.

3. KeyStore Class

The KeyStore class in Java is part of the java.security package and provides a comprehensive API for managing cryptographic keys and certificates. It serves as the core class for interacting with keystores, allowing us to create, load, store, and retrieve entries securely.

Here are some of the most important methods provided by the KeyStore class:

  • getInstance(String type): Creates a new KeyStore instance of the specified type (e.g., JKS, PKCS12, JCEKS)
  • store(OutputStream stream, char[] password): Saves the keystore to the specified output stream, protected by the given password
  • load(InputStream stream, char[] password): Loads the keystore from the specified input stream. If null is passed, it initializes an empty keystore
  • setEntry(String alias, KeyStore.Entry entry, KeyStore.ProtectionParameter protParam): Adds or updates an entry (e.g., key or certificate) in the keystore under the specified alias
  • getEntry(String alias, KeyStore.ProtectionParameter protParam): Retrieves an entry from the keystore using the specified alias and protection parameters
  • getCertificate(String alias): Retrieves a certificate from the keystore using the specified alias
  • setCertificateEntry(String alias, Certificate cert): Adds or updates a certificate entry in the keystore under the specified alias
  • containsAlias(String alias): Checks if the keystore contains an entry with the specified alias
  • aliases(): Returns an enumeration of all aliases in the keystore

4. Creating a Keystore

Now that we’ve established some background, let’s create our first one.

4.1. Construction

We can easily create a keystore using keytool, or we can do it programmatically using the KeyStore API:

KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());

Here we used the default type, though there are a few keystore types available, like jceks or pkcs12.

We can override the default “JKS”(an Oracle-proprietary keystore protocol) type using a -Dkeystore.type parameter:

-Dkeystore.type=pkcs12

Or we can list one of the supported formats in getInstance:

KeyStore ks = KeyStore.getInstance("pkcs12");

4.2. Initialization

Initially, we need to load the keystore:

char[] pwdArray = "password".toCharArray();
ks.load(null, pwdArray);

We use load whether we’re creating a new keystore or opening up an existing one. We’ll tell KeyStore to create a new one by passing null as the first parameter.

We also provide a password, which will be used for accessing the keystore in the future. We can also set this to null, though that would make our secrets open.

4.3. Storage

Finally, we save our new keystore to the file system:

try (FileOutputStream fos = new FileOutputStream("newKeyStoreFileName.jks")) {
    ks.store(fos, pwdArray);
}

Note that not shown above are the several checked exceptions that getInstanceload, and store each throw.

5. Loading a Keystore

To load a keystore, we first need to create a KeyStore instance, like before.

This time though, we’ll specify the format, since we’re loading an existing one:

KeyStore ks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream("newKeyStoreFileName.jks"), pwdArray);

If our JVM doesn’t support the keystore type we passed, or if it doesn’t match the type of the keystore on the filesystem that we’re opening, we’ll get a KeyStoreException:

java.security.KeyStoreException: KEYSTORE_TYPE not found

Also, if the password is wrong, we’ll get an UnrecoverableKeyException:

java.security.UnrecoverableKeyException: Password verification failed

6. Storing Entries

In the keystore, we can store three different kinds of entries, each under its alias:

  • Symmetric Keys (referred to as Secret Keys in the JCE)
  • Asymmetric Keys (referred to as Public and Private Keys in the JCE)
  • Trusted Certificates

Let’s take a look at each one.

6.1. Saving a Symmetric Key

The simplest thing we can store in a keystore is a Symmetric Key.

To save a symmetric key, we’ll need three things:

  1. an alias – this is simply the name that we’ll use in the future to refer to the entry
  2. a key – which is wrapped in a KeyStore.SecretKeyEntry
  3. a password – which is wrapped in what is called a ProtectionParam
KeyStore.SecretKeyEntry secret
 = new KeyStore.SecretKeyEntry(secretKey);
KeyStore.ProtectionParameter password
 = new KeyStore.PasswordProtection(pwdArray);
ks.setEntry("db-encryption-secret", secret, password);

Keep in mind that the password can’t be null; however, it can be an empty String. If we leave the password null for an entry, we’ll get a KeyStoreException:

java.security.KeyStoreException: non-null password required to create SecretKeyEntry

It may seem a little weird that we need to wrap the key and the password in wrapper classes.

We wrap the key because setEntry is a generic method that can be used for the other entry types as well. The type of entry allows the KeyStore API to treat it differently.

We wrap the password because the KeyStore API supports callbacks to GUIs and CLIs to collect the password from the end user. We can check out the KeyStore.CallbackHandlerProtection Javadoc for more details.

We can also use this method to update an existing key; we just need to call it again with the same alias and password and our new secret.

6.2. Saving a Private Key

Storing asymmetric keys is a bit more complex, since we need to deal with certificate chains.

The KeyStore API gives us a dedicated method called setKeyEntry, which is more convenient than the generic setEntry method.

So to save an asymmetric key, we’ll need four things:

  1. an alias – like before
  2. a private key – because we aren’t using the generic method, the key won’t get wrapped. Also, in our case, it should be an instance of PrivateKey.
  3. a password – used to access the entry. This time, the password is mandatory.
  4. a certificate chain – this certifies the corresponding public key
X509Certificate[] certificateChain = new X509Certificate[2];
chain[0] = clientCert;
chain[1] = caCert;
ks.setKeyEntry("sso-signing-key", privateKey, pwdArray, certificateChain);

Lots can go wrong here, of course, like if pwdArray is null:

java.security.KeyStoreException: password can't be null

But there’s a really strange exception to be aware of, which occurs if pwdArray is an empty array:

java.security.UnrecoverableKeyException: Given final block not properly padded

To update, we can simply call the method again with the same alias and a new privateKey and certificateChain.

It might also be valuable to do a quick refresher on how to generate a certificate chain.

6.3. Saving a Trusted Certificate

Storing trusted certificates is quite simple. It only requires the alias and the certificate itself, which is of type Certificate:

ks.setCertificateEntry("google.com", trustedCertificate);

Usually, the certificate is one that we didn’t generate, and instead came from a third-party.

Because of that, it’s important to note here that KeyStore doesn’t actually verify this certificate. We should verify it on our own before storing it.

To update, we can simply call the method again with the same alias and a new trustedCertificate.

7. Reading Entries

Now that we’ve written some entries, we’ll certainly want to read them.

7.1. Reading a Single Entry

First, we can pull keys and certificates out by their alias:

Key ssoSigningKey = ks.getKey("sso-signing-key", pwdArray);
Certificate google = ks.getCertificate("google.com");

If there’s no entry by that name, or it’s of a different type, then getKey simply returns null:

public void whenEntryIsMissingOrOfIncorrectType_thenReturnsNull() {
    // ... initialize keystore
    // ... add an entry called "widget-api-secret"

   Assert.assertNull(ks.getKey("some-other-api-secret"));
   Assert.assertNotNull(ks.getKey("widget-api-secret"));
   Assert.assertNull(ks.getCertificate("widget-api-secret")); 
}

But if the password for the key is wrong, we’ll get that same odd error we talked about earlier:

java.security.UnrecoverableKeyException: Given final block not properly padded

7.2. Checking if a Keystore Contains an Alias

Since KeyStore just stores entries using a Map, it exposes the ability to check for existence without retrieving the entry:

public void whenAddingAlias_thenCanQueryWithoutSaving() {
    // ... initialize keystore
    // ... add an entry called "widget-api-secret"
    assertTrue(ks.containsAlias("widget-api-secret"));
    assertFalse(ks.containsAlias("some-other-api-secret"));
}

7.3. Checking the Kind of Entry

KeyStore#entryInstanceOf is a bit more powerful.

It’s similar to containsAlias, except it also checks the entry type:

public void whenAddingAlias_thenCanQueryByType() {
    // ... initialize keystore
    // ... add a secret entry called "widget-api-secret"
    assertTrue(ks.containsAlias("widget-api-secret"));
    assertFalse(ks.entryInstanceOf(
      "widget-api-secret",
      KeyType.PrivateKeyEntry.class));
}

8. Deleting Entries

KeyStore, of course, supports deleting the entries we’ve added:

public void whenDeletingAnAlias_thenIdempotent() {
    // ... initialize a keystore
    // ... add an entry called "widget-api-secret"
    assertEquals(ks.size(), 1);
    ks.deleteEntry("widget-api-secret");
    ks.deleteEntry("some-other-api-secret");
    assertFalse(ks.size(), 0);
}

Fortunately, deleteEntry is idempotent, so the method reacts the same whether the entry exists or not.

9. Deleting a Keystore

If we want to delete our keystore, the API is no help to us, but we can still use Java to do it:

Files.delete(Paths.get(keystorePath));

Or, as an alternative, we can keep the keystore around and just remove entries:

Enumeration<String> aliases = keyStore.aliases();
while (aliases.hasMoreElements()) {
    String alias = aliases.nextElement();
    keyStore.deleteEntry(alias);
}

10. Conclusion

In this article, we learned how to manage certificates and keys using KeyStore API. We discussed what a keystore is, and explored how to create, load and delete one. We also demonstrated how to store a key or certificate in the keystore, and how to load and update existing entries with new values.

The code backing this article is available on GitHub. Once you're logged in as a Baeldung Pro Member, start learning and coding on the project.
Baeldung Pro – NPI EA (cat = Baeldung)
announcement - icon

Baeldung Pro comes with both absolutely No-Ads as well as finally with Dark Mode, for a clean learning experience:

>> Explore a clean Baeldung

Once the early-adopter seats are all used, the price will go up and stay at $33/year.

eBook – HTTP Client – NPI EA (cat=HTTP Client-Side)
announcement - icon

The Apache HTTP Client is a very robust library, suitable for both simple and advanced use cases when testing HTTP endpoints. Check out our guide covering basic request and response handling, as well as security, cookies, timeouts, and more:

>> Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

Course – LS – NPI EA (cat=REST)

announcement - icon

Get started with Spring Boot and with core Spring, through the Learn Spring course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (tag=Refactoring)
announcement - icon

Modern Java teams move fast — but codebases don’t always keep up. Frameworks change, dependencies drift, and tech debt builds until it starts to drag on delivery. OpenRewrite was built to fix that: an open-source refactoring engine that automates repetitive code changes while keeping developer intent intact.

The monthly training series, led by the creators and maintainers of OpenRewrite at Moderne, walks through real-world migrations and modernization patterns. Whether you’re new to recipes or ready to write your own, you’ll learn practical ways to refactor safely and at scale.

If you’ve ever wished refactoring felt as natural — and as fast — as writing code, this is a good place to start.

Course – LSS – NPI (cat=Security/Spring Security)
announcement - icon

I just announced the new Learn Spring Security course, including the full material focused on the new OAuth2 stack in Spring Security:

>> CHECK OUT THE COURSE

eBook Jackson – NPI EA – 3 (cat = Jackson)