JAVA - 从文本中读取和加密大量密码 - 任何加速它的方法?

时间:2015-06-21 22:10:19

标签: java performance api encryption passwords

我正在尝试读取一个大文件,其中的行由电子邮件组成:密码组合。然后我使用Mega.co.nz的API加密它们。这很好,但加密过程太慢,无法在合理的时间内处理100 + MB文本文件。

我最初是用Python制作的,但速度太慢了。我认为JAVA会大大加快速度,但事实并非如此。它确实加快了一点,但不是很多。

这是一项适合多线程的任务吗?

谢谢!

import java.io.*;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.util.Arrays;

class RunnableDemo implements Runnable {
   private Thread t;
   private String threadName;
   private long[] password_aes;
   private String uh = "";
   private static final char[] CA = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray();
   private static final int[] IA = new int[256];
   private String fileName = "C://combo_encrypted.txt";



    static {
        Arrays.fill(IA, -1);
        for (int i = 0, iS = CA.length; i < iS; i++)
            IA[CA[i]] = i;
        IA['='] = 0;
    }

   RunnableDemo( String name){
       threadName = name;
   }

   public void run() {


   FileWriter fileWriter;
try {
    fileWriter = new FileWriter(fileName, true);
    BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);

    String finalString = "";
    String[] parts = threadName.split(":");
    password_aes = prepare_key_pw(parts[1]);
    uh = stringhash(parts[0], password_aes);
    finalString = (parts[0] + ":" + parts[1] + ":" + uh + "\n");
    System.out.println(finalString);
    bufferedWriter.write(finalString);
} catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

   }



   public void start ()
   {
      System.out.println("Starting " +  threadName );
      if (t == null)
      {
         t = new Thread (this, threadName);
         t.start ();
      }
   }


public static long[] str_to_a32(String string) {
    if (string.length() % 4 != 0) {
        string += new String(new char[4 - string.length() % 4]);
    }
    long[] data = new long[string.length() / 4];

    byte[] part = new byte[8];
    for (int k = 0, i = 0; i < string.length(); i += 4, k++) {
        String sequence = string.substring(i, i + 4);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try {
            baos.write(sequence.getBytes("ISO-8859-1"));
            System.arraycopy(baos.toByteArray(), 0, part, 4, 4);
            ByteBuffer bb = ByteBuffer.wrap(part);
            data[k] = bb.getLong();
        } catch (IOException e) {
            data[k] = 0;
        }
    }
    return data;
}

public static String a32_to_str(long[] data) {
    byte[] part = null;
    StringBuilder builder = new StringBuilder();
    ByteBuffer bb = ByteBuffer.allocate(8);
    for (int i = 0; i < data.length; i++) {
        bb.putLong(data[i]);
        part = Arrays.copyOfRange(bb.array(), 4, 8);
        bb.clear();
        ByteArrayInputStream bais = new ByteArrayInputStream(part);
        while (bais.available() > 0) {
            builder.append((char) bais.read());
        }
    }
    return builder.toString();
}

public static byte[] aes_cbc_encrypt(byte[] data, byte[] key) {
    String iv = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
    IvParameterSpec ivSpec = new IvParameterSpec(iv.getBytes());
    byte[] output = null;
    try {
        SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
        Cipher cipher = Cipher.getInstance("AES/CBC/NOPADDING");
        cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
        output = cipher.doFinal(data);

    } catch (Exception e) {
        e.printStackTrace();
    }
    return output;
}

public static long[] aes_cbc_encrypt_a32(long[] idata, long[] ikey) {
    try {
        byte[] data = a32_to_str(idata).getBytes("ISO-8859-1");
        byte[] key = a32_to_str(ikey).getBytes("ISO-8859-1");
        byte[] encrypt = aes_cbc_encrypt(data, key);

        return str_to_a32(new String(encrypt, "ISO-8859-1"));

    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }
    return new long[0];
}

public static String base64_url_encode(String data) {

    try {
        data = new String(base64_url_encode_byte((data.getBytes("ISO-8859-1")),true), "ISO-8859-1");
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }
    data = data.replaceAll("\\+", "-");
    data = data.replaceAll("/", "_");
    data = data.replaceAll("=", "");

    return data;
}

public static String a32_to_base64(long[] a) {
    return base64_url_encode(a32_to_str(a));
}

public static String stringhash(String email, long[] aeskey) {
    long[] s32 = str_to_a32(email);
    long[] h32 = {0, 0, 0, 0};
    for (int i = 0; i < s32.length; i++) {
        h32[i % 4] ^= s32[i];
    }
    for (int r = 0; r < 0x4000; r++) {
        h32 = aes_cbc_encrypt_a32(h32, aeskey);
    }
    long[] h32Part = new long[2];
    h32Part[0] = h32[0];
    h32Part[1] = h32[2];
    return a32_to_base64(h32Part);
}

public static long[] prepare_key(long[] password) {
    long[] pkey = {0x93C467E3, 0x7DB0C7A4, 0xD1BE3F81, 0x0152CB56};
    for (int r = 0; r < 0x10000; r++) {
        for (int j = 0; j < password.length; j += 4) {
            long[] key = {0, 0, 0, 0};
            for (int i = 0; i < 4; i++) {
                if (i + j < password.length) {
                    key[i] = password[i + j];
                }
            }
            pkey = aes_cbc_encrypt_a32(pkey, key);
        }
    }
    return pkey;}

public static long[] prepare_key_pw(String password) {
    return prepare_key(str_to_a32(password));
}

   public final static byte[] base64_url_encode_byte(byte[] sArr, boolean lineSep){
        // Check special case
        int sLen = sArr != null ? sArr.length : 0;
        if (sLen == 0)
            return new byte[0];

        int eLen = (sLen / 3) * 3;                              // Length of even 24-bits.
        int cCnt = ((sLen - 1) / 3 + 1) << 2;                   // Returned character count
        int dLen = cCnt + (lineSep ? (cCnt - 1) / 76 << 1 : 0); // Length of returned array
        byte[] dArr = new byte[dLen];

        // Encode even 24-bits
        for (int s = 0, d = 0, cc = 0; s < eLen;) {
            // Copy next three bytes into lower 24 bits of int, paying attension to sign.
            int i = (sArr[s++] & 0xff) << 16 | (sArr[s++] & 0xff) << 8 | (sArr[s++] & 0xff);

            // Encode the int into four chars
            dArr[d++] = (byte) CA[(i >>> 18) & 0x3f];
            dArr[d++] = (byte) CA[(i >>> 12) & 0x3f];
            dArr[d++] = (byte) CA[(i >>> 6) & 0x3f];
            dArr[d++] = (byte) CA[i & 0x3f];

            // Add optional line separator
            if (lineSep && ++cc == 19 && d < dLen - 2) {
                dArr[d++] = '\r';
                dArr[d++] = '\n';
                cc = 0;

            }
        }

        // Pad and encode last bits if source isn't an even 24 bits.
        int left = sLen - eLen; // 0 - 2.
        if (left > 0) {
            // Prepare the int
            int i = ((sArr[eLen] & 0xff) << 10) | (left == 2 ? ((sArr[sLen - 1] & 0xff) << 2) : 0);

            // Set last four chars
            dArr[dLen - 4] = (byte) CA[i >> 12];
            dArr[dLen - 3] = (byte) CA[(i >>> 6) & 0x3f];
            dArr[dLen - 2] = left == 2 ? (byte) CA[i & 0x3f] : (byte) '=';
            dArr[dLen - 1] = '=';
        }
        return dArr;
    }

}


public class TestThread {


   final static String OUTPUT_FILE_NAME = "C:\\combo_encrypted.txt";

   public static void main(String args[]) throws IOException {





  File file1 = new File("File1.txt");
  File file2 = new File("File2.txt");
  File file3 = new File("File3.txt");
  File file4 = new File("File4.txt");

  FileInputStream fis1 = null;
  FileInputStream fis2 = null;
  FileInputStream fis3 = null;
  FileInputStream fis4 = null;

  BufferedInputStream bis1 = null;
  BufferedInputStream bis2 = null;
  BufferedInputStream bis3 = null;
  BufferedInputStream bis4 = null;

  DataInputStream dis1 = null;
  DataInputStream dis2 = null;
  DataInputStream dis3 = null;
  DataInputStream dis4 = null;

  fis1 = new FileInputStream(file1);    
  fis2 = new FileInputStream(file2);
  fis3 = new FileInputStream(file3);
  fis4 = new FileInputStream(file4);

  bis1 = new BufferedInputStream(fis1);
  bis2 = new BufferedInputStream(fis2);
  bis3 = new BufferedInputStream(fis3);
  bis4 = new BufferedInputStream(fis4);

  dis1 = new DataInputStream(bis1);
  dis2 = new DataInputStream(bis2);
  dis3 = new DataInputStream(bis3);
  dis4 = new DataInputStream(bis4);

  while ( (dis4.available() != 0) ) {
        String combo1 = dis1.readLine();
        String combo2 = dis2.readLine();
        String combo3 = dis3.readLine();
        String combo4 = dis4.readLine();

        RunnableDemo R1 = new RunnableDemo(combo1);
        RunnableDemo R2 = new RunnableDemo(combo2);
        RunnableDemo R3 = new RunnableDemo(combo3);
        RunnableDemo R4 = new RunnableDemo(combo4);

        R1.start();
        R2.start();
        R3.start();
        R4.start();
  }

  fis1.close();
  fis2.close();
  fis3.close();
  fis4.close();

  bis1.close();
  bis2.close();
  bis3.close();
  bis4.close();

  dis1.close();
  dis2.close(); 
  dis3.close(); 
  dis4.close(); 

   }   
}

3 个答案:

答案 0 :(得分:0)

你正在做什么有趣的事情?你真的想加密一个文件吗?如果是这样,那就去做吧。文件是一个字节序列,这正是Cipher.updateCipher.doFinal的工作原理。

读取字节,加密字节,写入字节。完成。转换为字符串,base64,long[]和whatelse无用的东西只会减慢它们的速度。

也许你想要的不是文件加密,但是你应该清楚地描述它。你似乎正在做一些行式处理,这可能是必要的,但我无法理解它。

您可以通过避免从字节到字符串和类似内容的转换来加速逐行处理。此外,创建一个新的密码和类似的东西不会加快速度。

  

这是一项适合多线程的任务吗?

如果你真的需要逐行处理,我想是的。但除非你有几十个核心,否则你可以先通过清理代码来获得更多。

答案 1 :(得分:0)

由于加密是罪魁祸首,因此请尝试使用多个线程来执行加密阶段。你可以通过像这样管道你的程序来实现这个目的: Pipeline

然而,这假设结果列表的顺序无关紧要。如果它确实重要,那么在加密阶段之后你需要进行某种排序。

答案 2 :(得分:0)

代码很慢,因为代码实现了某种 Key stretching 它的目的很慢)。由于它的CPU绑定,如果你可以让它使用你的所有内核,它将运行得更快。

但是,如果不改变使用的密码算法,请不要期望找到真正加快速度的方法。