java - 使用RC4加密和解密

标签 java

我正在尝试使用 RC4 编写用于加密和解密输入文本的代码在 java 。有谁知道如何解决吗?

我的代码:

import java.util.Arrays;

public class RC4 {

    private static final int SBOX_LEN = 256;
    private static final int MIN_KEY_LEN = 5;

    private byte[] key = new byte[SBOX_LEN - 1];

    private int[] sbox = new int[SBOX_LEN];

    public RC4() {
        initialize();
    }

    public RC4(String key) {

        this();
        setKey(key);
    }

    public static void main(String[] args) {

        RC4 rc4 = new RC4();

        byte[] cipherText = rc4.encryptMessage(args[0], args[1]);
        System.out.println(Arrays.toString(cipherText));

        String plainText = rc4.decryptMessage(cipherText, args[1]);
        System.out.println(plainText);
    }

    private void initialize() {

        Arrays.fill(key, (byte) 0);
        Arrays.fill(sbox, 0);
    }

    public byte[] encryptMessage(String message, String key) {

        initialize();
        setKey(key);

        byte[] crypt = crypt(message.getBytes());
        initialize();

        return crypt;
    }

    public String decryptMessage(byte[] message, String key) {

        initialize();
        setKey(key);

        byte[] msg = crypt(message);
        initialize();

        return new String(msg);
    }

    public byte[] crypt(final byte[] msg) {

        sbox = initializeSBox(key);

        byte[] code = new byte[msg.length];
        int i = 0;
        int j = 0;

        for (int n = 0; n < msg.length; n++) {

            i = (i + 1) % SBOX_LEN;
            j = (j + sbox[i]) % SBOX_LEN;
            swap(i, j, sbox);

            int rand = sbox[(sbox[i] + sbox[j]) % SBOX_LEN];
            code[n] = (byte) (rand ^ msg[n]);
        }

        return code;
    }

    private int[] initializeSBox(byte[] key) {

        int[] sbox = new int[SBOX_LEN];
        int j = 0;

        for (int i = 0; i < SBOX_LEN; i++) {
            sbox[i] = i;
        }

        for (int i = 0; i < SBOX_LEN; i++) {
            j = ((j + sbox[i] + (key[i % key.length])) & 0xFF) % SBOX_LEN;
            swap(i, j, sbox);
        }

        return sbox;
    }

    private void swap(int i, int j, int[] sbox) {

        int temp = sbox[i];

        sbox[i] = sbox[j];
        sbox[j] = temp;
    }

    public void setKey(String key) {

        if (!((key.length() >= MIN_KEY_LEN) && (key.length() < SBOX_LEN))) {

            throw new RuntimeException(String.format("Key length must be between %d and %d", MIN_KEY_LEN, SBOX_LEN - 1));
        }

        this.key = key.getBytes();
    }
}

最佳答案

RC4 是一种损坏的算法,如果要保持数据的高度安全,建议不要再使用相同的算法。

如果您仍然需要有效的实现,则无需在代码中重新创建算法。 Java API javax.crypto 可以为您做到这一点。只需生成 key 并调用 init 方法并将模式设置为加密/解密即可。

static String decryptRC4() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException{

    byte[] testDataBytes = "testString".getBytes();

    KeyGenerator rc4KeyGenerator = KeyGenerator.getInstance("RC4");
    SecretKey key = rc4KeyGenerator.generateKey();

    // Create Cipher instance and initialize it to encrytion mode
    Cipher cipher = Cipher.getInstance("RC4");  // Transformation of the algorithm
    cipher.init(Cipher.ENCRYPT_MODE, key);
    byte[] cipherBytes = cipher.doFinal(testDataBytes);

    // Reinitialize the Cipher to decryption mode
    cipher.init(Cipher.DECRYPT_MODE,key, cipher.getParameters());
    byte[] testDataBytesDecrypted = cipher.doFinal(cipherBytes);

    System.out.println("Decrypted Data : "+new String(testDataBytesDecrypted));
    return new String(testDataBytesDecrypted);
}

输出: enter image description here

如果您需要将加密数据作为网址的一部分发送,请使用 Base64Encoding 然后发送。

例如

    static String decryptRC4() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException{

    byte[] plainBytes = "testString".getBytes();

    KeyGenerator rc4KeyGenerator = KeyGenerator.getInstance("RC4");
    SecretKey key = rc4KeyGenerator.generateKey();

    // Create Cipher instance and initialize it to encrytion mode
    Cipher cipher = Cipher.getInstance("RC4");  // Transformation of the algorithm
    cipher.init(Cipher.ENCRYPT_MODE, key);
    byte[] cipherBytes = cipher.doFinal(plainBytes);

    String encoded = encodeBase64(cipherBytes);

    String decoded = decodeBase64(encoded);

    // Reinitialize the Cipher to decryption mode
    cipher.init(Cipher.DECRYPT_MODE,key, cipher.getParameters());
    byte[] plainBytesDecrypted = cipher.doFinal(Hex.decode(decoded));

    System.out.println("Decrypted Data : "+new String(plainBytesDecrypted));
    return new String(plainBytesDecrypted);
}

static String decodeBase64(String encodedData){
    byte[] b = Base64.getDecoder().decode(encodedData);
    String decodedData = DatatypeConverter.printHexBinary(b);
    return decodedData;
}

static String encodeBase64(byte[] data){
    byte[] b = Base64.getEncoder().encode(data);
    String encodedData = new String(b);
    /*String encodedData = DatatypeConverter.printHexBinary(b);*/
    return encodedData;
}

** 提示:** 如上所示使用 Hex.decode 从 Base64 解码字符串中获取字节,否则您将遇到编码问题。尽可能使用十六进制进行转换并使用 bouncycaSTLe 方法转换为字节数组。

需要进口:

import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.xml.bind.DatatypeConverter;

import org.apache.commons.codec.DecoderException;
import org.bouncycastle.util.encoders.Hex;

此外,如果您要从自己的字符串生成 key ,则可以使用 MD5Hashing 来实现相同的目的。

关于java - 使用RC4加密和解密,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43420997/

相关文章:

JAVA小程序最简单的程序

java - Jackson:仅从接口(interface)导出 setter/getter

java - 没有找到接口(interface) org.springframework.data.jpa.domain.Specification] 的主要或默认构造函数,其根本原因

java - 在 JAVA 中动态确定用户输入的数据类型

java - 使用大字典执行logstash时出现堆空间错误(翻译过滤器)

java - 将 Spring-ws webservicetemplate 请求以 XML 格式保存到 DB

java - 在 <div> 中动态加载 Wicket 面板

Java 正则表达式问题

java - Springfox Swagger : Could not resolve pointer:/definitions/Instant

java - Spring Boot 和 Hibernate 5 的类加载错误