title: Encrypt and Decrypt Implementation in Java gives warning by security analysis tool
body: <p>I have written encrypt and decrypt methods to encrypt or decrypt string data. We have some vulnerability analyzer tool that says &quot;<code>javas.crypto.spec.SecretKeySpec.SecretKeySpec(byte[], java.lang.String) uses the constant string as a cryptographic key</code>&quot; at this line:</p>
  <pre><code>return new SecretKeySpec(decoded, keyAlgorithm);
  </code></pre>
  <p>I tried giving &quot;AES&quot; directly instead of variable/field, still it gave the same error. Can you please help me on what changes need to be done in this code so that the errors won't appear and make this implementation more secure?</p>
  <p>Here is the complete code for it:</p>
  <pre><code>import javax.crypto.BadPaddingException;
  import javax.crypto.Cipher;
  import javax.crypto.IllegalBlockSizeException;
  import javax.crypto.NoSuchPaddingException;
  import javax.crypto.spec.IvParameterSpec;
  import javax.crypto.spec.SecretKeySpec;
  import java.nio.ByteBuffer;
  import java.nio.charset.StandardCharsets;
  import java.security.*;
  import java.util.Base64;
  
  public class EncryptDecryptImpl {
  
  private static final String secretKey = &quot;abcdefghijklmnop&quot;;
  private static final String otherSecretKey = &quot;somesecret&quot;;
  
  private static final String encryptionAlgorithm = &quot;AES/CBC/PKCS5Padding&quot;;
  private static final String keyAlgorithm = &quot;AES&quot;;
  
  public static String encrypt(String data, String secret) {
      try {
          Key key = generateKey(secret);
          Cipher cipher = Cipher.getInstance(encryptionAlgorithm);
          SecureRandom secureRandom = new SecureRandom();
          byte[] iv = new byte[16];
          secureRandom.nextBytes(iv);
          cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));
          byte[] ciphertext = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
          byte[] encryptedValue  = ByteBuffer.allocate(iv.length + ciphertext.length)
                  .put(iv).put(ciphertext).array();
          return Base64.getEncoder().encodeToString(encryptedValue);
      } catch (InvalidKeyException | NoSuchPaddingException | NoSuchAlgorithmException |
              BadPaddingException | IllegalBlockSizeException | InvalidAlgorithmParameterException e) {
          e.printStackTrace();
      }
      return null;
  }
  
  public static String decrypt(String strToDecrypt, String secret) {
      try {
          Key key = generateKey(secret);
          Cipher cipher = Cipher.getInstance(encryptionAlgorithm);
          cipher.init(Cipher.DECRYPT_MODE, key);
          return new String(cipher.doFinal(Base64.getDecoder().decode(strToDecrypt)));
      } catch (NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeyException |
              BadPaddingException | IllegalBlockSizeException e) {
          e.printStackTrace();
      }
      return null;
  }
  
  private static Key generateKey(String secret) {
      byte[] decoded = Base64.getDecoder().decode(secret.getBytes());
      return new SecretKeySpec(decoded, keyAlgorithm);
  }
  
  public static String encodeKey(String key) {
      byte[] encoded = Base64.getEncoder().encode(key.getBytes());
      return new String(encoded);
  }
  
  public static String decodeKey(String key) {
      byte[] decoded = Base64.getDecoder().decode(key.getBytes());
      return new String(decoded);
  }
  
  public static String encodedBase64Key() {
      return encodeKey(secretKey); // need to be shared between client and server
  }
  
  public static String decodedBase64Key(String encryptedSecretKey) {
      return decodeKey(encryptedSecretKey);
  }
  
  public static String aesEncryptedSecretKey() {
      return EncryptDecryptImpl.encrypt(otherSecretKey, encodedBase64Key());
  }
  
  public static String aesDecryptedSecretKey() {
      return EncryptDecryptImpl.decrypt(aesEncryptedSecretKey(), encodedBase64Key());
  }
  }
  </code></pre>
  <p>Caller:</p>
  <pre><code>@RestController
  @RequestMapping(&quot;/service/crypto&quot;)
  public class EncryptDecryptController {
  
      @GetMapping(value = &quot;/secret-key&quot;)
      public ResponseEntity&lt;?&gt; getEncryptedSecretKey() {
          try {
              String encryptedSecretKey = EncryptDecryptImpl.aesEncryptedSecretKey(); // cipher text
              return ResponseEntity.ok(new ApiResponse(true, encryptedSecretKey));
          } catch (Exception e) {
              return ResponseEntity.ok(new ApiResponse(false, &quot;Error getting key&quot;));
             // throw new ResponseStatusException(HttpStatus.BAD_REQUEST, &quot;Error getting key&quot;, e);
          }
      }
  }
  </code></pre>
  <p>And at the client side, I'm using like this:</p>
  <pre><code>export const getSecretKey = () =&gt; {
    const encryptedBase64Key = '&lt;--base64kyesharedbyserver--&gt;';
    const parsedBase64Key = enc.Base64.parse(encryptedBase64Key);
    let encryptedCipherText = '';
    if (getSessionStorageItem('appKey') !== null) {
      encryptedCipherText = getSessionStorageItem('appKey');
    }
    const parsedCipherText = enc.Base64.parse(encryptedCipherText);
    const iv = lib.WordArray.create(parsedCipherText.words.slice(0, 16 / 4));
    const ciphertext = lib.WordArray.create(parsedCipherText.words.slice(16 / 4));
    let decryptedData = '';
    if (encryptedCipherText !== '' || encryptedCipherText !== undefined) {
      decryptedData = AES.decrypt({
        ciphertext: ciphertext
      }, parsedBase64Key,{
        iv: iv
      });
    }
    return decryptedData.toString(enc.Utf8).toString();
  }
  
  export const encryptData = (data) =&gt; {
    return AES.encrypt(data, getSecretKey());
  }
  
  export const decryptData = (data) =&gt; {
    if (data !== undefined) {
      return AES.decrypt(data, getSecretKey()).toString(enc.Utf8);
    } else {
      return '';
    }
  }
  </code></pre>