title: AES/GCM/NoPadding JAVA encryption doesn't match C# encryption
body: <p>I'm using some encryption functions in C# and Java whose output doesn't seem to match. I've been fighting with this for a few days and thought I'd finally turn here for help.</p>
  <p><strong>Input string</strong>: &quot;a&quot;</p>
  <p>Here is a snippet of the java implementation:</p>
  <blockquote>
  <p>CryptoAesGcmService.getInstance().encryptData(&quot;a&quot;, aes_key)</p>
  </blockquote>
  <pre><code>    import javax.crypto.Cipher;
      import javax.crypto.spec.GCMParameterSpec;
      import javax.crypto.spec.SecretKeySpec;
      
      import java.nio.charset.StandardCharsets;
      import java.security.MessageDigest;
      import java.security.NoSuchAlgorithmException;
      import java.util.Base64;
      
      public class CryptoAesGcmService {
      
          private static CryptoAesGcmService instance;
          private static final int GCM_TAG_LENGTH = 16;
          private static final int GCM_IV_LENGTH = 12;
      
          public static CryptoAesGcmService getInstance() {
              if (instance == null) {
                  instance = new CryptoAesGcmService();
              }
              return instance;
      
          }
          
          public String encryptData(String plaintext, String key) throws Exception {
              return encrypt2(plaintext, key, createGCMParameter());
          }
          
          private static String encrypt(String plaintext, String key, GCMParameterSpec gcmParameterSpec) throws Exception {
      //      return plaintext;
              try {
                  byte[] plainTextByte = plaintext.getBytes(StandardCharsets.UTF_8);
                  Cipher cipher = Cipher.getInstance(&quot;AES/GCM/NoPadding&quot;);
                  cipher.init(Cipher.ENCRYPT_MODE, createSecretKeySpec(key), gcmParameterSpec);
                  byte[] cipherText = cipher.doFinal(plainTextByte);
                  return Base64.getEncoder().encodeToString(cipherText);
              } catch (Exception e) {
                  throw new Exception(&quot;Unexpected exception occur.&quot;, e);
              }
          }
      
          private static SecretKeySpec createSecretKeySpec(String secretKey) throws NoSuchAlgorithmException {
              MessageDigest md = MessageDigest.getInstance(&quot;SHA-256&quot;);
              md.update(secretKey.getBytes(StandardCharsets.UTF_8));
              return new SecretKeySpec(md.digest(), &quot;AES&quot;);
          }
      
          private static GCMParameterSpec createGCMParameter() {
              return new GCMParameterSpec(GCM_TAG_LENGTH * 8, new byte[GCM_IV_LENGTH]);
          }
          
      }
  
  </code></pre>
  <p><strong>Output: fix</strong> <code>3UhjsGLxeoCyP/cd7c7p++I=</code></p>
  <p>Here is a snippet of the .Net implementation:</p>
  <blockquote>
  <p>aes.Encrypt(&quot;a&quot;, aes_key);</p>
  </blockquote>
  <pre><code>
  using System;
  using System.Buffers.Binary;
  using System.IO;
  using System.Security.Cryptography;
  using System.Text;
  using Org.BouncyCastle.Crypto;
  using Org.BouncyCastle.Crypto.Engines;
  using Org.BouncyCastle.Crypto.Modes;
  using Org.BouncyCastle.Crypto.Parameters;
  using Org.BouncyCastle.Security;
  
  namespace api.Class
  {
      public class AESGCM
      {
          private const int KEY_BIT_SIZE = 256;
          private const int MAC_BIT_SIZE = 128;
          private const int NONCE_BIT_SIZE = 128;
  
          private readonly SecureRandom random;
  
          private static AESGCM instance;
  
          public static AESGCM Instance //property of this class. Create an instance if it is not created yet
          {
              get
              {
                  if (instance == null)
                      instance = new AESGCM();
                  return instance;
              }
          }
  
          public AESGCM()
          {
              random = new SecureRandom();
          }
  
          //encrypt with strings
          public string Encrypt(string text, string key, byte[] nonSecretPayload = null)
          {
              if (string.IsNullOrEmpty(text))
                  throw new ArgumentException(&quot;Text required!&quot;, &quot;text&quot;);
              //var decodedKey = Convert.FromBase64String(key);
              var decodedKey = Encoding.UTF8.GetBytes(key);
              var plainText = Encoding.UTF8.GetBytes(text);
              var cipherText = EncryptWithKey(plainText, decodedKey, nonSecretPayload);
              return Convert.ToBase64String(cipherText);
          }
  
          //encrypt with byte array
          private byte[] EncryptWithKey(byte[] text, byte[] key, byte[] nonSecretPayload = null)
          {
              if (key == null || key.Length != KEY_BIT_SIZE / 8)
                  throw new ArgumentException(String.Format(&quot;Key needs to be {0} bit!&quot;, KEY_BIT_SIZE), &quot;key&quot;);
  
              nonSecretPayload = nonSecretPayload ?? new byte[] { };
              var nonce = new byte[NONCE_BIT_SIZE / 8];
              random.NextBytes(nonce, 0, nonce.Length);
              var cipher = new GcmBlockCipher(new AesEngine());
              var parameters = new AeadParameters(new KeyParameter(key), MAC_BIT_SIZE, nonce, nonSecretPayload);
              cipher.Init(true, parameters);
              var cipherText = new byte[cipher.GetOutputSize(text.Length)];
              var len = cipher.ProcessBytes(text, 0, text.Length, cipherText, 0);
              cipher.DoFinal(cipherText, len);
              using (var combinedStream = new MemoryStream())
              {
                  using (var binaryWriter = new BinaryWriter(combinedStream))
                  {
                      binaryWriter.Write(nonSecretPayload);
                      binaryWriter.Write(nonce);
                      binaryWriter.Write(cipherText);
                  }
                  return combinedStream.ToArray();
              }
          }
      }
  }
  
  </code></pre>
  <p><strong>Output: always changing</strong></p>
  <p>example 1
  <code>4BNEStJ12YZIQsaFhOcufy1rgXW2/H5kBmPyBSVdf2qP</code></p>
  <p>example 2
  <code>z4xNJgr6YLg+lsCA2jUn0HKorN8UXrVm0QtKl10w/Yba</code></p>
  <p>example 3
  <code>0IxfAp2vIOmj3fvsJ25VVINHpnaxtZ5KNl89Qk7MNFcn</code></p>
  <p>I want output .net same java. I don't know enough about encryption nor Java to know where to turn next. Any guidance would be greatly appreciated</p>
  <p><strong>UPDATE</strong></p>
  <p>I try to follow the advice but not working.</p>
  <pre><code>using System;
  using System.Text;
  using Org.BouncyCastle.Crypto.Engines;
  using Org.BouncyCastle.Crypto.Modes;
  using Org.BouncyCastle.Crypto.Parameters;
  
  namespace api.Class
  {
      public class AESGCM
      {
          private const int KEY_BIT_SIZE = 256;
          private const int MAC_BIT_SIZE = 128;
  
          //encrypt with strings
          public string Encrypt(string text, string key)
          {
              if (string.IsNullOrEmpty(text))
                  throw new ArgumentException(&quot;Text required!&quot;, &quot;text&quot;);
  
              var decodedKey = Encoding.UTF8.GetBytes(key);
              var plainText = Encoding.UTF8.GetBytes(text);
              var cipherText = EncryptWithKey(plainText, decodedKey);
              return Convert.ToBase64String(cipherText);
          }
  
          //encrypt with byte array
          private byte[] EncryptWithKey(byte[] text, byte[] key)
          {
              if (key == null || key.Length != KEY_BIT_SIZE / 8)
                  throw new ArgumentException(String.Format(&quot;Key needs to be {0} bit!&quot;, KEY_BIT_SIZE), &quot;key&quot;);
  
              var nonce = new byte[12];
              var cipher = new GcmBlockCipher(new AesEngine());
              var parameters = new AeadParameters(new KeyParameter(key), MAC_BIT_SIZE, nonce);
              cipher.Init(true, parameters);
              var cipherText = new byte[cipher.GetOutputSize(text.Length)];
              var len = cipher.ProcessBytes(text, 0, text.Length, cipherText, 0);
              cipher.DoFinal(cipherText, len);
  
              return cipherText;
          }
      }
  }
  </code></pre>
  <p><strong>Output: fix</strong> <code>7szCRlNpTMM+93eTi332Gdw=</code></p>
  <p><strong>FINAL CODE</strong></p>
  <pre><code>using System;
  using System.Security.Cryptography;
  using System.Text;
  using Org.BouncyCastle.Crypto.Engines;
  using Org.BouncyCastle.Crypto.Modes;
  using Org.BouncyCastle.Crypto.Parameters;
  
  namespace api.Class
  {
      public class AESGCM
      {
          private const int KEY_BIT_SIZE = 256;
          private const int MAC_BIT_SIZE = 128;
  
          //encrypt with strings
          public string Encrypt(string text, string key)
          {
              if (string.IsNullOrEmpty(text))
                  throw new ArgumentException(&quot;Text required!&quot;, &quot;text&quot;);
  
              var decodedKey = sha256_hash(key);
              var plainText = Encoding.UTF8.GetBytes(text);
              var cipherText = EncryptWithKey(plainText, decodedKey);
              return Convert.ToBase64String(cipherText);
          }
  
          //encrypt with byte array
          private byte[] EncryptWithKey(byte[] text, byte[] key)
          {
              if (key == null || key.Length != KEY_BIT_SIZE / 8)
                  throw new ArgumentException(String.Format(&quot;Key needs to be {0} bit!&quot;, KEY_BIT_SIZE), &quot;key&quot;);
  
              var nonce = new byte[12];
              var cipher = new GcmBlockCipher(new AesEngine());
              var parameters = new AeadParameters(new KeyParameter(key), MAC_BIT_SIZE, nonce);
              cipher.Init(true, parameters);
              var cipherText = new byte[cipher.GetOutputSize(text.Length)];
              var len = cipher.ProcessBytes(text, 0, text.Length, cipherText, 0);
              cipher.DoFinal(cipherText, len);
  
              return cipherText;
          }
  
          private byte[] sha256_hash(string value)
          {
              Byte[] result;
  
              using (var hash = SHA256.Create())
              {
                  Encoding enc = Encoding.UTF8;
                  result = hash.ComputeHash(enc.GetBytes(value));
              }
  
              return result;
          }
      }
  }
  </code></pre>
  <p><strong>Output: same the java</strong></p>
  <p>Thank you very much, @user9014097</p>