RC4 Encryption/Decryption with C# and Java

10,808

Solution 1

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();
        }
    }
}

Solution 2

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
    ...
Share:
10,808
Renan Barbosa
Author by

Renan Barbosa

Updated on June 04, 2022

Comments

  • Renan Barbosa
    Renan Barbosa almost 2 years

    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.