javacryptographybouncycastle

Reason for the error: "input too short", when encrypting (with FPE and bouncy castle) in Java/Scala


Based on the answers of this another question, I am trying to encrypt some text but when the input data is 3 characters or less in lenght, I obtain this exception:

Exception in thread "main" java.lang.IllegalArgumentException: input too short
at org.bouncycastle.crypto.fpe.SP80038G.checkLength(Unknown Source)
at org.bouncycastle.crypto.fpe.SP80038G.checkData(Unknown Source)
at org.bouncycastle.crypto.fpe.SP80038G.checkArgs(Unknown Source)
at org.bouncycastle.crypto.fpe.SP80038G.encryptFF1(Unknown Source)
at org.bouncycastle.crypto.fpe.FPEFF1Engine.encryptBlock(Unknown Source)
at org.bouncycastle.crypto.fpe.FPEEngine.processBlock(Unknown Source)
at org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher$BufferedFPEBlockCipher.doFinal(Unknown Source)
at org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher.engineDoFinal(Unknown Source)
at java.base/javax.crypto.Cipher.doFinal(Cipher.java:2202)
at org.example.AESFPE2.encrypt(AESFPE2.scala:38)
at org.example.AESFPE2.encrypt_test(AESFPE2.scala:25)
at org.example.App$.main(Main.scala:18)
at org.example.App.main(Main.scala)

The method 'encrypt_test' in the next code is what I am using to test this problem (the rest of the methods are the same as the previously referenced question):

class AESFPE2 {
 @throws[Exception]
 def encrypt_test(): Unit = {
   val key = getKeyFromPassword("foo", "bar")
   val tweak = getTweak
   val alphabetMapper = new BasicAlphabetMapper("\"'^*[]{}<>ºª|+-ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzáéíóúü!¿?¡=()/\\ _;:,.ç")
   val radix = alphabetMapper.getRadix

   val plaintext = "abc".toCharArray

   val plain_bytes = alphabetMapper.convertToIndexes(plaintext)
   val cipher = Cipher.getInstance("AES/FF1/NoPadding", new BouncyCastleProvider())
   val cipher_bytes = encrypt(cipher, key, tweak, radix, plain_bytes)
   val decrypted = decrypt(cipher, key, tweak, radix, cipher_bytes)
   val cipher_chars = alphabetMapper.convertToChars(cipher_bytes)
   println(new String(cipher_chars))
   val plain_chars = alphabetMapper.convertToChars(decrypted)
   println(new String(plain_chars))

 }

 @throws[NoSuchAlgorithmException]
 @throws[InvalidKeySpecException]
 def getKeyFromPassword(password: String, salt: String): SecretKey = {
   val factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256")
   val spec = new PBEKeySpec(password.toCharArray, salt.getBytes, 65536, 256)
   val secret = new SecretKeySpec(factory.generateSecret(spec).getEncoded, "AES")
   secret
 }
}

Solution

  • According to the specification (here, page 13, line 504 ff), the following must be fulfilled to FF1:

    radix ∈ [2..216]
    radixminlen ≥ 1 000 000
    2 ≤ minlenmaxlen < 232

    Here, radix is the number of characters in the alphabet (99 in the sample code) and minlen and maxlen are the minimum and maximum allowed length of the plaintext.

    The constraint radixminlen ≥ 1 000 000 is fulfilled for minlen = 4, but no more for minlen = 3, i.e. the minimum length of the plaintext is 4 characters.

    The error message comes from here.