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.

  • What is the question exactly? You want an implementation of an encryption/decryption that works in both java and C# for RC4? – Ron Beyer Aug 18 '15 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](https://en.wikipedia.org/wiki/RC4#Security) on RC4 and it isn't a secure way to encrypt sensitive data. – Dave Aug 18 '15 at 20:33
  • Have you benchmarked AES? It's probably encrypting faster than you can read the data from disk anyway. – Artjom B. Aug 18 '15 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. – mvreijn Aug 18 '15 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? –  Aug 18 '15 at 20:38

2 Answers2

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 mjremijan@yahoo.com @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();
        }
    }
}
Renan Barbosa
  • 1,046
  • 3
  • 11
  • 31
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
    ...
mvreijn
  • 2,807
  • 28
  • 40
  • Using the CTR would be required to initialize the vector? dcipher.init(Cipher.DECRYPT_MODE, key, paramSpec); –  Aug 18 '15 at 21:24
  • @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. – Artjom B. Aug 18 '15 at 21:25
  • Yes, you would need to save the IV from the initialization of the cipher when encrypting. I will update with an example. – mvreijn Aug 18 '15 at 21:25
  • 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. –  Aug 18 '15 at 21:54
  • 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 http://stackoverflow.com/questions/3474355/fast-and-secure-cryptography-algorithm-c-sharp to help you decide. – mvreijn Aug 19 '15 at 19:15