0

One of my web services is about to start receiving responses from another API where the entire body of the response will be encrypted. Having never handled any type of encryption before, I am a bit lost in the weeds. I have a fully fleshed-out example of how to do the decryption, but it is in Java, using Java-native cryptography classes. Can some one please help me translate this to something that will run in .NET, either using BouncyCastle or the native AesGcm class?

Java Example

private static final String ALGORITHM_NAME = "PBKDF2WithHmacSHA512";
private static final String ALGORITHM_STANDARD = "AES";
private static final String CIPHER_TRANSFORMATION = "AES/GCM/NoPadding";
private static final int ITERATION_COUNT = 10000;
private static final int KEY_LENGTH = 256;
private static final GCM_IV_LENGTH = 16;
private static final GCM_TAG_LENGTH = 128;

 byte[] apiKeyBytes = Base64.getDecoder().decode(apiKey);
 String finalKey = new String(apiKeyBytes, StandardCharsets.UTF_8);
 PBEKeySpec spec = new PBEKeySpec(finalKey.toCharArray(), accessId.getBytes(), ITERATION_COUNT, KEY_LENGTH);
 SecretKey key = SecretKeyFactory.getInstance(ALGORITHM_NAME).generateSecret(spec); 
 SecretKeySpec secretKeySpec = new SecretKeySpec(key.getEncoded(), ALGORITHM_STANDARD);

public String decryptContent(String content) throws NoSuchAlgorithmException, NoSuchPaddingException, 
InvalidKeyException, IllegalBlockSizeException, BadPaddingException, DecoderException, 
InvalidKeySpecException, InvalidAlgorithmParameterException {
    byte[] decodedContent = Hex.decodeHex(content);
    ByteBuffer byteBuffer = ByteBuffer.wrap(decodedContent)
    byte[] ivArray = new byte[GCM_IV_LENGTH];
    byteBuffer.get(ivArray);
    byte[] encrypted = new byte[byteBuffer.remaining()];
    byteBuffer.get(encrypted);
    GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH, ivArray);
    Cipher cipher = Cipher.getInstance(CIPHER_TRANSFORMATION);
    cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, gcmParameterSpec);
    byte[] decryptedOutput = cipher.doFinal(encrypted);
    return new String(decryptedOutput, StandardCharsets.UTF_8);
}

I wish that I could even ask better questions for where I need help, but I'm so confused by the vast differences between the Java method and what I have so far in C#. Java for example, doesn't even mention a "nonce."

My current progress in C#

string secret = Encoding.UTF8.GetString(Convert.FromBase64String(APIKEY));
var keyGen = new Rfc2898DeriveBytes(Encoding.UTF8.GetBytes(secret), Encoding.UTF8.GetBytes(ACCESSID), 10000);
AesGcm _aes = new AesGcm(keyGen.GetBytes(256));

var decodedContent = Hex.Decode(cipher).AsSpan<byte>();
var nonce = decodedContent.Slice(0, 16);
var cipherText = decodedContent.Slice(16, 128);
_aes.Decrypt(nonce, cipherText, **TAG?**, **output byte array**);

What am I missing?

  • 1
    You should post sample data that can be decrypted with the Java code (password, salt, ciphertext, decrypted data). – Topaco Mar 12 '21 at 16:19
  • For GCM the recommended nonce/iv size is 12 bytes (and not 16 bytes as in the Java code), s. [here](https://crypto.stackexchange.com/q/41601). Can you change this size or is the Java code not allowed to be changed? – Topaco Mar 12 '21 at 17:09
  • @Topaco, I am coding to meet an external spec. We are only decrypting this data. It has to be per the sender's requirements. – user1161804 Mar 12 '21 at 18:23
  • Since the `AesGcm` class is available in your environment, you are using .NET Core version 3.0 or higher. Nevertheless, you should post your version. As far as I know, `AesGcm` only supports a nonce/IV size of 12 bytes (and not 16 bytes), see [here](https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.aesgcm.noncebytesizes?view=netcore-3.0#property-value). I.e. you probably have to use _BouncyCastle_ regardless of your version if you want to work with a 16 bytes nonce/IV. – Topaco Mar 12 '21 at 19:13
  • @Topaco, I guess that makes my question "How?". Can anyone point me towards the BC alternative to the Java code above? I have no experience in encryption. I have 25 tabs open and a headache. Any help would be greatly appreciated. – user1161804 Mar 12 '21 at 20:14
  • 1
    You can find C#/BouncyCastle implementations for AES-GCM on SO, e.g. [here](https://stackoverflow.com/q/56884217/9014097). The decryption part of this and the Java implementation are quite close. However, in the linked C# code the key is directly specified, while you have to derive it with `Rfc2898DeriveBytes`. – Topaco Mar 12 '21 at 20:50
  • Thanks @Topaco, this did indeed get me decrypting successfully. – user1161804 Mar 12 '21 at 21:37

0 Answers0