Durability of Nitrokey HSM (what is a write cycle)

Hello everybody,

the website states that the Nitrokey lasts >500.000 PIN entries, while smartcard hsm’s website states 500.000 write cycles. Is every PIN entry automatically a write cycle? Can one get around this by opening a session with the HSM (would require only one PIN entry if I am not mistaken)?

The background of my request is wether an application designed around the usage of a Nitrokey should start a session at start up, or login each time something from the HSM is required.

Thanks in advance.


1 Like

I know its bad etiquette to push a Topic, but it has been almost three months. Can anyone answer my Question? Maybe @sc-hsm directly?

Thanks in advance and sorry for pushing this up.

Best Regards


Sorry, that post slipped my attention.

The limitation on write-cycles is caused by the underlying memory technology. Up to version 4.0 the secure element chip (SmartMX2) was based on EEPROM cells, while the later secure element chips use Flash memory instead. In both EEPROM and Flash, you can write a single bit from 0 to 1, but you can erase only a complete row of bits. A row of bits is typically 16 bytes.

Now assume you have a PIN retry counter byte. This byte must be decreased before you compare the presented PIN with the stored PIN. If both values match, then you need to reset the retry counter to it initial value. That makes 2 writes to the cell.

NXP assures that each EEPROM memory cell survives at least 500.000 cycles. Then writing to it becomes unreliable. In our own tests, we did around 3.5 million writes to force failure of the cell.

The operating system running on the chip tries to counter the effects of cell wear-out, by switching memory areas. But that mechanism has it’s limitation in write transaction processing, which is required to mitigate tearing attacks (you remove the chipcard from the reader, while a cell write is in progress, leaving memory in fragile state).

Another effect is the design of the JavaCard VM, that executes the Java byte code in the operating system. The process model of the JavaCard is, that the heap is in EEPROM. When you allocate an object, then that is not in RAM like on a PC, but in persistent memory. During a power cycle, the object survives, so that the JavaCard application continues to run with the same object instances as before. Only very few objects are held in RAM (like the APDU buffer or transient arrays) and do not contribute to cell wear-out. RAM is compared to EEPROM a very rare resource in the chip.

When designing a JavaCard applet like the SmartCard-HSM, one obviously needs to carefully design the application with cell wear-out in mind. But some operations using the JavaCard API cause effects in memory that can not be circumvented. Those are specifically cryptographic primitives, which often have state flags in EEPROM.

The situation has improved a lot lately, mainly because SmartMX 3 is now using Flash memory and JCOP 4 uses JavaCard API 3.0.5. The JavaCard API now supports a OneShot API, that allows to call crypto primitives without a full instantiation of the API object.

A general recommendation is to switch to the 4.0 version, if you plan to use the device for a large number or crypto operations.

For versions before, the general recommendation is to do PIN verification only once per session and to do hashing outside the secure element.

Of course key management operations will always require EEPROM writes, as this creates objects in EEPROM memory. Unlike crypto operations, that just process some inbound data using key material read from EEPROM. But again for the 4.0 version cell wear-out should be no issue anymore (comparable to SSD disks).


One additional note: When using a long running session with a single login at the beginning, then I’d recommend to establish secure messaging before sending the PIN.

That way you are not only protecting the transmission of the PIN, but you also bind the authenticated session to the secure messaging session keys. An attacker intercepting the communication will loose the authentication state, and thus access to the device.

Secure messaging is available in the JCE-Provider and tools from OpenSCDP.

1 Like

Thank you very much for the great and thorough reply!
Thats very helpful to know. And I will make sure that we replace our older HSMs with SmartMX3 versions. Is there a way to know (for example using one of the OpenSC commandline tools) which Secure Element a given HSM uses?

Thanks again.

sc-hsm-tool tells you the version number:

asc@caprese:~$ sc-hsm-tool
Using reader with a card: Nitrokey Nitrokey HSM (010000000000000000000000) 00 00
Version              : 2.6
SO-PIN tries left    : 15
User PIN tries left  : 3

Version should read 4.0 at least.

1 Like

Thank you, realy apreciate it!

@sc-hsm what would be the fastest way to exhaust the write cycles on an HSM? We have one (Version 4.0) that we’d like to carry out a destruction test on to see how it behaves once it starts going bad, but signing certificates with it is rather slow (4+ second per signature). Is there a faster way to have a write attempt that you could suggest?

That would be a really interesting test. We have not gotten a hand on a 4.0 HSM yet.

4 seconds per Signature sounds slower than the old version. Do you mean key generation?

Otherwise I would probably just try closing and re-opening sessions on an almost empty HSM. This could be easily done in a small python script using pykcs11. If you need some code for this, I would be happy to provide help in exchange for the result :slight_smile:

It is signing a certificate through openssl (on Linux) with the pkcs11 backend from opensc (that could possibly be the reason I guess).

The nitrokey contains only 1 keypair.

Any input is helpful :slight_smile: I ran the existing test for ~3 weeks non stop and wrote about 300K certificates so far, but if the new durability is way above 500K (i.e. 2 million+) that might be a very long run, hence my request here.

Edit: the NitroKey HSM was purchased about 2 months ago, and based on the Version being 4.0 when querying with sc-hsm-tool I think it’s a 4.0 version that should have that increased durability.

from PyKCS11 import *
from os import environ
from getpass import getpass

PKCS11_LIB_PATH = '/usr/lib/softhsm/libsofthsm2.so' # Path to your OpenSC-PKCS11-Library here
environ['PYKCS11LIB'] = PKCS11_LIB_PATH

PKCS11_HSM_SLOT = 57171195 # Slot as shown by 'pkcs11-tool --list-slots' here (in integer)

pkcs11_obj = PyKCS11Lib()

write_count = 0
hsm_pin = getpass(prompt='Enter your HSM-Pin: ')
while True:
        session = pkcs11_obj.openSession(slot=PKCS11_HSM_SLOT, flags=CKF['CKF_SERIAL_SESSION'])
        write_count += 1

        if write_count % 10000 == 0:
    except Exception as e:
        print(f"Open: Something went wrong, HSM probably failed at {write_count} Session opens. Exception: \n{e}")

    except Exception as e:
        print(f"Close: Something went wrong, HSM probably failed at {write_count} Session opens. Exception: \n{e}")

This opens a Read-Session and then Closes it in a Loop (which according to this very thread should be a single write cycle :slight_smile:). Prints the current write-/session-open-count evers 10000 writes, or on Exception thrown, which should happen when the HSM eventually fails.

You obviously need to adjust the PKCS11-Library-Path (under Ubuntu 22.04 the default path is /usr/lib/x86_64-linux-gnu/opensc-pkcs11.so) and the HSM-Slot (I tried the script real quick with a Software HSM).

Only requirement is PyKCS11 which can be easily installed from Ubuntus Repository, if you are using Ubuntu (apt install python3-pykcs11), otherwise pip install PyKCS11 will do the trick


Thanks for that!

I’ll set that up and get that going, and once it fails I’ll report back the amount of writes I got on that one HSM before it failed :slight_smile:

1 Like

Nice. Let me know if anything doesnt work/you need help with something.

It’s running, chugging away at 85ms per attempt roughly, this should greatly speed it up, thanks again!

I’ll post here when it fails.

Is the HSM still going strong? That would be a pleasant surprise

It was until yesterday evening apparently.

It threw an error at run 6494048 (and count ~300K attempts before), so it failed at about 6.8 million attempts :slight_smile:

It failed with a CKR_GENERAL_ERROR, and upon retrying it’s an CKR_TOKEN_NOT_PRESENT

2024-04-16 23:45:02.636642 - 6494000
Open: Something went wrong, HSM probably failed at 6494048 Session opens. Exception:
CKR_GENERAL_ERROR (0x00000005)

Wow, thats quite good to hear. Way more than expected to be honest!
Thanks for getting those numbers :slightly_smiling_face:

You’re welcome. We’re also pretty surprised and happy it seems to be much higher than what the original spec sheet mentions (the 500.000 entries)

1 Like