javascalacryptographylibsodium

Decryption doesn't succeed consistently when decrypting a message with the same parameters using cryptoSecretBoxOpenEasy (lazysodium-java)


I've been using lazysodium-java (a wrapper for libsodium) to encrypt/decrypt certain information. I noticed some inconsistent behavior and created a test and found that indeed, for the same input, I will sometimes get a failure to decrypt an encrypted message. I am wondering if I am somehow using the library wrong? As far as I can tell, it should be consistent and thread-safe.

Here's an example of a test that reproduces the issue (Scala), fails at different iterations (i) each time (when cryptoSecretBoxOpenEasy fails it returns false and doesn't update the given message):

test("Decrypt you fool") {
    // encrypt a message
    val nonceSize = SecretBoxModule.NONCEBYTES
    val secret = SecretKey("secret")
    val nonce = lazySodium.nonce(nonceSize)
    val secretMessage = "catcher"
    val messageToEncrypt = secretMessage.getBytes(StandardCharsets.UTF_8)
    val cipher = new Array[Byte](messageToEncrypt.length + SecretBoxModule.MACBYTES)
    lazySodium.cryptoSecretBoxEasy(cipher, messageToEncrypt, messageToEncrypt.length, nonce, secret.keyBytes)
    val encrypted = nonce ++ cipher 

    // loop 1000 times to decrypt message
    for (i <- 1 to 1000) {
      println(s"Running $i")

      val message = new Array[Byte](encrypted.length - SecretBoxModule.MACBYTES - nonceSize)
      val (nonce, cipherText) = encrypted.splitAt(nonceSize)
      secretBoxModule.cryptoSecretBoxOpenEasy(message, cipherText, cipherText.length, nonce, secret.keyBytes)
      val response = new String(message, StandardCharsets.UTF_8)

      scala.Predef.assert(response == secretMessage)
    }
    assertCompletes
  
}

Any idea why the inconsistent decryption behavior?

I expected this to consistently decrypt my message successfully, but it actually fails every once in a while, despite the input not changing.


Solution

  • I found the issue: according to the docs, the secret key used for encryption must be 32 bytes (256 bits) long. In my tests I used dummy keys that did not meet this requirements which causes unexpected behavior.