2

I even use the AES algorithm to encrypt and decrypt files, but according to my research, the performance of this algorithm is slower than the RC4 algorithm in Java. I'm use this code for encrypt files in C#

public static class RC4
{
    public static byte[] Encrypt(byte[] key, byte[] data)
    {
        return EncryptOutput(key, data).ToArray();
    }

    private static byte[] EncryptInitalize(byte[] key)
    {
        byte[] s = Enumerable.Range(0, 256)
          .Select(i => (byte)i)
          .ToArray();

        for (int i = 0, j = 0; i < 256; i++)
        {
            j = (j + key[i % key.Length] + s[i]) & 255;

            Swap(s, i, j);
        }

        return s;
    }

    private static IEnumerable<byte> EncryptOutput(byte[] key, IEnumerable<byte> data)
    {
        byte[] s = EncryptInitalize(key);

        int i = 0;
        int j = 0;

        return data.Select((b) =>
        {
            i = (i + 1) & 255;
            j = (j + s[i]) & 255;

            Swap(s, i, j);

            return (byte)(b ^ s[(s[i] + s[j]) & 255]);
        });
    }

    private static void Swap(byte[] s, int i, int j)
    {
        byte c = s[i];

        s[i] = s[j];
        s[j] = c;
    }
}

I need to encrypt a file in C # and decrypt this file with java, but found no implementation for both languages.

5
  • What is the question exactly? You want an implementation of an encryption/decryption that works in both java and C# for RC4? Commented Aug 18, 2015 at 20:31
  • 1
    Don't choose RC4 over AES simply because you have anecdotal evidence that it may be slower. There are a number of well-known attacks on RC4 and it isn't a secure way to encrypt sensitive data. Commented Aug 18, 2015 at 20:33
  • Have you benchmarked AES? It's probably encrypting faster than you can read the data from disk anyway. Commented Aug 18, 2015 at 20:33
  • RC4 is a stream cipher, and known to be weak. You should ask yourself if you really need a stream cipher. AES is a block cipher and (the 256bit variant) fairly strong. Commented Aug 18, 2015 at 20:34
  • It happens that the AES algorithm took 27 seconds to decrypt an video file in an Android application. AES is really a more secure deployment, however I need to make it more agile. Any tips on how I can solve this? Commented Aug 18, 2015 at 20:38

2 Answers 2

2

This solution implemented by Michael Remijan showed better performance to decrypt files using AES. Encrypt and Decrypt files for I implemented just a string conversion to byte array.

Java Code

 package org.ferris.aes.crypto;

import java.io.UnsupportedEncodingException;
import java.security.Key;
import java.security.spec.KeySpec;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;

/**
 *
 * @author Michael Remijan [email protected] @mjremijan
 */
public class AesBase64Wrapper {

    private static String IV = "IV_VALUE_16_BYTE"; 
    private static String PASSWORD = "PASSWORD_VALUE"; 
    private static String SALT = "SALT_VALUE"; 

    public String encryptAndEncode(String raw) {
        try {
            Cipher c = getCipher(Cipher.ENCRYPT_MODE);
            byte[] encryptedVal = c.doFinal(getBytes(raw));
            String s = getString(Base64.encodeBase64(encryptedVal));
            return s;
        } catch (Throwable t) {
            throw new RuntimeException(t);
        }
    }

    public String decodeAndDecrypt(String encrypted) throws Exception {
        byte[] decodedValue = Base64.decodeBase64(getBytes(encrypted));
        Cipher c = getCipher(Cipher.DECRYPT_MODE);
        byte[] decValue = c.doFinal(decodedValue);
        return new String(decValue);
    }

    private String getString(byte[] bytes) throws UnsupportedEncodingException {
        return new String(bytes, "UTF-8");
    }

    private byte[] getBytes(String str) throws UnsupportedEncodingException {
        return str.getBytes("UTF-8");
    }

    private Cipher getCipher(int mode) throws Exception {
        Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
        byte[] iv = getBytes(IV);
        c.init(mode, generateKey(), new IvParameterSpec(iv));
        return c;
    }

    private Key generateKey() throws Exception {
        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        char[] password = PASSWORD.toCharArray();
        byte[] salt = getBytes(SALT);

        KeySpec spec = new PBEKeySpec(password, salt, 65536, 128);
        SecretKey tmp = factory.generateSecret(spec);
        byte[] encoded = tmp.getEncoded();
        return new SecretKeySpec(encoded, "AES");
    }
}

C# Code

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;

namespace EncryptDecryptTest
{
    class Program
    {
        class AesBase64Wrapper
        {
            private static string IV = "IV_VALUE_16_BYTE";
            private static string PASSWORD = "PASSWORD_VALUE";
            private static string SALT = "SALT_VALUE";

            public static string EncryptAndEncode(string raw)
            {
                using (var csp = new AesCryptoServiceProvider())
                {
                    ICryptoTransform e = GetCryptoTransform(csp, true);
                    byte[] inputBuffer = Encoding.UTF8.GetBytes(raw);
                    byte[] output = e.TransformFinalBlock(inputBuffer, 0, inputBuffer.Length);
                    string encrypted = Convert.ToBase64String(output);
                    return encrypted;
                }
            }

            public static string DecodeAndDecrypt(string encrypted)
            {
                using (var csp = new AesCryptoServiceProvider())
                {
                    var d = GetCryptoTransform(csp, false);
                    byte[] output = Convert.FromBase64String(encrypted);
                    byte[] decryptedOutput = d.TransformFinalBlock(output, 0, output.Length);
                    string decypted = Encoding.UTF8.GetString(decryptedOutput);
                    return decypted;
                }
            }

            private static ICryptoTransform GetCryptoTransform(AesCryptoServiceProvider csp, bool encrypting)
            {
                csp.Mode = CipherMode.CBC;
                csp.Padding = PaddingMode.PKCS7;
                var spec = new Rfc2898DeriveBytes(Encoding.UTF8.GetBytes(PASSWORD), Encoding.UTF8.GetBytes(SALT), 65536);
                byte[] key = spec.GetBytes(16);


                csp.IV = Encoding.UTF8.GetBytes(IV);
                csp.Key = key;
                if (encrypting)
                {
                    return csp.CreateEncryptor();
                }
                return csp.CreateDecryptor();
            }
        }

        static void Main(string[] args)
        {
            string encryptMe;
            string encrypted;
            string decrypted;

            encryptMe = "please encrypt me";
            Console.WriteLine("encryptMe = " + encryptMe);

            encrypted = AesBase64Wrapper.EncryptAndEncode(encryptMe);
            Console.WriteLine("encypted: " + encrypted);

            decrypted = AesBase64Wrapper.DecodeAndDecrypt(encrypted);
            Console.WriteLine("decrypted: " + decrypted);

            Console.WriteLine("press any key to exit....");
            Console.ReadKey();
        }
    }
}
Sign up to request clarification or add additional context in comments.

Comments

1

Based on your comments, I am assuming you want to know how to speed up your encryption / decryption process, and changing the main algorithm is not mandatory.

You could look at different modes for AES. For example, AES in counter (CTR) mode is significantly faster than cipher block chaining (CBC) which is often used.

Try creating your cipher like

Cipher myCipher = Cipher.getInstance("AES/CTR/NoPadding");

and you should see a performance increase. Additionally, using NoPadding will keep the size the same as the plaintext.

(Yes, I know that CTR mode turn AES into a stream cipher, never mind my comment)

UPDATE

I have used this in the past along these lines:

    Key key = new SecretKeySpec(yourKeyValue, "AES");
    Cipher enc = Cipher.getInstance("AES/CTR/NoPadding");
    enc.init(Cipher.ENCRYPT_MODE, key);
    // Get the IV that was generated
    byte[] iv = enc.getIV();
    // Encrypt your data
    ...
    Cipher dec = Cipher.getInstance("AES/CTR/NoPadding");
    dec.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
    // Decrypt your data
    ...

5 Comments

Using the CTR would be required to initialize the vector? dcipher.init(Cipher.DECRYPT_MODE, key, paramSpec);
@RenanPrológica Although you would pass an IV, it's actually called a nonce in case of CTR mode and it must be unique for every encryption with the same key.
Yes, you would need to save the IV from the initialization of the cipher when encrypting. I will update with an example.
Actually using CTR mode is faster, but I have an application in Windows Forms to encrypt the files, and C # CTR mode is not implemented.
Sorry to hear that, I am not very proficient in C# unfortunately. There is always a trade-off between security and speed, yours to make. You could take a look here stackoverflow.com/questions/3474355/… to help you decide.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.