{"record":{"id":"86f5f08b189754ef","repo":"SonarSource/sonarqube","slug":"decryption-failure-message","errorCode":null,"errorMessage":"DECRYPTION_FAILURE_MESSAGE","messagePattern":"DECRYPTION_FAILURE_MESSAGE","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"sonar-plugin-api-impl/src/main/java/org/sonar/api/config/internal/AesECBCipher.java","lineNumber":63,"sourceCode":"      cipher.init(javax.crypto.Cipher.ENCRYPT_MODE, loadSecretFile());\n      byte[] cipherData = cipher.doFinal(clearText.getBytes(StandardCharsets.UTF_8.name()));\n      return Base64.encodeBase64String(cipherData);\n    } catch (RuntimeException e) {\n      throw e;\n    } catch (Exception e) {\n      throw new IllegalStateException(e);\n    }\n  }\n\n  @Override\n  public String decrypt(String encryptedText) {\n    try {\n      javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance(CRYPTO_ALGO);\n      cipher.init(javax.crypto.Cipher.DECRYPT_MODE, loadSecretFile());\n      byte[] cipherData = cipher.doFinal(Base64.decodeBase64(StringUtils.trim(encryptedText)));\n      return new String(cipherData, StandardCharsets.UTF_8);\n    } catch (BadPaddingException | IllegalBlockSizeException e) {\n      throw new IllegalStateException(DECRYPTION_FAILURE_MESSAGE, e);\n    } catch (RuntimeException e) {\n      throw e;\n    } catch (Exception e) {\n      throw new IllegalStateException(e);\n    }\n  }\n\n}\n","sourceCodeStart":45,"sourceCodeEnd":72,"githubUrl":"https://github.com/SonarSource/sonarqube/blob/184c821202192afc1c599fc912d0889b69fffa53/sonar-plugin-api-impl/src/main/java/org/sonar/api/config/internal/AesECBCipher.java#L45-L72","documentation":"AesECBCipher.decrypt decodes Base64 ciphertext and decrypts it with the AES/ECB secret key loaded from the secret key file. BadPaddingException or IllegalBlockSizeException mean the data is not validly AES-encrypted with this key, so it is wrapped in this IllegalStateException. The library throws it because silently returning garbage from a bad ciphertext would be unsafe.","triggerScenarios":"Calling decrypt() (or clearText()) with: text encrypted with a different secret key; truncated or manually corrupted Base64 input; plaintext or non-encrypted values passed to decrypt; ciphertext whose length is not a multiple of the AES block size.","commonSituations":"sonar-secret.txt regenerated or copied from another SonarQube instance so old encrypted values no longer match; settings pasted between environments; encrypted property truncated in a database or properties file; forgetting the {aes}... prefix handling and decrypting an unencrypted value.","solutions":["Regenerate affected encrypted values with the current secret key (re-encrypt via the SonarQube UI/API)","Ensure the same sonar-secret.txt used at encryption time is installed at the configured path","Check the ciphertext is complete and not truncated (correct Base64 length, multiple of AES block size)","Only call decrypt on values reported as encrypted (encryption.isEncrypted(value))"],"exampleFix":"// before\nString clear = cipher.decrypt(suspiciousValue);\n// after\nif (cipher.isEncrypted(suspiciousValue)) {\n  String clear = cipher.decrypt(suspiciousValue);\n} else {\n  String clear = suspiciousValue;\n}","handlingStrategy":"validation","validationCode":"// only decrypt values the Encryption reports as encrypted\nif (encryptedText == null || encryptedText.trim().isEmpty()) {\n  throw new IllegalArgumentException(\"no ciphertext\");\n}\nbyte[] raw = java.util.Base64.getDecoder().decode(encryptedText.trim());\nif (raw.length == 0 || raw.length % 16 != 0) {\n  throw new IllegalArgumentException(\"ciphertext is truncated or not AES-block aligned\");\n}","typeGuard":null,"tryCatchPattern":"try {\n  return cipher.decrypt(encryptedText);\n} catch (IllegalStateException e) {\n  log.error(\"Decryption failed - secret key mismatch or corrupt ciphertext: {}\", e.getCause());\n  throw new ConfigurationException(\"Re-encrypt this value with the current sonar-secret.txt\", e);\n}","preventionTips":["Keep sonar-secret.txt identical across all nodes and migrations","Regenerate encrypted properties after rotating the secret key","Verify Base64 integrity before decrypting","Decrypt only values flagged by isEncrypted()"],"tags":["crypto","decryption","configuration"],"backgroundTag":"checksum-mismatch","analyzedSha":"184c821202192afc1c599fc912d0889b69fffa53","analyzedAt":"2026-09-09T12:23:51.573Z","contentChangedAt":"2026-09-09T12:23:51.573Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}