-
Notifications
You must be signed in to change notification settings - Fork 19
feat:added spotless and checkstyle configuration and added to maven b… #344
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: trunk
Are you sure you want to change the base?
Conversation
| String[] separatedByHyphen = errorCodeSegment.split("-"); | ||
| errorCode = separatedByHyphen[0].trim(); | ||
|
|
||
| errorText = rawErrorResponse.replaceFirst(errorCodeSegment + ":", "").trim(); |
Check failure
Code scanning / CodeQL
Regular expression injection High
user-provided value
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
will be addressed by #345
| IllegalBlockSizeException, BadPaddingException, NoSuchProviderException { | ||
| SecretKey key = _aesKeyFromBase64(keyBase64); | ||
| Cipher cipher = Cipher.getInstance("AES/SIC/PKCS7Padding", "BC"); | ||
| cipher.init(Cipher.ENCRYPT_MODE, key, EMPTY_IV); |
Check failure
Code scanning / CodeQL
Using a static initialization vector for encryption High
static initialization vector
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI about 10 hours ago
In general, the problem is that encryption uses a fixed, static IV (EMPTY_IV). For secure use of block ciphers in modes like CBC, GCM, or CTR/SIC, each encryption operation under the same key must use a fresh, unpredictable IV/nonce. The standard pattern is: (1) generate a random IV with SecureRandom, (2) initialize the cipher with that IV, (3) include the IV alongside the ciphertext so decryption can reconstruct it (e.g., prefix the IV to the ciphertext or return/provide it separately).
The best focused fix here, without changing external functionality more than necessary, is:
- Stop using
EMPTY_IVfor encryption. - Generate a random 16‑byte IV for each call to
aesEncryptToBase64. - Initialize the cipher with that random IV.
- Return the IV together with the ciphertext in a way that
aesDecryptFromBase64can consume without changing its signature. The simplest is to prefix the raw IV bytes to the ciphertext bytes and then base64-encode the combined array. - Update
aesDecryptFromBase64(String cipherTextBase64, String keyBase64)so that, whenivNonceis not provided, it expects this “IV + ciphertext” format: it decodes from base64, splits the first 16 bytes as IV and the rest as ciphertext, and then decrypts using the extracted IV. This preserves backward compatibility of the method signature while making encryption secure. - Keep the overload
aesDecryptFromBase64(String cipherTextBase64, String keyBase64, String ivNonce)for cases where the IV is transmitted separately, but discourage/default away from theEMPTY_IVpath.
Concretely, within EncryptionUtil.java:
- Add a
SecureRandom-based IV generation inaesEncryptToBase64, using a 16‑byte IV (AES block size): e.g.,SecureRandom random = new SecureRandom(); byte[] ivBytes = new byte[16]; random.nextBytes(ivBytes); IvParameterSpec iv = new IvParameterSpec(ivBytes);. - Change
cipher.init(Cipher.ENCRYPT_MODE, key, EMPTY_IV);to use the newly generated IV. - Change the encrypted output to prefix the IV bytes: allocate a new byte array of length
ivBytes.length + encrypted.length, copy the IV first, ciphertext after, then base64-encode that combined array. - In
aesDecryptFromBase64(String cipherTextBase64, String keyBase64, String ivNonce), avoid defaulting toEMPTY_IVexcept where strictly necessary. For the 2‑argument overload (no explicit IV), implement the “decode, split IV + ciphertext, then decrypt” logic rather than delegating withivNonce = null. - No new external dependencies are required;
java.security.SecureRandomis already imported viajava.security.*;.
-
Copy modified lines R28-R33 -
Copy modified lines R35-R41 -
Copy modified lines R62-R78
| @@ -25,9 +25,20 @@ | ||
| IllegalBlockSizeException, BadPaddingException, NoSuchProviderException { | ||
| SecretKey key = _aesKeyFromBase64(keyBase64); | ||
| Cipher cipher = Cipher.getInstance("AES/SIC/PKCS7Padding", "BC"); | ||
| cipher.init(Cipher.ENCRYPT_MODE, key, EMPTY_IV); | ||
| // Generate a fresh random IV for each encryption | ||
| byte[] ivBytes = new byte[16]; | ||
| SecureRandom secureRandom = new SecureRandom(); | ||
| secureRandom.nextBytes(ivBytes); | ||
| IvParameterSpec ivSpec = new IvParameterSpec(ivBytes); | ||
| cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec); | ||
| byte[] encrypted = cipher.doFinal(clearText.getBytes()); | ||
| return Base64.getEncoder().encodeToString(encrypted); | ||
|
|
||
| // Prefix IV to ciphertext so it can be recovered during decryption | ||
| byte[] ivAndCiphertext = new byte[ivBytes.length + encrypted.length]; | ||
| System.arraycopy(ivBytes, 0, ivAndCiphertext, 0, ivBytes.length); | ||
| System.arraycopy(encrypted, 0, ivAndCiphertext, ivBytes.length, encrypted.length); | ||
|
|
||
| return Base64.getEncoder().encodeToString(ivAndCiphertext); | ||
| } | ||
|
|
||
| public static String aesDecryptFromBase64(String cipherTextBase64, String keyBase64, String ivNonce) | ||
| @@ -49,7 +59,23 @@ | ||
| public static String aesDecryptFromBase64(String cipherTextBase64, String keyBase64) | ||
| throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, | ||
| IllegalBlockSizeException, BadPaddingException, NoSuchProviderException { | ||
| return aesDecryptFromBase64(cipherTextBase64, keyBase64, null); | ||
| SecretKey key = _aesKeyFromBase64(keyBase64); | ||
| Cipher cipher = Cipher.getInstance("AES/SIC/PKCS7Padding", "BC"); | ||
|
|
||
| byte[] ivAndCiphertext = Base64.getDecoder().decode(cipherTextBase64); | ||
| if (ivAndCiphertext.length < 16) { | ||
| throw new InvalidAlgorithmParameterException("Ciphertext too short to contain IV"); | ||
| } | ||
|
|
||
| byte[] ivBytes = new byte[16]; | ||
| byte[] ciphertextBytes = new byte[ivAndCiphertext.length - 16]; | ||
| System.arraycopy(ivAndCiphertext, 0, ivBytes, 0, 16); | ||
| System.arraycopy(ivAndCiphertext, 16, ciphertextBytes, 0, ciphertextBytes.length); | ||
|
|
||
| IvParameterSpec ivSpec = new IvParameterSpec(ivBytes); | ||
| cipher.init(Cipher.DECRYPT_MODE, key, ivSpec); | ||
| byte[] decrypted = cipher.doFinal(ciphertextBytes); | ||
| return new String(decrypted); | ||
| } | ||
|
|
||
| public static KeyPair generateRSAKeyPair() throws NoSuchAlgorithmException { |
| } else { | ||
| iv = _ivFromBase64(ivNonce); | ||
| } | ||
| cipher.init(Cipher.DECRYPT_MODE, key, iv); |
Check failure
Code scanning / CodeQL
Using a static initialization vector for encryption High
static initialization vector
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI about 10 hours ago
In general, the problem should be fixed by never using a fixed, static IV for encryption. Instead, generate a fresh, unpredictable IV (or nonce) per encryption using SecureRandom, and communicate that IV alongside the ciphertext so that decryption can reconstruct the cipher state. For decryption, you must use the IV that was actually used during encryption; only the encrypt side needs randomness, but both sides must agree on the IV value.
For this specific code, the minimal change while preserving existing functionality shape is:
- Stop using
EMPTY_IVfor encryption. InaesEncryptToBase64, generate a random 16‑byte IV usingSecureRandom, initialize the cipher with that IV, and then return both the IV and ciphertext to the caller. Since we must not change the method signature, the most backwards‑compatible approach within this snippet is to encode the IV together with the ciphertext in the returned Base64 string. A common pattern is to prepend the IV bytes to the ciphertext and Base64‑encode the concatenation. - Update
aesDecryptFromBase64so that, whenivNonceis null (the current path that usesEMPTY_IV), it instead parses the returned Base64 string by splitting it into IV and ciphertext: decode Base64, take the first 16 bytes as the IV, and the remaining bytes as ciphertext. WhenivNonceis non‑null, keep the current behavior of using_ivFromBase64(ivNonce)so that explicit IVs (if any) still work. - Remove usage of
EMPTY_IVfor encryption and, ideally, for decryption. If you still need a default for legacy data that truly used the all‑zero IV, you could keep a special case, but the safer default is to expect IV to be present in the encoded value.
This fix requires:
- Using
SecureRandomfromjava.security(already imported viaimport java.security.*;). - Some byte array concatenation logic inside
aesEncryptToBase64and corresponding splitting logic insideaesDecryptFromBase64. - Keeping the existing method signatures unchanged so external callers still compile, while changing the internal encoding of the returned/consumed Base64 values.
-
Copy modified lines R28-R43 -
Copy modified lines R51-R52 -
Copy modified lines R54-R55 -
Copy modified lines R57-R67 -
Copy modified line R70 -
Copy modified line R72 -
Copy modified lines R74-R75
| @@ -25,9 +25,22 @@ | ||
| IllegalBlockSizeException, BadPaddingException, NoSuchProviderException { | ||
| SecretKey key = _aesKeyFromBase64(keyBase64); | ||
| Cipher cipher = Cipher.getInstance("AES/SIC/PKCS7Padding", "BC"); | ||
| cipher.init(Cipher.ENCRYPT_MODE, key, EMPTY_IV); | ||
| byte[] encrypted = cipher.doFinal(clearText.getBytes()); | ||
| return Base64.getEncoder().encodeToString(encrypted); | ||
|
|
||
| // Generate a random IV for each encryption to avoid IV reuse | ||
| byte[] ivBytes = new byte[16]; | ||
| SecureRandom secureRandom = new SecureRandom(); | ||
| secureRandom.nextBytes(ivBytes); | ||
| IvParameterSpec ivSpec = new IvParameterSpec(ivBytes); | ||
|
|
||
| cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec); | ||
| byte[] ciphertext = cipher.doFinal(clearText.getBytes(StandardCharsets.UTF_8)); | ||
|
|
||
| // Prepend IV to ciphertext so the decrypt method can recover it | ||
| byte[] combined = new byte[ivBytes.length + ciphertext.length]; | ||
| System.arraycopy(ivBytes, 0, combined, 0, ivBytes.length); | ||
| System.arraycopy(ciphertext, 0, combined, ivBytes.length, ciphertext.length); | ||
|
|
||
| return Base64.getEncoder().encodeToString(combined); | ||
| } | ||
|
|
||
| public static String aesDecryptFromBase64(String cipherTextBase64, String keyBase64, String ivNonce) | ||
| @@ -35,15 +48,31 @@ | ||
| IllegalBlockSizeException, BadPaddingException, NoSuchProviderException { | ||
| SecretKey key = _aesKeyFromBase64(keyBase64); | ||
| Cipher cipher = Cipher.getInstance("AES/SIC/PKCS7Padding", "BC"); | ||
|
|
||
| byte[] cipherBytes = Base64.getDecoder().decode(cipherTextBase64); | ||
| IvParameterSpec iv; | ||
| byte[] actualCiphertext; | ||
|
|
||
| if (ivNonce == null) { | ||
| iv = EMPTY_IV; | ||
| // Expect IV to be prepended to the ciphertext | ||
| if (cipherBytes.length < 16) { | ||
| throw new IllegalBlockSizeException("Ciphertext too short to contain IV"); | ||
| } | ||
| byte[] ivBytes = new byte[16]; | ||
| System.arraycopy(cipherBytes, 0, ivBytes, 0, 16); | ||
| iv = new IvParameterSpec(ivBytes); | ||
|
|
||
| int ctLength = cipherBytes.length - 16; | ||
| actualCiphertext = new byte[ctLength]; | ||
| System.arraycopy(cipherBytes, 16, actualCiphertext, 0, ctLength); | ||
| } else { | ||
| iv = _ivFromBase64(ivNonce); | ||
| actualCiphertext = cipherBytes; | ||
| } | ||
|
|
||
| cipher.init(Cipher.DECRYPT_MODE, key, iv); | ||
| byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(cipherTextBase64)); | ||
| return new String(decrypted); | ||
| byte[] decrypted = cipher.doFinal(actualCiphertext); | ||
| return new String(decrypted, StandardCharsets.UTF_8); | ||
| } | ||
|
|
||
| public static String aesDecryptFromBase64(String cipherTextBase64, String keyBase64) |
03deeb9 to
2d47ef3
Compare
…uild lifecycle reformatted and adjusted to make code pass checkstyle and spotless rules
1ab1638 to
b556b75
Compare
- What I did
This PR introduces the spotless and checkstyle plugins to the maven lifecyle. To ensure that all the code conforms a single formatting convention (spotless) and established coding style practices (checkstyle).
In order to pass, the code base has been adjusted.
In the intention here is to standardize all the code in a single commit and make future PRs easier to diff.
- How I did it
Added checkstyle and spotless maven plugins
Added java spotless rules
Added java checkstyle
Fixed checkstyle failures (lots of IF without braces, some deep block nesting)
Fixed spotless failures
- How to verify it
Run the tests
closes #343
- Description for the changelog
enforce a single java format and style convention