Home > Software design >  Decrypt with public key?
Decrypt with public key?

Time:12-17

I've made a mistake when I was writing a promgram in Java.

package cf.huzpsb.jnip.security;

import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

public class Cipher {
    private static final byte[] pub = Base64.getDecoder().decode("MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCUjb /Ea3i9W53tASAu5OJ8vxf7 7oGberM5B6GIfu2uBMD0YfaQuGqInREop6kho7AHYd4oCq68fhQ4DbAtE RSy9Us4sCMpvvE4luLWoR3iZQtii7hyIoDSeXGaNVu6L3xbjFji7kSDPpWubdCuD6dCVYD5kS2N07m74d5grOwIDAQAB");
    private static final byte[] pri = Base64.getDecoder().decode("MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAJSNv78RreL1bne0BIC7k4ny/F/v7ugZt6szkHoYh 7a4EwPRh9pC4aoidESinqSGjsAdh3igKrrx FDgNsC0T5FLL1SziwIym 8TiW4tahHeJlC2KLuHIigNJ5cZo1W7ovfFuMWOLuRIM la5t0K4Pp0JVgPmRLY3Tubvh3mCs7AgMBAAECgYAPimSs0GSogZR04Vg3P2hH3iuYvbj4fvg/6L0MiNRvoGYmjtJ/JrYV Duyq4XhHLexxHKW3cMoHlJitnUcdEb/W5L0iOSXRN4W1WGBkGLv FE3TbFT0ruxbLTdcK cmiE6hWh2sO9xVXjIPxixuTrDvd7qyO0XyX0aNUU0/42FQQJBANwpKF6ZJRIHvF32RIfPjAxkTEY6Mq8IbxeuxsbN3IJ1aywK3bQdSxz0rd b/gR/3CJhjp9OUGt0KqYm6emVJrcCQQCsvHu30wrK8qfjQmlVxYlwgVitb3u pgRPO64neuucsbXPUEYnB/Ae9Y1QrdRUBWInhWfXpRK7m4LzK0udJvudAkEArWU9BkRXjfvJv7dWAiDUjG3yJN1xTam21VAx/iHkqlsQLX/hXRo1LnkG DZDugd5uRpc2ds0O20iqfm8ANwXwQJBAIVagdy5lfR1/zzIkY BEAkGIpLKpWrauir9NQcPs4PmAilJnM8XJr6P7YgimvA s7c1G6T0sJCbjy3x988cQFUCQBnPIMFNyfz t9Cg gA42ivbKQC9OnIpTD0Jsm8gyvh1C15Pkb4I0WYOQuh66AWHwrlqlkF6IdUVyM8JlNArI/M=");

    public static String encrypt(String text) {
        try {
            PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(pri);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
            javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance(keyFactory.getAlgorithm());
            cipher.init(javax.crypto.Cipher.ENCRYPT_MODE, privateKey);
            return Base64.getEncoder().encodeToString(cipher.doFinal(text.getBytes()));
        } catch (Exception e) {
            return "Failed";
        }
    }

    public static String decrypt(String text) {
        try {
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(pub);
            PublicKey pubKey = keyFactory.generatePublic(x509KeySpec);
            javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance(keyFactory.getAlgorithm());
            cipher.init(javax.crypto.Cipher.DECRYPT_MODE, pubKey);
            return new String(cipher.doFinal(Base64.getDecoder().decode(text)));
        } catch (Exception e) {
            return "Failed";
        }
    }
}

As you can see, I've used the wrong key when trying to encrypt/decrypt the data. However, the code didn't generate any exception.

If I compile and run:

String str = Cipher.encrypt("uwu");
System.out.println(str);
System.out.println(Cipher.decrypt(str));

The console would show:

GrKyCCML73yuJN/fsdevN00eOvWUDl7MTpW50iWhhnhqhMxelWPEQ4I2A7PPd0G8flVaZrabAIsYNNUBpEg96x 8zj3ZTh5u9rXbhJKbzHXSMbsuPCY39WqUOf6qqqWRxGL44E3ltIdE/wQr7XeRvqJa4Z089mSxl6VYB468BnA=
uwu

Although I've fixed the mistake, I still have a question:

What's going on here? Why did it seemingly running "properly"?


Edit:

I've seen some may say that it's a type of "sign". But if that's the case, is there a way that I read the data without either key, if I don't care whether or not the data is tampered? Why or why not? Thanks!

CodePudding user response:

Trying to encrypt data using RSA with a private key doesn't make sense. However, instead of throwing an exception when trying to do so, the Cipher class does something a little different. It assumes that you want to perform a signature operation and that you are supplying just the payload portion of the signature. It will then apply the PKCS1 padding string directly to your data, in this case the padding is 0x00 0x01 followed by as many 0xff 0xff ... 0xff 0x00 bytes as needed to fill out the length of the RSA block (128 bytes in this case) apply the exponentiation primitive with the private exponent. Thus the padded contents look like this in hex:

0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00757775

Proper PKCS1 signing requires that the data is hashed and then encapsulated into a DigestInfo ASN.1 structure, but Cipher doesn't do that. The Signature class will do that however.

The result can only be verified (or "decrypted") with the correct public key. You can't get the plaintext unless you have the public key.

  • Related