Search code examples
c#algorithmencryptionaesencryption-symmetric

Wrong algorithm: AES or Rijndael required on c#


I had andriod code and I tried to convert it to c#. It's a simple Encryption class. But when I try to decrypt data with it I catch: Wrong algorithm: AES or Rijndael required.
Here is my converted code:

public static string decrypt(string data)
{
    byte[] dataBytes = Convert.FromBase64String(data);
    SecretKey secretKey = getSecretKey(hashTheKey("ABCD"));

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

    cipher.init(2, secretKey, new IvParameterSpec(new byte[16]),
            SecureRandom.getInstance("SHA1PRNG"));
    var x = cipher.doFinal(dataBytes);
    return System.Text.Encoding.UTF8.GetString(x);
}
public static SecretKey getSecretKey(char[] key)
{
    var secretKeyType = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
    var secretkey = secretKeyType.generateSecret(new PBEKeySpec(key,
            System.Text.Encoding.UTF8
                .GetBytes("ABCD"),
            100, 128)).getEncoded();

    return new SecretKeySpec(secretkey, "AES/CBC/PKCS5Padding");
}
public static char[] hashTheKey(string key)
{
    MessageDigest messageDigest = MessageDigest.getInstance("SHA1");
    messageDigest.update(System.Text.Encoding.UTF8.GetBytes(key));
    return Convert.ToBase64String(messageDigest.digest()).ToCharArray();
}

Here is my original android code:

private char[] hashTheKey(String key) throws UnsupportedEncodingException, NoSuchAlgorithmException {
    MessageDigest messageDigest = MessageDigest.getInstance("SHA1");
    messageDigest.update(key.getBytes());
    return Base64.encodeToString(messageDigest.digest(),
                                 Base64.NO_PADDING).toCharArray();
}

private SecretKey getSecretKey(char[] key) throws NoSuchAlgorithmException, UnsupportedEncodingException, InvalidKeySpecException {
    return new SecretKeySpec(
        SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1")
        .generateSecret(new PBEKeySpec(key,
                       "ABCD".getBytes("UTF8"),
                       100, 128)).getEncoded(), "AES");
}

public String decrypt(String data) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, UnsupportedEncodingException, InvalidKeySpecException {
    byte[] dataBytes = Base64.decode(data, Base64.DEFAULT);
    SecretKey secretKey = getSecretKey(hashTheKey("ABCD"));
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipher.init(2, secretKey, new IvParameterSpec(new byte[16]),
            SecureRandom.getInstance("SHA1PRNG"));
    return new String(cipher.doFinal(dataBytes));
}

Solution

  • and are using the same well-estabilished cryptography algorithms, but differs in approach how to invoke them. It is still possible to convert the code though.

    One key point is difference in base64 encoding - C# always use padding.

    Converted code goes like:

    const int KeySize = 128;
    
    static string HashTheKey(string key) {
      String hashKey;
      using (var sha = new SHA1Managed()) {
       hashKey = Convert.ToBase64String(sha.ComputeHash(Encoding.UTF8.GetBytes(key)));
      }
      // beware - you're on C# now so remove the padding and add the newline to match java
      return hashKey.Replace("=", "") + "\n";
    }
    
    static byte[] GetSecretKey(string password) {
      var salt = Encoding.UTF8.GetBytes("JVAaVhAiddKAaghraikhmaini");
      using (var pass = new Rfc2898DeriveBytes(password, salt, 65536)) {
        return pass.GetBytes(KeySize / 8);
      }
    }
    
    static void Main(string[] args) {
      string encrypted = "vtlkQHTz7/oz2weuAAkLz2Q5c2yj2LGukF7SHJjT+TA8oRLixTQSXQ7dG1O736hyT1HJxcz0P4DzzVaO5chWKKSJQ2uPEpDQJu/fZGguqDw=";
      byte[] encryptedBytes = Convert.FromBase64String(encrypted);
      using (var aes = new AesManaged()) {
        aes.KeySize = KeySize;
        aes.Padding = PaddingMode.PKCS7;
        aes.Key = GetSecretKey(HashTheKey("Android"));
        // you're using the same init vector in your android code
        aes.IV = new byte[16];
        using (var decryptor = aes.CreateDecryptor()) {
          // dumps {"barcode":"12345678","token":"cad603fc-1e53-4a95-9150-f1694baa07f9"}
          Console.Out.WriteLine(Encoding.UTF8.GetString(decryptor.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length)));
        }
      }
    }