6

こんにちは、Java で RC4 アルゴリズムを実装しようとしています。アイデアを理解するのに役立つ例として、次のコードを見つけました。

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

いくつか質問があります:

  1. 上記のコードでプレーンテキストがint配列になっているのはなぜですか?

  2. このコードをテストすると、奇妙な結果が得られます。誰か説明してもらえますか? テストするコードは次のとおりです。

    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
4

6 に答える 6

10

注意すべき点がいくつかあります。

  • 符号なしバイトが必要な場合 (インデックス作成など)、Java を使用するのは簡単ではありません。
  • とで状態を作成するST、これらの値が変化することに気付くはずです。同じインスタンスで復号化すると、暗号化に使用された状態になります。
  • 上記のコードはメモリに関してはあまり効率的ではなく、バイト配列を取るように簡単に書き直すことができます。
  • 文字列を使用するには、引数を にリファクタリングした後、最初にbyte[]を使用する必要があります。String.getBytes(Charset charset)

生活を楽にし、深夜のハッキングを楽しむために、コードを改善し、バイト配列をゼロにしてrfc6229の単一ベクトルに対してテストしました。

更新: micahk が以下で指摘しているように、使用された悪意のある C XOR スワップにより、このコードは Java の入力の最終バイトを暗号化できませんでした。通常の古いスワップを使用すると修正されます。

警告: 以下のコードは、コーディング演習と見なす必要があります。アプリケーションで RC4 (または Ron's Code 4、ARC4 など) を実行するには、以下のコード スニペットの代わりに十分に吟味されたライブラリを使用してください。つまりCipher.getInstance("RC4");、Bouncy Castle で または 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);
    }
}

ハッピーコーディング。

于 2012-09-05T22:53:48.707 に答える
3

xor-swap 手法を使用しているため、Java コードにはバグがあります。

        S[i] ^= S[j];
        S[j] ^= S[i];
        S[i] ^= S[j];

これの代わりに、以下のように一時変数を使用する必要があります。xor スワップで結果が期待どおりにならない理由を詳しく調べていませんが、単純なスワップを実行するだけで解決される復号化エラーがありました。xor 操作を行うために発生する byte から int への暗黙的なキャストの微妙な副作用であると思われます。

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;
            for (int i = 0; i < 256; i++) {
                j = (j + S[i] + T[i]) & 0xFF;
                byte temp = S[i];
                S[i] = S[j];
                S[j] = temp;
            }
        }
    }

    public byte[] encrypt(final byte[] plaintext) {
        final byte[] ciphertext = new byte[plaintext.length];
        int i = 0, j = 0, k, t;
        for (int counter = 0; counter < plaintext.length; counter++) {
            i = (i + 1) & 0xFF;
            j = (j + S[i]) & 0xFF;
            byte temp = S[i];
            S[i] = S[j];
            S[j] = temp;
            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);
    }
}
于 2013-11-27T02:29:44.637 に答える
3

あなたの整数配列ST構築されていません。したがって、NullPointerExceptionそれらを使用しようとするとすぐに取得します。

コードの残りの部分を見ると、それらは 256 項目の配列であるべきだったと思います。

private int[] S = new int[256];
private int[] T = new int[256];
于 2012-09-05T21:14:12.923 に答える