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
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 }
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:
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.