Skip to content

Instantly share code, notes, and snippets.

@patrickfav
Last active February 27, 2024 11:32
Show Gist options
  • Save patrickfav/7e28d4eb4bf500f7ee8012c4a0cf7bbf to your computer and use it in GitHub Desktop.
Save patrickfav/7e28d4eb4bf500f7ee8012c4a0cf7bbf to your computer and use it in GitHub Desktop.

Revisions

  1. patrickfav revised this gist Feb 25, 2023. No changes.
  2. patrickfav revised this gist Apr 19, 2020. 1 changed file with 24 additions and 0 deletions.
    24 changes: 24 additions & 0 deletions AesGcmTest.java
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,5 @@
    package at.favre.lib.bytes.otherPackage;

    import org.junit.Test;

    import javax.crypto.Cipher;
    @@ -11,12 +13,16 @@

    import static org.junit.Assert.assertEquals;

    /**
    * A simple showcase for encryption and decryption with AES + GCM in Java
    */
    public class AesGcmTest {
    private final SecureRandom secureRandom = new SecureRandom();
    private final static int GCM_IV_LENGTH = 12;

    @Test
    public void testEncryption() throws Exception {
    //create new random key
    byte[] key = new byte[16];
    secureRandom.nextBytes(key);
    SecretKey secretKey = new SecretKeySpec(key, "AES");
    @@ -30,6 +36,15 @@ public void testEncryption() throws Exception {
    assertEquals(message, decrypted);
    }

    /**
    * Encrypt a plaintext with given key.
    *
    * @param plaintext to encrypt (utf-8 encoding will be used)
    * @param secretKey to encrypt, must be AES type, see {@link SecretKeySpec}
    * @param associatedData optional, additional (public) data to verify on decryption with GCM auth tag
    * @return encrypted message
    * @throws Exception if anything goes wrong
    */
    private byte[] encrypt(String plaintext, SecretKey secretKey, byte[] associatedData) throws Exception {

    byte[] iv = new byte[GCM_IV_LENGTH]; //NEVER REUSE THIS IV WITH SAME KEY
    @@ -50,6 +65,15 @@ private byte[] encrypt(String plaintext, SecretKey secretKey, byte[] associatedD
    return byteBuffer.array();
    }

    /**
    * Decrypts encrypted message (see {@link #encrypt(String, SecretKey, byte[])}).
    *
    * @param cipherMessage iv with ciphertext
    * @param secretKey used to decrypt
    * @param associatedData optional, additional (public) data to verify on decryption with GCM auth tag
    * @return original plaintext
    * @throws Exception if anything goes wrong
    */
    private String decrypt(byte[] cipherMessage, SecretKey secretKey, byte[] associatedData) throws Exception {
    final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
    //use first 12 bytes for iv
  3. patrickfav revised this gist Apr 19, 2020. 1 changed file with 5 additions and 4 deletions.
    9 changes: 5 additions & 4 deletions AesGcmTest.java
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,3 @@
    package at.favre.lib.bytes.otherPackage;

    import org.junit.Test;

    import javax.crypto.Cipher;
    @@ -9,6 +7,7 @@
    import java.nio.ByteBuffer;
    import java.nio.charset.StandardCharsets;
    import java.security.SecureRandom;
    import java.security.spec.AlgorithmParameterSpec;

    import static org.junit.Assert.assertEquals;

    @@ -53,12 +52,14 @@ private byte[] encrypt(String plaintext, SecretKey secretKey, byte[] associatedD

    private String decrypt(byte[] cipherMessage, SecretKey secretKey, byte[] associatedData) throws Exception {
    final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
    cipher.init(Cipher.DECRYPT_MODE, secretKey, new GCMParameterSpec(128, cipherMessage, 0, GCM_IV_LENGTH));
    //use first 12 bytes for iv
    AlgorithmParameterSpec gcmIv = new GCMParameterSpec(128, cipherMessage, 0, GCM_IV_LENGTH);
    cipher.init(Cipher.DECRYPT_MODE, secretKey, gcmIv);

    if (associatedData != null) {
    cipher.updateAAD(associatedData);
    }

    //use everything from 12 bytes on as ciphertext
    byte[] plainText = cipher.doFinal(cipherMessage, GCM_IV_LENGTH, cipherMessage.length - GCM_IV_LENGTH);

    return new String(plainText, StandardCharsets.UTF_8);
  4. patrickfav created this gist Apr 19, 2020.
    66 changes: 66 additions & 0 deletions AesGcmTest.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,66 @@
    package at.favre.lib.bytes.otherPackage;

    import org.junit.Test;

    import javax.crypto.Cipher;
    import javax.crypto.SecretKey;
    import javax.crypto.spec.GCMParameterSpec;
    import javax.crypto.spec.SecretKeySpec;
    import java.nio.ByteBuffer;
    import java.nio.charset.StandardCharsets;
    import java.security.SecureRandom;

    import static org.junit.Assert.assertEquals;

    public class AesGcmTest {
    private final SecureRandom secureRandom = new SecureRandom();
    private final static int GCM_IV_LENGTH = 12;

    @Test
    public void testEncryption() throws Exception {
    byte[] key = new byte[16];
    secureRandom.nextBytes(key);
    SecretKey secretKey = new SecretKeySpec(key, "AES");
    byte[] associatedData = "ProtocolVersion1".getBytes(StandardCharsets.UTF_8); //meta data you want to verify with the secret message

    String message = "the secret message";

    byte[] cipherText = encrypt(message, secretKey, associatedData);
    String decrypted = decrypt(cipherText, secretKey, associatedData);

    assertEquals(message, decrypted);
    }

    private byte[] encrypt(String plaintext, SecretKey secretKey, byte[] associatedData) throws Exception {

    byte[] iv = new byte[GCM_IV_LENGTH]; //NEVER REUSE THIS IV WITH SAME KEY
    secureRandom.nextBytes(iv);
    final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
    GCMParameterSpec parameterSpec = new GCMParameterSpec(128, iv); //128 bit auth tag length
    cipher.init(Cipher.ENCRYPT_MODE, secretKey, parameterSpec);

    if (associatedData != null) {
    cipher.updateAAD(associatedData);
    }

    byte[] cipherText = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));

    ByteBuffer byteBuffer = ByteBuffer.allocate(iv.length + cipherText.length);
    byteBuffer.put(iv);
    byteBuffer.put(cipherText);
    return byteBuffer.array();
    }

    private String decrypt(byte[] cipherMessage, SecretKey secretKey, byte[] associatedData) throws Exception {
    final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
    cipher.init(Cipher.DECRYPT_MODE, secretKey, new GCMParameterSpec(128, cipherMessage, 0, GCM_IV_LENGTH));

    if (associatedData != null) {
    cipher.updateAAD(associatedData);
    }

    byte[] plainText = cipher.doFinal(cipherMessage, GCM_IV_LENGTH, cipherMessage.length - GCM_IV_LENGTH);

    return new String(plainText, StandardCharsets.UTF_8);
    }
    }