4
votes

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

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

I do the encryption by calling the encrypt function:

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

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.

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
2
Can you show us your encrypt and decrypt methods?skynet

2 Answers

5
votes

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.

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 00 valued 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 00 padding still in place.

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.

0
votes
//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);
}