Fix AES-GCM encryption/decryption so that it works with Conversations
Fixes #497
This commit is contained in:
parent
dd71d6ee9b
commit
1d5cf8eb7c
60
dist/converse.js
vendored
60
dist/converse.js
vendored
@ -71570,7 +71570,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
|
||||
// Copyright (c) 2013-2018, the Converse.js developers
|
||||
// Licensed under the Mozilla Public License (MPLv2)
|
||||
|
||||
/* global libsignal, ArrayBuffer, parseInt */
|
||||
/* global libsignal, ArrayBuffer, parseInt, crypto */
|
||||
(function (root, factory) {
|
||||
!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(/*! converse-core */ "./src/converse-core.js"), __webpack_require__(/*! templates/toolbar_omemo.html */ "./src/templates/toolbar_omemo.html")], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory),
|
||||
__WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ?
|
||||
@ -71769,6 +71769,29 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
|
||||
});
|
||||
},
|
||||
|
||||
async encryptMessage(plaintext) {
|
||||
// The client MUST use fresh, randomly generated key/IV pairs
|
||||
// with AES-128 in Galois/Counter Mode (GCM).
|
||||
const iv = crypto.getRandomValues(new window.Uint8Array(16));
|
||||
const key = await crypto.subtle.generateKey(KEY_ALGO, true, ["encrypt", "decrypt"]);
|
||||
const algo = {
|
||||
'name': 'AES-GCM',
|
||||
'iv': iv,
|
||||
'tagLength': TAG_LENGTH
|
||||
};
|
||||
const encrypted = await crypto.subtle.encrypt(algo, key, u.stringToArrayBuffer(plaintext));
|
||||
const length = encrypted.byteLength - (128 + 7 >> 3),
|
||||
ciphertext = encrypted.slice(0, length),
|
||||
tag = encrypted.slice(length);
|
||||
const exported_key = await crypto.subtle.exportKey("raw", key);
|
||||
return Promise.resolve({
|
||||
'key': key,
|
||||
'key_and_tag': u.appendArrayBuffer(exported_key, tag),
|
||||
'payload': u.arrayBufferToBase64(ciphertext),
|
||||
'iv': u.arrayBufferToBase64(iv)
|
||||
});
|
||||
},
|
||||
|
||||
decryptMessage(obj) {
|
||||
return crypto.subtle.importKey('raw', obj.key, KEY_ALGO, true, ['encrypt', 'decrypt']).then(key_obj => {
|
||||
const algo = {
|
||||
@ -71776,15 +71799,16 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
|
||||
'iv': u.base64ToArrayBuffer(obj.iv),
|
||||
'tagLength': TAG_LENGTH
|
||||
};
|
||||
return window.crypto.subtle.decrypt(algo, key_obj, u.base64ToArrayBuffer(obj.payload));
|
||||
}).then(out => new TextDecoder().decode(out));
|
||||
const cipher = u.appendArrayBuffer(u.base64ToArrayBuffer(obj.payload), obj.tag);
|
||||
return crypto.subtle.decrypt(algo, key_obj, cipher);
|
||||
}).then(out => u.arrayBufferToString(out));
|
||||
},
|
||||
|
||||
reportDecryptionError(e) {
|
||||
const _converse = this.__super__._converse,
|
||||
__ = _converse.__;
|
||||
this.messages.create({
|
||||
'message': __("Sorry, could not decrypt a received OMEMO message due to an error.") + `${e.name} ${e.message}`,
|
||||
'message': __("Sorry, could not decrypt a received OMEMO message due to an error.") + ` ${e.name} ${e.message}`,
|
||||
'type': 'error'
|
||||
});
|
||||
|
||||
@ -71879,34 +71903,6 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
|
||||
return Promise.all(devices.map(device => this.getSession(device))).then(() => devices);
|
||||
},
|
||||
|
||||
encryptMessage(plaintext) {
|
||||
// The client MUST use fresh, randomly generated key/IV pairs
|
||||
// with AES-128 in Galois/Counter Mode (GCM).
|
||||
const iv = window.crypto.getRandomValues(new window.Uint8Array(16));
|
||||
let key;
|
||||
return window.crypto.subtle.generateKey(KEY_ALGO, true, // extractable
|
||||
["encrypt", "decrypt"] // key usages
|
||||
).then(result => {
|
||||
key = result;
|
||||
const algo = {
|
||||
'name': 'AES-GCM',
|
||||
'iv': iv,
|
||||
'tagLength': TAG_LENGTH
|
||||
};
|
||||
return window.crypto.subtle.encrypt(algo, key, new TextEncoder().encode(plaintext));
|
||||
}).then(ciphertext => {
|
||||
return window.crypto.subtle.exportKey("raw", key).then(key => {
|
||||
const tag = ciphertext.slice(ciphertext.byteLength - (TAG_LENGTH + 7 >> 3));
|
||||
return Promise.resolve({
|
||||
'key': key,
|
||||
'key_and_tag': u.appendArrayBuffer(key, tag),
|
||||
'payload': u.arrayBufferToBase64(ciphertext),
|
||||
'iv': u.arrayBufferToBase64(iv)
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
getSessionCipher(jid, id) {
|
||||
const _converse = this.__super__._converse,
|
||||
address = new libsignal.SignalProtocolAddress(jid, id);
|
||||
|
@ -4,7 +4,7 @@
|
||||
// Copyright (c) 2013-2018, the Converse.js developers
|
||||
// Licensed under the Mozilla Public License (MPLv2)
|
||||
|
||||
/* global libsignal, ArrayBuffer, parseInt */
|
||||
/* global libsignal, ArrayBuffer, parseInt, crypto */
|
||||
|
||||
(function (root, factory) {
|
||||
define([
|
||||
@ -201,6 +201,30 @@
|
||||
});
|
||||
},
|
||||
|
||||
async encryptMessage (plaintext) {
|
||||
// The client MUST use fresh, randomly generated key/IV pairs
|
||||
// with AES-128 in Galois/Counter Mode (GCM).
|
||||
const iv = crypto.getRandomValues(new window.Uint8Array(16));
|
||||
const key = await crypto.subtle.generateKey(KEY_ALGO, true, ["encrypt", "decrypt"]);
|
||||
const algo = {
|
||||
'name': 'AES-GCM',
|
||||
'iv': iv,
|
||||
'tagLength': TAG_LENGTH
|
||||
}
|
||||
const encrypted = await crypto.subtle.encrypt(algo, key, u.stringToArrayBuffer(plaintext));
|
||||
const length = encrypted.byteLength - ((128 + 7) >> 3),
|
||||
ciphertext = encrypted.slice(0, length),
|
||||
tag = encrypted.slice(length);
|
||||
|
||||
const exported_key = await crypto.subtle.exportKey("raw", key)
|
||||
return Promise.resolve({
|
||||
'key': key,
|
||||
'key_and_tag': u.appendArrayBuffer(exported_key, tag),
|
||||
'payload': u.arrayBufferToBase64(ciphertext),
|
||||
'iv': u.arrayBufferToBase64(iv)
|
||||
});
|
||||
},
|
||||
|
||||
decryptMessage (obj) {
|
||||
return crypto.subtle.importKey('raw', obj.key, KEY_ALGO, true, ['encrypt','decrypt'])
|
||||
.then(key_obj => {
|
||||
@ -209,15 +233,16 @@
|
||||
'iv': u.base64ToArrayBuffer(obj.iv),
|
||||
'tagLength': TAG_LENGTH
|
||||
}
|
||||
return window.crypto.subtle.decrypt(algo, key_obj, u.base64ToArrayBuffer(obj.payload));
|
||||
}).then(out => (new TextDecoder()).decode(out));
|
||||
const cipher = u.appendArrayBuffer(u.base64ToArrayBuffer(obj.payload), obj.tag);
|
||||
return crypto.subtle.decrypt(algo, key_obj, cipher);
|
||||
}).then(out => u.arrayBufferToString(out));
|
||||
},
|
||||
|
||||
reportDecryptionError (e) {
|
||||
const { _converse } = this.__super__,
|
||||
{ __ } = _converse;
|
||||
this.messages.create({
|
||||
'message': __("Sorry, could not decrypt a received OMEMO message due to an error.") + `${e.name} ${e.message}`,
|
||||
'message': __("Sorry, could not decrypt a received OMEMO message due to an error.") + ` ${e.name} ${e.message}`,
|
||||
'type': 'error',
|
||||
});
|
||||
_converse.log(e, Strophe.LogLevel.ERROR);
|
||||
@ -300,37 +325,6 @@
|
||||
return Promise.all(devices.map(device => this.getSession(device))).then(() => devices);
|
||||
},
|
||||
|
||||
encryptMessage (plaintext) {
|
||||
// The client MUST use fresh, randomly generated key/IV pairs
|
||||
// with AES-128 in Galois/Counter Mode (GCM).
|
||||
const iv = window.crypto.getRandomValues(new window.Uint8Array(16));
|
||||
let key;
|
||||
return window.crypto.subtle.generateKey(
|
||||
KEY_ALGO,
|
||||
true, // extractable
|
||||
["encrypt", "decrypt"] // key usages
|
||||
).then(result => {
|
||||
key = result;
|
||||
const algo = {
|
||||
'name': 'AES-GCM',
|
||||
'iv': iv,
|
||||
'tagLength': TAG_LENGTH
|
||||
}
|
||||
return window.crypto.subtle.encrypt(algo, key, new TextEncoder().encode(plaintext));
|
||||
}).then(ciphertext => {
|
||||
return window.crypto.subtle.exportKey("raw", key)
|
||||
.then(key => {
|
||||
const tag = ciphertext.slice(ciphertext.byteLength - ((TAG_LENGTH + 7) >> 3));
|
||||
return Promise.resolve({
|
||||
'key': key,
|
||||
'key_and_tag': u.appendArrayBuffer(key, tag),
|
||||
'payload': u.arrayBufferToBase64(ciphertext),
|
||||
'iv': u.arrayBufferToBase64(iv)
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
getSessionCipher (jid, id) {
|
||||
const { _converse } = this.__super__,
|
||||
address = new libsignal.SignalProtocolAddress(jid, id);
|
||||
|
Loading…
Reference in New Issue
Block a user