使用 Java 的 RSA 加密/解密

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19623367/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 18:53:58  来源:igfitidea点击:

RSA Encryption / Decryption using Java

javacryptographyrsa

提问by user2192774

I am doing a simple program to encrypt/decrypt using RSA algorithm in Java. I create a cipher object as follows:

我正在做一个简单的程序来使用 Java 中的 RSA 算法进行加密/解密。我创建一个密码对象如下:

//Create a Cipher object
Cipher rsaCipher = Cipher.getInstance("RSA/ECB/NoPadding");

I do the encryption by calling the encrypt function:

我通过调用 encrypt 函数进行加密:

String cipher=encrypt(textByte, pair, rsaCipher);
System.out.println("The Encryption using RSA Algorithm : "+cipher);

And the decryption as:

解密为:

//Decryption
String plain=decrypt(Base64.decodeBase64(cipher),pair, rsaCipher);
System.out.println("The Decryption using RSA Algorithm : "+plain);

When I display the output, the decryption output returns a long space before the original text: enter image description here

当我显示输出时,解密输出在原始文本之前返回一个长空格: 在此处输入图片说明

However, when I edit the code for creating the Cipher object to be: //Create a Cipher object Cipher rsaCipher = Cipher.getInstance("RSA");

但是,当我编辑用于创建 Cipher 对象的代码时: //Create a Cipher object Cipher rsaCipher = Cipher.getInstance("RSA");

i.e, removed the operation mode and padding arguments, the problem get resolved and the output becomes: enter image description here

即,删除操作模式和填充参数,问题得到解决,输出变为: 在此处输入图片说明

Where is the problem. In the first case (when the space appears), I specified NoPadding? Why the spaces appears in the decrypted message ? Even if I used padding, I expect this should not happen.

问题出在哪儿。在第一种情况下(当出现空格时),我指定了 NoPadding? 为什么在解密的消息中出现空格?即使我使用了填充,我也希望这不会发生。

EDIT:This is the encrypt and decrypt methods:

编辑:这是加密和解密方法:

public static String encrypt(byte[] textBytes, KeyPair pair, Cipher rsaCipher) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException
{
    //get the public key
    PublicKey pk=pair.getPublic(); 


    //Initialize the cipher for encryption. Use the public key.
    rsaCipher.init(Cipher.ENCRYPT_MODE, pk);

    //Perform the encryption using doFinal
    byte[] encByte = rsaCipher.doFinal(textBytes);

    // converts to base64 for easier display.
    byte[] base64Cipher = Base64.encodeBase64(encByte);

    return new String(base64Cipher);
}//end encrypt

public static String decrypt(byte[] cipherBytes, KeyPair pair, Cipher rsaCipher) throws IllegalBlockSizeException, BadPaddingException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException
{
    //get the public key
    PrivateKey pvk=pair.getPrivate(); 

    //Create a Cipher object
    //Cipher rsaCipher = Cipher.getInstance("RSA/ECB/NoPadding");

    //Initialize the cipher for encryption. Use the public key.
    rsaCipher.init(Cipher.DECRYPT_MODE, pvk);

    //Perform the encryption using doFinal
    byte[] decByte = rsaCipher.doFinal(cipherBytes);

    return new String(decByte);

}//end decrypt

采纳答案by Maarten Bodewes

Your problem is indeed with the padding. Some kind of padding, either PKCS#1 1.5 or OAEP padding in practice, is required for secure RSA functionality. Furthermore, it is required to find the start and end of the encrypted plain text.

您的问题确实与填充有关。安全 RSA 功能需要某种填充,实践中的 PKCS#1 1.5 或 OAEP 填充。此外,还需要找到加密明文的开头和结尾。

The modular exponentiation of RSA is performed using large integers. The results of these operations are then represented as octet strings. These octet strings are basically big endian, unsigned, fixed length representation of an integer. These integers are left padded with 00valued bytes (this is called the I2OS primitive in the RSA standard). So what you are seeing is the result of the modular exponentiation, with the 00padding still in place.

RSA 的模幂运算是使用大整数执行的。然后将这些操作的结果表示为八位字节字符串。这些八位字节字符串基本上是一个整数的大端、无符号、固定长度表示。这些整数用00有价值的字节填充(这在 RSA 标准中称为 I2OS 原语)。所以你看到的是模幂运算的结果,00填充仍然存在。

Long story short, always use a padding scheme. Nowadays, OAEP would be preferable. Use it together with hybrid encryption scheme, or use a higher level container format such as CMS or PGP.

长话短说,始终使用填充方案。如今,OAEP 将更可取。将它与混合加密方案一起使用,或者使用更高级别的容器格式,例如 CMS 或 PGP。

回答by VAIBHAV SHEERSH

//This is a complete encryption and decryption module using 
//Algorithm: JWEAlgorithm.RSA_OAEP_256
//Encryption Method: A128CBC_HS256

public static String  encrypt(String text) throws Exception {
    // Set the plain text
    Payload payload = new Payload(text);
    // Create the header
    JWEHeader header = new JWEHeader(JWEAlgorithm.RSA_OAEP_256, EncryptionMethod.A128CBC_HS256);
    // Create the JWE object and encrypt it
    JWEObject jweObject = new JWEObject(header, payload);
    jweObject.encrypt(new RSAEncrypter(getPublicKey()));
    // Serialise to compact JOSE form...
    String jweString = jweObject.serialize();
    LOG.info("Generated Encrypted Key : {}", jweString);
    return jweString;
}

public static String decrypt(String text) throws Exception {
    // Parse into JWE object...
    JWEObject jweObject = JWEObject.parse(text);
    jweObject.decrypt(new RSADecrypter(getPrivateKey()));
    // Get the plain text
    Payload payload = jweObject.getPayload();
    System.out.println(payload.toString());
    return payload.toString();
}

private static RSAPublicKey getPublicKey() throws Exception {
    String filename = "/home/vaibhav/Setups/cert/pub.der";
    File f = new File(filename);
    FileInputStream fis = new FileInputStream(f);
    DataInputStream dis = new DataInputStream(fis);
    byte[] keyBytes = new byte[(int)f.length()];
    dis.readFully(keyBytes);
    dis.close();

    X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
    KeyFactory kf = KeyFactory.getInstance("RSA");
    return (RSAPublicKey) kf.generatePublic(spec);
}

private static RSAPrivateKey getPrivateKey() throws Exception {
    String filename = "/home/vaibhav/Setups/cert/private.pkcs8";
    File f = new File(filename);
    FileInputStream fis = new FileInputStream(f);
    DataInputStream dis = new DataInputStream(fis);
    byte[] keyBytes = new byte[(int)f.length()];
    dis.readFully(keyBytes);
    dis.close();

    PKCS8EncodedKeySpec spec1 = new PKCS8EncodedKeySpec(keyBytes);
    KeyFactory kf = KeyFactory.getInstance("RSA");
    return (RSAPrivateKey) kf.generatePrivate(spec1);
}