RC4加密Java - java

嗨,我正在尝试用Java实现RC4算法。我找到了这个code作为示例,可以帮助我理解这个想法:

public class RC4 {
  private int[] S = new int[256];
  private int[] T = new int[256];
  private int keylen;

  public RC4(byte[] key) throws Exception {
    if (key.length < 1 || key.length > 256) {
      throw new Exception("key must be between 1 and 256 bytes");
    } else {
      keylen = key.length;
      for (int i = 0; i < 256; i++) {
        S[i] = i;
        T[i] = key[i % keylen];
      }
      int j = 0;
      for (int i = 0; i < 256; i++) {
        j = (j + S[i] + T[i]) % 256;
        S[i] ^= S[j];
        S[j] ^= S[i];
        S[i] ^= S[j];
      }
    }
  }

  public int[] encrypt(int[] plaintext) {
    int[] ciphertext = new int[plaintext.length];
    int i = 0, j = 0, k, t;
    for (int counter = 0; counter < plaintext.length; counter++) {
      i = (i + 1) % 256;
      j = (j + S[i]) % 256;
      S[i] ^= S[j];
      S[j] ^= S[i];
      S[i] ^= S[j];
      t = (S[i] + S[j]) % 256;
      k = S[t];
      ciphertext[counter] = plaintext[counter] ^ k;
    }
    return ciphertext;
  }

  public int[] decrypt(int[] ciphertext) {
    return encrypt(ciphertext);
  }
}

我有几个问题:

  • 为什么上述代码中的纯文本是int数组?
  • 测试此代码时,我得到奇怪的结果,有人可以向我解释吗?这里是我的代码要测试:
    public class RC4_Main {
    
        public static void main(String args[]) throws Exception {
            String keyword = "hello";
            byte[] keytest = keyword.getBytes(); //convert keyword to byte
    
            int[] text = {1, 2, 3, 4, 5}; // text as 12345
    
            RC4 rc4 = new RC4(keytest);
    
            System.out.print("\noriginal text: ");
            for (int i = 0; i < text.length; i++) {          
                System.out.print(text[i]);          
            }    
    
            int[] cipher = rc4.encrypt(text); //encryption      
            System.out.print("\ncipher: ");
            for (int i = 0; i < cipher.length; i++) {          
                System.out.print(cipher[i]);          
            }    
    
            int[] backtext = rc4.decrypt(cipher); //decryption
            System.out.print("\nback to text: ");
            for (int i = 0; i < backtext.length; i++) {          
                System.out.print(backtext[i]);            
            } 
            System.out.println();
        }
    }
    
  • 结果如下:(原始和返回文本不完全相同)为什么???

    original text: 12345
    cipher: 1483188254174
    back to text: 391501310217
    

    参考方案

    有几件事要注意:

  • 当您需要无符号字节(例如用于索引)时,Java并不是很容易使用;
  • 如果您在ST中创建一个状态,您应该真正注意到这些值会发生变化,当您使用相同的实例解密时,会采用用于加密的状态。
  • 上面的代码在内存方面不是很有效,您可以轻松地重写它以获取字节数组;
  • 使用字符串,将参数重构为byte[]后,您首先需要首先使用character-encoding,例如使用 String.getBytes(Charset charset) ;
  • 为了使生活更轻松,并有一些有趣的深夜黑客,我改进了您的代码,并使用零进位字节数组对rfc6229中的单个向量进行了测试。

    更新:正如micahk在下面指出的那样,使用了邪恶的C XOR交换,阻止了此代码对Java中输入的最后字节进行加密。使用常规的旧交换程序可以解决此问题。

    警告:以下代码应视为编码练习。请使用经过严格审查的库,而不是下面的代码片段,以在您的应用程序中执行RC4(或Ron的代码4,ARC4等)。这意味着在Bouncy Castle中使用Cipher.getInstance("RC4");或ARC4类。

    public class RC4 {
        private final byte[] S = new byte[256];
        private final byte[] T = new byte[256];
        private final int keylen;
    
        public RC4(final byte[] key) {
            if (key.length < 1 || key.length > 256) {
                throw new IllegalArgumentException(
                        "key must be between 1 and 256 bytes");
            } else {
                keylen = key.length;
                for (int i = 0; i < 256; i++) {
                    S[i] = (byte) i;
                    T[i] = key[i % keylen];
                }
                int j = 0;
                byte tmp;
                for (int i = 0; i < 256; i++) {
                    j = (j + S[i] + T[i]) & 0xFF;
                    tmp = S[j];
                    S[j] = S[i];
                    S[i] = tmp;
                }
            }
        }
    
        public byte[] encrypt(final byte[] plaintext) {
            final byte[] ciphertext = new byte[plaintext.length];
            int i = 0, j = 0, k, t;
            byte tmp;
            for (int counter = 0; counter < plaintext.length; counter++) {
                i = (i + 1) & 0xFF;
                j = (j + S[i]) & 0xFF;
                tmp = S[j];
                S[j] = S[i];
                S[i] = tmp;
                t = (S[i] + S[j]) & 0xFF;
                k = S[t];
                ciphertext[counter] = (byte) (plaintext[counter] ^ k);
            }
            return ciphertext;
        }
    
        public byte[] decrypt(final byte[] ciphertext) {
            return encrypt(ciphertext);
        }
    }
    

    快乐的编码。

    JAVA:字节码和二进制有什么区别? - java

    java字节代码(已编译的语言,也称为目标代码)与机器代码(当前计算机的本机代码)之间有什么区别?我读过一些书,他们将字节码称为二进制指令,但我不知道为什么。 参考方案 字节码是独立于平台的,在Windows中运行的编译器编译的字节码仍将在linux / unix / mac中运行。机器代码是特定于平台的,如果在Windows x86中编译,则它将仅在Win…

    Java-将int更改为ascii - java

    java有没有办法将int转换为ascii符号? 参考方案 您是否要将int转换为char?:int yourInt = 33; char ch = (char) yourInt; System.out.println(yourInt); System.out.println(ch); // Output: // 33 // ! 还是要将int转换为Stri…

    Java:正则表达式模式匹配器是否有大小限制? - java

    我的模式类似于OR:“word1 | word2 | word3”我大约有800个字。可能有问题吗? 参考方案 您仅受记忆和理智的限制。 :)

    Java:线程池如何将线程映射到可运行对象 - java

    试图绕过Java并发问题,并且很难理解线程池,线程以及它们正在执行的可运行“任务”之间的关系。如果我创建一个有10个线程的线程池,那么我是否必须将相同的任务传递给池中的每个线程,或者池化的线程实际上只是与任务无关的“工人无人机”可用于执行任何任务?无论哪种方式,Executor / ExecutorService如何将正确的任务分配给正确的线程? 参考方案 …

    java:继承 - java

    有哪些替代继承的方法? java大神给出的解决方案 有效的Java:偏重于继承而不是继承。 (这实际上也来自“四人帮”)。他提出的理由是,如果扩展类未明确设计为继承,则继承会引起很多不正常的副作用。例如,对super.someMethod()的任何调用都可以引导您通过未知代码的意外路径。取而代之的是,持有对本来应该扩展的类的引用,然后委托给它。这是与Eric…