I am working on a project where I generate an EC private key using Java and then import it in the browser using JavaScript. The key imports successfully in Chrome, but it fails in Safari.Here’s my JavaScript code for importing private key:
[Try running this html file in browser]
<!DOCTYPE html>
<html>
<head>
<title>ECDH Key Pair Generation</title>
</head>
<body>
<script>
//Utils
function _extractRawKeyMaterial(pem, type) {
const pemHeader = `-----BEGIN ${type} KEY-----`;
const pemFooter = `-----END ${type} KEY-----`;
const endingIndex = pem.indexOf(pemFooter);
const startingIndex = pem.indexOf(pemHeader) + pemHeader.length;
const pemContents = pem.substring(startingIndex, endingIndex);
var return_object = convertBase64StringToArrayBuffer(pemContents.trim());
return return_object;
}
const convertBase64StringToArrayBuffer = base64String => {
const text = window.atob(base64String);
return convertStringToArrayBuffer(text);
};
const convertStringToArrayBuffer = str => {
const buf = new ArrayBuffer(str.length);
const bufView = new Uint8Array(buf);
for (let i = 0, strLen = str.length; i < strLen; i++) {
bufView[i] = str.charCodeAt(i);
}
return buf;
};
// private key
var privateKeyGenerated = `-----BEGIN PRIVATE KEY-----
ME4CAQAwEAYHKoZIzj0CAQYFK4EEACIENzA1AgEBBDAMvyd7HU0FwJxgs5N87NVw
MPOR60umJXnhPjdtn0O0RHgx2J0sVnvw7B6ue1Wb5uQ=
-----END PRIVATE KEY-----`
// Pass the loaded private key to your function
_loadEccPrivateKey(privateKeyGenerated);
// Code working in chrome but fails in safari with an error : Data provided to an operation does not meet requirements
async function _loadEccPrivateKey(pemKey) {
try {
const rawKey = _extractRawKeyMaterial(pemKey.trim(), "PRIVATE");
//console.log(rawKey)
const key = await window.crypto.subtle.importKey(
"pkcs8", // Format for private keys
rawKey,
{
name: "ECDH",
namedCurve: "P-384",
},
true,
["deriveBits", "deriveKey"] // Key usages
);
console.log('Imported Private Key:', key);
return key;
} catch (e) {
console.error('Error importing private key:', e);
throw e;
}
}
</script>
</body>
</html>
The code works perfectly in Chrome but throws an error in Safari. The error message is "DATA PROVIDED TO AN OPERATION DOES NOT MEET REQUIREMENTS"
Here is my JAVA CODE for more information:
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.*;
import java.security.spec.ECGenParameterSpec;
import java.util.Base64;
public class TestApplication {
private static final String CURVE = "secp384r1"; // P-384 curve
public static void main(String[] args) {
try {
// Add BouncyCastle Provider
Security.addProvider(new BouncyCastleProvider());
// Generate EC key pair
ECGenParameterSpec parameterSpec = new ECGenParameterSpec(CURVE);
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC", "BC");
keyPairGenerator.initialize(parameterSpec, new SecureRandom());
KeyPair keyPair = keyPairGenerator.generateKeyPair();
// Extract and print private key
PrivateKey privateKey = keyPair.getPrivate();
String privateKeyPem = convertToPem(privateKey);
System.out.println("Private Key in PEM format:\n" + privateKeyPem);
// Save the private key in binary format to a file (optional)
String privateKeyFilePath = "private_key.bin";
saveKeyToBinaryFile(privateKey, privateKeyFilePath);
} catch (Exception e) {
e.printStackTrace();
}
}
// Convert private key to PEM format
private static String convertToPem(PrivateKey privateKey) {
String base64Key = Base64.getEncoder().encodeToString(privateKey.getEncoded());
return "-----BEGIN PRIVATE KEY-----\n" +
base64Key +
"\n-----END PRIVATE KEY-----";
}
// Save the private key in binary format
private static void saveKeyToBinaryFile(PrivateKey privateKey, String filePath) {
try (FileOutputStream fos = new FileOutputStream(filePath)) {
fos.write(privateKey.getEncoded());
} catch (IOException e) {
e.printStackTrace();
}
}
}
If you want to try it yourself, just run this Java POC: https://github.com/ChetanTailor/JavaPrivateKeyPOC
key
variable received by_loadEccPrivateKey
+It is very strange that you generated a key server side (Java) and sent it to the browser. Might be a good question to ask on Stack Exchange.... – Kumkumagai