public static String decrypt(SecretKey secretKey, String encryptedText) throws Exception { Cipher cipher = Cipher.getInstance(CIPHER_MODE, PROVIDER_NAME); // separate and decode the initializationVector and aad from the encryptedBytes; String[] sections = encryptedText.split(PAYLOAD_SEPARATOR); byte[] iv = Base64.getDecoder().decode(sections[0]); byte[] aad = Base64.getDecoder().decode(sections[1]); byte[] encryptedTextBytes = Base64.getDecoder().decode(sections[2]); GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(128, iv); cipher.init(Cipher.DECRYPT_MODE, secretKey, gcmParameterSpec); cipher.updateAAD(aad); byte[] byteDecryptedText = cipher.doFinal(encryptedTextBytes); return new String(byteDecryptedText); }
public static String encrypt(SecretKey secretKey, String clearText) throws Exception { Cipher cipher = Cipher.getInstance(CIPHER_MODE, PROVIDER_NAME); final byte[] iv = new byte[12]; new SecureRandom().nextBytes(iv); GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(128, iv); cipher.init(Cipher.ENCRYPT_MODE, secretKey, gcmParameterSpec); final byte[] aad = new byte[12]; new SecureRandom().nextBytes(aad); cipher.updateAAD(aad); byte[] encryptedBytes = cipher.doFinal(clearText.getBytes("UTF-8")); // The encrypted string will consist of the initializationVector + the authenticated encryption // data + the encryptedBytes; return new String(Base64.getEncoder().encode(iv), "UTF-8") + PAYLOAD_SEPARATOR + new String(Base64.getEncoder().encode(aad), "UTF-8") + PAYLOAD_SEPARATOR + new String(Base64.getEncoder().encode(encryptedBytes), "UTF-8"); }
private void testGCMGeneric(byte[] K, byte[] N, byte[] A, byte[] P, byte[] C) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, NoSuchProviderException, IOException, InvalidParameterSpecException { Cipher eax = Cipher.getInstance("AES/GCM/NoPadding", "BC"); SecretKeySpec key = new SecretKeySpec(K, "AES"); // GCMParameterSpec mapped to AEADParameters and overrides default MAC // size GCMParameterSpec spec = new GCMParameterSpec(128, N); eax.init(Cipher.ENCRYPT_MODE, key, spec); eax.updateAAD(A); byte[] c = eax.doFinal(P); if (!areEqual(C, c)) { fail("JCE encrypt with additional data and GCMParameterSpec failed."); } eax = Cipher.getInstance("GCM", "BC"); eax.init(Cipher.DECRYPT_MODE, key, spec); eax.updateAAD(A); byte[] p = eax.doFinal(C); if (!areEqual(P, p)) { fail("JCE decrypt with additional data and GCMParameterSpec failed."); } AlgorithmParameters algParams = eax.getParameters(); byte[] encParams = algParams.getEncoded(); GCMParameters gcmParameters = GCMParameters.getInstance(encParams); if (!Arrays.areEqual(spec.getIV(), gcmParameters.getNonce()) || spec.getTLen() != gcmParameters.getIcvLen()) { fail("parameters mismatch"); } GCMParameterSpec gcmSpec = algParams.getParameterSpec(GCMParameterSpec.class); if (!Arrays.areEqual(gcmSpec.getIV(), gcmParameters.getNonce()) || gcmSpec.getTLen() != gcmParameters.getIcvLen() * 8) { fail("spec parameters mismatch"); } if (!Arrays.areEqual(eax.getIV(), gcmParameters.getNonce())) { fail("iv mismatch"); } }
private static byte[] gcmDecrypt(byte[] key, byte[] cipherText, byte[] aad, byte[] iv) throws AEADBadTagException { byte[] plainText = new byte[cipherText.length - BLOCK_SIZE]; try { SecretKeySpec keySpec = new SecretKeySpec(key, ALGORITHM); GCMParameterSpec gcmSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, iv); Cipher cipher = Cipher.getInstance(ALGORITHM + "/" + MODE + "/NoPadding"); cipher.init(Cipher.DECRYPT_MODE, keySpec, gcmSpec); if (aad != null && aad.length != 0) { cipher.updateAAD(aad); } // store internally until decryptFinal is called cipher.doFinal(cipherText, 0, cipherText.length, plainText, 0); } catch (AEADBadTagException e) { System.out.println(e.getMessage()); throw e; } catch (Exception e) { System.out.println(e.getMessage()); } return plainText; }
private static byte[] gcmEncrypt(byte[] key, byte[] plainText, byte[] aad, byte[] iv) { byte[] cipherText = new byte[plainText.length + 16]; try { SecretKeySpec keySpec = new SecretKeySpec(key, ALGORITHM); GCMParameterSpec gcmSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, iv); Cipher cipher = Cipher.getInstance(ALGORITHM + "/" + MODE + "/NoPadding"); cipher.init(Cipher.ENCRYPT_MODE, keySpec, gcmSpec); if (aad != null && aad.length != 0) { cipher.updateAAD(aad); } // if has more than one blocks, test cipher.update if (plainText.length > 16) { cipher.update(plainText, 0, 16, cipherText, 0); cipher.doFinal(plainText, 16, plainText.length - 16, cipherText, 16); } else { // doFinal(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) cipher.doFinal(plainText, 0, plainText.length, cipherText, 0); } } catch (Exception e) { System.out.println(e.getMessage()); } return cipherText; }
private void checkCipherWithAD(byte[] K, byte[] N, byte[] A, byte[] P, byte[] C) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, NoSuchProviderException { Cipher eax = Cipher.getInstance("AES/EAX/NoPadding", "BC"); SecretKeySpec key = new SecretKeySpec(K, "AES"); IvParameterSpec iv = new IvParameterSpec(N); eax.init(Cipher.ENCRYPT_MODE, key, iv); eax.updateAAD(A); byte[] c = eax.doFinal(P); if (!areEqual(C, c)) { fail("JCE encrypt with additional data failed."); } eax.init(Cipher.DECRYPT_MODE, key, iv); eax.updateAAD(A); byte[] p = eax.doFinal(C); if (!areEqual(P, p)) { fail("JCE decrypt with additional data failed."); } }
private void testGCMParameterSpecWithRepeatKey(byte[] K, byte[] N, byte[] A, byte[] P, byte[] C) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, NoSuchProviderException, IOException { Cipher eax = Cipher.getInstance("AES/EAX/NoPadding", "BC"); SecretKeySpec key = new SecretKeySpec(K, "AES"); GCMParameterSpec spec = new GCMParameterSpec(128, N); eax.init(Cipher.ENCRYPT_MODE, key, spec); eax.updateAAD(A); byte[] c = eax.doFinal(P); if (!areEqual(C, c)) { fail("JCE encrypt with additional data and RepeatedSecretKeySpec failed."); } // Check GCMParameterSpec handling knows about RepeatedSecretKeySpec eax.init(Cipher.DECRYPT_MODE, new RepeatedSecretKeySpec("AES"), spec); eax.updateAAD(A); byte[] p = eax.doFinal(C); if (!areEqual(P, p)) { fail("JCE decrypt with additional data and RepeatedSecretKeySpec failed."); } AlgorithmParameters algParams = eax.getParameters(); byte[] encParams = algParams.getEncoded(); GCMParameters gcmParameters = GCMParameters.getInstance(encParams); if (!Arrays.areEqual(spec.getIV(), gcmParameters.getNonce()) || spec.getTLen() != gcmParameters.getIcvLen()) { fail("parameters mismatch"); } }