let from64 = v => { // allow whitespace in the strings.
let stripped = v.replace(/ |\t|\r|\n/g, ""); returnnew Uint8Array(
ChromeUtils.base64URLDecode(stripped, { padding: "reject" })
);
};
let to64 = v => ChromeUtils.base64URLEncode(v, { pad: false });
// A helper function to take a public key (as a buffer containing a 65-byte // buffer of uncompressed EC points) and a private key (32byte buffer) and // return 2 crypto keys.
async function importKeyPair(publicKeyBuffer, privateKeyBuffer) {
let jwk = {
kty: "EC",
crv: "P-256",
x: to64(publicKeyBuffer.slice(1, 33)),
y: to64(publicKeyBuffer.slice(33, 65)),
ext: true,
};
let publicKey = await crypto.subtle.importKey( "jwk",
jwk,
{ name: "ECDH", namedCurve: "P-256" }, true,
[]
);
jwk.d = to64(privateKeyBuffer);
let privateKey = await crypto.subtle.importKey( "jwk",
jwk,
{ name: "ECDH", namedCurve: "P-256" }, true,
["deriveBits"]
); return { publicKey, privateKey };
}
// The example from draft-ietf-webpush-encryption-09.
add_task(async function static_aes128gcm() {
let fixture = {
ciphertext:
from64(`DGv6ra1nlYgDCS1FRnbzlwAAEABBBP4z9KsN6nGRTbVYI_c7VJSPQTBtkgcy27ml
mlMoZIIgDll6e3vCYLocInmYWAmS6TlzAC8wEqKK6PBru3jl7A_yl95bQpu6cVPT
pK4Mqgkf1CXztLVBSt2Ks3oZwbuwXPXLWyouBWLVWGNWQexSgSxsj_Qulcy4a-fN`),
plaintext: new TextEncoder().encode( "When I grow up, I want to be a watermelon"
),
authSecret: from64("BTBZMqHH6r4Tts7J_aSIgg"),
receiver: { private: from64("q1dXpw3UpT5VOmu_cf_v6ih07Aems3njxI-JWgLcM94"), public: from64(`BCVxsr7N_eNgVRqvHtD0zTZsEc6-VV-JvLexhqUzORcx
aOzi6-AYWXvTBHm4bjyPjs7Vd8pZGH6SRpkNtoIAiw4`),
},
sender: { private: from64("yfWPiYE-n46HLnH0KqZOF1fJJU3MYrct3AELtAQ-oRw"), public: from64(`BP4z9KsN6nGRTbVYI_c7VJSPQTBtkgcy27mlmlMoZIIg
Dll6e3vCYLocInmYWAmS6TlzAC8wEqKK6PBru3jl7A8`),
},
salt: from64("DGv6ra1nlYgDCS1FRnbzlw"),
};
// and for fun, decrypt it and check the plaintext.
let recvKeyPair = await importKeyPair(
fixture.receiver.public,
fixture.receiver.private
);
let jwk = await crypto.subtle.exportKey("jwk", recvKeyPair.privateKey);
let plaintext = await PushCrypto.decrypt(
jwk,
fixture.receiver.public,
fixture.authSecret,
{ encoding: "aes128gcm" },
ciphertext
); Assert.deepEqual(plaintext, fixture.plaintext);
});
// This is how we expect real code to interact with .encrypt.
add_task(async function aes128gcm_simple() {
let [recvPublicKey, recvPrivateKey] = await PushCrypto.generateKeys();
let message = new TextEncoder().encode("Fast for good.");
let authSecret = crypto.getRandomValues(new Uint8Array(16));
let { ciphertext, encoding } = await PushCrypto.encrypt(
message,
recvPublicKey,
authSecret
); Assert.equal(encoding, "aes128gcm"); // and decrypt it.
let plaintext = await PushCrypto.decrypt(
recvPrivateKey,
recvPublicKey,
authSecret,
{ encoding },
ciphertext
);
deepEqual(message, plaintext);
});
// Variable record size tests
add_task(async function aes128gcm_rs() {
let [recvPublicKey, recvPrivateKey] = await PushCrypto.generateKeys();
for (let rs of [-1, 0, 1, 17]) {
let payload = "x".repeat(1024);
info(`testing expected encoder failure with rs=${rs}`);
let message = new TextEncoder().encode(payload);
let authSecret = crypto.getRandomValues(new Uint8Array(16));
await Assert.rejects(
PushCrypto.encrypt(message, recvPublicKey, authSecret, { rs }),
/recordsize is too small/
);
} for (let rs of [-1, 0, 1, 17]) {
let payload = "x".repeat(1024);
info(`testing expected decoder failure with rs=${rs}`);
let message = new TextEncoder().encode(payload);
let authSecret = crypto.getRandomValues(new Uint8Array(16)); const { ciphertext, encoding } = await PushCrypto.encrypt(
message,
recvPublicKey,
authSecret
); // Given it doesn't make sense to encrypt with invalid param, // we just overwrite the header with invalid value new DataView(ciphertext.buffer).setUint32(16, rs);
await Assert.rejects(
PushCrypto.decrypt(
recvPrivateKey,
recvPublicKey,
authSecret,
{ encoding },
ciphertext
),
/Record sizes smaller than 18 are invalid/
);
} for (let rs of [18, 50, 1024, 4096, 16384]) {
info(`testing expected success with rs=${rs}`);
let payload = "x".repeat(rs * 3);
let message = new TextEncoder().encode(payload);
let authSecret = crypto.getRandomValues(new Uint8Array(16));
let { ciphertext, encoding } = await PushCrypto.encrypt(
message,
recvPublicKey,
authSecret,
{ rs }
); Assert.equal(encoding, "aes128gcm"); // and decrypt it.
let plaintext = await PushCrypto.decrypt(
recvPrivateKey,
recvPublicKey,
authSecret,
{ encoding },
ciphertext
);
deepEqual(message, plaintext);
}
});
// And try and hit some edge-cases.
add_task(async function aes128gcm_edgecases() {
let [recvPublicKey, recvPrivateKey] = await PushCrypto.generateKeys();
for (let size of [
0,
4096 - 16,
4096 - 16 - 1,
4096 - 16 + 1,
4095,
4096,
4097,
10240,
]) {
info(`testing encryption of ${size} byte payload`);
let message = new TextEncoder().encode("x".repeat(size));
let authSecret = crypto.getRandomValues(new Uint8Array(16));
let { ciphertext, encoding } = await PushCrypto.encrypt(
message,
recvPublicKey,
authSecret
); Assert.equal(encoding, "aes128gcm"); // and decrypt it.
let plaintext = await PushCrypto.decrypt(
recvPrivateKey,
recvPublicKey,
authSecret,
{ encoding },
ciphertext
);
deepEqual(message, plaintext);
}
});
Messung V0.5
¤ Dauer der Verarbeitung: 0.0 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.