docs: protected static final byte[] signISO9796(byte[][] key, byte[] data, int off, int len) throws Exception {
          CachingKey ck = new CachingKey(key, data, off, len);
          CachingKey result = cryptoKeysMap.get(ck);
  
          if (result != null) {
              result.successfulUses += 1;
              result.reused = true;
              return result.result;
          } else {
              if (cryptoKeysMap.size() > MAX_CACHE) {
                  try {
                      CachingKey[] keys = cryptoKeysMap.keySet().toArray(new CachingKey[cryptoKeysMap.size()]);
                      Arrays.sort(keys, cachingKeyComparator);
                      if (cachingKeyComparator.compare(keys[0], keys[keys.length - 1]) < 0) {
                          for (int i = 0; i < cryptoKeysMap.size() / 5; i++) {
                              cryptoKeysMap.remove(keys[i]);
                              keys[i + 1 * cryptoKeysMap.size() / 5].successfulUses--;
                              keys[i + 2 * cryptoKeysMap.size() / 5].successfulUses--;
                              keys[i + 3 * cryptoKeysMap.size() / 5].successfulUses--;
                              keys[i + 4 * cryptoKeysMap.size() / 5].successfulUses--;
                          }
                      } else {
                          for (int i = 0; i < cryptoKeysMap.size() / 5; i++) {
                              cryptoKeysMap.remove(keys[keys.length - 1 - i]);
                              keys[keys.length - 1 - i - 1 * cryptoKeysMap.size() / 5].successfulUses--;
                              keys[keys.length - 1 - i - 2 * cryptoKeysMap.size() / 5].successfulUses--;
                              keys[keys.length - 1 - i - 3 * cryptoKeysMap.size() / 5].successfulUses--;
                              keys[keys.length - 1 - i - 4 * cryptoKeysMap.size() / 5].successfulUses--;
                          }
                      }
                  } catch (Exception e) {
                      // do nothing. since this code is used for the command line utility, no log is taken.
                  }
                   
              }
          }
  
          /** Invoked by LTPADigSignature **/
          BigInteger n = new BigInteger(key[0]);
          BigInteger e = new BigInteger(key[2]);
          BigInteger p = new BigInteger(key[3]);
          BigInteger q = new BigInteger(key[4]);
          BigInteger d = e.modInverse((p.subtract(BigInteger.ONE)).multiply(q.subtract(BigInteger.ONE)));
          KeyFactory kFact = null;
          if (LTPAKeyUtil.isIBMJCEAvailable()) {
              kFact = KeyFactory.getInstance(CRYPTO_ALGORITHM, IBMJCE_NAME);
          } else {
              kFact = KeyFactory.getInstance(CRYPTO_ALGORITHM);
          }
  
  
          BigInteger pep = new BigInteger(key[5]);
          BigInteger peq = new BigInteger(key[6]);
          BigInteger crtC = new BigInteger(key[7]);
          RSAPrivateCrtKeySpec privCrtKeySpec = new RSAPrivateCrtKeySpec(n, e, d, p, q, pep, peq, crtC);
          PrivateKey privKey = kFact.generatePrivate(privCrtKeySpec);
  
          Signature rsaSig = null;
          if (LTPAKeyUtil.isIBMJCEAvailable()) {
              rsaSig = Signature.getInstance(SIGNATURE_ALGORITHM, IBMJCE_NAME);
          } else {
              rsaSig = Signature.getInstance(SIGNATURE_ALGORITHM);
          }
          rsaSig.initSign(privKey);
          rsaSig.update(data, off, len);
          byte[] sig = rsaSig.sign();
  
          cryptoKeysMap.put(ck, ck);
          ck.result = sig;
          ck.successfulUses = 0;
  
          return sig;
      }