I generated a RSA key pair based this command:
openssl genrsa -out key_pair.pem 2048
openssl pkcs8 -topk8 -inform PEM -outform PEM -in key_pair.pem -out private.pem
openssl rsa -in key_pair.pem -pubout -outform PEM -out public.pem
then I wrote this codes to make a server-side program that used above private key to generate encrypt/decrypt message that send/receive to/from client side application.
public static String encryptByPrivate(String strToEncrypt) {
try {
var inputStream = EncryptDecryptHelper.class.getResourceAsStream(PRIVATE_KEY_PATH);
byte[] privateKeyBytes = inputStream.readAllBytes();
KeyFactory privateKeyFactory = KeyFactory.getInstance("RSA");
PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
PrivateKey privateKey = privateKeyFactory.generatePrivate(privateKeySpec);
Cipher encryptCipher = Cipher.getInstance("RSA");
encryptCipher.init(Cipher.ENCRYPT_MODE, privateKey);
byte[] secretMessageBytes = strToEncrypt.getBytes(StandardCharsets.UTF_8);
byte[] encrypted = encryptCipher.doFinal(secretMessageBytes);
String encryptedText = Base64.getEncoder().encodeToString(encrypted);
return encryptedText;
} catch (Exception e) {
e.printStackTrace();
throw new EncryptBodyFailException("Encoding error, please contact the system administrator.");
}
}
public static String decryptByPrivate(String strToDecrypt) {
try {
var inputStream = EncryptDecryptHelper.class.getResourceAsStream(PRIVATE_KEY_PATH);
byte[] privateKeyBytes = inputStream.readAllBytes();
KeyFactory privateKeyFactory = KeyFactory.getInstance("RSA");
PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
PrivateKey privateKey = privateKeyFactory.generatePrivate(privateKeySpec);
Cipher decryptCipher = Cipher.getInstance("RSA");
decryptCipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] decryptedMessageBytes = decryptCipher.doFinal(Base64.getDecoder().decode(strToDecrypt));
return new String(decryptedMessageBytes, StandardCharsets.UTF_8);
} catch (Exception e) {
e.printStackTrace();
throw new DecryptBodyFailException("Decoding error, please contact the system administrator.");
}
}
public static String encryptByPublic(String strToEncrypt) {
try {
var inputStream = EncryptDecryptHelper.class.getResourceAsStream(PUBLIC_KEY_PATH);
byte[] publicKeyBytes = inputStream.readAllBytes();
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(keySpec);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encryptedBytes = cipher.doFinal(strToEncrypt.getBytes("UTF-8"));
String encryptedText = Base64.getEncoder().encodeToString(encryptedBytes);
return encryptedText;
} catch (Exception e) {
e.printStackTrace();
throw new EncryptBodyFailException("Encoding error, please contact the system administrator.");
}
}
public static String decryptByPublic(String strToDecrypt) {
try {
var inputStream = EncryptDecryptHelper.class.getResourceAsStream(PUBLIC_KEY_PATH);
byte[] publicKeyBytes = inputStream.readAllBytes();
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(keySpec);
Cipher decryptCipher = Cipher.getInstance("RSA");
decryptCipher.init(Cipher.DECRYPT_MODE, publicKey);
byte[] decryptedMessageBytes = decryptCipher.doFinal(Base64.getDecoder().decode(strToDecrypt));
return new String(decryptedMessageBytes, StandardCharsets.UTF_8);
} catch (Exception e) {
e.printStackTrace();
throw new DecryptBodyFailException("Decoding error, please contact the system administrator.");
}
}
Then, we try to wrote javascript app fopr client side. I have a react-js app that use public key to encrypt/decrypt message using Public key that send or receive from server. the java script code is :
const publicKeyPEM = "-----BEGIN PUBLIC KEY-----n" +
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwFSqIsNbDl/bBhHMQLwAn" +
...................
"OvkGLdI1AR0MtaCRrllE3yO3n5bAqqeZQjMl0C4ZURxjEzE7aTn2Hq3AU2conIwen" +
"EQIDAQABn" +
"-----END PUBLIC KEY-----";
const plaintext = "plain text that we want to send...";
function pemToArrayBuffer(pem) {
const lines = pem.split('n');
const base64 = lines.slice(1, lines.length - 1).join('');
const binaryString = window.atob(base64);
const bytes = new Uint8Array(binaryString.length);
for (let i = 0; i < binaryString.length; i++) {
bytes[i] = binaryString.charCodeAt(i);
}
return bytes.buffer;
}
const publicKey = pemToArrayBuffer(publicKeyPEM);
window.crypto.subtle.importKey(
"spki",
publicKey,
{
name: "RSA-OAEP",
hash: { name: "SHA-256" },
},
true,
["encrypt"]
)
.then((cryptoKey) => {
const encodedText = new TextEncoder().encode(plaintext);
return window.crypto.subtle.encrypt(
{
name: "RSA-OAEP"
},
cryptoKey,
encodedText
);
})
.then((encrypted) => {
const encryptedText = btoa(String.fromCharCode.apply(null, new Uint8Array(encrypted)));
console.log("encrypted message: ", encryptedText);
})
.catch((error) => {
console.error("error on encrypt: ", error);
});
const encryptedText = "encrypted base64 string that server side application send to me...";
const encryptedData = new Uint8Array(atob(encryptedText).split('').map((c) => c.charCodeAt(0)));
window.crypto.subtle.importKey(
"spki",
publicKey,
{
name: "RSA-OAEP",
hash: { name: "SHA-256" },
},
true,
["decrypt"]
)
.then((cryptoKey) => {
const encryptedData = new Uint8Array(atob(encryptedText).split('').map((c) => c.charCodeAt(0)));
console.log()
return window.crypto.subtle.decrypt(
{
name: "RSA-OAEP"
},
cryptoKey,
encryptedData
);
})
.then((decrypted) => {
const decryptedText = new TextDecoder().decode(decrypted);
console.log("decrypted test:", decryptedText);
})
.catch((error) => {
console.error("error on decrypt :", error);
});
When a client sending message to server first step encrypt requested message with Public key and server decrypt message with private key. after that server encrypt response message with private key and cleint must can be to decrypt encrypted response message.
when we encrypt message y public in client side every thins is OK. but decryption method return error : DOMException: Data provided to an operation does not meet requirements
I try another library like Crypto-js, Hybid-Crypto-js and NodeRSA. but cannot reach to Goal.