Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/jsp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 用RSA和其他密钥加密邮件_Java_Encryption - Fatal编程技术网

Java 用RSA和其他密钥加密邮件

Java 用RSA和其他密钥加密邮件,java,encryption,Java,Encryption,我正在尝试用Java加密和解密一条消息,但每次都会遇到相同的错误: java.security.InvalidKeyException:密钥太长,无法展开 我试图模拟从服务器向客户端发送加密消息 第一:客户端生成私钥和公钥 第二,客户端向服务器发送公钥 第三:服务器生成对称AES密钥 4t:服务器用AES密钥加密要发送给客户端的文本 5e:服务器使用从客户端接收的公钥加密AES密钥 6e:服务器向客户端发送加密文本和加密AES密钥 7e:客户机使用其私钥解密AES密钥 8e:客户端使用解密的AE

我正在尝试用Java加密和解密一条消息,但每次都会遇到相同的错误:

java.security.InvalidKeyException:密钥太长,无法展开

我试图模拟从服务器向客户端发送加密消息

第一:客户端生成私钥和公钥

第二,客户端向服务器发送公钥

第三:服务器生成对称AES密钥

4t:服务器用AES密钥加密要发送给客户端的文本

5e:服务器使用从客户端接收的公钥加密AES密钥

6e:服务器向客户端发送加密文本和加密AES密钥

7e:客户机使用其私钥解密AES密钥

8e:客户端使用解密的AES密钥对从服务器接收的文本进行解密

public class Test {

    private static SecretKey secretKey;
    private static KeyPair keyPair;
    private static final String STRINGTOENCRYPT = "This is a test";
    private static String stringEncripted;
    private static String keyEncripted;
    public static final byte[] IV_PARAM = {0x00, 0x01, 0x02, 0x03,
            0x04, 0x05, 0x06, 0x07,
            0x08, 0x09, 0x0A, 0x0B,
            0x0C, 0x0D, 0x0E, 0x0F};


    public static void main(String[] args) {
        generateKeys();
    }

    private static void generateKeys() {

        secretKey = generateSecretKey(128);
        keyPair = generateKeyPair(512);
        stringEncripted = encriptString(STRINGTOENCRYPT);
        keyEncripted = encriptKey(keyPair.getPublic());

        decryptString();

    }

    private static void decryptString() {
        Cipher cipher = null;
        Key keyDecrypted = null;
        try {
            cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
            cipher.init(Cipher.UNWRAP_MODE, keyPair.getPrivate());
            keyDecrypted = cipher.unwrap(keyEncripted.getBytes(), "AES", Cipher.SECRET_KEY);

            cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            IvParameterSpec iv = new IvParameterSpec(IV_PARAM);
            cipher.init(Cipher.DECRYPT_MODE, keyDecrypted, iv);
            byte[] stringDecryptedBytes = cipher.doFinal(stringEncripted.getBytes());
            String stringDecrypted = new String(stringDecryptedBytes);

            System.out.println(stringDecrypted);

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


    private static KeyPair generateKeyPair(int lenght) {
        KeyPair keyPublicAndPrivate = null;

        try {
            KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
            keyGen.initialize(lenght);
            keyPublicAndPrivate = keyGen.genKeyPair();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return keyPublicAndPrivate;

    }

    private static SecretKey generateSecretKey(int lenght) {


        SecretKey sKey = null;
        if ((lenght == 128) || (lenght == 192) || (lenght == 256)) {
            try {
                KeyGenerator kgen = KeyGenerator.getInstance("AES");
                kgen.init(lenght);
                sKey = kgen.generateKey();
            } catch (NoSuchAlgorithmException ex) {
                ex.printStackTrace();
            }
        }
        return sKey;

    }

    private static String encriptString(String stringtoencrypt) {

        byte[] stringtoencryptBytes = stringtoencrypt.getBytes();
        Cipher cipher = null;

        String stringEncrypted = null;
        try {
            cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            IvParameterSpec iv = new IvParameterSpec(IV_PARAM);
            cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);

            byte[] stringEncryptedBytes = cipher.doFinal(stringtoencryptBytes);
            stringEncrypted = new String(cipher.doFinal(stringtoencryptBytes), "UTF-8");
        } catch (Exception e) {
            e.printStackTrace();
        }


        return stringEncrypted;
    }


    private static String encriptKey(PublicKey aPublic) {
        String keyEncryptedString = null;
        try {
            Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
            cipher.init(Cipher.WRAP_MODE, aPublic);
            byte[] keyEncriptedBytes = cipher.wrap(secretKey);
            keyEncryptedString = new String(keyEncriptedBytes, "UTF-8");

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

}

知道为什么会发生这种情况吗?

问题在于,您不能仅仅假设RSA或AES加密会产生表示字符串的字节。当您使用
newstring
生成字符串时,它将以静默方式删除所有不代表字符的字节。如果您想拥有更多控制权并引发异常(应该是默认情况),可以使用
CharsetDecoder

问题是,当您重新转换为字节时,某些字节可能丢失。这意味着这个数字可能要小得多,这将以某种方式引发异常,因为“展开”的输入现在太小了

下面是一些变化,展示了如何让它工作。我刚刚注释了你的代码,这样你就可以比较了

import java.security.Key;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;

public class Test {

    private static SecretKey secretKey;
    private static KeyPair keyPair;
    private static final String STRINGTOENCRYPT = "This is a test";
    private static String stringEncripted;
    private static byte[] ct;
    private static String keyEncripted;
    private static byte[] wrapped;
    public static final byte[] IV_PARAM = {0x00, 0x01, 0x02, 0x03,
            0x04, 0x05, 0x06, 0x07,
            0x08, 0x09, 0x0A, 0x0B,
            0x0C, 0x0D, 0x0E, 0x0F};


    public static void main(String[] args) {
        generateKeys();
    }

    private static void generateKeys() {

        secretKey = generateSecretKey(128);
        keyPair = generateKeyPair(512);
        stringEncripted = encriptString(STRINGTOENCRYPT);
        keyEncripted = encriptKey(keyPair.getPublic());

        decryptString();

    }

    private static void decryptString() {
        Cipher cipher = null;
        Key keyDecrypted = null;
        try {
            cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
            cipher.init(Cipher.UNWRAP_MODE, keyPair.getPrivate());
            // keyDecrypted = cipher.unwrap(keyEncripted.getBytes(), "AES", Cipher.SECRET_KEY);
            keyDecrypted = cipher.unwrap(wrapped, "AES", Cipher.SECRET_KEY);

            cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            IvParameterSpec iv = new IvParameterSpec(IV_PARAM);
            cipher.init(Cipher.DECRYPT_MODE, keyDecrypted, iv);
            byte[] stringDecryptedBytes = cipher.doFinal(ct);
            String stringDecrypted = new String(stringDecryptedBytes);

            System.out.println(stringDecrypted);

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


    private static KeyPair generateKeyPair(int lenght) {
        KeyPair keyPublicAndPrivate = null;

        try {
            KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
            keyGen.initialize(lenght);
            keyPublicAndPrivate = keyGen.genKeyPair();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return keyPublicAndPrivate;

    }

    private static SecretKey generateSecretKey(int lenght) {


        SecretKey sKey = null;
        if ((lenght == 128) || (lenght == 192) || (lenght == 256)) {
            try {
                KeyGenerator kgen = KeyGenerator.getInstance("AES");
                kgen.init(lenght);
                sKey = kgen.generateKey();
            } catch (NoSuchAlgorithmException ex) {
                ex.printStackTrace();
            }
        }
        return sKey;

    }

    private static String encriptString(String stringtoencrypt) {

        byte[] stringtoencryptBytes = stringtoencrypt.getBytes();
        Cipher cipher = null;

        String stringEncrypted = null;
        try {
            cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            IvParameterSpec iv = new IvParameterSpec(IV_PARAM);
            cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);

            // byte[] stringEncryptedBytes = cipher.doFinal(stringtoencryptBytes);
            ct = cipher.doFinal(stringtoencryptBytes);
            stringEncrypted = new String(cipher.doFinal(stringtoencryptBytes), "UTF-8");
        } catch (Exception e) {
            e.printStackTrace();
        }


        return stringEncrypted;
    }


    private static String encriptKey(PublicKey aPublic) {
        String keyEncryptedString = null;
        try {
            Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
            cipher.init(Cipher.WRAP_MODE, aPublic);
//            byte[] keyEncriptedBytes = cipher.wrap(secretKey);
//            keyEncryptedString = new String(keyEncriptedBytes, "UTF-8");
            wrapped = cipher.wrap(secretKey);

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

}

请注意,PKCS#1填充(RSA加密)和CBC都容易受到填充oracle攻击。您可能希望对AES使用RSA/OAEP和GCM模式

尝试用私钥解密aes密钥..已经更改了,但是我得到了相同的错误这可能不是导致错误的原因,但是我希望你知道512位RSA现在很容易被破解。您应该使用,最好更长。请使用完整的堆栈跟踪以及它在代码中出现的位置。不是在评论中,而是在问题中。现代(计算机)加密(AES和RSA,以及许多其他类似SHA2的东西)产生的字节包含明显的随机位,而不是有效的字符码。试图将这些字节“解码”成Java
字符串,然后恢复它们通常是行不通的。最好使用字节或无损编码,如十六进制或base64;如果必须使用原始字符,请尝试“charset”
ISO-8859-1
,它将所有八位字节值(0-255)标识映射到Unicode块0,但在大多数JVM实例上不是默认值。请注意,代码还有许多其他错误。异常处理不正常(如果您不知道如何处理
e
,请使用
抛出新的RuntimeException(e)
)。AES密钥大小的检查不是快速失败的;返回
null
不是一个好主意。在未指定字符集的情况下,切勿使用
new String()
String#getBytes()
(除非您需要在计算机上使用默认字符集)。使一切
都是静态的
当然不好;我希望这是您的“让它工作”版本:)