mirror of
https://github.com/vector-im/hydrogen-web.git
synced 2024-12-23 03:25:12 +01:00
move base64/58 encoding into platform
fixes https://github.com/vector-im/hydrogen-web/issues/99
This commit is contained in:
parent
2bb7b3b598
commit
bbab1e9ecc
@ -207,7 +207,12 @@ export class Session {
|
||||
|
||||
async _createSessionBackup(ssssKey, txn) {
|
||||
const secretStorage = new SecretStorage({key: ssssKey, platform: this._platform});
|
||||
this._sessionBackup = await SessionBackup.fromSecretStorage({olm: this._olm, secretStorage, hsApi: this._hsApi, txn});
|
||||
this._sessionBackup = await SessionBackup.fromSecretStorage({
|
||||
platform: this._platform,
|
||||
olm: this._olm, secretStorage,
|
||||
hsApi: this._hsApi,
|
||||
txn
|
||||
});
|
||||
if (this._sessionBackup) {
|
||||
for (const room of this._rooms.values()) {
|
||||
if (room.isEncrypted) {
|
||||
|
@ -14,8 +14,6 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import base64 from "../../../lib/base64-arraybuffer/index.js";
|
||||
|
||||
/**
|
||||
* Decrypt an attachment.
|
||||
* @param {ArrayBuffer} ciphertextBuffer The encrypted attachment data buffer.
|
||||
@ -25,12 +23,14 @@ import base64 from "../../../lib/base64-arraybuffer/index.js";
|
||||
* @param {string} info.hashes.sha256 Base64 encoded SHA-256 hash of the ciphertext.
|
||||
* @return {Promise} A promise that resolves with an ArrayBuffer when the attachment is decrypted.
|
||||
*/
|
||||
export async function decryptAttachment(crypto, ciphertextBuffer, info) {
|
||||
export async function decryptAttachment(platform, ciphertextBuffer, info) {
|
||||
if (info === undefined || info.key === undefined || info.iv === undefined
|
||||
|| info.hashes === undefined || info.hashes.sha256 === undefined) {
|
||||
throw new Error("Invalid info. Missing info.key, info.iv or info.hashes.sha256 key");
|
||||
}
|
||||
|
||||
const {crypto} = platform;
|
||||
const {base64} = platform.encoding;
|
||||
var ivArray = base64.decode(info.iv);
|
||||
// re-encode to not deal with padded vs unpadded
|
||||
var expectedSha256base64 = base64.encode(base64.decode(info.hashes.sha256));
|
||||
@ -59,6 +59,7 @@ export async function decryptAttachment(crypto, ciphertextBuffer, info) {
|
||||
|
||||
export async function encryptAttachment(platform, blob) {
|
||||
const {crypto} = platform;
|
||||
const {base64} = platform.encoding;
|
||||
const iv = await crypto.aes.generateIV();
|
||||
const key = await crypto.aes.generateKey("jwk", 256);
|
||||
const buffer = await blob.readAsBuffer();
|
||||
@ -69,20 +70,10 @@ export async function encryptAttachment(platform, blob) {
|
||||
info: {
|
||||
v: "v2",
|
||||
key,
|
||||
iv: encodeUnpaddedBase64(iv),
|
||||
iv: base64.encodeUnpadded(iv),
|
||||
hashes: {
|
||||
sha256: encodeUnpaddedBase64(digest)
|
||||
sha256: base64.encodeUnpadded(digest)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function encodeUnpaddedBase64(buffer) {
|
||||
const str = base64.encode(buffer);
|
||||
const paddingIdx = str.indexOf("=");
|
||||
if (paddingIdx !== -1) {
|
||||
return str.substr(0, paddingIdx);
|
||||
} else {
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
@ -14,8 +14,6 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import base64 from "../../../../lib/base64-arraybuffer/index.js";
|
||||
|
||||
export class SessionBackup {
|
||||
constructor({backupInfo, decryption, hsApi}) {
|
||||
this._backupInfo = backupInfo;
|
||||
@ -41,10 +39,10 @@ export class SessionBackup {
|
||||
this._decryption.free();
|
||||
}
|
||||
|
||||
static async fromSecretStorage({olm, secretStorage, hsApi, txn}) {
|
||||
static async fromSecretStorage({platform, olm, secretStorage, hsApi, txn}) {
|
||||
const base64PrivateKey = await secretStorage.readSecret("m.megolm_backup.v1", txn);
|
||||
if (base64PrivateKey) {
|
||||
const privateKey = new Uint8Array(base64.decode(base64PrivateKey));
|
||||
const privateKey = new Uint8Array(platform.encoding.base64.decode(base64PrivateKey));
|
||||
const backupInfo = await hsApi.roomKeysVersion().response();
|
||||
const expectedPubKey = backupInfo.auth_data.public_key;
|
||||
const decryption = new olm.PkDecryption();
|
||||
|
@ -55,7 +55,7 @@ export class MediaRepository {
|
||||
async downloadEncryptedFile(fileEntry, cache = false) {
|
||||
const url = this.mxcUrl(fileEntry.url);
|
||||
const {body: encryptedBuffer} = await this._platform.request(url, {method: "GET", format: "buffer", cache}).response();
|
||||
const decryptedBuffer = await decryptAttachment(this._platform.crypto, encryptedBuffer, fileEntry);
|
||||
const decryptedBuffer = await decryptAttachment(this._platform, encryptedBuffer, fileEntry);
|
||||
return this._platform.createBlob(decryptedBuffer, fileEntry.mimetype);
|
||||
}
|
||||
|
||||
|
@ -14,8 +14,6 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import base64 from "../../../lib/base64-arraybuffer/index.js";
|
||||
|
||||
export class SecretStorage {
|
||||
constructor({key, platform}) {
|
||||
this._key = key;
|
||||
@ -40,17 +38,17 @@ export class SecretStorage {
|
||||
}
|
||||
|
||||
async _decryptAESSecret(type, encryptedData) {
|
||||
const {base64, utf8} = this._platform.encoding;
|
||||
// now derive the aes and mac key from the 4s key
|
||||
const hkdfKey = await this._platform.crypto.derive.hkdf(
|
||||
this._key.binaryKey,
|
||||
new Uint8Array(8).buffer, //zero salt
|
||||
this._platform.utf8.encode(type), // info
|
||||
utf8.encode(type), // info
|
||||
"SHA-256",
|
||||
512 // 512 bits or 64 bytes
|
||||
);
|
||||
const aesKey = hkdfKey.slice(0, 32);
|
||||
const hmacKey = hkdfKey.slice(32);
|
||||
|
||||
const ciphertextBytes = base64.decode(encryptedData.ciphertext);
|
||||
|
||||
const isVerified = await this._platform.crypto.hmac.verify(
|
||||
@ -67,6 +65,6 @@ export class SecretStorage {
|
||||
data: ciphertextBytes
|
||||
});
|
||||
|
||||
return this._platform.utf8.decode(plaintextBytes);
|
||||
return utf8.decode(plaintextBytes);
|
||||
}
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ export async function keyFromCredential(type, credential, storage, platform, olm
|
||||
if (type === "phrase") {
|
||||
key = await keyFromPassphrase(keyDescription, credential, platform);
|
||||
} else if (type === "key") {
|
||||
key = keyFromRecoveryKey(olm, keyDescription, credential);
|
||||
key = keyFromRecoveryKey(keyDescription, credential, olm, platform);
|
||||
} else {
|
||||
throw new Error(`Invalid type: ${type}`);
|
||||
}
|
||||
|
@ -33,11 +33,12 @@ export async function keyFromPassphrase(keyDescription, passphrase, platform) {
|
||||
if (passphraseParams.algorithm !== "m.pbkdf2") {
|
||||
throw new Error(`Unsupported passphrase algorithm: ${passphraseParams.algorithm}`);
|
||||
}
|
||||
const {utf8} = platform.encoding;
|
||||
const keyBits = await platform.crypto.derive.pbkdf2(
|
||||
platform.utf8.encode(passphrase),
|
||||
utf8.encode(passphrase),
|
||||
passphraseParams.iterations || DEFAULT_ITERATIONS,
|
||||
// salt is just a random string, not encoded in any way
|
||||
platform.utf8.encode(passphraseParams.salt),
|
||||
utf8.encode(passphraseParams.salt),
|
||||
"SHA-512",
|
||||
passphraseParams.bits || DEFAULT_BITSIZE);
|
||||
return new Key(keyDescription, keyBits);
|
||||
|
@ -13,7 +13,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
import bs58 from "../../../lib/bs58/index.js";
|
||||
import {Key} from "./common.js";
|
||||
|
||||
const OLM_RECOVERY_KEY_PREFIX = [0x8B, 0x01];
|
||||
@ -24,8 +23,8 @@ const OLM_RECOVERY_KEY_PREFIX = [0x8B, 0x01];
|
||||
* @param {string} recoveryKey
|
||||
* @return {Key}
|
||||
*/
|
||||
export function keyFromRecoveryKey(olm, keyDescription, recoveryKey) {
|
||||
const result = bs58.decode(recoveryKey.replace(/ /g, ''));
|
||||
export function keyFromRecoveryKey(keyDescription, recoveryKey, olm, platform) {
|
||||
const result = platform.encoding.base58.decode(recoveryKey.replace(/ /g, ''));
|
||||
|
||||
let parity = 0;
|
||||
for (const b of result) {
|
||||
|
@ -19,7 +19,7 @@ import {xhrRequest} from "./dom/request/xhr.js";
|
||||
import {StorageFactory} from "../../matrix/storage/idb/StorageFactory.js";
|
||||
import {SessionInfoStorage} from "../../matrix/sessioninfo/localstorage/SessionInfoStorage.js";
|
||||
import {SettingsStorage} from "./dom/SettingsStorage.js";
|
||||
import {UTF8} from "./dom/UTF8.js";
|
||||
import {Encoding} from "./utils/Encoding.js";
|
||||
import {OlmWorker} from "../../matrix/e2ee/OlmWorker.js";
|
||||
import {IDBLogger} from "../../logs/IDBLogger.js";
|
||||
import {RootView} from "./ui/RootView.js";
|
||||
@ -85,8 +85,8 @@ export class Platform {
|
||||
constructor(container, paths, cryptoExtras = null) {
|
||||
this._paths = paths;
|
||||
this._container = container;
|
||||
this.utf8 = new UTF8();
|
||||
this.logger = new IDBLogger("hydrogen_logs", this);
|
||||
this.encoding = new Encoding();
|
||||
this.clock = new Clock();
|
||||
this.history = new History();
|
||||
this.onlineStatus = new OnlineStatus();
|
||||
|
@ -14,6 +14,8 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import base64 from "../../../../lib/base64-arraybuffer/index.js";
|
||||
|
||||
// turn IE11 result into promise
|
||||
function subtleCryptoResult(promiseOrOp, method) {
|
||||
if (promiseOrOp instanceof Promise) {
|
||||
@ -302,7 +304,6 @@ function rawKeyToJwk(key) {
|
||||
};
|
||||
}
|
||||
|
||||
import base64 from "../../../../lib/base64-arraybuffer/index.js";
|
||||
|
||||
class AESLegacyCrypto {
|
||||
constructor(aesjs, crypto) {
|
||||
|
27
src/platform/web/utils/Base58.js
Normal file
27
src/platform/web/utils/Base58.js
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import bs58 from "../../../../lib/bs58/index.js";
|
||||
|
||||
export class Base58 {
|
||||
encode(buffer) {
|
||||
return bs58.encode(buffer);
|
||||
}
|
||||
|
||||
decode(str) {
|
||||
return bs58.decode(str);
|
||||
}
|
||||
}
|
37
src/platform/web/utils/Base64.js
Normal file
37
src/platform/web/utils/Base64.js
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import base64 from "../../../../lib/base64-arraybuffer/index.js";
|
||||
|
||||
export class Base64 {
|
||||
encodeUnpadded(buffer) {
|
||||
const str = base64.encode(buffer);
|
||||
const paddingIdx = str.indexOf("=");
|
||||
if (paddingIdx !== -1) {
|
||||
return str.substr(0, paddingIdx);
|
||||
} else {
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
encode(buffer) {
|
||||
return base64.encode(buffer);
|
||||
}
|
||||
|
||||
decode(str) {
|
||||
return base64.decode(str);
|
||||
}
|
||||
}
|
27
src/platform/web/utils/Encoding.js
Normal file
27
src/platform/web/utils/Encoding.js
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import {UTF8} from "../dom/UTF8.js";
|
||||
import {Base64} from "./Base64.js";
|
||||
import {Base58} from "./Base58.js";
|
||||
|
||||
export class Encoding {
|
||||
constructor() {
|
||||
this.utf8 = new UTF8();
|
||||
this.base64 = new Base64();
|
||||
this.base58 = new Base58();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user