Install SoftHSM and Access it via Java Program

SoftHSM is a software implementation of HSM (Hardware Security Module) aims to perform all the functions that a proper HSM would perform without providing the hardware security protections afforded by a real HSM. If you are a user who is not willing to invest in a new hardware device, then you can use SoftHSM which is a cryptographic store accessible through a PKCS#11 interface. It is developed as part of the OpenDNSSEC project designed to meet the requirements of OpenDNSSEC, but can also work together with other cryptographic products because of its PKCS#11 interface. This article will help you to install SoftHSM.

How to install SoftHSM

You can install SoftHSM using multiple ways. First, let’s see through package managers such as apt-get for Ubuntu and yum for CentOS.

SoftHSM depends on below cryptographic library and its required version:

Botan 2.0.0 (Use at least 2.6.0 for better performance)
or
OpenSSL 1.0.0

How to install SoftHSM on Ubuntu

Use the below commands to install SoftHSM

# sudo apt-get install softhsm
Old SoftHSM version

If SoftHSM version is old and if you need the latest version, then follow the source installation below.

How to install SoftHSM on CentOS

Use YUM to install SoftHSM

$ sudo yum install softhsm

You can also download the SoftHSM rpm package and install it as below:

$ wget http://mirror.centos.org/centos/7/os/x86_64/Packages/softhsm-2.1.0-3.el7.x86_64.rpm
$ sudo yum install softhsm-2.1.0-3.el7.x86_64.rpm -y
or
$ sudo rpm -Uvh softhsm-2.1.0-3.el7.x86_64.rpm

How to install SoftHSM through source compilation

Make sure you have GNU Autotools (Autoconf, Automake, Libtool) for building the software. It is also recommended to install pkg-config so that the configure script can find the installed software. You also need libp11-kit-dev to install SoftHSM as a PKCS#11 module on the system.

Step 1: Make sure you have automake, autoconf, libtool, pkg-config git packages installed

Step 2: Download the SoftHSM package

# git clone https://github.com/opendnssec/SoftHSMv2.git
# cd SoftHSMv2

Step 3: Configure the installation script

$ ./configure

Follow if you encounter OpenSSL library has no GOST support

Step 4: Compile

$ make

Step 5: Install SoftHSM

$ sudo make install

How to use SoftHSM

After installing the SoftHSM, you can access it via SoftHSM Utility commands as shown below.

$ softhsm2-util

In order to initialize the soft token, execute the below command:

$ softhsm2-util --init-token --slot 0 --label "encryptionkey"

When initializing the soft token, you will be asked to set User Pin and SO pin. The User pin is used by an application to interact with the token and SO pin for reinitializing the token. So you need to remember the pin that you are going to set.

The below command will list slots:

$ softhsm2-util --show-slots
Available slots:
Slot 462451351
Slot info:
Description: SoftHSM slot ID 0x1b907297
Manufacturer ID: SoftHSM project
Hardware version: 2.5
Firmware version: 2.5
Token present: yes
Token info:
Manufacturer ID: SoftHSM project
Model: SoftHSM v2
Hardware version: 2.5
Firmware version: 2.5
Serial number: 360a5ad59b907297
Initialized: yes
User PIN init.: yes
Label: encryptionkey
Slot 1
Slot info:
Description: SoftHSM slot ID 0x1
Manufacturer ID: SoftHSM project
Hardware version: 2.5
Firmware version: 2.5
Token present: yes
Token info:
Manufacturer ID: SoftHSM project
Model: SoftHSM v2
Hardware version: 2.5
Firmware version: 2.5
Serial number:
Initialized: no
User PIN init.: no
Label:

That’s it, the SoftHSM has been successfully installed and configured. Shall we now communicate with it programmatically?

In order to communicate with SoftHSM, we need to create a configuration file that has to be stored in the root directory of the project.

name = SoftHSM
library = /usr/local/lib/softhsm/libsofthsm2.so
slot = 462451351
attributes(generate, *, *) = {
   CKA_TOKEN = true
}
attributes(generate, CKO_CERTIFICATE, *) = {
   CKA_PRIVATE = false
}
attributes(generate, CKO_PUBLIC_KEY, *) = {
   CKA_PRIVATE = false
}
Replace slot

You need to replace the slot ID with your own.

Let me take you through a Java program for communicating with SoftHSM. The program will take a string as an input, encrypt it and decrypt it back for us.

package tg.blr;

import java.io.FileWriter;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.Provider;
import java.security.Security;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.util.Scanner;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class SoftHsmTest {

private static final String TRANSFORMATION = "AES/ECB/PKCS5Padding";
public static String encodedString = new String();

static { 
Security.addProvider(new BouncyCastleProvider()); 
}

static byte[] decryptbytes;

public static void main(String[] args) {

System.out.println("Enter the text to be encrypted: ");
Scanner s = new Scanner(System.in);
String inputtext = s.nextLine();
s.close();

try {
String filePath = "/usr/local/lib/softhsm/libsofthsm2.so";
//To create softhsm.cfg
FileWriter fw = new FileWriter("softhsm.cfg");
fw.write("name = SoftHSM\n" + "library = " + filePath);
//Change the slot ID
fw.write("\n slot = 462451351\n" + "attributes(generate, *, *) = {\n");
fw.write("\t CKA_TOKEN = true\n}\n" + "attributes(generate, CKO_CERTIFICATE, *) = {\n");
fw.write("\t CKA_PRIVATE = false\n}\n" + "attributes(generate, CKO_PUBLIC_KEY, *) = {\n");
fw.write("\t CKA_PRIVATE = false\n}\n");
fw.close();
} catch (IOException e2) {
e2.printStackTrace();
}
String pkcs11ConfigData = "softhsm.cfg";
Provider pkcs11Provider = Security.getProvider("SunPKCS11");
pkcs11Provider = pkcs11Provider.configure(pkcs11ConfigData);

if (-1 == Security.addProvider(pkcs11Provider)) {
throw new RuntimeException("could not add security provider");
} else {
System.out.println("provider initialized !!!");
}

Security.addProvider(pkcs11Provider);
//User pin created while initializing soft token
char[] pin = "sukumar123".toCharArray();
KeyStore keyStore;
try {
keyStore = KeyStore.getInstance("PKCS11", pkcs11Provider);
keyStore.load(null, pin); 
SecretKeySpec secretKeySpec = new SecretKeySpec("0123456789ABCDEF".getBytes(), 0, 16, "AES");
Key key = new SecretKeySpec(secretKeySpec.getEncoded(), 0, 16, "AES");
keyStore.setKeyEntry("AA", key, "sukumar123".toCharArray(), null);
keyStore.store(null);
SecretKey key1 = (SecretKey) keyStore.getKey("AA", "sukumar123".toCharArray());
System.out.println("the algorithm: "+key1.getAlgorithm()+", the key: "+key1.toString()+", format: "+key1.serialVersionUID);

String encryptedString = performEncryption(key1, inputtext);

System.out.println("encryptedString : "+encryptedString);

performDecryption(key1, encryptedString);

} catch (KeyStoreException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (UnrecoverableKeyException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}


private static String performEncryption(Key secretKey, String inputtext) throws Exception {
String encryptedText = new String();
Cipher cipher;
try {
cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] cipherText = cipher.doFinal(inputtext.getBytes("utf-8"));
encryptedText = java.util.Base64.getEncoder().encodeToString(cipherText);
} catch (NoSuchAlgorithmException e) {
System.out.println("No such algorithm exception");
e.printStackTrace();
} catch (NoSuchPaddingException e) {
System.out.println("No such padding exception");
e.printStackTrace();
} catch (InvalidKeyException e) {
System.out.println("Invalid key exception");
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
System.out.println("Illegal block size exception");
e.printStackTrace();
} catch (BadPaddingException e) {
System.out.println("Bad padding exception");
e.printStackTrace();
} finally {

}
return encryptedText;
}


private static void performDecryption(Key key, String encryptedString) throws Exception {
Key secretKey = key;
Cipher cipher;
try {
cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(Cipher.DECRYPT_MODE, secretKey);
byte[] deciphered = cipher.doFinal(java.util.Base64.getDecoder().decode(encryptedString));
System.out.println("decrypted text: "+new String(deciphered));
} catch (NoSuchAlgorithmException e) {
System.out.println("No such algorithm exception");
e.printStackTrace();
} catch (NoSuchPaddingException e) {
System.out.println("No such padding exception");
e.printStackTrace();
} catch (InvalidKeyException e) {
System.out.println("Invalid key exception");
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
System.out.println("Illegal block size exception");
e.printStackTrace();
} catch (BadPaddingException e) {
System.out.println("Bad padding exception");
e.printStackTrace();
} finally {

}
}
}

Sample output:

SoftHSM access

If you are stuck with an error: Illegal block size exception – CKR_ENCRYPTED_DATA_LEN_RANGE, then here’s the solution to fix the same.

Updated on September 29, 2021

Was this article helpful?

Related Articles

Leave a Comment