IV and salt handling in Java encryption and decryption

So, I am trying to decrypt the message in the method, but it does not work, because I need to do cipher.init(Cipher.ENCRYPT_MODE, secret) before trying to add new IvParameterSpec(iv) to cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv)); . Otherwise, it simply returns a NullPointerException. I am wondering if it is possible to do this in a method, and not write it all the time. I can’t think of a solution, so I am here. Encryption works fine, but not decrypted.

Project Implementation: JRE 7

Encryption Code:

 public static String encrypt(String str) { try { SecureRandom random = new SecureRandom(); byte[] salt = new byte[16]; random.nextBytes(salt); SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); KeySpec spec = new PBEKeySpec(str.toCharArray(), salt, 65536, 256); SecretKey tmp = factory.generateSecret(spec); SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES"); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); cipher.init(Cipher.ENCRYPT_MODE, secret); //<--- Need to do this before writing IvPerameterSpec, // But I think that it not possible if I have it in another method. byte[] encryptedText = cipher.doFinal(str.getBytes("UTF-8")); return new String(encryptedText); } catch (Exception e) { e.printStackTrace(); } return null; } 

Decrypt Code:

 public static String decrypt(String str) { try { SecureRandom random = new SecureRandom(); byte[] salt = new byte[16]; random.nextBytes(salt); SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); KeySpec spec = new PBEKeySpec(str.toCharArray(), salt, 65536, 256); SecretKey tmp = factory.generateSecret(spec); SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES"); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); AlgorithmParameters params = cipher.getParameters(); byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV(); cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv)); // ^^^ Returns NullPointerException byte[] ciphertext = cipher.doFinal(str.getBytes("UTF-8")); String decryptedText = new String(cipher.doFinal(ciphertext), "UTF-8"); return new String(decryptedText); } catch (Exception e) { e.printStackTrace(); } return null; } 

An exception:

 java.lang.NullPointerException at me.Sansanvi.Encryption.api.ComputerAPI.decrypt(ComputerAPI.java:149) at me.Sansanvi.Encryption.EncryptionMain.initializeFiles(EncryptionMain.java:46) at me.Sansanvi.Encryption.EncryptionMain.<init>(EncryptionMain.java:36) at me.Sansanvi.Encryption.EncryptionMain$1.run(EncryptionMain.java:23) at java.awt.event.InvocationEvent.dispatch(Unknown Source) at java.awt.EventQueue.dispatchEventImpl(Unknown Source) at java.awt.EventQueue.access$200(Unknown Source) at java.awt.EventQueue$3.run(Unknown Source) at java.awt.EventQueue$3.run(Unknown Source) at java.security.AccessController.doPrivileged(Native Method) at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source) at java.awt.EventQueue.dispatchEvent(Unknown Source) at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source) at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source) at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source) at java.awt.EventDispatchThread.pumpEvents(Unknown Source) at java.awt.EventDispatchThread.pumpEvents(Unknown Source) at java.awt.EventDispatchThread.run(Unknown Source) 

I changed the methods to the following and they work:

 private static final String ALGORITHM = "AES"; public static byte[] encrypt(byte[] str) { try { SecretKeySpec secretKey = new SecretKeySpec("MZygpewJsCpRrfOr".getBytes(StandardCharsets.UTF_8), ALGORITHM); Cipher cipher = Cipher.getInstance(ALGORITHM); cipher.init(Cipher.ENCRYPT_MODE, secretKey); return cipher.doFinal(str); } catch (Exception e) { e.printStackTrace(); } return null; } public static byte[] decrypt(byte[] str) { try { SecretKeySpec secretKey = new SecretKeySpec("MZygpewJsCpRrfOr".getBytes(StandardCharsets.UTF_8), ALGORITHM); Cipher cipher = Cipher.getInstance(ALGORITHM); cipher.init(Cipher.DECRYPT_MODE, secretKey); return cipher.doFinal(str); } catch (Exception e) { e.printStackTrace(); } return null; } 

I no longer get any errors / exceptions, but I get this in the console when I close the application:

 [0x7FFC837C7430] ANOMALY: use of REX.w is meaningless (default operand size is 64) [0x7FFC837C7430] ANOMALY: use of REX.w is meaningless (default operand size is 64) [0x7FFC837C7430] ANOMALY: use of REX.w is meaningless (default operand size is 64) [0x7FFC837C7430] ANOMALY: use of REX.w is meaningless (default operand size is 64) [0x7FFC837C7430] ANOMALY: use of REX.w is meaningless (default operand size is 64) [0x7FFC837C7430] ANOMALY: use of REX.w is meaningless (default operand size is 64) [0x7FFC837C7430] ANOMALY: use of REX.w is meaningless (default operand size is 64) [0x7FFC837C7430] ANOMALY: use of REX.w is meaningless (default operand size is 64) 
0
java nullpointerexception encryption
Jul 03 '17 at 6:25
source share
2 answers

You have at least three problems, and you have found only one of them.

  • IV is generated during en and used. Exact IV should be used during de . IV should not be secret. You can simply send / save it along with the ciphertext. Typically, IV is stored before encrypted text and cut before decryption.
    For CBC mode, it just has to be unpredictable (read: random). For CTR mode, it must be unique (when using the same key).

  • Random salt needs to be processed in the same way as IV: it is not secret and can be written before encrypted text.

  • String not a container for binary data. When you use new String(encryptedText) , you are likely to lose some non-printable bytes that break your ciphertext and make the incomplete text open. You need to use something like Base64 or Hex encoding to represent binary data as printed text.

Thus, the resulting code will look something like this:

 public static String encrypt(String str) { try { SecureRandom random = new SecureRandom(); byte[] salt = new byte[16]; random.nextBytes(salt); SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); KeySpec spec = new PBEKeySpec(str.toCharArray(), salt, 65536, 256); SecretKey tmp = factory.generateSecret(spec); SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES"); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); cipher.init(Cipher.ENCRYPT_MODE, secret); AlgorithmParameters params = cipher.getParameters(); byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV(); byte[] encryptedText = cipher.doFinal(str.getBytes("UTF-8")); // concatenate salt + iv + ciphertext ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); outputStream.write(salt); outputStream.write(iv); outputStream.write(encryptedText); // properly encode the complete ciphertext return DatatypeConverter.printBase64Binary(outputStream.toByteArray()); } catch (Exception e) { e.printStackTrace(); } return null; } public static String decrypt(String str) { try { byte[] ciphertext = DatatypeConverter.parseBase64Binary(str); if (ciphertext.length < 48) { return null; } byte[] salt = Arrays.copyOfRange(ciphertext, 0, 16); byte[] iv = Arrays.copyOfRange(ciphertext, 16, 32); byte[] ct = Arrays.copyOfRange(ciphertext, 32, ciphertext.length); SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); KeySpec spec = new PBEKeySpec(str.toCharArray(), salt, 65536, 256); SecretKey tmp = factory.generateSecret(spec); SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES"); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv)); byte[] plaintext = cipher.doFinal(ct); return new String(plaintext, "UTF-8"); } catch (Exception e) { e.printStackTrace(); } return null; } 

I used this one to encode / decode Base64 compatible with Java 7.

+3
Jul 03 '17 at 18:18
source share

You do not initialize the cipher correctly, first you need an instance (you do it right):

 Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 

Then you need to initialize it, there are several init methods:

 public void init(int opmode, Key key); public void init(int opmode, Certificate certificate); public void init(int opmode, Key key, SecureRandom random); public void init(int opmode, Certificate certificate, SecureRandom random); public void init(int opmode, Key key, AlgorithmParameterSpec params); public void init(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random); public void init(int opmode, Key key, AlgorithmParameters params); public void init(int opmode, Key key, AlgorithmParameters params, SecureRandom random); 

In this case, you want to use this:

 public void init(int opmode, Key key, AlgorithmParameterSpec params); 

However, a call to cipher.getParameters(); before init always returns null. There is your NullPointerException exception.

In addition, there are more errors in the code, for example, using data for encryption as a key.

-one
Jul 03 '17 at 7:53 on
source share



All Articles