简体   繁体   中英

Java unreliable RSA encryption/decryption of strings

I have a very annoying problem with the unreliable encryption and decryption of string with the RSA algorithm in Java. It seams to only work about 35% of the times, and I can't figure out why it sometimes does work and sometimes don't. Here's some test-code I wrote to try to verify the randomness in the encryption/decryption. It runs 100 laps and it encrypts and decrypts the same string every time and prints the number of times it was successful:

    public static void main(String[] args) throws Exception {
    byte[] dataToEncrypt = "Hello World!".getBytes("UTF-16LE");
    byte[] cipherData = null;
    byte[] decryptedData;

    KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
    kpg.initialize(512);
    KeyPair kp = kpg.genKeyPair();
    Key publicKey = kp.getPublic();
    Key privateKey = kp.getPrivate();
    KeyFactory fact = KeyFactory.getInstance("RSA");

    RSAPublicKeySpec pub = (RSAPublicKeySpec) fact.getKeySpec(publicKey,
            RSAPublicKeySpec.class);

    RSAPublicKeySpec spec = new RSAPublicKeySpec(pub.getModulus(), pub
            .getPublicExponent());
    KeyFactory factory = KeyFactory.getInstance("RSA");

    PublicKey publicKeyRSA = factory.generatePublic(spec);
    Cipher cipher = Cipher.getInstance("RSA");

    int k = 0;
    for (int i = 0; i < 100; i++) {
        try {
            cipher.init(Cipher.ENCRYPT_MODE, publicKeyRSA);
            cipherData = cipher.doFinal(dataToEncrypt);
        } catch (Exception e1) {
            System.out.println("Encrypt error");
        }

        String s = new String(cipherData, "UTF-16LE");
        cipher.init(Cipher.DECRYPT_MODE, privateKey);

        try {
            decryptedData = cipher.doFinal(s.getBytes("UTF-16LE"));
            System.out.println("Decrypted: "
                    + new String(decryptedData, "UTF-16LE"));
            k += 1;
        } catch (Exception e1) {
            System.out.println("Decrypt error");
        }
    }
    System.out.println("Number of correct decryptions is: " + k);

}

I've tried to initialize the KeyPairGenerator with various values without any success.

Edit: Now it works like a charm, thanks to Base64 :

    import java.io.FileOutputStream;
    import java.io.OutputStream;
    import java.security.Key;
    import java.security.KeyFactory;
    import java.security.KeyPair;
    import java.security.KeyPairGenerator;
    import java.security.PublicKey;
    import java.security.spec.RSAPublicKeySpec;
    import javax.crypto.Cipher;

    public class Test {

    public static void main(String[] args) throws Exception {
    byte[] dataToEncrypt = "Hello World!".getBytes("UTF-16LE");
    byte[] cipherData = null;
    byte[] decryptedData;


    KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
    kpg.initialize(512);
    KeyPair kp = kpg.genKeyPair();
    Key publicKey = kp.getPublic();
    Key privateKey = kp.getPrivate();
    KeyFactory fact = KeyFactory.getInstance("RSA");

    RSAPublicKeySpec pub = (RSAPublicKeySpec) fact.getKeySpec(publicKey,
            RSAPublicKeySpec.class);

    RSAPublicKeySpec spec = new RSAPublicKeySpec(pub.getModulus(), pub
            .getPublicExponent());
    KeyFactory factory = KeyFactory.getInstance("RSA");

    PublicKey publicKeyRSA = factory.generatePublic(spec);
    Cipher cipher = Cipher.getInstance("RSA");

    int k = 0;
    for (int i = 0; i < 100; i++) {
        try {
            cipher.init(Cipher.ENCRYPT_MODE, publicKeyRSA);
            cipherData = cipher.doFinal(dataToEncrypt);
        } catch (Exception e1) {
            System.out.println("Encrypt error");
        }

        String s = Base64.encodeBytes(cipherData);
        cipher.init(Cipher.DECRYPT_MODE, privateKey);

        try {
            decryptedData = cipher.doFinal(Base64.decode(s));
            System.out.println("Decrypted: "
                    + new String(decryptedData, "UTF-16LE"));
            k += 1;
        } catch (Exception e1) {
            System.out.println("Decrypt error");
        }
    }
    System.out.println("Number of correct decryptions is: " + k);

}

}

This is the problem, or at least a problem:

String s = new String(cipherData, "UTF-16LE");

You're taking arbitrary binary data and trying to create a string from it, treating it as if it's UTF-16-encoded text. It's not. It's arbitrary binary data.

Either keep it in binary form (as byte[] ) or use base64 to convert it to text in a safe, reversible manner. ( This public domain base64 encoder has a reasonable API, for example.)

可能是因为您将加密的字节流转换为UTF16-LE,这是您不应该做的。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM