Ich versuche, einen Server zu erstellen fähig Push-Nachrichten zu senden, die Push-API: https://developer.mozilla.org/en-US/docs/Web/API/Push_APINachricht verschlüsseln für Web-Push-API in Java
Ich habe die Client-Seite arbeiten habe, aber jetzt möchte ich in der Lage sein Senden Sie Nachrichten mit einer Payload von einem Java-Server.
Ich habe das Nodejs Web-Push-Beispiel (https://www.npmjs.com/package/web-push) gesehen, aber ich konnte das nicht korrekt in Java übersetzen.
Ich habe versucht, das Beispiel nach dem DH-Schlüsselaustausch hier zu verwenden: http://docs.oracle.com/javase/7/docs/technotes/guides/security/crypto/CryptoSpec.html#DH2Ex
Mit Hilfe sheltond unten konnte ich einige Code, um herauszufinden, das ist arbeiten sollte, aber nicht.
Wenn ich die verschlüsselte Nachricht an den Push-Dienst poste, erhalte ich den erwarteten Statuscode 201, aber der Push erreicht nie Firefox. Wenn ich die Payload und die Header entferne und einfach eine POST-Anfrage an dieselbe URL sende, kommt die Nachricht erfolgreich in Firefox ohne Daten an. Ich vermute, dass es etwas damit zu tun hat, wie ich die Daten mit Cipher.getInstance ("AES/GCM/NoPadding") verschlüsseln;
Dies ist der Code, den ich zur Zeit bin mit:
try {
final byte[] alicePubKeyEnc = Util.fromBase64("BASE_64_PUBLIC_KEY_FROM_PUSH_SUBSCRIPTION");
KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC");
ECGenParameterSpec kpgparams = new ECGenParameterSpec("secp256r1");
kpg.initialize(kpgparams);
ECParameterSpec params = ((ECPublicKey) kpg.generateKeyPair().getPublic()).getParams();
final ECPublicKey alicePubKey = fromUncompressedPoint(alicePubKeyEnc, params);
KeyPairGenerator bobKpairGen = KeyPairGenerator.getInstance("EC");
bobKpairGen.initialize(params);
KeyPair bobKpair = bobKpairGen.generateKeyPair();
KeyAgreement bobKeyAgree = KeyAgreement.getInstance("ECDH");
bobKeyAgree.init(bobKpair.getPrivate());
byte[] bobPubKeyEnc = toUncompressedPoint((ECPublicKey) bobKpair.getPublic());
bobKeyAgree.doPhase(alicePubKey, true);
Cipher bobCipher = Cipher.getInstance("AES/GCM/NoPadding");
SecretKey bobDesKey = bobKeyAgree.generateSecret("AES");
byte[] saltBytes = new byte[16];
new SecureRandom().nextBytes(saltBytes);
Mac extract = Mac.getInstance("HmacSHA256");
extract.init(new SecretKeySpec(saltBytes, "HmacSHA256"));
final byte[] prk = extract.doFinal(bobDesKey.getEncoded());
// Expand
Mac expand = Mac.getInstance("HmacSHA256");
expand.init(new SecretKeySpec(prk, "HmacSHA256"));
String info = "Content-Encoding: aesgcm128";
expand.update(info.getBytes(StandardCharsets.US_ASCII));
expand.update((byte) 1);
final byte[] key_bytes = expand.doFinal();
// Use the result
SecretKeySpec key = new SecretKeySpec(key_bytes, 0, 16, "AES");
bobCipher.init(Cipher.ENCRYPT_MODE, key);
byte[] cleartext = "{\"this\":\"is a test that is supposed to be working but it is not\"}".getBytes();
byte[] ciphertext = bobCipher.doFinal(cleartext);
URL url = new URL("PUSH_ENDPOINT_URL");
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("POST");
urlConnection.setRequestProperty("Content-Length", ciphertext.length + "");
urlConnection.setRequestProperty("Content-Type", "application/octet-stream");
urlConnection.setRequestProperty("Encryption-Key", "keyid=p256dh;dh=" + Util.toBase64UrlSafe(bobPubKeyEnc));
urlConnection.setRequestProperty("Encryption", "keyid=p256dh;salt=" + Util.toBase64UrlSafe(saltBytes));
urlConnection.setRequestProperty("Content-Encoding", "aesgcm128");
urlConnection.setDoInput(true);
urlConnection.setDoOutput(true);
final OutputStream outputStream = urlConnection.getOutputStream();
outputStream.write(ciphertext);
outputStream.flush();
outputStream.close();
if (urlConnection.getResponseCode() == 201) {
String result = Util.readStream(urlConnection.getInputStream());
Log.v("PUSH", "OK: " + result);
} else {
InputStream errorStream = urlConnection.getErrorStream();
String error = Util.readStream(errorStream);
Log.v("PUSH", "Not OK: " + error);
}
} catch (Exception e) {
Log.v("PUSH", "Not OK: " + e.toString());
}
wo „BASE_64_PUBLIC_KEY_FROM_PUSH_SUBSCRIPTION“ der Schlüssel Abonnement Methode der Push-API im Browser zur Verfügung gestellt und „PUSH_ENDPOINT_URL“ ist der Push den Browser bereitgestellt Endpunkt.
Wenn ich Werte (Chiffretext, base64 bobPubKeyEnc und Salz) von einer erfolgreichen Nodejs Web-Push-Anfrage erhalten und sie in Java fest codiere, funktioniert es. Wenn ich den obigen Code mit dynamischen Werten verwende, funktioniert es nicht.
Ich habe festgestellt, dass der Chiffretext, der in der Nodejs-Implementierung arbeitete, immer 1 Byte größer ist als der Java-Chiffretext mit dem obigen Code. Das Beispiel, das ich hier verwendete, erzeugt immer einen Chiffretext von 81 Byte, aber in Nodejs ist es immer 82 Bytes zum Beispiel. Gibt uns das einen Hinweis darauf, was falsch sein könnte?
Wie verschlüssele ich die Payload korrekt, sodass sie Firefox erreicht?
Vielen Dank im Voraus für jede Hilfe
verwenden Sie wirklich "BASE_64_PUBLIC_KEY_FROM_PUSH_SUBSCRIPTION"? – Dawnkeeper
Sorry, nein, das ist nur ein Platzhalter für den Schlüssel, den der Browser zurückgibt. Ich werde die Frage bearbeiten, danke – joaomgcd
Wir sind an der gleichen Stelle fest. Der Versuch, genau dasselbe mit .NET zu tun. Ich fühle deinen Schmerz. –