github-advanced-security[bot] commented on code in PR #610:
URL: https://github.com/apache/airavata/pull/610#discussion_r3012055642


##########
airavata-api/src/main/java/org/apache/airavata/security/util/SecurityUtil.java:
##########
@@ -35,52 +39,59 @@
 
     public static final String PASSWORD_HASH_METHOD_PLAINTEXT = "PLAINTEXT";
     public static final String CHARSET_ENCODING = "UTF-8";
-    public static final String PADDING_MECHANISM = "AES/CBC/PKCS5Padding";
+    public static final String CIPHER_NAME = "AES/GCM/NoPadding";
+    public static final int GCM_IV_BYTES = 12; // 96 bits
+    public static final int GCM_TAG_BITS = 128;
 
     private static final Logger logger = 
LoggerFactory.getLogger(SecurityUtil.class);
 
-    public static byte[] encryptString(
-            String keyStorePath, String keyAlias, KeyStorePasswordCallback 
passwordCallback, String value)
-            throws GeneralSecurityException, IOException {
-        return encrypt(keyStorePath, keyAlias, passwordCallback, 
value.getBytes(CHARSET_ENCODING));
-    }
-
-    public static byte[] encrypt(
-            String keyStorePath, String keyAlias, KeyStorePasswordCallback 
passwordCallback, byte[] value)
-            throws GeneralSecurityException, IOException {
-
-        Key secretKey = getSymmetricKey(keyStorePath, keyAlias, 
passwordCallback);
-
-        Cipher cipher = Cipher.getInstance(PADDING_MECHANISM);
-        cipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(new 
byte[16]));
-        return cipher.doFinal(value);
-    }
-
-    private static Key getSymmetricKey(String keyStorePath, String keyAlias, 
KeyStorePasswordCallback passwordCallback)
+    public static Key getSymmetricKey(String keyStorePath, String keyAlias, 
KeyStorePasswordCallback passwordCallback)
             throws CertificateException, NoSuchAlgorithmException, 
KeyStoreException, IOException,
                     UnrecoverableKeyException {
         KeyStore ks = SecurityUtil.loadKeyStore(keyStorePath, 
passwordCallback);
         return ks.getKey(keyAlias, 
passwordCallback.getSecretKeyPassPhrase(keyAlias));
     }
 
-    public static byte[] decrypt(
-            String keyStorePath, String keyAlias, KeyStorePasswordCallback 
passwordCallback, byte[] encrypted)
-            throws GeneralSecurityException, IOException {
-
-        Key secretKey = getSymmetricKey(keyStorePath, keyAlias, 
passwordCallback);
+    public static byte[] encrypt(byte[] data, Key key) throws 
GeneralSecurityException {
+        var cipher = Cipher.getInstance(CIPHER_NAME);
+        cipher.init(Cipher.ENCRYPT_MODE, key);
+        var iv = cipher.getIV();
+        var encryptedData = cipher.doFinal(data);
+        return ByteBuffer.allocate(iv.length + encryptedData.length)
+                .put(iv)
+                .put(encryptedData)
+                .array();
+    }
 
-        Cipher cipher = Cipher.getInstance(PADDING_MECHANISM);
-        cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(new 
byte[16]));
+    public static byte[] decrypt(byte[] tag, Key key) throws 
GeneralSecurityException {
+        var iv = Arrays.copyOfRange(tag, 0, GCM_IV_BYTES);
+        var encryptedData = Arrays.copyOfRange(tag, GCM_IV_BYTES, tag.length);
+        var cipher = Cipher.getInstance(CIPHER_NAME);
+        var spec = new GCMParameterSpec(GCM_TAG_BITS, iv);
+        cipher.init(Cipher.DECRYPT_MODE, key, spec);
+        return cipher.doFinal(encryptedData);
+    }
 
-        return cipher.doFinal(encrypted);
+    /**
+     * Try GCM decryption first; if the auth tag fails, fall back to the legacy
+     * AES/CBC/PKCS5Padding scheme (static zero IV) used before the GCM 
migration.
+     */
+    public static byte[] decryptWithLegacyFallback(byte[] data, Key key) 
throws GeneralSecurityException {
+        try {
+            return decrypt(data, key);
+        } catch (AEADBadTagException e) {
+            logger.info("GCM decryption failed, falling back to legacy 
AES/CBC");
+            return decryptLegacy(data, key);
+        }
     }
 
-    public static String decryptString(
-            String keyStorePath, String keyAlias, KeyStorePasswordCallback 
passwordCallback, byte[] encrypted)
-            throws GeneralSecurityException, IOException {
+    private static final String LEGACY_CIPHER_NAME = "AES/CBC/PKCS5Padding";
+    private static final int LEGACY_IV_BYTES = 16;
 
-        byte[] decrypted = decrypt(keyStorePath, keyAlias, passwordCallback, 
encrypted);
-        return new String(decrypted, CHARSET_ENCODING);
+    private static byte[] decryptLegacy(byte[] encrypted, Key key) throws 
GeneralSecurityException {
+        var cipher = Cipher.getInstance(LEGACY_CIPHER_NAME);
+        cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(new 
byte[LEGACY_IV_BYTES]));

Review Comment:
   ## Using a static initialization vector for encryption
   
   A [static initialization vector](1) should not be used for encryption.
   
   [Show more 
details](https://github.com/apache/airavata/security/code-scanning/128)



##########
airavata-api/src/main/java/org/apache/airavata/security/util/SecurityUtil.java:
##########
@@ -35,52 +39,59 @@
 
     public static final String PASSWORD_HASH_METHOD_PLAINTEXT = "PLAINTEXT";
     public static final String CHARSET_ENCODING = "UTF-8";
-    public static final String PADDING_MECHANISM = "AES/CBC/PKCS5Padding";
+    public static final String CIPHER_NAME = "AES/GCM/NoPadding";
+    public static final int GCM_IV_BYTES = 12; // 96 bits
+    public static final int GCM_TAG_BITS = 128;
 
     private static final Logger logger = 
LoggerFactory.getLogger(SecurityUtil.class);
 
-    public static byte[] encryptString(
-            String keyStorePath, String keyAlias, KeyStorePasswordCallback 
passwordCallback, String value)
-            throws GeneralSecurityException, IOException {
-        return encrypt(keyStorePath, keyAlias, passwordCallback, 
value.getBytes(CHARSET_ENCODING));
-    }
-
-    public static byte[] encrypt(
-            String keyStorePath, String keyAlias, KeyStorePasswordCallback 
passwordCallback, byte[] value)
-            throws GeneralSecurityException, IOException {
-
-        Key secretKey = getSymmetricKey(keyStorePath, keyAlias, 
passwordCallback);
-
-        Cipher cipher = Cipher.getInstance(PADDING_MECHANISM);
-        cipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(new 
byte[16]));
-        return cipher.doFinal(value);
-    }
-
-    private static Key getSymmetricKey(String keyStorePath, String keyAlias, 
KeyStorePasswordCallback passwordCallback)
+    public static Key getSymmetricKey(String keyStorePath, String keyAlias, 
KeyStorePasswordCallback passwordCallback)
             throws CertificateException, NoSuchAlgorithmException, 
KeyStoreException, IOException,
                     UnrecoverableKeyException {
         KeyStore ks = SecurityUtil.loadKeyStore(keyStorePath, 
passwordCallback);
         return ks.getKey(keyAlias, 
passwordCallback.getSecretKeyPassPhrase(keyAlias));
     }
 
-    public static byte[] decrypt(
-            String keyStorePath, String keyAlias, KeyStorePasswordCallback 
passwordCallback, byte[] encrypted)
-            throws GeneralSecurityException, IOException {
-
-        Key secretKey = getSymmetricKey(keyStorePath, keyAlias, 
passwordCallback);
+    public static byte[] encrypt(byte[] data, Key key) throws 
GeneralSecurityException {
+        var cipher = Cipher.getInstance(CIPHER_NAME);
+        cipher.init(Cipher.ENCRYPT_MODE, key);
+        var iv = cipher.getIV();
+        var encryptedData = cipher.doFinal(data);
+        return ByteBuffer.allocate(iv.length + encryptedData.length)
+                .put(iv)
+                .put(encryptedData)
+                .array();
+    }
 
-        Cipher cipher = Cipher.getInstance(PADDING_MECHANISM);
-        cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(new 
byte[16]));
+    public static byte[] decrypt(byte[] tag, Key key) throws 
GeneralSecurityException {
+        var iv = Arrays.copyOfRange(tag, 0, GCM_IV_BYTES);
+        var encryptedData = Arrays.copyOfRange(tag, GCM_IV_BYTES, tag.length);
+        var cipher = Cipher.getInstance(CIPHER_NAME);
+        var spec = new GCMParameterSpec(GCM_TAG_BITS, iv);
+        cipher.init(Cipher.DECRYPT_MODE, key, spec);
+        return cipher.doFinal(encryptedData);
+    }
 
-        return cipher.doFinal(encrypted);
+    /**
+     * Try GCM decryption first; if the auth tag fails, fall back to the legacy
+     * AES/CBC/PKCS5Padding scheme (static zero IV) used before the GCM 
migration.
+     */
+    public static byte[] decryptWithLegacyFallback(byte[] data, Key key) 
throws GeneralSecurityException {
+        try {
+            return decrypt(data, key);
+        } catch (AEADBadTagException e) {
+            logger.info("GCM decryption failed, falling back to legacy 
AES/CBC");
+            return decryptLegacy(data, key);
+        }
     }
 
-    public static String decryptString(
-            String keyStorePath, String keyAlias, KeyStorePasswordCallback 
passwordCallback, byte[] encrypted)
-            throws GeneralSecurityException, IOException {
+    private static final String LEGACY_CIPHER_NAME = "AES/CBC/PKCS5Padding";
+    private static final int LEGACY_IV_BYTES = 16;
 
-        byte[] decrypted = decrypt(keyStorePath, keyAlias, passwordCallback, 
encrypted);
-        return new String(decrypted, CHARSET_ENCODING);
+    private static byte[] decryptLegacy(byte[] encrypted, Key key) throws 
GeneralSecurityException {
+        var cipher = Cipher.getInstance(LEGACY_CIPHER_NAME);

Review Comment:
   ## Use of a broken or risky cryptographic algorithm
   
   Cryptographic algorithm [AES/CBC/PKCS5Padding](1) is insecure. CBC mode with 
PKCS#5 or PKCS#7 padding is vulnerable to padding oracle attacks. Consider 
using GCM instead.
   
   [Show more 
details](https://github.com/apache/airavata/security/code-scanning/127)



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to