Úspěšně jsem nainstaloval a nakonfiguroval SoftHSM na CentOS. Abych si ověřil, zda mohu komunikovat se SoftHSM programově, napsal jsem program Java, který spolupracuje s softwarovým tokenem a provádí šifrování a dešifrování vstupního řetězce. Programu se však podařilo vstup úspěšně zašifrovat, ale nepodařilo se jej dešifrovat. Metoda dešifrování se nezdaří s chybou – Výjimka neplatná velikost bloku – CKR_ENCRYPTED_DATA_LEN_RANGE.
Zde je částečný kód.
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); char[] pin = "abcdef123".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, "abcdef123".toCharArray(), null); keyStore.store(null); SecretKey key1 = (SecretKey) keyStore.getKey("AA", "abcdef123".toCharArray()); System.out.println("the algorithm: "+key1.getAlgorithm()+", the key: "+key1.toString()+", format: "+key1.serialVersionUID); doCrypto(Cipher.ENCRYPT_MODE, key1, inputtext); doCrypto(Cipher.DECRYPT_MODE, key1, encryptedtext); } 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 void doCrypto(int cipherMode, Key key, String inputtext) throws Exception { Key secretKey = key; Cipher cipher; try { cipher = Cipher.getInstance(TRANSFORMATION); cipher.init(cipherMode, secretKey); byte[] inputBytes = inputtext.getBytes(); byte[] outputBytes; outputBytes = cipher.doFinal(inputBytes); if(cipherMode == Cipher.ENCRYPT_MODE) { encryptedtext = outputBytes.toString(); System.out.println("=========================================="); System.out.println("encrypted text: "+outputBytes.toString()); System.out.println("=========================================="); } if(cipherMode == Cipher.DECRYPT_MODE) { System.out.println("*****************************************"); System.out.println("decrypted text: "+outputBytes.toString()); System.out.println("*****************************************"); } } 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 { } }
Chyba výstupu:
Tak jak se mi to povedlo? Zde je řešení.
Jak opravit Neplatná výjimka velikosti bloku – chyba CKR_ENCRYPTED_DATA_LEN_RANGE při přístupu k SoftHSM pomocí kódu Java?
Protože šifruji řetězec pomocí algoritmu AES, očekávaná návratnost je pole bajtů. Takže převod těchto bajtů přímo na řetězec, jak je uvedeno níže, způsobil problém.
encryptedtext = outputBytes.toString();
Ve výše uvedeném řádku kódu outputBytes
je typu bytes []
a převést jej přímo na řetězec byl problém.
K vyřešení tohoto problému musíme použít Base64
místo přímého převodu na řetězec.
byte[] cipherText = cipher.doFinal(inputtext.getBytes("utf-8")); encryptedText = java.util.Base64.getEncoder().encodeToString(cipherText);
Výše uvedené řádky jsou mírně přepsány, aby zakódovaly cipherText
pomocí Base64
a uložte totéž do encryptedText
.
Podobně při dešifrování potřebujeme převést Base64
řetězec zpět do bajtového pole před dešifrováním bajtového pole.
byte[] deciphered = cipher.doFinal(java.util.Base64.getDecoder().decode(encryptedText));
Výše uvedený řádek kódu naznačuje, že musíme provést Base64
dekódovat a předat jej jako argument metodě dešifrování.
A je to! Zde je úplný kód pro referenci.
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 { } }
Díky této odpovědi od Stackflow, která mi pomohla problém vyřešit.
Konečně snímek obrazovky úspěšného výstupu.